Skip to content

Commit b57e178

Browse files
authored
both modes + inf table
1 parent 7a7eb9a commit b57e178

3 files changed

Lines changed: 324 additions & 32 deletions

File tree

tool/web-app/index.html

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<body>
1010
<header>
1111
<h1>Azure Database Selector</h1>
12-
<button id="theme-toggle" aria-label="Toggle dark mode" title="Toggle dark mode">🌙</button>
12+
<button id="theme-toggle" aria-label="Switch to dark mode" title="Switch to dark mode" tabindex="0">🌙</button>
1313
</header>
1414
<main class="two-panel-layout">
1515
<section class="left-panel">
@@ -111,35 +111,58 @@ <h2 id="form-title">Select Your Database Preferences</h2>
111111
<option value="no">No</option>
112112
</select>
113113

114-
<label for="query-complexity">Query Complexity:
115-
<span class="info-icon" tabindex="0" data-tooltip="Select the complexity level of the queries you will perform. For instance, simple queries are used for CRUD operations, while complex queries are needed for AI/ML workloads.">ℹ️</span>
116-
</label>
117-
<select id="query-complexity" name="query-complexity">
118-
<option value="simple">Simple (e.g., basic CRUD operations)</option>
119-
<option value="moderate">Moderate (e.g., joins, aggregations)</option>
120-
<option value="complex">Complex (e.g., advanced analytics, AI/ML queries)</option>
121-
</select>
114+
<button id="toggle-advanced" aria-expanded="false" type="button">Show Advanced Settings</button>
115+
<div id="advanced-settings" style="display:none;">
116+
<label for="query-complexity">Query Complexity:
117+
<button class="tooltip-icon" aria-label="More info" data-tooltip="Select the complexity level of the queries you will perform. For instance, simple queries are used for CRUD operations, while complex queries are needed for AI/ML workloads.">ℹ️</button>
118+
</label>
119+
<select id="query-complexity" name="query-complexity">
120+
<option value="simple">Simple (CRUD, Key-Value)</option>
121+
<option value="moderate">Moderate (Joins, Aggregations)</option>
122+
<option value="complex">Complex (AI/ML, Graph, Analytics)</option>
123+
</select>
122124

123-
<label for="data-retention">Data Retention Policy:
124-
<span class="info-icon" tabindex="0" data-tooltip="Specify how long you need to retain your data. For example, short-term retention is suitable for temporary logs, while long-term retention is needed for compliance data.">ℹ️</span>
125-
</label>
126-
<select id="data-retention" name="data-retention">
127-
<option value="short-term">Short-term (e.g., days or weeks)</option>
128-
<option value="medium-term">Medium-term (e.g., months)</option>
129-
<option value="long-term">Long-term (e.g., years)</option>
130-
</select>
125+
<label for="data-retention">Data Retention Policy:
126+
<button class="tooltip-icon" aria-label="More info" data-tooltip="Specify how long you need to retain your data. For example, short-term retention is suitable for temporary logs, while long-term retention is needed for compliance data.">ℹ️</button>
127+
</label>
128+
<select id="data-retention" name="data-retention">
129+
<option value="short-term">Short-term (logs, cache)</option>
130+
<option value="medium-term">Medium-term (months, analytics)</option>
131+
<option value="long-term">Long-term (compliance, archive)</option>
132+
</select>
133+
</div>
131134
<button type="submit">Get Recommendation</button>
135+
<button type="reset" id="reset-form">Reset Form</button>
132136
</form>
133137
</section>
134138
<section class="right-panel">
135-
<div id="live-summary" class="summary-card">
139+
<div id="live-summary" class="summary-card" aria-live="polite">
136140
<h3>Live Summary</h3>
137141
<ul id="summary-list"></ul>
138142
</div>
139143
<div id="recommendation-panel">
140144
<div id="loading-spinner" style="display:none;">Loading...</div>
141-
<div id="recommendation-result"></div>
145+
<div id="recommendation-result" aria-live="polite"></div>
146+
<div id="confidence-score" style="display:none;">
147+
<strong>Match Confidence:</strong> <span id="confidence-value">--</span>
148+
</div>
149+
<div id="recommendation-justification" class="justification-card" style="display:none;">
150+
<h4>Why this recommendation?</h4>
151+
<p id="justification-text"></p>
152+
</div>
153+
<div id="comparison-table" style="display:none;">
154+
<h4>Compare Options</h4>
155+
<!-- Table will be generated dynamically -->
156+
</div>
142157
<button id="export-btn" style="display:none;">Export/Share</button>
158+
<div id="feedback-section">
159+
<label for="feedback">Was this recommendation helpful?</label>
160+
<select id="feedback" name="feedback">
161+
<option value="">-- Select --</option>
162+
<option value="yes">Yes</option>
163+
<option value="no">No</option>
164+
</select>
165+
</div>
143166
</div>
144167
</section>
145168
</main>

tool/web-app/script.js

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,21 @@ document.querySelectorAll('.info-icon').forEach(icon => {
5858

5959
// --- Theme toggle logic ---
6060
const themeToggle = document.getElementById('theme-toggle');
61+
function updateThemeToggleButton() {
62+
const isDark = document.body.classList.contains('dark-mode');
63+
if (isDark) {
64+
themeToggle.innerHTML = '☀️ Light Mode';
65+
themeToggle.setAttribute('aria-label', 'Switch to light mode');
66+
themeToggle.setAttribute('title', 'Switch to light mode');
67+
} else {
68+
themeToggle.innerHTML = '🌙 Dark Mode';
69+
themeToggle.setAttribute('aria-label', 'Switch to dark mode');
70+
themeToggle.setAttribute('title', 'Switch to dark mode');
71+
}
72+
}
6173
themeToggle.addEventListener('click', () => {
6274
document.body.classList.toggle('dark-mode');
63-
const isDark = document.body.classList.contains('dark-mode');
64-
themeToggle.textContent = isDark ? '☀️' : '🌙';
75+
updateThemeToggleButton();
6576
// Add a note indicating which mode is being switched to
6677
let note = document.getElementById('theme-note');
6778
if (!note) {
@@ -70,8 +81,11 @@ themeToggle.addEventListener('click', () => {
7081
note.style.marginTop = '8px';
7182
themeToggle.parentNode.appendChild(note);
7283
}
73-
note.textContent = isDark ? 'Switched to dark mode. Click to change to light mode.' : 'Switched to light mode. Click to change to dark mode.';
84+
note.textContent = document.body.classList.contains('dark-mode')
85+
? 'Switched to dark mode. Click to change to light mode.'
86+
: 'Switched to light mode. Click to change to dark mode.';
7487
});
88+
updateThemeToggleButton();
7589

7690
// --- Preset use case autofill ---
7791
const presetMap = {
@@ -100,6 +114,20 @@ document.getElementById('preset-usecase').addEventListener('change', function ()
100114
const formFields = [
101115
'data-volume','data-type','latency','scalability','consistency','integration-needs','security','budget','use-case','backup-recovery','query-complexity','data-retention'
102116
];
117+
const summaryIcons = {
118+
'data-volume': '💾',
119+
'data-type': '📦',
120+
'latency': '⚡',
121+
'scalability': '🌍',
122+
'consistency': '🔗',
123+
'integration-needs': '🔌',
124+
'security': '🔒',
125+
'budget': '💸',
126+
'use-case': '🗄️',
127+
'backup-recovery': '🛡️',
128+
'query-complexity': '🧩',
129+
'data-retention': '⏳'
130+
};
103131
function updateSummary() {
104132
const ul = document.getElementById('summary-list');
105133
ul.innerHTML = '';
@@ -108,7 +136,8 @@ function updateSummary() {
108136
if (el) {
109137
const label = document.querySelector(`label[for="${id}"]`);
110138
const li = document.createElement('li');
111-
li.textContent = `${label ? label.childNodes[0].textContent.trim() : id}: ${el.value}`;
139+
const icon = summaryIcons[id] || '';
140+
li.innerHTML = `<span class="summary-icon">${icon}</span><span class="summary-label">${label ? label.childNodes[0].textContent.trim() : id}:</span> <span>${el.value}</span>`;
112141
ul.appendChild(li);
113142
}
114143
});
@@ -256,20 +285,75 @@ document.getElementById('advisor-form').addEventListener('submit', async (event)
256285
</div>
257286
`;
258287
document.getElementById('export-btn').style.display = 'inline-block';
288+
showJustification(justification, confidence);
259289
} catch (error) {
260290
document.getElementById('recommendation-result').innerHTML = `<span class="error">Error: ${error.message}</span>`;
261291
} finally {
262292
document.getElementById('loading-spinner').style.display = 'none';
263293
}
264294
});
265295

266-
// --- Export/share functionality ---
267-
document.getElementById('export-btn').addEventListener('click', function () {
268-
const summary = document.getElementById('live-summary').innerText;
269-
const recommendation = document.getElementById('recommendation-result').innerText;
270-
const blob = new Blob([summary + '\n\n' + recommendation], { type: 'text/plain' });
271-
const link = document.createElement('a');
272-
link.href = URL.createObjectURL(blob);
273-
link.download = 'azure-db-recommendation.txt';
274-
link.click();
296+
// --- Show Justification and Confidence Score ---
297+
function showJustification(justification, confidence) {
298+
const justDiv = document.getElementById('recommendation-justification');
299+
const confDiv = document.getElementById('confidence-score');
300+
document.getElementById('justification-text').textContent = justification;
301+
justDiv.style.display = 'block';
302+
document.getElementById('confidence-value').textContent = confidence + '%';
303+
confDiv.style.display = 'block';
304+
}
305+
306+
// --- Reset Button Logic ---
307+
document.getElementById('reset-form').addEventListener('click', function () {
308+
setTimeout(() => {
309+
updateSummary();
310+
document.getElementById('recommendation-result').innerHTML = '';
311+
document.getElementById('recommendation-justification').style.display = 'none';
312+
document.getElementById('confidence-score').style.display = 'none';
313+
document.getElementById('comparison-table').style.display = 'none';
314+
}, 10);
315+
});
316+
317+
// --- Feedback Widget ---
318+
document.getElementById('feedback').addEventListener('change', function () {
319+
if (this.value === 'yes') {
320+
this.style.background = '#c8e6c9';
321+
} else if (this.value === 'no') {
322+
this.style.background = '#ffcdd2';
323+
} else {
324+
this.style.background = '';
325+
}
326+
});
327+
328+
// --- Accessibility: Focus on recommendation result after submit ---
329+
function focusRecommendation() {
330+
const rec = document.getElementById('recommendation-result');
331+
if (rec) rec.setAttribute('tabindex', '-1');
332+
rec && rec.focus && rec.focus();
333+
}
334+
335+
// --- Comparison Table (stub, to be filled with real data if needed) ---
336+
function showComparisonTable(options) {
337+
const tableDiv = document.getElementById('comparison-table');
338+
if (!options || !options.length) {
339+
tableDiv.style.display = 'none';
340+
return;
341+
}
342+
let html = '<table><tr><th>Option</th><th>Strengths</th><th>Weaknesses</th></tr>';
343+
options.forEach(opt => {
344+
html += `<tr><td>${opt.name}</td><td>${opt.strengths}</td><td>${opt.weaknesses}</td></tr>`;
345+
});
346+
html += '</table>';
347+
tableDiv.innerHTML = '<h4>Compare Options</h4>' + html;
348+
tableDiv.style.display = 'block';
349+
}
350+
351+
// --- Advanced Settings Toggle ---
352+
const advToggle = document.getElementById('toggle-advanced');
353+
const advSettings = document.getElementById('advanced-settings');
354+
advToggle.addEventListener('click', function () {
355+
const expanded = advToggle.getAttribute('aria-expanded') === 'true';
356+
advToggle.setAttribute('aria-expanded', !expanded);
357+
advSettings.style.display = expanded ? 'none' : 'block';
358+
advToggle.textContent = expanded ? 'Show Advanced Settings' : 'Hide Advanced Settings';
275359
});

0 commit comments

Comments
 (0)