Frontend architecture¶
On this page¶
- Component registration
- Mount and update lifecycle
- Feature modules
- State and payload flow
- Managed exploration
- Layout and resize guards
- Bundle structure
Component registration¶
The Python wrapper registers st_graph_workbench.graph_workbench through
Streamlit Components v2. It supplies component HTML, scoped CSS, and one hashed
JavaScript entry bundle. The component mounts in the light DOM, which allows
reliable pointer handling for Cytoscape box selection.
Each public key is encoded losslessly into a Streamlit-safe internal key. Per-instance state prevents selection, viewport, custom listeners, and command history from leaking between multiple graphs.
Mount and update lifecycle¶
- Python validates options, elements, styles, layouts, events, and commands.
- Components v2 passes normalized props into the frontend render function.
- The frontend creates one Cytoscape instance or reuses the existing instance.
- Full elements are reconciled or unseen command IDs are applied.
- Styles, layouts, tool groups, selection modes, and viewport bounds update.
- Browser interactions produce normalized JSON event dictionaries.
- Cleanup disconnects resize/listener resources and destroys the Cytoscape instance when the component unmounts.
Feature modules¶
The frontend is divided by user behavior rather than by screen: graph creation, selection, box interaction, search, analysis, CRUD intents, graph commands, progressive loading, bounded connected dragging, node actions, edit tools, viewport tools, exports, styles, layouts, expansion badges, information panels, and payload construction. See the capability matrix for the complete map.
State and payload flow¶
Browser state tracks the current selection, active style/theme, layout, last
expansion, and expansion-badge visibility. Modules subscribe only to the state
they need. setImmediateStreamlitValue is used for interactions that must
return immediately; Components v2 state supports persistent component values.
Payload helpers normalize selected and connected records, search matches, CRUD context, edit details, viewport values, and positions before Python sees them.
Managed exploration¶
ExpansionController is independent of Streamlit. The provider owns the source;
the controller owns validated cached records and projects a displayed graph.
Branches identify an anchor plus normalized filters and record their node/edge
contributions. Visibility is computed from the starting graph, protected records,
and reachable open branches. It is not recursive deletion of graph neighbors:
shared records survive other active branches, while disconnected cycles cannot
keep themselves alive. Nested open flags can be suspended without being forgotten.
expansionControls.js supplies opt-in branch actions, filters, scope controls,
and one-batch-at-a-time continuation. Requests persist through Components v2
reruns until Python returns their receipt IDs. Provider responses additionally
must match the request, source version, and branch revision. A receipt does not
mean that an application-owned asynchronous provider has completed its work.
Managed graph commands remain queued until the browser acknowledges applying them. The controller emits only actual differences; unchanged selection or analysis events do not start a graph-update feedback loop. Commands preserve positions and viewport, and the current Python view remains the recovery checkpoint if the browser needs to synchronize again.
Loaded-record analysis uses a separate headless Cytoscape instance; the displayed renderer highlights only available result IDs. Source analysis stays with a capable provider. See the expansion API for snapshots, cache invalidation, and the branch guide for the complete executable workflow.
Layout and resize guards¶
Async layout extensions can finish out of order. A request token ensures only
the newest layout callback changes readiness or viewport state. A
ResizeObserver calls cy.resize() after container changes, and height updates
do not require remounting.
Bundle structure¶
Webpack produces one hashed entry bundle plus asynchronously loaded layout and
connected-drag chunks, copied component markup/CSS, and packaged SVG icons.
Cytoscape Automove and its controller load only when connected_drag is
configured, so the default graph path does not download that feature. The entry and asset
budget is 512000 bytes. Wheels contain runtime build assets, while source
distributions also contain frontend source and developer configuration.
Conclusion¶
The architecture keeps Streamlit reruns, component updates, and Cytoscape's long-lived browser state explicit. New capabilities should expose a typed Python surface, a focused frontend module, a normalized event shape, and tests at both boundaries.