Diff panel Improvements: file collapse, full-width toggle and better per thread state management#2444
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR introduces new user-facing features (file collapse, full-width toggle) and refactors diff panel state management from URL params to a per-thread store. While well-tested and frontend-only, the scope of new UI capabilities and ~750 lines of new logic warrants human review. You can customize Macroscope's approvability policy. Learn more. |
8cbe456 to
1dece16
Compare
Move diff-panel UI state from URL search params and component-local useState into the Zustand UI store. State that is meaningful per thread is keyed by scopedThreadKey so two threads can have different diff panels open / expanded / collapsed independently. Wider state (render mode, line wrap) lives in the store globally so it survives the remount that expand/collapse causes. Per-thread (persisted to localStorage): - diff panel open/closed (replaces ?diff=1 in URL) - full-width vs split-pane (new toolbar toggle) - per-file collapse (new chevron on each file header) Global session (in store, not persisted to disk): - render mode (split/stacked) - line wrap, hydrated once from settings.diffWordWrap The per-file collapse swaps the FileDiff out for a small CollapsedFileHeader rather than hiding content via CSS — the library's Virtualizer reserves vertical space from hunk metadata, so a CSS hide leaves a tall empty box and triggers ResizeObserver thrashing during scroll. The collapsed header inlines the same change-type SVG paths the library renders inside its shadow DOM so the new/modified/deleted/renamed icon is identical between collapsed and expanded views. Co-Authored-By: Claude Opus 4.7 <[email protected]>
1dece16 to
3a11c8d
Compare
Summary
-N +McountsScreenshots
File Collapse/Expand in diff view
Full Width Toggle Button
Full Width Diff View
Why per-file collapse swaps the component instead of hiding via CSS
The
@pierre/diffsVirtualizerreserves vertical space for each file based on hunk metadata —<div data-virtualizer-buffer>siblings of thepreget explicit pixel heights and grid columns inside thepregetmin-height: calc(N * 1lh). A CSS-only hide (e.g.[data-diff] > *:not([data-diffs-header]) { display: none }) leaves a tall empty box below collapsed files and causes ResizeObserver thrashing as the buffers and content fight to be measured (visible as scroll flicker). Rendering a small fixed-height stand-in lets the Virtualizer measure a stable height and lays the panel out cleanly.The compact header inlines the same change-type SVG paths the library uses in its sprite (the sprite lives inside each FileDiff's shadow DOM, so it can't be
<use>d from outside) so the icon next to the file path is pixel-identical to the expanded view.State scoping
Stored in
useUiStateStore:threadDiffOpenByIdthreadDiffFullWidthByIdthreadDiffFileCollapsedByIddiffRenderModediffWordWrapsettings.diffWordWrap?diff=1is removed fromDiffRouteSearch. Legacy URLs that still carry it parse cleanly and are ignored.diffTurnIdanddiffFilePathremain in the URL since they identify a specific selection within the panel and are useful for sharing.Test plan
package-lock.json(or any large file); confirm no empty space below the header and no flicker while scrollingvitest run(apps/web) andtsc --noEmitpass🤖 Generated with Claude Code
Note
Medium Risk
Medium risk because it rewires diff panel open/selection behavior from URL params to persisted Zustand state (per-thread) and changes routing/search parsing, which could cause regressions in navigation or state restoration across threads/sessions.
Overview
Moves diff panel open/closed, full-width, and per-file collapse state from URL/search params and component-local state into
useUiStateStore, persisted in localStorage and scoped per thread.Adds a diff toolbar toggle to expand the diff view to full width (hiding the chat pane) and implements per-file collapse/expand in
DiffPanel, while keeping sharable selection in the URL viadiffTurnId/diffFilePath.Removes the legacy
?diff=1flag fromDiffRouteSearchparsing/validation (still stripped for backward compatibility) and updatesChatViewand the chat route to toggle diff visibility via the UI store instead of navigation/search updates.Reviewed by Cursor Bugbot for commit 3a11c8d. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Move diff panel open/collapsed and full-width state to per-thread UI store
useUiStateStoreinstead of via the?diff=1URL query param, which is removed from routing and URL generation throughout.DiffPanelmount.?diff=1is no longer written to or read from the URL; onlydiffTurnIdanddiffFilePathremain as URL state. Existing bookmarks or links containing?diff=1will silently ignore that parameter.Macroscope summarized 3a11c8d.