Fixed the bundled Dependency Graph view load path in the dashboard app, adding regression tests across the App and plugin registration test suites, and documenting the bundled loading contract in the plugin README. Fusion-Task-Id: FN-3916
6.8 KiB
6.8 KiB
fusion-plugin-dependency-graph
Plugin-provided top-level Graph dashboard view for Fusion.
Host registration and bundled loading
The dependency graph view is registered as a bundled plugin view in the dashboard. This means:
registerBundledPluginViews()(called at dashboard startup) registers the view component in the static plugin view registry under keyplugin:fusion-plugin-dependency-graph:graph.- The view component is resolved via a literal-specifier lazy import (
import("@fusion-plugin-examples/dependency-graph/dashboard-view")) — this is critical for Vite/esbuild to emit a production chunk. - In Vite dev/build and Vitest,
@fusion-plugin-examples/dependency-graph/dashboard-viewis aliased toplugins/fusion-plugin-dependency-graph/src/dashboard-view.tsx(source, notdist/). This avoids stale dist artifacts breaking the dashboard view. - The App.tsx graph route resolves to the bundled view via
isPluginViewRegisteredfallback, so the graph view works even when the plugin is not installed/loaded through the PluginLoader API (e.g. fresh DB). - The canonical route ID is
plugin:fusion-plugin-dependency-graph:graph.
Rendering approach
- Filtering: includes
triage,todo,in-progress,in-review; excludesdone,archived - Graph build: edges are resolved only from
task.dependenciesassource=dependent,target=dependency - Orphan dependency handling: if a visible task depends on an excluded/missing dependency (for example
done/archivedafter filtering), the missing edge is silently dropped and graph rendering continues without broken connectors - Auto-layout: Sugiyama-style layered layout (
computeAutoLayout) groups nodes by dependency depth and spaces layers consistently - Edge drawing: SVG bezier curves from source bottom-center to target top-center, with arrowheads showing dependent → dependency direction
- Interaction: drag-to-pan canvas background, drag-to-reposition nodes, cursor-centered wheel zoom, pinch-to-zoom with stationary midpoint, keyboard shortcuts, zoom toolbar, reset, and fit-to-graph
- Fit-to-graph: computes node bounding box with layout node dimensions and applies zoom/pan so the graph fits in viewport with padding
- Initial auto-fit: when no saved scoped positions exist, the first non-empty render auto-fits once; subsequent updates preserve user navigation state
- Position persistence: dragged node positions are stored per project in browser localStorage and restored on reload
- Animated transitions: fit/reset operations animate
transform(var(--transition-normal)), while continuous drag/wheel/pinch stays transition-free for responsiveness - Node rendering: each graph node renders the real dashboard
TaskCardviaGraphTaskNode(no duplicated card markup) - Task detail integration: a primary non-drag click on a graph node surface opens the native dashboard task detail modal exactly once through host context (
openTaskDetail), matching board/list behavior - In-progress behavior: steps are visible by default and active-task glow (
agent-active) is preserved because node cards reuse TaskCard directly - Active-state indicator bar: active nodes render a compact top bar (
.graph-task-active-indicator) with the current execution status label (for exampleExecuting,Planning) and pulsing--in-progressemphasis - Current-step highlighting: active nodes set
data-current-stepfor valid native step indices so CSS selectors highlight the currently executing.card-step-itemand pulse its step dot - Zoom-out differentiation:
.graph-task-node--activeadds amplified glow and subtle scale/border tint so active nodes remain distinguishable at reduced zoom levels - In-review visual treatment:
in-reviewnodes get a static.graph-task-node--in-reviewleft accent in--in-reviewto distinguish waiting-review work from active execution nodes - Graph node classes:
.graph-task-node,.graph-task-node--active,.graph-task-node--in-review,.graph-task-node--highlighted,.graph-task-node--dimmed,.graph-node--highlighted, and.graph-node--dimmedare available for graph-specific layering/highlight states while card internals remain owned byTaskCard.css - Graph edge classes:
.graph-edge--highlightedand.graph-edge--dimmedare applied during dependency-chain emphasis states - Drag behavior: graph nodes pass
disableDrag={true}toTaskCardso card-level HTML5 drag does not conflict with canvas pan/zoom
Position persistence
- Canonical base key:
fusion-plugin-dependency-graph:positions - Storage key format:
kb:${projectId}:fusion-plugin-dependency-graph:positions(falls back tofusion-plugin-dependency-graph:positionswhen no project is selected) - Read path: positions load on graph mount and whenever
projectIdchanges, then merge with fresh auto-layout so new tasks still receive layout defaults - Write path: positions persist on drag end only (not on every drag frame), filtered to currently visible tasks for stale cleanup
- Reset behavior: Fit to graph / Reset view clear persisted positions and re-apply auto-layout
- Implementation detail: the plugin now reuses dashboard
projectStoragehelpers (getScopedItem/setScopedItem/removeScopedItem) instead of duplicating scoped localStorage logic
Dependency chain highlighting
- Hover a node to highlight the full transitive upstream + downstream chain for that task.
- Click a node to persist selection highlighting until the same node is clicked again or the canvas pane is clicked; this same click also opens task detail once through the host detail callback.
- Priority: hover state overrides selected state; when hover leaves, selected highlighting reappears.
- Dimming: when a chain is active, unrelated nodes and edges are dimmed.
- Neutral state: when nothing is hovered/selected, no highlight/dim classes are applied.
- Drag suppression: drag movements above the node drag threshold suppress the post-drag click, preventing accidental detail opens on pointer release.
- Edge rule: an edge is highlighted only when both its source and target nodes are in the active chain.
Controls
Toolbar (bottom-right)
- Zoom in (
ZoomIn) — button +Ctrl+=/Cmd+= - Zoom out (
ZoomOut) — button +Ctrl+-/Cmd+- - Zoom percent label — live readout (for example
100%,75%,250%) - Fit to graph (
Maximize) — button +Ctrl+Shift+F/Cmd+Shift+F - Reset view (
RotateCcw) — button +Ctrl+0/Cmd+0
Additional keyboard behavior
- Escape resets to default view (
zoom=1,pan=0,0) - Shortcuts are suppressed when focus is inside
input,textarea,select, orcontentEditableelements
All controls are rendered as floating .btn-icon actions in the bottom-right corner, with mobile-friendly 44px touch targets in the @media (max-width: 768px) override.