Previously the only VLAN visual was a small 14px swatch inside the detail
table -- easy to miss, not what the user meant by 'legend'. Added a
dedicated colored block per VLAN (VLAN <id> on a color fill, name in a
matching-outline box next to it), stacked left of the existing detail
table, same layout idea as the reference diagram this was modeled on.
Also fixed a real bug this surfaced: vlan_color() picked a palette color
by hash(vid), which let two different VLANs collide on the same color
(209 and 217 both landed on green). Colors are now assigned by position
among the VLANs actually present, which can't collide as long as there
are <= 8 of them (the palette size) -- true here with room to grow.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NM3nivbufxEWiKKmatEtEe
Connector VLAN tags were 7.5px on a ~4000x9400px page -- effectively
invisible unless zoomed in hard inside draw.io itself. Bumped:
- connector labels: 7.5px -> 13px, bold, darker color
- VLAN table: title 11->15px, header 9->12px, rows 9->12px (row/header
height grown to match, table height computed from the same constants
so nothing clips)
Page height barely moved (4656 -> 4692px) since only the VLAN panel grew.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NM3nivbufxEWiKKmatEtEe
Found while wiring up VLAN 214 on switch uplink ports: export_topology.py
deduped edges by DEVICE PAIR, so when a switch had two real cables to the
same neighboring device (very common here -- most FS.com field switches
run both SFP ports 9 and 10 into the same local patch panel before fanning
out from its rear side) only one of the two cables survived into the
graph. 43 real physical links across 30 device pairs were silently
missing from the diagram.
- export_topology.py: edges keyed per Cable (cable_id), never deduped by
device pair. Edge count 80 -> 123.
- generate_drawio.py: the tree-layout DFS had a matching bug -- a node's
neighbor list wasn't deduped before recursing, so a parallel edge to an
already-visited node got walked a second time, found no unvisited
children, and got counted as a phantom extra leaf. One phantom leaf per
redundant cable was inflating page height for no reason (bogus page
height >16000px, clipped by draw.io's render cap, before this fix).
NetBox changes (per user): all 42 FS.com IES3110-8TFP-R field switches'
SFP ports (9 and 10, whichever are actually cabled -- chain-end switches
only use port 9) are now interface.mode='tagged' with untagged_vlan=214
(Switch Management), the native VLAN on what the user confirmed are
redundant trunk uplinks. 63 interfaces updated; the diagram now shows
'9·V214' style tags on those connectors. Department-VLAN tagging (the
other half of each trunk) is intentionally not done yet -- needs a real
per-switch mapping, not a guess.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NM3nivbufxEWiKKmatEtEe
Inspired by a reference diagram the user liked (VLAN legend/mapping table,
per-port VLAN info) but explicitly without the literal switch CLI config
dumps that diagram also had.
- export_topology.py: pulls ipam.VLAN (with prefixes) plus, for every
edge whose endpoint is a real Interface, that port's mode/untagged/
tagged VLANs. NetBox has zero VLANs defined right now, so this comes
back empty/null throughout -- the plumbing is real, the data just
isn't there yet.
- generate_drawio.py: renders a VLAN table (VLAN/Name/Description/
Subnet/Site) at the top of the diagram. With no VLANs it shows an
explicit dashed 'not configured yet' placeholder row instead of
either fabricating VLAN numbers or silently omitting the table.
Connector labels get a 'V<id>' / 'V<id>,<id>T' suffix per side
whenever that port actually has VLAN config -- currently a no-op,
activates automatically the moment VLANs exist in NetBox.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NM3nivbufxEWiKKmatEtEe
- export_topology.py: edges now carry the exact port name on both ends
(pulled directly from Cable/CableTermination, not inferred from the
trace chain), so the diagram can label each connector.
- generate_drawio.py: patch panels are now a small rack-unit shape
(header strip + port ticks, parented to the panel body so they move
together) instead of a plain box; connectors show 'porta <-> portb'
and no longer carry a directional arrowhead (these are physical
cables, not directed links); switches keep the network-switch icon.
- render_png.js + render_host.html: headless Puppeteer driver for
embed.diagrams.net's postMessage export protocol -- an actual
render of the .drawio file, not an approximation. Field-Switch-
Topology.png is the committed output, for anyone who wants a look
without opening draw.io.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NM3nivbufxEWiKKmatEtEe
- export_topology.py: dumps switch + patch-panel cable graph from NetBox
(Django shell, read-only)
- generate_drawio.py: renders topo_full.json as a draw.io diagram with
natively-glued connectors (source/target by shape id, no hand-rolled
glue formulas)
- topo_full.json + Field-Switch-Topology.drawio: current snapshot
Replaces the earlier hand-built .vsdx approach: plain-text format diffs
meaningfully in git, no Visio license needed to view/edit, and edges glue
natively instead of needing point-to-point formula hacks.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NM3nivbufxEWiKKmatEtEe