Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7c00f19
chore: update gitignore
nfurfaro Apr 2, 2026
781ee6b
docs: design and impl plans
nfurfaro Apr 2, 2026
c1beaa7
feat(web): add @xyflow/react and elkjs dependencies
nfurfaro Apr 2, 2026
fc7f074
feat(web): create DotNode custom React Flow node component
nfurfaro Apr 2, 2026
5b76469
feat(web): create ELK graph layout helper
nfurfaro Apr 2, 2026
315ba9f
feat(web): create GraphView component with React Flow + ELK layout
nfurfaro Apr 2, 2026
67fea77
feat(web): wire GraphView toggle into Workspace header
nfurfaro Apr 2, 2026
c26bf29
fix(web): prevent graph view from auto-zooming out on interaction
nfurfaro Apr 2, 2026
008ad5e
feat(web): switch graph to stress layout for dense, radial clustering
nfurfaro Apr 2, 2026
1a14921
fix(web): show labels only on selected node, position popover near click
nfurfaro Apr 2, 2026
c5daf23
feat(web): switch to tree layout with smooth edges
nfurfaro Apr 2, 2026
4f7a475
feat(web): radial tree layout with root at center, children in concen…
nfurfaro Apr 2, 2026
b59d989
feat(web): wedge-based radial layout to minimize edge crossings
nfurfaro Apr 2, 2026
cc53c72
fix(web): sync graph selection with outliner — selecting in outliner …
nfurfaro Apr 2, 2026
5e76870
feat(web): visually distinguish root nodes with larger size and halo
nfurfaro Apr 2, 2026
ab0a4c0
feat(web): organic radial layout with variable distance and overlap r…
nfurfaro Apr 2, 2026
f7f1414
feat(web): DotNode supports layout-computed sizing, collapse indicato…
nfurfaro Apr 2, 2026
656cffe
feat(web): add depth collapse control and color mode toggles to graph…
nfurfaro Apr 2, 2026
5caab8c
fix(web): tune radial layout — fixed ring distance, better spacing
nfurfaro Apr 2, 2026
7efc5c4
fix(web): adaptive ring distance based on sibling count
nfurfaro Apr 2, 2026
e05ff3e
feat(web): custom RadialEdge with gentle curves clipped at node perim…
nfurfaro Apr 2, 2026
45a9ad8
fix(web): RadialEdge connects to dot center, not wrapper center
nfurfaro Apr 2, 2026
d393aa0
fix(web): clear node label on pane click — only show label for graph-…
nfurfaro Apr 2, 2026
fe49ae4
docs: impl plan
nfurfaro Apr 2, 2026
3c2e370
fix(web): use showLabel (not selected) to control label visibility in…
nfurfaro Apr 2, 2026
c228a5d
fix(web): prevent graph flicker from polling — only re-layout when st…
nfurfaro Apr 2, 2026
d64a322
fix(web): vivid heatmap gradient with log scaling for better contrast
nfurfaro Apr 2, 2026
5175d48
fix(web): only fitView on initial load and depth change, preserve man…
nfurfaro Apr 2, 2026
2957227
fix(web): semantic heatmap gradient — cool blue → purple → magenta → …
nfurfaro Apr 2, 2026
c11c448
fix(web): reduce root node halo glow to avoid giant dark blobs at sha…
nfurfaro Apr 2, 2026
bb434e8
fix(web): normalize heatmap colors relative to dataset min/max
nfurfaro Apr 2, 2026
a62abce
fix(web): normalize heatmap over actual [min, max] range for full gra…
nfurfaro Apr 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
target
.fastembed_cache/
.claude/worktrees/
.claude/settings.local.json
*.db
*.db-shm
*.db-wal
Expand All @@ -9,4 +10,4 @@ web/playwright-report/
web/e2e/ux-audit/ux-audit-results/
web/ux-audit-results/
macos/.build
macos/.build-output
macos/.build-output
71 changes: 71 additions & 0 deletions docs/plans/2026-04-02-graph-view-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Graph View Design

## Goal

Add an interactive graph visualization to the Workspace that shows the full DAG (nodes and edges) as a zoomable, filterable dot-based view. Toggled via a button in the Workspace header, replacing SimpleFocusView in the center area.

## Architecture

New `GraphView.tsx` component renders in the Workspace center area when `centerView === "graph"`. A toggle button in the header switches between `"focus"` (SimpleFocusView) and `"graph"` (GraphView). The outliner and all side panels remain available in both modes.

**Dependencies**: `@xyflow/react` (React Flow v12) for the canvas, `elkjs` for auto-layout. Both lazy-imported to avoid bloating the initial bundle.

**Data flow**: Workspace already has `nodeMap` and `edges`. These are transformed into React Flow `Node[]` and `Edge[]`, passed through ELK layout for positioning, then rendered.

## Node Rendering

- **Dots only by default** — circles, no text at rest
- **Size proportional to entropy** — high entropy = larger dot (24px), low = smaller (12px), no data = default (16px). Linear mapping across the visible set's min/max entropy.
- **Color by state** — green (answered), amber (unanswered), blue (needs_review), gray (deleted). Subtle glow on hover.
- **Adaptive labels** — when zoom level > 1.5, a short label fades in below the dot (first ~30 chars of the question). Below that zoom, dots only.

## Edges

- Thin lines (1-2px), `gray-600`, small arrowheads at child end
- Edges connected to the selected node highlight in `gray-400`

## Interactions

- **Hover**: Tooltip with question text (~100 chars), state, entropy score
- **Click**: Node selected — a floating detail card appears near the node showing question, answer preview, entropy, and an **"Open in Focus View"** button
- **"Open in Focus View"**: Sets `focusNodeId` and switches `centerView` to `"focus"` — same as clicking a node in the outliner

## Filtering & Search

Slim filter bar docked at the top of the graph area:

- **Search input**: Debounced (200ms) text filter on question/answer content. Non-matching nodes fade to low opacity (not removed — preserves spatial context). Matching nodes get a highlight ring.
- **State filter pills**: Toggle pills for answered, unanswered, needs_review. All active by default. Toggling off fades those nodes.
- **Entropy range**: Min/max slider when entropy data exists.
- **Re-layout button**: Recomputes ELK positions using only the visible (non-faded) nodes for a compact filtered view.
- **Fit-to-view button**: Zooms/pans to fit all visible nodes (`fitView()`).

Fade-not-remove keeps the spatial map stable — nodes don't shift when you filter.

## Layout

**ELK layered layout** (Sugiyama-style), top-to-bottom:

- Roots at top, leaves at bottom, edges flow downward
- Spacing adapts to node count — generous for small graphs (<30), tighter for large (100+)
- Feature roots placed in distinct horizontal lanes via ELK partitioning (independent subtrees don't overlap)
- Layout runs in a **web worker** to avoid blocking the UI thread
- Recomputes when node/edge set changes or when "Re-layout" is clicked after filtering

**Pan & zoom**: React Flow built-in — scroll to zoom, drag to pan. Minimap in bottom-right corner with dots colored to match node state.

**Initial view**: `fitView()` on mount centers the entire graph.

## Integration Points

- **Workspace.tsx**: New `centerView` state (`"focus" | "graph"`), toggle button in header, conditional render of GraphView vs SimpleFocusView
- **Outliner sync**: Selecting a node in the outliner highlights it in the graph; selecting in the graph highlights in the outliner
- **Existing data**: Reuses `nodeMap`, `edges`, `computeSubtreeEntropy()` from `graph-utils.ts`

## Files

- Create: `web/src/GraphView.tsx` — main graph component
- Create: `web/src/DotNode.tsx` — custom React Flow node component
- Create: `web/src/graph-layout.ts` — ELK layout helper (web worker wrapper)
- Modify: `web/src/Workspace.tsx` — toggle state, conditional render, header button
- Modify: `web/package.json` — add `@xyflow/react`, `elkjs`
Loading