feat(desktop): move the changed-files list back into the right sidebar

Merged
AV
2mo ago
+1046-398

What & why

#7102 folded the sidebar's Changes tab into the Changes pane on the assumption that the right sidebar was going away. It isn't yet, so the changed-files list returns to the sidebar as a Changes tab — keeping the pane-era design (one scope row "Commits N vs base", per-section diffstats, staging, hover discard, context menus, drag-to-terminal) rather than the old three-row header. The Changes pane keeps only the diff: its resizable tree panel and the toolbar's Files pill are gone.

A few things that surfaced while putting it back:

  • Top-bar Changes control is a toggle. Clicking the diff-stats pill or the PR badge closes the Changes pane when the active tab shows one, and opens/focuses one otherwise. The face reads as pressed while a pane is in view (aria-pressed, filled pill, brighter PR number) and the pill's label flips to "Close changes".
  • "Open Changes" reveals the sidebar tab. The control, ⌘⇧L, the "+" menu, and the empty-state action open the sidebar on Changes as well as the pane — the pane alone has no file picker any more. Closing leaves the sidebar alone.
  • Section label in the toolbar row. "Unstaged 21" / "Against base 17" now sits in the diff toolbar after the collapse-all button instead of on a strip of its own.
  • Polish: the scope row's "vs" gets equal spacing on both sides (the base-branch trigger is now the same chip as the commit-filter trigger); sidebar tabs size by content so "Changes 99+" no longer truncates at the default width; a collapsed file card closes with a full border and rounded corners instead of an open bottom edge.

How it works

  • The panel subtree moves wholesale to WorkspaceSidebar/hooks/useChangesTab (git renames), returning a SidebarTabDefinition like useReviewTab. Rows navigate the workspace's diff pane through openDiffPane; ⇧-tier clicks open a new diff tab.
  • useDiffPaneTarget reads the focused diff pane's path/change key from the pane store and feeds it back as the row highlight, held while focus moves to a terminal or file pane and cleared once no diff pane remains.
  • setWorkspaceSidebarTab is the one place that switches the sidebar's per-workspace tab, shared by the Files reveal and Open Changes.
  • findVisibleChangesPane / closeVisibleChangesPane sit beside openChangesPaneInStore and drive the toggle (the store drops a tab whose last pane closes).
  • DiffViewToolbar's tree pill becomes an optional tree prop and it gains a children slot; the PR Code tab passes its own tree and is otherwise unchanged.
  • The changes sidebar tab id returns to the schema as the default (pages stays retired); rows healed to files by #7102 keep their stored value.
  • Collapsed cards: Pierre drops the [data-diff] body from a file's shadow root when collapsed, so a :has() rule closes a header with no body sibling.

How I tested it

Live over CDP in this worktree's dev app (zero console errors throughout):

  • Sidebar shows Files / Changes (99+) / Review; Changes renders the scope row and sectioned list
  • Clicking a row opens the diff pane and highlights the row; clicking another row moves the highlight
  • ⌘L closes the sidebar; ⌘⇧L reopens it on Changes with the highlight kept and the pane focused
  • Files tab → top-bar pill switches the sidebar back to Changes
  • Top-bar face (stats pill and PR badge) closes the visible pane, clears the pressed state, and reopens on the next click
  • No Files pill / tree panel in the Changes pane; PR Code tab keeps its tree
  • Scope row measures 10px on each side of "vs"; tab labels no longer clip at the default sidebar width
  • Section label renders inside the toolbar row with no stray strip
  • Collapsed-card rule checked in a shadow-root fixture inside the renderer (diff body: open bottom; no body: closed; plain-file body: open) after observing the collapsed DOM shape live

Automated:

  • bun run typecheck, bun run lint
  • bun test in apps/desktop: 3338 pass. The one failure is LeaderboardRank expecting production URLs while the worktree .env points NEXT_PUBLIC_MARKETING_URL at localhost — unrelated to this branch
  • bun run --cwd packages/i18n check — "Changes" tab label restored with its previous 16 translations; new "Close changes" label translated in all locales
  • New unit tests for the close/toggle helpers (split pane, diff-only tab, background diff tab)

Screenshots: captured over CDP; not embedded here because nothing in the repo hosts images from the CLI. Happy to add them to the description.

Known limitations / follow-ups

  • docs/pages/changes-pane-pr-parity.html still describes the in-pane tree from #7102.
  • Only the top-bar control toggles; ⌘⇧L, the "+" menu item, and the empty-state action keep open-or-focus semantics.
  • Deferred/binary placeholder items render Pierre [data-code] bodies, which don't get the card body border — pre-existing, untouched here.

Checklist

  • PR title follows conventional commits (type(scope): subject)
  • bun run lint and bun run typecheck pass (CI fails on lint warnings too)
  • "Allow edits from maintainers" is checked on fork PRs (not a fork)

https://claude.ai/code/session_01F5ZQf3BWvxUwSRcKj12x1m


Summary by cubic

Moves the changed-files list out of the Changes pane and back into the right sidebar as a "Changes" tab — #7102 folded it in on the assumption the sidebar was going away, which hasn't happened. The pane now shows only the diff (its resizable tree panel and the toolbar's Files pill are gone), while the tab keeps the pane-era design: one scope row, per-section diffstats, staging, hover discard, context menus, and drag-to-terminal.

Behavior changes

  • The top-bar Changes control (diff-stats pill or PR badge) now toggles the pane: it closes a visible one and opens or focuses one otherwise, reading as pressed while a pane is in view.
  • Opening Changes from any entry point — the control, ⌘⇧L, the "+" menu, the empty-state action — also reveals the sidebar's Changes tab, since the pane alone has no file picker.
  • Closing from the top-bar control takes the sidebar down too if it's still on Changes, and leaves it alone once it has moved to Files or Review.
  • The "changes" tab id returns to the schema as the default; "pages" stays retired, and rows healed to "files" by #7102 keep their stored value.
  • Sidebar tab switches (tab strip, file reveal, Open Changes) share one helper that falls back to a session-only store when a workspace has no local-state row. The choice carries into that workspace's row once one is created (e.g. pinning a local main), and the session entry is dropped.
  • The row highlight clears when the focused diff pane releases its path (e.g. collapse-all) and holds only while focus is on a terminal or file pane; toggling closes the focused diff pane when a tab holds several.
  • The PR badge's aria-label names the action ("Open changes, #N" / "Close changes, #N"), and commit-row ages use formatCompactRelativeTime.

UI polish

  • The current-section label ("Unstaged 21", "Against base 17") moved into the diff toolbar row instead of its own strip.
  • The base-branch trigger matches the commit-filter chip so "vs" gets equal spacing; sidebar tabs size by content so "Changes 99+" no longer truncates; collapsed file cards close with a full border and rounded corners.
  • Diff card +/- counts hug the right edge; hover actions surface to their left.

Summary by CodeRabbit

  • New Features
    • Added a Changes tab to the workspace sidebar with file counts, selection, tree and folder views.
    • Added commit and branch filters, range selection, staging, discarding, file actions, drag-and-drop, and editor access.
    • Changes controls now toggle the pane and reflect its open state.
  • Style
    • Improved sidebar labels, badges, branch selector styling, and collapsed diff appearance.
  • Refactor
    • Diff panes now focus on diff content while Changes is managed from the sidebar.
  • Tests
    • Added coverage for loading behavior and changes-pane navigation.