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:
@@ -724,20 +724,6 @@
|
||||
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::after { content: ' ...'; animation: blink 1s step-end infinite; }
|
||||
|
||||
+43
-38
@@ -270,44 +270,49 @@
|
||||
<div class="g-section-header">
|
||||
<h2 class="g-section-title">UniFi Devices</h2>
|
||||
</div>
|
||||
<div class="lt-table-wrap">
|
||||
<table class="lt-table" id="unifi-table">
|
||||
<caption class="lt-sr-only">UniFi network devices</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Model</th>
|
||||
<th>IP</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for d in snapshot.unifi %}
|
||||
<tr class="{% if not d.connected %}row-critical{% endif %}">
|
||||
<td>
|
||||
<span class="dot-{{ 'up' if d.connected else 'down' }}"></span>
|
||||
{{ 'ONLINE' if d.connected else 'OFFLINE' }}
|
||||
</td>
|
||||
<td><strong>{{ d.name }}</strong></td>
|
||||
<td>{{ d.type }}</td>
|
||||
<td>{{ d.model }}</td>
|
||||
<td>{{ d.ip }}</td>
|
||||
<td>
|
||||
{% if not d.connected %}
|
||||
<button class="lt-btn lt-btn-ghost lt-btn-sm btn-suppress"
|
||||
data-sup-type="unifi_device"
|
||||
data-sup-name="{{ d.name }}"
|
||||
data-sup-detail="">
|
||||
🔕 Suppress
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span>
|
||||
<span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Device Inventory</div>
|
||||
<div class="lt-table-wrap">
|
||||
<table class="lt-table" id="unifi-table">
|
||||
<caption class="lt-sr-only">UniFi network devices</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Model</th>
|
||||
<th>IP</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for d in snapshot.unifi %}
|
||||
<tr class="{% if not d.connected %}row-critical{% endif %}">
|
||||
<td>
|
||||
<span class="dot-{{ 'up' if d.connected else 'down' }}"></span>
|
||||
{{ 'ONLINE' if d.connected else 'OFFLINE' }}
|
||||
</td>
|
||||
<td><strong>{{ d.name }}</strong></td>
|
||||
<td>{{ d.type }}</td>
|
||||
<td>{{ d.model }}</td>
|
||||
<td>{{ d.ip }}</td>
|
||||
<td>
|
||||
{% if not d.connected %}
|
||||
<button class="lt-btn lt-btn-ghost lt-btn-sm btn-suppress"
|
||||
data-sup-type="unifi_device"
|
||||
data-sup-name="{{ d.name }}"
|
||||
data-sup-detail="">
|
||||
🔕 Suppress
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
+26
-4
@@ -13,6 +13,19 @@
|
||||
</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 class="link-loading">Loading link statistics</div>
|
||||
</div>
|
||||
@@ -439,10 +452,6 @@ function renderLinks(data) {
|
||||
const parts = [];
|
||||
|
||||
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">');
|
||||
|
||||
for (const [hostname, ifaces] of Object.entries(hosts)) {
|
||||
@@ -471,6 +480,17 @@ function renderLinks(data) {
|
||||
parts.push('</div>');
|
||||
document.getElementById('links-container').innerHTML = parts.join('');
|
||||
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() {
|
||||
@@ -552,5 +572,7 @@ document.addEventListener('click', e => {
|
||||
if (e.target.closest('[data-action="collapse-all"]')) { collapseAll(); return; }
|
||||
if (e.target.closest('[data-action="expand-all"]')) { expandAll(); return; }
|
||||
});
|
||||
|
||||
document.getElementById('links-search')?.addEventListener('input', applyLinksSearch);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
+18
-11
@@ -184,20 +184,27 @@
|
||||
<div class="g-section-header">
|
||||
<h2 class="g-section-title">Available Targets</h2>
|
||||
</div>
|
||||
<div class="targets-grid">
|
||||
{% for name, host in snapshot.hosts.items() %}
|
||||
<div class="target-card">
|
||||
<div class="target-name">{{ name }}</div>
|
||||
<div class="target-type">{{ 'Proxmox Host (prometheus)' if host.source == 'prometheus' else 'Ping-only host' }}</div>
|
||||
{% if host.interfaces %}
|
||||
<div class="target-ifaces">
|
||||
{% for iface in host.interfaces.keys() | sort %}
|
||||
<code class="iface-chip">{{ iface }}</code>
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span>
|
||||
<span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Host & Interface Reference</div>
|
||||
<div style="padding:12px 14px">
|
||||
<div class="targets-grid">
|
||||
{% for name, host in snapshot.hosts.items() %}
|
||||
<div class="target-card">
|
||||
<div class="target-name">{{ name }}</div>
|
||||
<div class="target-type">{{ 'Proxmox Host (prometheus)' if host.source == 'prometheus' else 'Ping-only host' }}</div>
|
||||
{% if host.interfaces %}
|
||||
<div class="target-ifaces">
|
||||
{% for iface in host.interfaces.keys() | sort %}
|
||||
<code class="iface-chip">{{ iface }}</code>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user