feat: sidebar device grouping when multiple sources configured (task-16)
- Replace renderSidebar to group sessions by deviceName when _sources.length > 1 - Render sidebar-device-header h4 elements before each device's sessions - When single source configured, render flat list with no headers - Click handlers now pass sourceUrl to openSession - Add tests: groups with header when multiple sources, flat when single source 🤖 Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
This commit is contained in:
+24
-3
@@ -561,14 +561,35 @@ function renderSidebar(sessions, currentSession) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
list.innerHTML = visible.map((session) => buildSidebarHTML(session, currentSession)).join('');
|
let html = '';
|
||||||
|
|
||||||
// Bind click handlers on each sidebar item
|
if (_sources.length > 1) {
|
||||||
|
// Group sessions by deviceName when multiple sources configured
|
||||||
|
const groups = new Map();
|
||||||
|
for (const session of visible) {
|
||||||
|
const deviceName = session.deviceName || 'Unknown';
|
||||||
|
if (!groups.has(deviceName)) groups.set(deviceName, []);
|
||||||
|
groups.get(deviceName).push(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [deviceName, deviceSessions] of groups) {
|
||||||
|
html += `<h4 class="sidebar-device-header">${escapeHtml(deviceName)}</h4>`;
|
||||||
|
html += deviceSessions.map((session) => buildSidebarHTML(session, currentSession)).join('');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Single source: flat list with no device headers
|
||||||
|
html = visible.map((session) => buildSidebarHTML(session, currentSession)).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
list.innerHTML = html;
|
||||||
|
|
||||||
|
// Bind click handlers on each sidebar item, passing sourceUrl
|
||||||
if (typeof list.querySelectorAll === 'function') {
|
if (typeof list.querySelectorAll === 'function') {
|
||||||
list.querySelectorAll('.sidebar-item').forEach((item) => {
|
list.querySelectorAll('.sidebar-item').forEach((item) => {
|
||||||
const name = item.dataset.session;
|
const name = item.dataset.session;
|
||||||
|
const sourceUrl = item.dataset.sourceUrl || '';
|
||||||
on(item, 'click', () => {
|
on(item, 'click', () => {
|
||||||
if (name !== currentSession) openSession(name);
|
if (name !== currentSession) openSession(name, { sourceUrl });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2666,4 +2666,75 @@ test('saveGridViewMode stores to localStorage when scope is local', () => {
|
|||||||
app._setGridViewMode('flat');
|
app._setGridViewMode('flat');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- renderSidebar device grouping (task-16) ---
|
||||||
|
|
||||||
|
test('renderSidebar groups sessions by device with sidebar-device-header when multiple sources configured', () => {
|
||||||
|
let capturedHTML = '';
|
||||||
|
const mockList = {
|
||||||
|
get innerHTML() { return capturedHTML; },
|
||||||
|
set innerHTML(v) { capturedHTML = v; },
|
||||||
|
querySelectorAll: () => [],
|
||||||
|
};
|
||||||
|
const origGetById = globalThis.document.getElementById;
|
||||||
|
globalThis.document.getElementById = (id) => {
|
||||||
|
if (id === 'sidebar-list') return mockList;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up multiple sources
|
||||||
|
app._setSources([
|
||||||
|
{ url: '', name: 'Laptop', type: 'local', status: 'authenticated', backoffMs: 2000 },
|
||||||
|
{ url: 'https://remote.example.com', name: 'Server', type: 'remote', status: 'authenticated', backoffMs: 2000 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
app._setViewMode('fullscreen');
|
||||||
|
const sessions = [
|
||||||
|
{ name: 'alpha', deviceName: 'Laptop', sourceUrl: '', sessionKey: '::alpha', snapshot: '', bell: { unseen_count: 0 } },
|
||||||
|
{ name: 'beta', deviceName: 'Server', sourceUrl: 'https://remote.example.com', sessionKey: 'https://remote.example.com::beta', snapshot: '', bell: { unseen_count: 0 } },
|
||||||
|
];
|
||||||
|
app.renderSidebar(sessions, null);
|
||||||
|
|
||||||
|
assert.ok(capturedHTML.includes('sidebar-device-header'), 'sidebar HTML should contain sidebar-device-header elements when multiple sources');
|
||||||
|
assert.ok(capturedHTML.includes('Laptop'), 'sidebar HTML should contain device name "Laptop"');
|
||||||
|
assert.ok(capturedHTML.includes('Server'), 'sidebar HTML should contain device name "Server"');
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
app._setSources([]);
|
||||||
|
globalThis.document.getElementById = origGetById;
|
||||||
|
app._setViewMode('grid');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('renderSidebar does NOT group when only one source configured', () => {
|
||||||
|
let capturedHTML = '';
|
||||||
|
const mockList = {
|
||||||
|
get innerHTML() { return capturedHTML; },
|
||||||
|
set innerHTML(v) { capturedHTML = v; },
|
||||||
|
querySelectorAll: () => [],
|
||||||
|
};
|
||||||
|
const origGetById = globalThis.document.getElementById;
|
||||||
|
globalThis.document.getElementById = (id) => {
|
||||||
|
if (id === 'sidebar-list') return mockList;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up single source
|
||||||
|
app._setSources([
|
||||||
|
{ url: '', name: 'Laptop', type: 'local', status: 'authenticated', backoffMs: 2000 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
app._setViewMode('fullscreen');
|
||||||
|
const sessions = [
|
||||||
|
{ name: 'alpha', deviceName: 'Laptop', sourceUrl: '', sessionKey: '::alpha', snapshot: '', bell: { unseen_count: 0 } },
|
||||||
|
{ name: 'beta', deviceName: 'Laptop', sourceUrl: '', sessionKey: '::beta', snapshot: '', bell: { unseen_count: 0 } },
|
||||||
|
];
|
||||||
|
app.renderSidebar(sessions, null);
|
||||||
|
|
||||||
|
assert.ok(!capturedHTML.includes('sidebar-device-header'), 'sidebar HTML should NOT contain sidebar-device-header when only one source');
|
||||||
|
assert.ok(capturedHTML.includes('sidebar-item'), 'sidebar HTML should still contain sidebar-item elements');
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
app._setSources([]);
|
||||||
|
globalThis.document.getElementById = origGetById;
|
||||||
|
app._setViewMode('grid');
|
||||||
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user