Repository navigation
Graph views: flame, balloon, and hyperbolic layouts with a docked side panel - #102
Conversation
Implements the three alternative dependency visualizations from docs/VIZ-VIEWS-HANDOFF.md (issue #91), switchable from a segmented control in the graph toolbar, and moves selection details from the floating popover into a docked side panel shared by all four modes. - vizModel.ts: shared derivation layer per workspace — path-expanded subtree sizes, heaviest-first child ordering, BFS spanning tree, distinct-path counts, lineage hues — all cycle-guarded. - flameView.ts: icicle plot with lazy draw-time layout (sub-pixel blocks pruned into a spray strip), ancestors-pinned zoom, lineage hue per root subtree, red override for vulnerable packages. - balloonView.ts: constellation balloon tree with the tuned constants from the prototypes (SHRINK 0.52, FAN 3.6, sub-linear node sizing, two-tier root orbits, minimum hub screen sizes, biggest-first label budget, spatial-hash picking, LOD while interacting). - hyperbolicView.ts: Poincaré disk with Möbius-translation drag, animated click focus, geodesic edges, meaningful range rings; every transform is applied to the virtual hub as well (the documented hub-pinning bug). - graphModes.ts: mode switcher with reset-on-switch, shared docked dossier (version, kind, licence, vulnerabilities, subtree size, appears-in-N, clickable depends-on / required-by chips, open-in-list), shared search with fly-to/focus per mode, and a bottom status line showing the hover path trail instead of a tooltip covering the graph. - Classic graph view now reports selection through a new onSelect option and its floating popover is retired in favour of the side panel; its canvas, controls, and behaviour are otherwise untouched. - Alternative views mount their own canvas and clean up fully on switch (AbortController-scoped listeners, cancelled animation frames) — no leaked handlers across mode changes. - Theme-aware: colours resolve from the report's CSS variables at draw time; dev-only deps render dimmer; vulnerable packages red in all views. Verified in-browser on the repo's own scan and on a ~3,600-package monorepo scan (cal.diy, @calcom/web workspace: 98k-block flame renders in ~16 ms via lazy layout; all modes responsive, console clean, single canvas across rapid mode cycling). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
It no longer occupies layout space above the report: it floats bottom-right over the content with a close button. The header stat chips still convey missing evidence in place after dismissal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Skipped-collector warnings now say why: '(scan ran with --offline)' or '(scan ran with --no-maintenance)', flowing through to the report toast. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e dossier - The side panel now floats over the canvas with the toolbar's translucent blur treatment instead of occupying layout space. Every mode's fit-to-view subtracts the covered width (shared --graph-panel-space token, read by the classic graph view too, so content centres in the uncovered region); small screens switch to a bottom-sheet panel with no inset. - Balloon: the minor-root orbit is arc-packed instead of fixed-radius, so many light roots spread on a readable ring rather than piling into an overlapping donut; at idle every node keeps a >=0.85 px dot so leaf systems are visible in the fitted overview (interaction LOD unchanged). - Dossier header facts are now skimmable coloured chips with icons: version, kind (dot-coloured to match the graph key), licence, vulnerability status (green check / red warning), subtree size, and appears-in-N. - The toolbar key now explains each mode's colours: lineage-hue legend for flame/balloon, direct/sub for hyperbolic, plus the vulnerable marker — the hues were meaningful but undocumented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Alt-view canvases now span the whole shell underneath the translucent toolbar and status line (no seam band); views inset their content via a shared insetTop instead. - Balloon: minor-orbit roots get angular shares proportional to their enclosing radius (even-by-count spacing let differently-sized minors overlap into a rope); labels are collision-pruned biggest-first instead of drawn into each other; the depth-0 minimum screen size adapts to root count so hundreds of direct deps stop forcing ring overlap at fit zoom, while roots stay label-eligible at the reduced floor. - Overlay backgrounds carry ~0.92 opacity: Chromium's backdrop-filter does not blur composited canvas layers, so translucency over the graph was unreadable; blur remains for surfaces where it works. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, zoom-to-selection - .graph-overlay-top gets an explicit z-index so alt-view canvases can no longer paint over the toolbar or side panel. - buildVizModel now mirrors the classic view's fallback: a workspace with no direct dependencies (hoisting-only monorepo roots) promotes up to 40 parentless packages, so Workspace root shows the same tree in every mode. - Classic pan/zoom controls restyled into a compact cluster. - Balloon and hyperbolic get a floating "Reset view" button (flame resets via its pinned ancestors / double-click). - Balloon's picking grid now indexes every body, so deep leaf nodes are selectable once zoomed in; clicking a body flies to it (never zooming out), matching search/chip behaviour. - Classic graph focus now fits the highlighted subtree's bounding box into the uncovered viewport instead of just panning to the node. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…disk - Balloon: fly-to now animates the target's SCREEN position on a straight path to centre while scale eases. Interpolating pan and zoom independently could send the target off screen mid-flight and back, which read as a jarring detour. - Hyperbolic: mouse-wheel zoom magnifies the disk Euclideanly (1x-12x), anchored at the cursor, composing with the Möbius drag. Node radii, geodesics, and range rings all scale, so crushed near-rim clusters become readable; double-click and Reset view also clear magnification. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- focusOn animates the Euclidean magnification offsets back to zero alongside the Mobius translation, so a focused node lands at the viewport centre regardless of prior zoom/pan. - The classic controls and Reset button now sit 12px from the side panel, matching the 12px gap below the toolbar. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d labels - Sibling fans larger than six stagger across three radial shells, tripling angular breathing room for equal-weight leaf children that previously crushed onto a single arc. - On-screen node radius is capped at 22px: magnification now separates nodes instead of inflating them into each other. - Labels get the same biggest-first collision pruning as the balloon view, so focus fans show a readable subset instead of overprinted text (hovered/selected labels always win). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- README: the four switchable layouts, shared side panel/search/status line, lineage colour semantics, and workspace scoping get their own section; feature bullet and image captions updated. - Screenshots refreshed from a current full scan, plus two new ones for the flame and balloon views (05 shows a red vulnerability ring in orbit). - docs/VIZ-VIEWS-HANDOFF.md removed from the repo: it was a working handoff, not user documentation. It is preserved with the prototypes in the code-radar research directory, and its one open follow-up (hyperbolic re-rooting on focus) is now tracked as issue #101. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Derivation (vizModel):
- occ now counts a root's top-level appearance PLUS paths through its
dependents, matching the flame view's per-path rendering ("appears in N
places" was systematically 1 for direct deps that are also transitive).
- Root slugs are filtered against the dependencies map BEFORE the
parentless fallback check, and the fallback ignores self-dependencies -
both restoring parity with the classic view.
Hyperbolic:
- Focus animations are cancelled/retargeted by new interactions instead of
clobbering drags or silently dropping navigation for 420ms.
- Drag detection uses a cumulative screen-space threshold (slow drags no
longer register as clicks); pointerleave clears hover state; pick()
skips invisible nodes so empty-space double-click works near the rim;
focusIndex bounds-checks its index (stale out-of-range indices could
NaN-corrupt every position); focus/hover labels are exempt from the
70-label cap they were meant to be forced into.
Balloon:
- flyTo cancels the previous animation; resize() refits only when
dimensions change (theme flips no longer wipe pan/zoom); fitView seeds
bounds with the central body; wheel min-zoom tracks the fitted scale;
spatial-hash pick reach derives from the largest body; cumulative drag
threshold; devicePixelRatio re-read on resize; placement recursion skips
subtrees that stay sub-pixel even at maximum zoom.
Flame: hover indices invalidated on relayout; double-click no longer
double-focuses first; dead path cap removed; dpr re-read on resize.
Integration: workspace changes clear stale search results (whose closures
held indices into the discarded model - the NaN-corruption vector).
UI/docs: mode switcher is now an aria-pressed button group instead of an
incomplete ARIA tablist; the scan-status toast dodges the docked panel in
graph mode; README no longer claims the hover trail for the classic view.
Review: 7 dimension reviewers + 29 adversarial verifiers (36 agents);
2 findings refuted, duplicates merged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe report UI adds Flame, Balloon, and Hyperbolic layouts beside the classic graph. Shared models, search, selection dossiers, workspace handling, responsive controls, and canvas interactions support all layouts. The CLI adds explicit offline collector state and warnings. ChangesGraph layouts and shared navigation
Offline collector state
Estimated code review effort: 5 (Critical) | ~100 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant Main
participant GraphModes
participant AlternativeView
participant Dossier
User->>Main: select graph layout or package
Main->>GraphModes: route mode or search action
GraphModes->>AlternativeView: mount or focus layout
AlternativeView->>GraphModes: report hover or selection
GraphModes->>Dossier: render package details
Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (8)
report-ui/style.css (3)
1320-1341: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMerge the duplicated
.graph-controlsand.graph-canvas-shellrule blocks.
.graph-controlssetsright: 12pxat Line 1326 and then a second block at Line 1377 overrides it withright: max(var(--graph-panel-space, 0px), 12px)..graph-canvas-shellis likewise declared at Line 1121 and again at Line 1337 only to add--graph-panel-space. Source order makes the result correct, but a reader editing the first block will not see the later override.Move
--graph-panel-spaceinto the Line 1121 block and keep onerightdeclaration for.graph-controls.Also applies to: 1376-1378
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@report-ui/style.css` around lines 1320 - 1341, Merge the duplicate `.graph-controls` and `.graph-canvas-shell` declarations: move `--graph-panel-space` into the existing `.graph-canvas-shell` block, remove the later duplicate block, and retain a single `.graph-controls` `right` declaration using the intended panel-aware value.
379-389: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDerive the graph-mode offset from a shared custom property.
Line 381 hard-codes
right: 340px. The panel geometry is defined separately:--graph-panel-space: 324pxat Line 1340, and the panel itself iswidth: 300pxatright: 12px(Lines 1347-1349). The toast cannot read--graph-panel-spacebecause that property is declared on.graph-canvas-shelland the toast is a body-level fixed element.Declare
--graph-panel-spaceon:rootand override it inside the media query, then useright: calc(var(--graph-panel-space) + 16px)here. One value then drives the panel, the fit insets, and the toast offset.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@report-ui/style.css` around lines 379 - 389, Move the shared --graph-panel-space declaration to :root so the body-level .graph-mode .scan-status-banner can access it, and override that property in the relevant media query for responsive layouts. Replace the hard-coded right offset in .graph-mode .scan-status-banner with calc(var(--graph-panel-space) + 16px), preserving the existing mobile override behavior as appropriate.
1676-1679: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe popover is hidden by CSS while its logic still runs every frame.
display: none !importantsuppresses the popover, butreport-ui/graphView.tsstill callsupdatePopoverPositionat the end of everyrenderGraph(Line 2595). That readsgetBoundingClientRecton adisplay: noneelement each frame and computes clamped coordinates that are never shown.Note that the popover path is load-bearing:
showPopoverfiresoptions.onSelect, which drives the docked dossier. Do not delete it. Instead, add an early return inupdatePopoverPositionwhen the popover is not rendered, and record why the element is retained.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@report-ui/style.css` around lines 1676 - 1679, Keep the popover behavior and showPopover flow intact, but update updatePopoverPosition in graphView.ts to return immediately when the popover is not rendered or is hidden, before calling getBoundingClientRect or calculating coordinates. Add a concise comment documenting that the hidden element is retained because showPopover triggers options.onSelect for the docked dossier.report-ui/vizModel.ts (1)
239-260: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winCache the resolved theme;
resolveVizThemeruns on the render hot path.
resolveVizThemeperforms sevengetComputedStyle(...).getPropertyValuereads per call.graphModes.tspassesresolveVizThemedirectly as thethemecallback.flameView.fillForcallscb.theme()once per drawn bar, so a single frame with thousands of blocks triggers thousands of style resolutions. Cache the resolved value and invalidate it whendata-themechanges.♻️ Proposed memoisation
+let themeCache: { key: string; value: VizTheme } | null = null; + export function resolveVizTheme(): VizTheme { const isDark = document.documentElement.getAttribute("data-theme") !== "light"; + const key = isDark ? "dark" : "light"; + if (themeCache && themeCache.key === key) return themeCache.value; - return { + const value: VizTheme = { isDark, @@ panelText: cssVar("--text-primary", isDark ? "`#e6eef8`" : "`#0f172a`"), }; + themeCache = { key, value }; + return value; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@report-ui/vizModel.ts` around lines 239 - 260, Cache the resolved VizTheme used by resolveVizTheme so repeated calls reuse one computed value instead of rereading CSS variables. Invalidate the cache whenever the document root’s data-theme value changes, ensuring subsequent calls recompute the correct light or dark theme while preserving the existing fallback values.report-ui/main.ts (2)
3692-3694: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winAvoid the second
adaptDatasetcall.
initGraphViewalready callsadaptDataset(options.report, options.knownDepKeys, options.resolveDepKey)internally atreport-ui/graphView.tsLine 946. Line 3693 runs the same adaptation again over the whole dependency set.adaptDatasetiterates every dependency record several times and rebuilds the full dependency map, so the report pays that cost twice when the graph view opens.Compute the dataset once before
initGraphViewand pass the same object to both, or expose the adapted dataset onGraphViewHandle.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@report-ui/main.ts` around lines 3692 - 3694, Eliminate the duplicate adaptDataset call between initGraphModes and initGraphView: compute the adapted dataset once and reuse the same object for both consumers. Update the surrounding initialization flow in initGraphView and the graphModes setup so the existing dataset behavior is preserved without rebuilding the dependency map.
2373-2381: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConfirm the dismiss button keeps a visible focus indicator.
all: unsetinstyle.cssat Line 392 removes the default focus outline. The:focus-visiblerule at Lines 408-412 restores onlycolorandbackground. Verify that the resulting contrast change is perceivable in both themes, or add an explicitoutline.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@report-ui/main.ts` around lines 2373 - 2381, Update the scan status dismiss button created in the dismiss handler to retain a clearly visible keyboard-focus indicator despite the global all: unset styling. Ensure its :focus-visible styling in the scan-status-dismiss CSS provides sufficient perceivable contrast in both themes, adding an explicit outline if necessary while preserving the existing color and background behavior.report-ui/graphModes.ts (1)
377-396: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winPrecompute lowercase package names for the search.
The handler runs on every
inputevent. Line 384 callstoLowerCase()on each package name during the scan, so each keystroke allocates one string per scanned package. A query with no match scans the whole index. Build the lowercase names once when the model is built, then reuse them.Also consider adding
aria-live="polite"to the results list so assistive technology announces the result count.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@report-ui/graphModes.ts` around lines 377 - 396, Precompute and store lowercase package names when ensureModel builds the model, then update the search handler to compare q against those cached values instead of calling toLowerCase() for each scanned ref. Preserve the existing match limit and result rendering, and mark options.searchResults with aria-live="polite" so result updates are announced.src/report.ts (1)
392-404: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKeep the graph markup synchronized.
report-ui/index.htmlandsrc/report.tscontain duplicate graph markup. The build does not synchronize these HTML blocks. A future ID change can preventinitGraphModesfrom initializing in the generated report while the development harness still works. Extract a shared template or add a test that compares their graph IDs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/report.ts` around lines 392 - 404, Synchronize the duplicate graph markup used by report-ui/index.html and src/report.ts by extracting a shared template, or add a test that compares all graph-related IDs in both blocks. Ensure initGraphModes receives the same required elements in generated reports and the development harness.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@report-ui/balloonView.ts`:
- Around line 460-473: The pointer gesture cleanup is missing cancellation
handling in both views. In report-ui/balloonView.ts lines 460-473, add a canvas
pointercancel listener using { signal } that resets dragging and movedInDrag and
removes the dragging class; in report-ui/hyperbolicView.ts lines 428-441, add
the same cleanup and also clear last so stale coordinates cannot affect the next
gesture.
- Around line 556-561: Update focusIndex to handle packages absent from
firstIdxOf instead of returning silently: either preserve a pickable entry for
pruned packages during place, or resolve and flyTo the nearest placed ancestor.
Ensure search results still move the balloon view for pruned packages.
- Around line 65-118: Update place to enforce a hard maximum on materialised
placements before creating or expanding a node, using a shared placement-budget
constant and the existing px length as the count. When the budget is exhausted,
retain the current placement as a leaf and stop recursing into its children,
preserving already-created arrays and spatial-grid behavior while defining the
truncated view through the resulting leaf node.
In `@report-ui/graphModes.ts`:
- Around line 354-365: Update the workspaceSelect change handler to call
renderDossierEmpty() unconditionally after clearing the discarded model, rather
than only inside the mode !== "graph" branch; keep the existing destroyActive,
mountActive, and statusHint behavior scoped to alternative modes.
In `@report-ui/graphView.ts`:
- Around line 1946-1979: Update the JSDoc for focusViewportOn to describe
fitting the focus layout’s bounding box within the available viewport and
directly assigning the calculated zoom, removing references to the obsolete
1.35× zoom comparison and easing behavior.
In `@report-ui/hyperbolicView.ts`:
- Around line 221-272: In draw, precompute every node’s radius once per frame
into a typed radii array using nodeRadius, then use radii[id] for orderDraw
sorting, node rendering, and both forced and sized label filters. Ensure the
cached radii remains in scope through the label loop, including replacing its
nodeRadius(id) usage, without changing the existing ordering or filtering
behavior.
- Around line 486-501: Update the dpr declaration and resize function in
hyperbolicView so resize refreshes dpr from the current window.devicePixelRatio
before calculating canvas dimensions. Preserve the existing sizing and drawing
logic while ensuring canvas.width and canvas.height use the refreshed ratio.
In `@report-ui/style.css`:
- Around line 1414-1431: Restore a clear keyboard focus indicator by adding an
explicit outline declaration to the :focus-visible rules for
.graph-search-results li button, .graph-dossier-chip, .graph-dossier-open, and
.graph-mode-btn, while preserving their existing focus color, background, and
border styling.
---
Nitpick comments:
In `@report-ui/graphModes.ts`:
- Around line 377-396: Precompute and store lowercase package names when
ensureModel builds the model, then update the search handler to compare q
against those cached values instead of calling toLowerCase() for each scanned
ref. Preserve the existing match limit and result rendering, and mark
options.searchResults with aria-live="polite" so result updates are announced.
In `@report-ui/main.ts`:
- Around line 3692-3694: Eliminate the duplicate adaptDataset call between
initGraphModes and initGraphView: compute the adapted dataset once and reuse the
same object for both consumers. Update the surrounding initialization flow in
initGraphView and the graphModes setup so the existing dataset behavior is
preserved without rebuilding the dependency map.
- Around line 2373-2381: Update the scan status dismiss button created in the
dismiss handler to retain a clearly visible keyboard-focus indicator despite the
global all: unset styling. Ensure its :focus-visible styling in the
scan-status-dismiss CSS provides sufficient perceivable contrast in both themes,
adding an explicit outline if necessary while preserving the existing color and
background behavior.
In `@report-ui/style.css`:
- Around line 1320-1341: Merge the duplicate `.graph-controls` and
`.graph-canvas-shell` declarations: move `--graph-panel-space` into the existing
`.graph-canvas-shell` block, remove the later duplicate block, and retain a
single `.graph-controls` `right` declaration using the intended panel-aware
value.
- Around line 379-389: Move the shared --graph-panel-space declaration to :root
so the body-level .graph-mode .scan-status-banner can access it, and override
that property in the relevant media query for responsive layouts. Replace the
hard-coded right offset in .graph-mode .scan-status-banner with
calc(var(--graph-panel-space) + 16px), preserving the existing mobile override
behavior as appropriate.
- Around line 1676-1679: Keep the popover behavior and showPopover flow intact,
but update updatePopoverPosition in graphView.ts to return immediately when the
popover is not rendered or is hidden, before calling getBoundingClientRect or
calculating coordinates. Add a concise comment documenting that the hidden
element is retained because showPopover triggers options.onSelect for the docked
dossier.
In `@report-ui/vizModel.ts`:
- Around line 239-260: Cache the resolved VizTheme used by resolveVizTheme so
repeated calls reuse one computed value instead of rereading CSS variables.
Invalidate the cache whenever the document root’s data-theme value changes,
ensuring subsequent calls recompute the correct light or dark theme while
preserving the existing fallback values.
In `@src/report.ts`:
- Around line 392-404: Synchronize the duplicate graph markup used by
report-ui/index.html and src/report.ts by extracting a shared template, or add a
test that compares all graph-related IDs in both blocks. Ensure initGraphModes
receives the same required elements in generated reports and the development
harness.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 62f9b5be-b8c2-4054-9b38-3b958d1083dd
⛔ Files ignored due to path filters (10)
dist/cli.jsis excluded by!**/dist/**dist/report-assets.jsis excluded by!**/dist/**dist/report.jsis excluded by!**/dist/**docs/screenshot-01.jpgis excluded by!**/*.jpgdocs/screenshot-02.jpgis excluded by!**/*.jpgdocs/screenshot-03.jpgis excluded by!**/*.jpgdocs/screenshot-04.jpgis excluded by!**/*.jpgdocs/screenshot-05.jpgis excluded by!**/*.jpgreport-ui/dist/report.cssis excluded by!**/dist/**report-ui/dist/report.iife.jsis excluded by!**/dist/**
📒 Files selected for processing (13)
README.mdreport-ui/balloonView.tsreport-ui/flameView.tsreport-ui/graphModes.tsreport-ui/graphView.tsreport-ui/hyperbolicView.tsreport-ui/index.htmlreport-ui/main.tsreport-ui/style.cssreport-ui/vizModel.tssrc/cli.tssrc/report-assets.tssrc/report.ts
Valid findings fixed: - pointercancel now resets drag state in balloon and hyperbolic views (interrupted gestures could leave dragging stuck on). - hyperbolicView refreshes devicePixelRatio on resize (the balloon/flame fix from the agent review had missed this view) and caches per-frame node radii used across sorting, rendering, and label filtering. - Balloon placement gets a hard 250k budget (subtrees beyond it become leaves) on top of the geometric cutoff, and focusIndex falls back to the nearest placed spanning-tree ancestor so search still navigates to pruned packages. - Workspace changes clear the dossier in every mode, not just alt modes. - Focus-visible outlines restored on all unset-styled interactive elements (search results, chips, open-in-list, mode buttons, toast dismiss). - --graph-panel-space moved to :root so the fixed scan-status toast derives its graph-mode offset from the same token as everything else. - Search caches lowercased names per model and announces results via aria-live; theme token resolution is cached per data-theme value (it was re-reading CSS variables per flame bar per frame). - updatePopoverPosition skips layout work for the CSS-hidden popover, with a comment on why the element is retained; stale focus JSDoc corrected. - New test pins the graph-section ids of report-ui/index.html and the src/report.ts template together so the duplicated markup cannot drift. Skipped: deduplicating the adaptDataset call between initGraphView and initGraphModes - it is a one-time O(dependencies) adaptation (~ms at init) and removing it would widen initGraphView's API for no user-visible gain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/reportTemplateSync.test.ts`:
- Around line 13-14: Update the section extraction logic in the synchronization
test to fail immediately when source.indexOf('</section>', start) returns -1,
rather than passing undefined to source.slice. Preserve the existing slicing
behavior when the closing tag is present so malformed graph sections cannot
produce a false-positive test.
- Around line 15-19: Update the ID extraction helper in reportTemplateSync tests
to retain the raw IDs while separately validating uniqueness for each template.
Add an assertion that the number of extracted IDs equals the number of unique
IDs before sorting or comparing templates, so duplicate DOM IDs cause the test
to fail.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 56fb3295-d81d-401d-b16a-174d793bd1cd
⛔ Files ignored due to path filters (3)
dist/report-assets.jsis excluded by!**/dist/**report-ui/dist/report.cssis excluded by!**/dist/**report-ui/dist/report.iife.jsis excluded by!**/dist/**
📒 Files selected for processing (8)
report-ui/balloonView.tsreport-ui/graphModes.tsreport-ui/graphView.tsreport-ui/hyperbolicView.tsreport-ui/style.cssreport-ui/vizModel.tssrc/report-assets.tssrc/reportTemplateSync.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- report-ui/graphModes.ts
- report-ui/hyperbolicView.ts
- report-ui/graphView.ts
- report-ui/style.css
- report-ui/balloonView.ts
- report-ui/vizModel.ts
…icate ids An unclosed graph section previously sliced to end-of-file instead of failing, and the Set-based id collection would have masked duplicate DOM ids within one template. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements the graph-view overhaul requested in #91: the floating popover is replaced by a docked side panel shared across all views, and three new dependency visualizations join the classic graph, switchable from the toolbar.
The four layouts
Shared UX (the #91 asks)
Also on this branch
--offline, in each skipped-collector warning).Review
Beyond the usual suite (189 unit tests, dual typecheck, in-browser verification on a ~3,600-package monorepo), the branch went through a 36-agent review workflow: 7 dimension-focused reviewers (derivation math, each view, integration/lifecycle, DOM/CSS/security, CLI/docs) with every finding adversarially verified against the code. 27 confirmed findings were fixed in the final commit — including an "appears in N places" undercount, a NaN-corruption path via stale search results, animation-lifecycle races, and drag-vs-click misclassification. 2 findings were refuted.
Design provenance: ported from research prototypes (spiral-flame and fisheye-lens variants were evaluated and rejected; force-directed layouts deliberately avoided). Hyperbolic re-rooting-on-focus is tracked as follow-up #101.
Closes #91.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
UI Improvements