TDS polish: lt-frame tables, links search toolbar, dead CSS cleanup

- index.html: wrap UniFi devices table in lt-frame with section header
- links.html: add static lt-toolbar with lt-search filter and collapse
  controls above the dynamic container; remove collapse bar from
  renderLinks() since it's now static; add applyLinksSearch() to
  filter host/switch panels by name as user types
- suppressions.html: wrap Available Targets section in lt-frame
- style.css: remove unused .link-summary-panel and related rules
  (replaced by lt-stats-grid in previous commit)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-01 17:39:11 -04:00
parent c3aa3bea6f
commit d165d1fd10
4 changed files with 87 additions and 67 deletions
-14
View File
@@ -724,20 +724,6 @@
background: linear-gradient(90deg, transparent, var(--cyan), transparent); background: linear-gradient(90deg, transparent, var(--cyan), transparent);
} }
/* Link health summary */
.link-summary-panel {
background: var(--bg2);
border: 1px solid var(--border-color);
padding: 12px 16px;
margin-bottom: 12px;
}
.link-summary-panel.link-summary-has-alerts { border-color: var(--amber); }
.link-summary-grid { display: flex; flex-wrap: wrap; gap: 20px; align-items: flex-end; }
.link-summary-stat { min-width: 80px; }
.link-summary-stat.lss-alert .lss-label { color: var(--amber); }
.lss-label { display: block; font-size: .62em; color: var(--text-muted); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 2px; }
.lss-value { font-size: 1.2em; font-weight: bold; color: var(--text); }
.lss-sub { font-size: .7em; color: var(--text-muted); font-weight: normal; }
.link-loading { padding: 20px; text-align: center; color: var(--text-muted); font-size: .8em; } .link-loading { padding: 20px; text-align: center; color: var(--text-muted); font-size: .8em; }
.link-loading::after { content: ' ...'; animation: blink 1s step-end infinite; } .link-loading::after { content: ' ...'; animation: blink 1s step-end infinite; }
+5
View File
@@ -270,6 +270,10 @@
<div class="g-section-header"> <div class="g-section-header">
<h2 class="g-section-title">UniFi Devices</h2> <h2 class="g-section-title">UniFi Devices</h2>
</div> </div>
<div class="lt-frame">
<span class="lt-frame-bl">&#x255A;</span>
<span class="lt-frame-br">&#x255D;</span>
<div class="lt-section-header">Device Inventory</div>
<div class="lt-table-wrap"> <div class="lt-table-wrap">
<table class="lt-table" id="unifi-table"> <table class="lt-table" id="unifi-table">
<caption class="lt-sr-only">UniFi network devices</caption> <caption class="lt-sr-only">UniFi network devices</caption>
@@ -309,6 +313,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</section> </section>
{% endif %} {% endif %}
+26 -4
View File
@@ -13,6 +13,19 @@
</div> </div>
</div> </div>
<div class="lt-toolbar" id="links-toolbar" style="display:none">
<div class="lt-toolbar-left">
<div class="lt-search">
<input type="search" class="lt-input lt-search-input" id="links-search"
placeholder="Filter by host or switch name…" autocomplete="off">
</div>
</div>
<div class="lt-toolbar-right">
<button class="lt-btn lt-btn-ghost lt-btn-sm" data-action="collapse-all">Collapse All</button>
<button class="lt-btn lt-btn-ghost lt-btn-sm" data-action="expand-all">Expand All</button>
</div>
</div>
<div id="links-container"> <div id="links-container">
<div class="link-loading">Loading link statistics</div> <div class="link-loading">Loading link statistics</div>
</div> </div>
@@ -439,10 +452,6 @@ function renderLinks(data) {
const parts = []; const parts = [];
parts.push(buildLinkSummary(hosts, unifiSwitches)); parts.push(buildLinkSummary(hosts, unifiSwitches));
parts.push(`<div class="link-collapse-bar">
<button class="lt-btn lt-btn-ghost lt-btn-sm" data-action="collapse-all">Collapse All</button>
<button class="lt-btn lt-btn-ghost lt-btn-sm" data-action="expand-all">Expand All</button>
</div>`);
parts.push('<div class="link-host-list">'); parts.push('<div class="link-host-list">');
for (const [hostname, ifaces] of Object.entries(hosts)) { for (const [hostname, ifaces] of Object.entries(hosts)) {
@@ -471,6 +480,17 @@ function renderLinks(data) {
parts.push('</div>'); parts.push('</div>');
document.getElementById('links-container').innerHTML = parts.join(''); document.getElementById('links-container').innerHTML = parts.join('');
restoreCollapseState(); restoreCollapseState();
document.getElementById('links-toolbar').style.display = '';
applyLinksSearch();
}
// ── Host/switch search filter ─────────────────────────────────────
function applyLinksSearch() {
const q = (document.getElementById('links-search')?.value || '').trim().toLowerCase();
document.querySelectorAll('.link-host-panel').forEach(panel => {
const text = (panel.querySelector('.link-host-name')?.textContent || '').toLowerCase();
panel.style.display = (!q || text.includes(q)) ? '' : 'none';
});
} }
function collapseAll() { function collapseAll() {
@@ -552,5 +572,7 @@ document.addEventListener('click', e => {
if (e.target.closest('[data-action="collapse-all"]')) { collapseAll(); return; } if (e.target.closest('[data-action="collapse-all"]')) { collapseAll(); return; }
if (e.target.closest('[data-action="expand-all"]')) { expandAll(); return; } if (e.target.closest('[data-action="expand-all"]')) { expandAll(); return; }
}); });
document.getElementById('links-search')?.addEventListener('input', applyLinksSearch);
</script> </script>
{% endblock %} {% endblock %}
+7
View File
@@ -184,6 +184,11 @@
<div class="g-section-header"> <div class="g-section-header">
<h2 class="g-section-title">Available Targets</h2> <h2 class="g-section-title">Available Targets</h2>
</div> </div>
<div class="lt-frame">
<span class="lt-frame-bl">&#x255A;</span>
<span class="lt-frame-br">&#x255D;</span>
<div class="lt-section-header">Host &amp; Interface Reference</div>
<div style="padding:12px 14px">
<div class="targets-grid"> <div class="targets-grid">
{% for name, host in snapshot.hosts.items() %} {% for name, host in snapshot.hosts.items() %}
<div class="target-card"> <div class="target-card">
@@ -199,6 +204,8 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div>
</div>
</section> </section>
{% endblock %} {% endblock %}