Move the port inspector onto device pages
Lint / JS (eslint) (push) Successful in 1m14s
Lint / Python (flake8) (push) Successful in 2m12s
Lint / Notify on failure (push) Skipped
Lint / Deploy (push) Skipped
Security / Python Security (bandit) (push) Successful in 1m3s
Test / Python Tests (pytest) (push) Successful in 1m11s
Lint / Python (flake8) (pull_request) Successful in 1m1s
Lint / JS (eslint) (pull_request) Successful in 10s
Lint / Notify on failure (pull_request) Skipped
Lint / Deploy (pull_request) Skipped
Security / Python Security (bandit) (pull_request) Successful in 56s
Test / Python Tests (pytest) (pull_request) Successful in 1m5s

Replace the all-switches Inspector page with a per-device front panel,
port table and detail panel. /inspector now redirects to the dashboard,
and /device/<name>#port-<n> links directly to a port.

Restore neighbor names after UniFi's LLDP change: read local_port_idx
and resolve neighbors by MAC using Prometheus NIC data, UniFi devices
and the wired client table. This also brings back Run Diagnostics on
server ports, which depends on a named neighbor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 10:11:11 -05:00
co-authored by Claude Opus 5.5
parent e32499b7f6
commit bdcfb76c25
13 changed files with 484 additions and 226 deletions
+23
View File
@@ -1149,3 +1149,26 @@ a.device-link:hover { color: var(--text-accent); border-bottom-color: current
/* Scroll inside the wrapper rather than squeezing every column to a few letters */
#events-table { min-width: 760px; }
}
/* ── Port inspector on the device page ────────────────────────────── */
.device-inspector { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 14px 16px; align-items: start; }
.device-chassis { grid-column: 1; min-width: 0; }
.device-port-table { grid-column: 1; min-width: 0; }
.device-inspector .inspector-panel { grid-column: 2; grid-row: 1 / span 2; position: sticky; top: 70px; }
.device-inspector:not(.has-chassis) .inspector-panel,
.device-inspector:not(.has-chassis) .device-chassis { display: none; }
tr.device-row[data-port-idx] { cursor: pointer; }
tr.device-row.is-selected { background: var(--bg-tertiary); box-shadow: inset 3px 0 0 var(--terminal-cyan, #0ff); }
.device-chassis .switch-port-block,
.device-chassis .switch-port-block.sfp-port,
.device-chassis .switch-port-block.sfp-block { width: 50px; height: 50px; font-size: .68em; gap: 2px; }
.device-chassis .port-num { font-size: 1.2em; }
.device-chassis .port-speed { font-size: .85em; }
.device-chassis .port-lldp { font-size: .8em; max-width: 46px; margin: 0; }
@media (max-width: 900px) {
.device-inspector { grid-template-columns: minmax(0, 1fr); }
.device-inspector .inspector-panel { grid-column: 1; grid-row: auto; position: static; }
.device-inspector .inspector-panel.open { width: 100%; }
.device-inspector .inspector-panel-inner { width: 100%; max-height: none; }
.device-chassis .chassis-ear-l, .device-chassis .chassis-ear-r { display: none; }
}