The dashboard's hand-drawn "Network Topology" section was out of date. This replaces it with a new /topology page that shows the network as the switches report it right now. It leads with what needs a look; each device is a card with its real faceplate or chassis, and each physical cable leaves the exact port it is plugged into.
This is part 1 of 2. Part 2 adds the power map: outlet feed lines and editable assignments.
What's on the page
What needs a look, listed above the diagram:
Covers devices down, degraded or alerting; cables down or last seen elsewhere; ports named after the wrong device; and cables with errors.
Click an entry to zoom to it and open its details. A missing device is one entry that includes where it was last seen.
With nothing to report, it says all clear.
Problems are loud, healthy is quiet:
Problem cables glow and are always drawn, whatever the filters.
Problem cards get a red or amber border, plus an alert ring and count.
Healthy cables are drawn muted.
A card per device, all the same height:
Name and state.
UniFi gear shows its real faceplate cropped to the ports. Servers show their cutsheet Front drawing and a socket per physical NIC, with unused NICs dimmed.
Layout:
The internet, modem and gateway sit side by side along the top.
Below them is a row per hop, with unknown devices beside the gear on their switch.
Servers go along the bottom.
Cables run like cable management:
Each cable leaves the card edge right at its port, with a short tail to the port.
It drops into the tray above the row it goes to, runs along a lane of its own (10G on the upper lanes), and drops into its socket.
Cables never lie on top of each other, and crossings are square.
Less by default:
Each server's slower second cable (its 1G management link) is hidden while healthy, under the "Server 1G links" toggle.
Each switch's unknown devices are one card with one bundled cable; click it to open them.
Power gear is off until part 2 gives it outlet feeds.
One line per physical cable:
A switch-to-switch cable is reported from both ends; it is merged via cable_peer, the LLDP port ID, reverse LLDP, or the device's single uplink.
Colour shows the medium (DAC, multimode fibre, provider fibre, generic SFP+ module, copper) and thickness shows the speed.
A down cable is dashed red. A device with no live cable is drawn on its last seen port (from known_uplinks), dotted red.
Port-name mismatch ⚠: flags a port named after a different device than the one plugged in. "Port N", "SFP+ N", "Uplink" and "Downlink to X" with X on the far end never flag.
Interaction:
Click a card for the device page, or a faceplate port for #port-N.
Click a cable for its details: both ends, speed, medium and module, rates and utilisation, errors and drops, and the cutsheet record. On phones the panel is a bottom sheet.
Hover or focus a device to trace its path to the internet.
Drag, wheel or pinch to pan and zoom. Fit and + - 0 keys.
Filters are remembered per browser.
Refreshes every 30 s and keeps the view.
Code
topology.py: new. Pure build_graph(...) returning {nodes, links, warnings, updated}.
app.py:
GET /topology and GET /api/topology (auth).
_physical_interfaces moved to devices.physical_interfaces.
monitor.py: link_stats.host_macs (MAC to host NIC), returned by _resolve_neighbors. Part 2 uses it to match outlets named by MAC.
static/topology.js: problem summary, cards, layout, tray and lane routing, grouping, pan and zoom. Also templates/topology.html and topology CSS.
Nav link, drawer link and command-palette entry.
Removed: the dashboard diagram (index.html), updateTopology and the dead modem hooks in app.js, the topo-* CSS. The pulse-down keyframe is kept and renamed, because the critical chip uses it.
README: a new Topology section, gallery image and file layout.
Tests
tests/test_topology.py (35 tests) covers:
pair dedupe and far-port resolution
orientation and rates
medium
the WAN chain, with and without a modem
dual-homed hosts
IP-only targets as stubs
cutsheet chassis
stubs
mismatch rules
ghosts
depth
power kinds
alerts and suppression
cutsheet labels
the empty state
test_app.py:
auth on both routes
script order
API shape
cutsheet failure
suppressed alerts not drawn
dashboard no longer has the diagram
page title
test_monitor.py: host_macs holds the physical NIC.
Results: 456 passed; flake8 and bandit are clean; eslint is unchanged at 21 pre-existing warnings; no em or en dashes.
Screenshots
These come from prod-shaped data with addresses, MACs, serials and household port names replaced. 01 to 03 show the real state: monitor-01 is degraded because enp3s0 is waiting on a cable. The problems in 04 to 12 are simulated: pbs unplugged, a down cable, a port still named "Large1 Management", and alerts.
The dashboard's hand-drawn "Network Topology" section was out of date. This replaces it with a new **/topology** page that shows the network as the switches report it right now. It leads with what needs a look; each device is a card with its real faceplate or chassis, and each physical cable leaves the exact port it is plugged into.
This is part 1 of 2. Part 2 adds the power map: outlet feed lines and editable assignments.
## What's on the page
- **What needs a look**, listed above the diagram:
- Covers devices down, degraded or alerting; cables down or last seen elsewhere; ports named after the wrong device; and cables with errors.
- Click an entry to zoom to it and open its details. A missing device is one entry that includes where it was last seen.
- With nothing to report, it says all clear.
- **Problems are loud, healthy is quiet**:
- Problem cables glow and are always drawn, whatever the filters.
- Problem cards get a red or amber border, plus an alert ring and count.
- Healthy cables are drawn muted.
- **A card per device**, all the same height:
- Name and state.
- UniFi gear shows its real faceplate cropped to the ports. Servers show their cutsheet Front drawing and a socket per physical NIC, with unused NICs dimmed.
- **Layout**:
- The internet, modem and gateway sit side by side along the top.
- Below them is a row per hop, with unknown devices beside the gear on their switch.
- Servers go along the bottom.
- **Cables run like cable management**:
- Each cable leaves the card edge right at its port, with a short tail to the port.
- It drops into the tray above the row it goes to, runs along a lane of its own (10G on the upper lanes), and drops into its socket.
- Cables never lie on top of each other, and crossings are square.
- **Less by default**:
- Each server's slower second cable (its 1G management link) is hidden while healthy, under the "Server 1G links" toggle.
- Each switch's unknown devices are one card with one bundled cable; click it to open them.
- Power gear is off until part 2 gives it outlet feeds.
- **One line per physical cable**:
- A switch-to-switch cable is reported from both ends; it is merged via `cable_peer`, the LLDP port ID, reverse LLDP, or the device's single uplink.
- Colour shows the medium (DAC, multimode fibre, provider fibre, generic SFP+ module, copper) and thickness shows the speed.
- A down cable is dashed red. A device with no live cable is drawn on its **last seen** port (from `known_uplinks`), dotted red.
- **Port-name mismatch ⚠**: flags a port named after a different device than the one plugged in. "Port N", "SFP+ N", "Uplink" and "Downlink to X" with X on the far end never flag.
- **Interaction**:
- Click a card for the device page, or a faceplate port for `#port-N`.
- Click a cable for its details: both ends, speed, medium and module, rates and utilisation, errors and drops, and the cutsheet record. On phones the panel is a bottom sheet.
- Hover or focus a device to trace its path to the internet.
- Drag, wheel or pinch to pan and zoom. Fit and `+ - 0` keys.
- Filters are remembered per browser.
- Refreshes every 30 s and keeps the view.
## Code
- `topology.py`: new. Pure `build_graph(...)` returning `{nodes, links, warnings, updated}`.
- `app.py`:
- `GET /topology` and `GET /api/topology` (auth).
- `_physical_interfaces` moved to `devices.physical_interfaces`.
- `monitor.py`: `link_stats.host_macs` (MAC to host NIC), returned by `_resolve_neighbors`. Part 2 uses it to match outlets named by MAC.
- `static/faceplates.js`: `faceplatePortAnchor(spec, idx)`.
- `static/topology.js`: problem summary, cards, layout, tray and lane routing, grouping, pan and zoom. Also `templates/topology.html` and topology CSS.
- Nav link, drawer link and command-palette entry.
- **Removed**: the dashboard diagram (index.html), `updateTopology` and the dead modem hooks in app.js, the `topo-*` CSS. The `pulse-down` keyframe is kept and renamed, because the critical chip uses it.
- README: a new Topology section, gallery image and file layout.
## Tests
- `tests/test_topology.py` (35 tests) covers:
- pair dedupe and far-port resolution
- orientation and rates
- medium
- the WAN chain, with and without a modem
- dual-homed hosts
- IP-only targets as stubs
- cutsheet chassis
- stubs
- mismatch rules
- ghosts
- depth
- power kinds
- alerts and suppression
- cutsheet labels
- the empty state
- `test_app.py`:
- auth on both routes
- script order
- API shape
- cutsheet failure
- suppressed alerts not drawn
- dashboard no longer has the diagram
- page title
- `test_monitor.py`: `host_macs` holds the physical NIC.
- **Results**: 456 passed; flake8 and bandit are clean; eslint is unchanged at 21 pre-existing warnings; no em or en dashes.
## Screenshots
These come from prod-shaped data with addresses, MACs, serials and household port names replaced. 01 to 03 show the real state: monitor-01 is degraded because enp3s0 is waiting on a cable. The problems in 04 to 12 are simulated: pbs unplugged, a down cable, a port still named "Large1 Management", and alerts.
| | |
|---|---|
| Fit, dark  | Gateway and aggregation  |
| Servers and NICs  | Problems glow  |
| Last seen  | Hover traces the path  |
| Cable panel  | Light, with the problem list  |
| Light, cable panel  | Clicking a problem zooms to it  |
| Phone  | Phone, bottom sheet  |
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The dashboard's hand-drawn diagram was out of date. /topology replaces it
with the network as the switches report it, every device drawn to scale
from its faceplate or cutsheet front, and one cable per physical link
leaving the port it is plugged into.
- topology.py builds the graph: switch-to-switch cables seen from both ends
are merged, servers get one cable per NIC, the gateway's internet port
goes to the modem and on to the internet, unknown neighbours are stubs,
and gear with no live cable is drawn where it was last seen.
- Ports named after a different device than the one plugged in are flagged.
- Cables show medium, speed, state and traffic; click one for its details,
hover a device to trace its path to the internet; pan, zoom and filters.
- The monitor now keeps host_macs (MAC to host NIC) in link_stats.
- The old dashboard diagram and its JS and CSS are removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The curved cables piled on top of each other. Cables now run like cable
management: straight down from the port into the tray above the row they
go to, along a lane of their own (10G on the upper lanes), then straight
down into the socket. Nothing overlaps and crossings are square. Devices
sit clear of cables passing down through their row, under their fastest
cable.
Each switch's unknown devices are one block with a bundled cable; click
it to open them, or show them one by one or hide them from the toolbar.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drawn to true scale, the 4U servers dwarfed the switches and no label
could be read without zooming. Every device is now a card of the same
height: its name and state on top, and below that its real faceplate
(cropped to the ports) or, for a server, its front and a socket per NIC.
Cables meet the card edge right at the port, with a short tail to it.
The internet, modem and gateway sit side by side along the top, and
unknown devices share the row of the gear on their switch, so the whole
network fits a normal screen. On a phone the canvas takes the diagram's
shape instead of leaving most of it empty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A bar above the diagram lists what needs attention: devices down,
degraded or alerting, cables down or last seen elsewhere, mislabelled
ports, cables with errors. Click one to zoom to it; a missing device
is one entry, with where it was last seen. All clear says so.
- Problem cables glow and are always drawn, whatever the filters; problem
cards get a red or amber border. Healthy cables are drawn quietly.
- Each server's slower second cable (its 1G management link) is hidden
by default while healthy: "Server 1G links" shows them. That was most
of the clutter. "10G only" is gone, since this covers it.
- Power gear is off by default until the power map (part 2) gives the
rail something to show.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jared
scheduled this pull request to auto merge when all checks succeed 2026-11-14 20:10:16 -05:00
jared
merged commit dcf5fdf4cc into main2026-11-14 20:10:20 -05:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The dashboard's hand-drawn "Network Topology" section was out of date. This replaces it with a new /topology page that shows the network as the switches report it right now. It leads with what needs a look; each device is a card with its real faceplate or chassis, and each physical cable leaves the exact port it is plugged into.
This is part 1 of 2. Part 2 adds the power map: outlet feed lines and editable assignments.
What's on the page
cable_peer, the LLDP port ID, reverse LLDP, or the device's single uplink.known_uplinks), dotted red.#port-N.+ - 0keys.Code
topology.py: new. Purebuild_graph(...)returning{nodes, links, warnings, updated}.app.py:GET /topologyandGET /api/topology(auth)._physical_interfacesmoved todevices.physical_interfaces.monitor.py:link_stats.host_macs(MAC to host NIC), returned by_resolve_neighbors. Part 2 uses it to match outlets named by MAC.static/faceplates.js:faceplatePortAnchor(spec, idx).static/topology.js: problem summary, cards, layout, tray and lane routing, grouping, pan and zoom. Alsotemplates/topology.htmland topology CSS.updateTopologyand the dead modem hooks in app.js, thetopo-*CSS. Thepulse-downkeyframe is kept and renamed, because the critical chip uses it.Tests
tests/test_topology.py(35 tests) covers:test_app.py:test_monitor.py:host_macsholds the physical NIC.Screenshots
These come from prod-shaped data with addresses, MACs, serials and household port names replaced. 01 to 03 show the real state: monitor-01 is degraded because enp3s0 is waiting on a cable. The problems in 04 to 12 are simulated: pbs unplugged, a down cable, a port still named "Large1 Management", and alerts.
🤖 Generated with Claude Code