Fix topology layout collapsing to a single column/line#76
Open
N34AY wants to merge 2 commits into
Open
Conversation
computeLayers() tries to infer a network hierarchy by matching device role slugs against a hardcoded set of hints (router, core, access, server, etc). A single incidentally-matching role among an otherwise unrelated set of role names was enough to flip the *entire* graph into hint mode, even though only that one device had a real hint. Every other device fell through a single-pass neighbor-averaging loop that, lacking a resolved neighbor, defaulted to the same layer as that one hint — collapsing the whole diagram onto a single column. Repro: 609 devices, one of which has role "Server". That one match was enough to collapse all 609 nodes onto layer 5 (1 column). Fixed to require hinted roles to cover >=15% of the graph before trusting them, otherwise falls back to the connectivity-based layering below. Separately, the non-hint fallback path only ever BFS-explored from a single global root, dumping every other connected component (and any fully isolated device) into one shared fallback layer — the same collapse, via a different path, for graphs that aren't one connected mesh (e.g. several independent switch stars plus many unwired spare devices, which is typical DCIM data). Fixed to layer each connected component independently, all starting at layer 0, so components share layer columns as siblings instead of stacking into one bucket. Verified against a real 609-device / 189-cable topology: before, all 609 nodes landed in 1 layer; after, they spread across 7 layers with a 420/16/21/42/53/35/22 split matching the actual cable hierarchy.
Stencil (card) view and Node (circle) view use fundamentally different layout strategies — hierarchical columns vs. a force simulation — but share the same underlying node objects for x/y. Switching modes used to carry one view's computed positions over as the other's starting point, which produces nonsense: Node View's force simulation would inherit Stencil View's layout (e.g. a single-file column) as its initial shape, and repulsion alone can't break a degenerate starting shape like that apart into a readable spread. Clear non-pinned node positions on every mode switch — the same thing the existing "Reset Layout" button already does — so each view always computes its own fresh layout instead of inheriting the other's.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
computeLayers()intopology_renderer.jstries to infer a network hierarchy by matching device role slugs against a hardcoded set of hints (router,core,access,server, etc). A single incidentally-matching role — e.g. one device with role "Server" among an otherwise unrelated set of custom role names — was enough to flip the entire graph into hint mode, even though only that one device had a real hint. Every other device fell through a single-pass neighbor-averaging loop that, lacking a resolved neighbor, defaulted to the same layer as that one hint, collapsing the whole diagram onto a single column.Repro case: 609 devices, one of which has role "Server". That one match collapsed all 609 nodes onto a single layer (1 column) in Stencil/Card view.
Separately, the non-hint fallback path only ever BFS-explored from a single global root, dumping every other connected component (and any fully isolated device) into one shared fallback layer — the same collapse via a different path, for graphs that aren't one connected mesh (e.g. several independent switch stars plus many unwired spare devices — typical DCIM data).
Finally, Node (circle) view and Stencil (card) view share the same underlying node objects for x/y, but use completely different layout strategies (force simulation vs. hierarchical columns). Switching between them used to carry one view's computed positions over as the other's starting point — so Node View's force simulation would inherit Stencil View's collapsed single-file column as its initial shape, and stay collapsed since repulsion alone doesn't break a degenerate 1-D starting condition apart.
Changes
computeLayers(): only trust role hints once they cover a meaningful share of the graph (>=15%), otherwise fall back to connectivity-based layering.computeLayers(): layer each connected component independently (BFS per-component, each restarting at layer 0) instead of a single global BFS run whose leftover nodes all collapse into one fallback layer.switchView(): clear non-pinned node positions on every mode switch (mirrors what the existing "Reset Layout" button does), so each view always computes its own fresh layout instead of inheriting the other's.Test plan