@@ -349,7 +349,7 @@ function renderUnifiSwitches(unifiSwitches, dataUpdated) {
return `
return `
< div class = "link-host-panel" id = "panel-${CSS.escape(swName)}" >
< div class = "link-host-panel" id = "panel-${CSS.escape(swName)}" >
< div class = "link-host-title" data-action = "toggle-panel" >
< div class = "link-host-title" data-action = "toggle-panel" role = "button" tabindex = "0" aria-expanded = "true" >
< span class = "link-host-name" > ${escHtml(swName)}< / span >
< span class = "link-host-name" > ${escHtml(swName)}< / span >
< span class = "link-host-ip" > ${escHtml(sw.ip || '')}< / span >
< span class = "link-host-ip" > ${escHtml(sw.ip || '')}< / span >
< span class = "link-host-upd" > ${escHtml(sw.model || '')}${updStr ? ' · ' + updStr : ''}${poeLoad}< / span >
< span class = "link-host-upd" > ${escHtml(sw.model || '')}${updStr ? ' · ' + updStr : ''}${poeLoad}< / span >
@@ -366,8 +366,11 @@ function renderUnifiSwitches(unifiSwitches, dataUpdated) {
// ── Panel collapse / expand ───────────────────────────────────────
// ── Panel collapse / expand ───────────────────────────────────────
function togglePanel(panel) {
function togglePanel(panel) {
panel.classList.toggle('collapsed');
panel.classList.toggle('collapsed');
const btn = panel.querySelector('.panel-toggle ');
const isCollapsed = panel.classList.contains('collapsed ');
if (btn) btn.textContent = panel.classList.contains('collapsed') ? '[+]' : '[– ]' ;
const btn = panel.querySelector('.panel-toggle') ;
const title = panel.querySelector('.link-host-title');
if (btn) btn.textContent = isCollapsed ? '[+]' : '[– ]';
if (title) title.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');
const id = panel.id;
const id = panel.id;
if (id) {
if (id) {
const collapsed = JSON.parse(sessionStorage.getItem('linksCollapsed') || '{}');
const collapsed = JSON.parse(sessionStorage.getItem('linksCollapsed') || '{}');
@@ -383,8 +386,10 @@ function restoreCollapseState() {
if (!panel) continue;
if (!panel) continue;
if (isCollapsed) {
if (isCollapsed) {
panel.classList.add('collapsed');
panel.classList.add('collapsed');
const btn = panel.querySelector('.panel-toggle');
const btn = panel.querySelector('.panel-toggle');
if (btn) btn.textContent = '[+]' ;
const title = panel.querySelector('.link-host-title') ;
if (btn) btn.textContent = '[+]';
if (title) title.setAttribute('aria-expanded', 'false');
}
}
}
}
}
}
@@ -463,12 +468,12 @@ function renderLinks(data) {
const sample = Object.values(ifaces)[0] || {};
const sample = Object.values(ifaces)[0] || {};
const ip = sample.host_ip || '';
const ip = sample.host_ip || '';
const updStr = data.updated
const updStr = data.updated
? new Date(data.updated.replace(' UTC', 'Z').replace(' ', 'T' )).toLocaleTimeString()
? new Date(_toIso( data.updated)).toLocaleTimeString()
: '';
: '';
parts.push(`
parts.push(`
< div class = "link-host-panel" id = "panel-${CSS.escape(hostname)}" >
< div class = "link-host-panel" id = "panel-${CSS.escape(hostname)}" >
< div class = "link-host-title" data-action = "toggle-panel" >
< div class = "link-host-title" data-action = "toggle-panel" role = "button" tabindex = "0" aria-expanded = "true" >
< span class = "link-host-name" > ${escHtml(hostname)}< / span >
< span class = "link-host-name" > ${escHtml(hostname)}< / span >
< span class = "link-host-ip" > ${escHtml(ip)}< / span >
< span class = "link-host-ip" > ${escHtml(ip)}< / span >
< span class = "link-host-upd" > ${updStr}< / span >
< span class = "link-host-upd" > ${updStr}< / span >
@@ -498,8 +503,10 @@ function applyLinksSearch() {
function collapseAll() {
function collapseAll() {
document.querySelectorAll('.link-host-panel').forEach(p => {
document.querySelectorAll('.link-host-panel').forEach(p => {
p.classList.add('collapsed');
p.classList.add('collapsed');
const btn = p.querySelector('.panel-toggle');
const btn = p.querySelector('.panel-toggle');
if (btn) btn.textContent = '[+]' ;
const title = p.querySelector('.link-host-title') ;
if (btn) btn.textContent = '[+]';
if (title) title.setAttribute('aria-expanded', 'false');
});
});
sessionStorage.setItem('linksCollapsed', JSON.stringify(
sessionStorage.setItem('linksCollapsed', JSON.stringify(
Object.fromEntries([...document.querySelectorAll('.link-host-panel')].map(p => [p.id, true]))
Object.fromEntries([...document.querySelectorAll('.link-host-panel')].map(p => [p.id, true]))
@@ -509,8 +516,10 @@ function collapseAll() {
function expandAll() {
function expandAll() {
document.querySelectorAll('.link-host-panel').forEach(p => {
document.querySelectorAll('.link-host-panel').forEach(p => {
p.classList.remove('collapsed');
p.classList.remove('collapsed');
const btn = p.querySelector('.panel-toggle');
const btn = p.querySelector('.panel-toggle');
if (btn) btn.textContent = '[– ]' ;
const title = p.querySelector('.link-host-title') ;
if (btn) btn.textContent = '[– ]';
if (title) title.setAttribute('aria-expanded', 'true');
});
});
sessionStorage.setItem('linksCollapsed', '{}');
sessionStorage.setItem('linksCollapsed', '{}');
}
}
@@ -575,6 +584,12 @@ document.addEventListener('click', e => {
if (e.target.closest('[data-action="expand-all"]')) { expandAll(); return; }
if (e.target.closest('[data-action="expand-all"]')) { expandAll(); return; }
});
});
document.addEventListener('keydown', e => {
if (e.key !== 'Enter' & & e.key !== ' ') return;
const toggleTitle = e.target.closest('[data-action="toggle-panel"]');
if (toggleTitle) { e.preventDefault(); togglePanel(toggleTitle.closest('.link-host-panel')); }
});
document.getElementById('links-search')?.addEventListener('input', applyLinksSearch);
document.getElementById('links-search')?.addEventListener('input', applyLinksSearch);
< / script >
< / script >
{% endblock %}
{% endblock %}