Skip to content

Collapsed subtopology view with bus notation and click-to-open (CLI + VS Code) - #2

Open
devin-ai-integration[bot] wants to merge 8 commits into
masterfrom
devin/1790713352-collapsed-subtopology
Open

devin-ai-integration[bot] wants to merge 8 commits into
masterfrom
devin/1790713352-collapsed-subtopology

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Summary

Topology (and connection-group) diagrams gain an opt-in collapsed view. Today lower_topology flattens every import: each imported topology's component instances become nodes and every connection is resolved to underlying component ports, so the subtopology structure and its declared ports vanish. The collapsed view keeps them:

  • each directly imported topology is one node:topology carrying its declared ports (port x = inst.p), with its internal connections hidden;
  • the diagrammed topology's own declared ports are drawn on the diagram boundary as node:boundary chevrons (ELK pins inputs to a first column and outputs to a last column), each joined to the port it aliases;
  • a connection that reaches directly into an imported topology (e.g. wasmSeq.getTlmChan -> CdhCore.tlmSend.TlmGet, not via a declared port) becomes an implicit edge whose endpoint is the collapsed node itself — no boundary port is invented — drawn dashed, with the underlying inst.port -> inst.port pairs as hover text. Implicit edges between the same two elements are merged into one.

Flattened stays the default everywhere; all existing tests are untouched.

// fpp_diagram (additive; existing signatures unchanged)
pub enum TopologyView { Flattened /* default */, Collapsed }
pub fn lower_view(a, kind, name, view) -> Result<Diagram, LowerError>
pub fn lower_to_smodel_with(a, kind, name, options: SmodelOptions) -> Result<Value, LowerError>  // see below

pub struct Diagram { ..., topology_nodes: Vec<TopologyNode>, boundary_ports: Vec<Port> }  // both skipped when empty
pub struct Edge { ..., implicit: bool, detail: String }                                  // both skipped when default

Lowering (CollapsedScope in fpp_diagram/src/lower.rs): analysis stores connection endpoints already resolved to component ports, but each resolved Endpoint keeps the alias it came through in topology_port. The scope walks that chain back out (as_written) and resolves the outermost identifier: a port on a directly imported topology → rendered port on the collapsed node; a component owned by an imported topology → the collapsed node's boundary (implicit); anything else → the component port as before. Details settled during review:

  • edges come from connection_map (imported connections that cross a collapsed boundary are drawn; those wholly inside one collapsed node are hidden);
  • an instance reachable through more than one import is owned by the innermost import; if that is ambiguous (unrelated imports share it) or the diagrammed topology declares it itself, it is drawn standalone, and a collapsed node's declared port that aliases it gets an alias.<Topology>.<port>.<i> edge to it (implicit when the target is another collapsed node);
  • group views keep a collapsed node whose wiring is wholly internal, and follow alias chains across collapsed nodes to a fixed point.

Surfaces:

  • CLI: fpp-diagram --kind topology --name Ref.Ref --format sprotty --view collapsed (default flattened).
  • LSP: fpp/diagram params gain optional topologyView: "flattened" | "collapsed".
  • VS Code: FPP: Toggle Collapsed Subtopologies command/editor-title button on the diagram panel; webview registers node:topology (dashed box) and node:boundary (chevron pointing in the flow direction); implicit edges are dashed. Graphs with boundary chevrons are laid out as one piece (elk.separateConnectedComponents=false) so the first/last-layer constraints hold globally.

On F Prime Ref.Ref: flattened = 49 component nodes / 372 edges; collapsed = 21 component nodes + 4 subtopology nodes / 198 edges (123 implicit). CdhCore.Subtopology collapsed: 8 components, 16 boundary chevrons (9 in / 7 out), 17 edges.

Tests: new fpp_diagram/tests/collapsed.rs (13 tests: IR, pruning, connection groups, sprotty JSON, legacy-API equivalence, CLI switch, imported/shared/nested/chained aliases).

Bus notation and click-to-open (second iteration)

Buses. Diagram::bundle_edges folds edges that join the same two rendered elements in the same direction — element = component node, collapsed node:topology, or boundary chevron — into one edge between the elements themselves:

pub struct Edge { ..., count: u32 }   // 1 = a wire (omitted from JSON); >1 = a bus
impl Diagram { pub fn bundle_edges(&mut self) }
// bus: id "bus.<from>.<to>", from_port/to_port = element ids, count = Σ wires,
//      detail = one "inst.port -> inst.port" line per wire, implicit = all wires implicit,
//      graph_name kept only if every wire shares it. A lone wire keeps its ports.

Sprotty: the edge carries count and, for a bus, a label:edge child "/N" (ELK places it at the edge centre). The webview draws a bus as a 3 px stroke (.edge-bus; implicit buses stay dashed, 8 5) with a 60° slash at the path midpoint; the <title> lists the wires. Bundling is opt-in below the extension: fpp-diagram --bundle-edges, LSP bundleEdges: bool (default false); VS Code turns it on by default with FPP: Toggle Bus Wires on the panel toolbar. hide_unused_ports runs after bundling, so ports used only by a bus are dropped.

// lower_to_smodel_view (introduced earlier on this branch) is replaced by:
pub struct SmodelOptions { hide_unused_ports, transition_action_mode, topology_view, bundle_edges }  // Default = legacy flattened
pub fn lower_to_smodel_with(a, kind, name, options: SmodelOptions) -> Result<Value, LowerError>

Ref.Ref collapsed: 198 edges → 98 edges, 44 of them buses (largest /27), same 305 wires. Flattened + bundled: 372 → 309 edges (56 buses).

Note: in collapsed view, implicit reach-ins with an identical source port were already merged into one edge; they now report their count, so a few /N labels remain with bus wires toggled off.

Click-to-open. node:topology carries qualifiedName and is registered with Sprotty's openFeature: a double-click dispatches OpenAction(elementId), which FppWebviewPanelManager.addOpenHandler turns into the existing displayDiagram(DiagramType.topology, qualifiedName) — the same panel now shows that subtopology (its declared ports as boundary chevrons).

Tests: new fpp_diagram/tests/bundle.rs (8 tests: opt-in/count round-trip, bundling by element incl. direction and mixed groups, bundle-then-prune, implicit merge counts, all-implicit bus, sprotty count/label:edge, qualifiedName, CLI --bundle-edges).

Video (VS Code, Ref.Ref collapsed → double-click CdhCore.Subtopology)

bus notation and double-click navigation

Ref.Ref collapsed, buses on bus detail: fat wire, slash, /N, hover lists the wires
Ref.Ref collapsed bundled bus detail and tooltip
buses toggled off (198 individual edges) after double-clicking CdhCore.Subtopology
Ref.Ref unbundled CdhCore opened

Screenshots of the collapsed view (first iteration) (VS Code extension-development host, local fpp_lsp_server)

Ref.Ref flattened (default, unchanged) vs collapsed — the four grey dashed boxes are CdhCore.Subtopology, ComCcsds.Subtopology, ComFprime.Subtopology, FileHandling.Subtopology:

flattened collapsed
Ref.Ref flattened Ref.Ref collapsed

Zoom on CdhCore.Subtopology inside collapsed Ref.Ref: solid edges land on declared ports (healthRun, eventsRun, seqCmdBuff[0]…); dashed implicit edges cross the boundary with no port, and hover shows the underlying pair:

CdhCore collapsed node in Ref.Ref, implicit edge tooltip

CdhCore.Subtopology diagrammed on its own, collapsed view — its declared ports as boundary chevrons (inputs left, outputs right):

CdhCore.Subtopology collapsed

Toolbar toggle:

toolbar

Known limitations / follow-ups

  • Navigation is one-way: there is no back button; return via the CodeLens of the parent topology. Doing so while the panel is open can leave the previous diagram displayed until an option is toggled; this reproduces with the default flattened view and displayDiagram is unchanged here, so it appears preexisting — not verified against master.
  • A collapsed connection-group view whose connections all lie inside one imported topology shows that node with no edges (intentional: the group is internal to the subtopology).
  • /N labels are small at fit-to-screen zoom on Ref.Ref; the count is also in the hover text.

AI Used (y/n)

y

AI Usage

Implemented, tested and iterated by Devin (Cognition) under direction of Michael Starch; design decisions (collapsed view as an opt-in switch, implicit reach-in edges crossing the boundary with no rendered port, bus notation as one fat wire with a slash and count, double-click to open a subtopology) are the requester's. Reviewed by Devin Review with each finding fixed and replied to on its thread.

Link to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/41ec9ea5fc0a4076b6ca8e2280206d69
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/41ec9ea5fc0a4076b6ca8e2280206d69?variant=devin


Devin Review

Topology and connection-group diagrams gain a TopologyView (flattened |
collapsed). Collapsed draws each directly imported topology as one
node:topology carrying its declared ports, the diagrammed topology's own
declared ports as node:boundary elements, and connections that reach into
an imported topology as implicit edges ending on the collapsed node's
boundary (no rendered port is invented). Flattened remains the default.

Exposed as fpp-diagram --view {flattened,collapsed}, the fpp/diagram LSP
request's optional topologyView, and the FPP: Toggle Collapsed
Subtopologies command in the VS Code diagram panel.

Co-Authored-By: michael.d.starch <michael.d.starch@jpl.nasa.gov>
@devin-ai-integration

Copy link
Copy Markdown
Author

I'll fix CI failures and address comments from users with write access that start with 'Devin'.

  • Disable automatic comment, CI, and merge conflict monitoring

Original prompt from michael.d.starch

I would like to build an F Prime topology visualizer that can run in the github renderer or in github.io pages.

It must work with subtopologies (showing the boundary ports) and with full topologies. imported subtopologies should be clickable and the expand into the rendering of that subtopology.

https://github.com/fprime-community/fpp-tools

That repo contains our tooling for extended FPP work.

You are allowed to:

  1. Run that tooling and cache the results (hosted on a github branch)
  2. Proposed changes to the tooling
  3. Propose new GH pages, or other GH content on a branch.

We should not:

  1. Break existing functionality of fpp-tools
  2. Require changes to the F Prime devel branch
  3. Re-write or re-develop substantial portions of code (e.g. don't just write fpp-tools in JavaScript)
  4. Create tons of cached data (e.g. > 1GB total, or files requiring Git LFS)

Please develop a plan for this

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 3 commits September 29, 2026 20:45
…mbiguate shared instances

Edges now come from connection_map (imported connections included), dropping
only those wholly inside one collapsed node. An instance owned by two unrelated
imports, or declared by the diagrammed topology itself, stays a node of its own;
an instance inside nested imports is owned by the innermost. An imported
connection group keeps the collapsed node it lives in. Fix the CSS selector so
implicit edges render dashed inside the edge's <g>.

Co-Authored-By: michael.d.starch <michael.d.starch@jpl.nasa.gov>
…ses outside the node

A declared port of an imported topology that names an instance drawn on its own
(shared by unrelated imports, or declared by the parent) or owned by another
collapsed node gets an alias edge to it, mirroring the boundary-port edges. Group
views bring in those alias targets for the collapsed nodes they draw.

Co-Authored-By: michael.d.starch <michael.d.starch@jpl.nasa.gov>
'elk.layered.layerConstraint' is not an ELK option; boundary ports were laid
out as ordinary nodes next to what they connect to.

Co-Authored-By: michael.d.starch <michael.d.starch@jpl.nasa.gov>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 4 commits September 29, 2026 20:54
A collapsed node brought in by an alias edge contributes its own alias edges
in turn, so a group reaching a re-exported port shows the whole chain.

Co-Authored-By: michael.d.starch <michael.d.starch@jpl.nasa.gov>
ELK packs connected components separately by default, so first/last layer
constraints only lined boundary ports up per component.

Co-Authored-By: michael.d.starch <michael.d.starch@jpl.nasa.gov>
…logies

Diagram::bundle_edges folds edges joining the same two rendered elements
(component, collapsed topology, or boundary port) into one edge with a wire
count, listing the wires in its hover detail. The sprotty model carries the
count and a '/N' edge label; the webview draws buses as a fat wire with a
slash. Bundling is opt-in: --bundle-edges on the CLI, bundleEdges on
fpp/diagram, and on by default in VS Code with a toggle command.

node:topology now carries qualifiedName and is openable: double-clicking
sends OpenAction, which the extension host turns into displayDiagram for
that topology.

lower_to_smodel_view (added on this branch) is replaced by
lower_to_smodel_with(SmodelOptions).

Co-Authored-By: michael.d.starch <michael.d.starch@jpl.nasa.gov>
Co-Authored-By: michael.d.starch <michael.d.starch@jpl.nasa.gov>
@devin-ai-integration devin-ai-integration Bot changed the title Add collapsed subtopology view to topology diagrams (CLI + VS Code) Collapsed subtopology view with bus notation and click-to-open (CLI + VS Code) Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants