refactor: implement custom diagram layout algorithm and remove elkjs dependency#14
Conversation
…dependency - Eliminated the elkjs library from package.json and bun.lock. - Refactored DiagramView to remove references to elkjs, simplifying the layout logic. - Adjusted column gap in DiagramView for improved spacing.
WalkthroughMigrates diagram layout from ELK to an in-component deterministic lane-based layout, removes the Changes
Sequence DiagramsequenceDiagram
participant DV as DiagramView
participant Data as Source Nodes/Edges
participant Layout as In-component Layout
participant Render as Renderer
DV->>Data: Inspect nodes (internal vs external)
alt no internal nodes
DV->>DV: Clear layoutNodes/layoutEdges
DV->>Render: Render empty/early exit
else has internal nodes
DV->>Layout: Allocate lanes (with fallback/expand)
Layout-->>DV: Lane assignments
DV->>Layout: Sort nodes (depth→lane→createdAt→id)
Layout-->>DV: Sorted nodes
DV->>Layout: Compute x (lane) / y (depth) positions (colGap=80)
Layout-->>DV: Positioned nodes
DV->>DV: Build Node & Edge entries with active/inactive styling
DV->>Render: Render positioned nodes & edges
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/components/DiagramView.tsx (1)
201-305: Custom layout effect is sound; consider minor refactors for clarityThe new layout effect correctly:
- Bails out cleanly when there are no internal nodes, resetting
layoutNodes/layoutEdges.- Produces a deterministic ordering by
(depth, lane, createdAt, id).- Uses
laneAssignments/depthByNodeconsistently to compute positions and active-path styling for nodes and edges.Two optional refinements you might consider:
- The
getLanehelper is only expected to allocate in pathological cases (sincelaneAssignmentsalready gives every node a lane). You could turn that path into a stricter dev-only assertion to catch inconsistencies earlier, rather than silently assigning a new lane.- To keep the comparator obviously side‑effect‑free, you could precompute lanes for all
internalNodesbeforesort(e.g., build a flatMap<id, lane>and use it read‑only inside the comparator). The current approach is functionally fine but a small refactor would make the intent clearer.Otherwise the in‑component layout logic looks coherent and matches the stated PR goals.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (3)
package.json(0 hunks)src/components/DiagramView.tsx(2 hunks)src/types/elk.d.ts(0 hunks)
💤 Files with no reviewable changes (2)
- package.json
- src/types/elk.d.ts
🔇 Additional comments (1)
src/components/DiagramView.tsx (1)
29-31: Column gap change looks good and consistent with layout mathThe updated
columnGap = 80is wired correctly into the position formula (x: lane * (boxSize.width + columnGap)), so the only impact is the intended horizontal spacing tweak; no behavioural issues here.
…ance - Introduced a laneLookup map to cache lane values for internal nodes, reducing redundant function calls. - Updated sorting logic to utilize cached lane values, enhancing the efficiency of node ordering. - Adjusted lane retrieval in node rendering to use the new lookup, maintaining existing functionality.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/components/DiagramView.tsx (2)
201-235: Empty-graph guard and lane fallback logic look robustThe new effect correctly:
- Short-circuits to an empty layout when there are no
treeNodes, avoiding stale nodes/edges.- Clones
laneAssignmentsand derivesnextLanefrom the current maximum, then usesgetLaneto lazily allocate lanes for any node missing an assignment, with a dev‑only warning. This should keep layout stable even while the tree is in a transient/inconsistent state.If you want to trim a tiny bit of duplication, you could skip the extra
laneLookupmap and just rely onlaneByIddirectly in the sorter and node mapping, sincegetLanealready guarantees every node ends up with an entry.
237-307: Deterministic sort and Node/Edge construction are correct and type-safeThe
(depth, lane, createdAt, id)sort yields a stable, predictable ordering, and usingdepth/laneto computepositiongives a clean grid layout. The Node/Edge objects:
- Respect React Flow’s expectations (
id,position,data,style,source,target,type,animated).- Apply active-path styling via
activePathIdsin a straightforward way.- Use
satisfies Node/satisfies Edgeto keep the typings honest.If this JSX label block grows further, consider extracting it into a small presentational component for readability, but it’s perfectly fine as-is.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/DiagramView.tsx(2 hunks)
🔇 Additional comments (1)
src/components/DiagramView.tsx (1)
29-30: Column gap increase is safe and improves readabilityBumping
columnGapto 80 cleanly widens horizontal spacing without affecting layout logic (positions are already computed fromboxSize.width + columnGap), so this is a low‑risk, purely visual tweak.
Summary by CodeRabbit
Chores
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.