Paradev · Engineering note

The Changes pane learns from the PR view

The v2 workspace Changes pane now renders like the PR view's Code tab — card-per-file diffs, a resizable file tree, a real toolbar — and links straight to the in-app PR view when the branch has one. Built by extracting the PR tab into shared components, not by copying it.

branch changes-pane-pr-view feat 92fa049 · merge 6244f3a 37 files · +1387 −503 then merged main (131 commits) 2026-09-01
01

What shipped

Full visual & structural parity

Bordered, rounded card per file with a 16px gap; filename-first headers with the directory trailing off muted; emerald/red ± counts; always-visible collapse chevrons; a resizable in-pane file tree with ± row decorations and click-to-navigate; a toolbar with the Files pill, collapse/expand-all, prev/next comment navigation, and the unified/split toggles. Everything workspace-specific survived: section bar, inline editing, per-file actions, viewed-files, ⌘F search, scroll persistence.

A link into the in-app PR view

When the workspace's branch has a linked pull request, the pane header shows a state-tinted PR icon and #number. Clicking it opens /pull-requests/$prNumber inside the app — until now, every PR affordance in the product linked out to github.com. Hidden when there is no PR, and for session workspaces that have no project scope.

02

The pane, after

Changes #6882 💬 👁 ⫽ ✕ opens the in-app PR view → Files 39 ⌵⌵ ↑ 1/7 ↓ ▤ ▥ ▾ lib/pierreTree formatDiffStats.ts +11 formatDiffStats.test.ts +20 ▾ …/DiffPane DiffPane.tsx +229 −45 DiffFileTree.tsx +89 DiffPanePRLink.tsx +76 ▾ …/PullRequestCodeTab PullRequestCodeTab.tsx −346 ChangesTreeView.tsx +2 −8 resizable · auto-hides under 700px UNSTAGED 37 ▾ formatDiffStats.ts apps/desktop/src/renderer/lib/pierreTree/ +11 1 /** `+N −M` summary for a file's diff stats … */ 6 export function formatDiffStats(additions, deletions) { 7 if (additions === 0 && deletions === 0) return ""; 8 … 16px gap ▸ DiffFileTree.tsx …/DiffPane/components/DiffFileTree/ +89 ▾ reference.md .agents/skills/design-system/ +88 52 ## Known deviations (documented, not yet fixed) coderabbitai 1h ago Update the sidebar showcase-gap statement… Resolve conversation ↑↓ walks these
Schematic of the redesigned pane, drawn from the verified build (the session's live screenshots were session-local and expired; every element here was exercised over CDP against the running app — including that exact CodeRabbit thread on PR #6882).
03

One diff surface, shared

The PR Code tab was the styling source, so its pieces were promoted into shared code and both surfaces now consume them. PullRequestCodeTab.tsx dropped ~300 lines in the process. When main's i18n sweep landed mid-branch, the components adopted the exact message ids of the strings they replaced, so every existing translation carried over.

Extracted / created
What it is
useDiffCardCodeViewTheme + diffCardUnsafeCss
The card look: bordered rounded header/body pairs, 16px gaps, PR-row ± colors, app background instead of the terminal theme's.
DiffViewToolbar
Files pill, collapse/expand-all, comment prev/next, unified/split — writing the same persisted setting on both surfaces.
DiffFileHeaderName + splitPath
Filename-first header title with the truncating muted directory.
DiffFileCollapseButton
The per-file chevron; replaces DiffPane's old FileIcon-on-hover prefix (DiffHeaderPrefix deleted).
lib/pierreTree ← formatDiffStats, buildCollisionSafeTreePaths
Promoted from two single-use homes into the shared Pierre-tree library.
DiffFileTree + buildDiffTreeData
New: the in-pane tree. Dedupes a path listed in two sections (staged + unstaged) into one row — summed ± counts, first occurrence wins the click target.
useDiffCommentNavigation + buildOrderedThreads
New: prev/next over review threads in diff order, tracked by thread id so background refetches can't desync the cursor.
DiffPanePRLink
New: the pane-header chip into the in-app PR view. Its two strings are the only new i18n messages — translated across all 16 locales.
04

Found live, fixed live

Verification ran against the real app over CDP — real clicks, screenshots, and DOM measurement, using this very worktree's own 39-file diff as the test changeset. Four real bugs surfaced that code review alone would have missed; zero console errors across the whole session.

4.1Long paths painted under the ± counts

Pierre slots the filename suffix through an unstyled light-DOM wrapper div. As a flex item it defaults to min-width: auto and refuses to shrink — measured 893px inside a 513px header — so the directory text overflowed beneath the diff-stat counts. Latent in the PR tab too; its pane was just always wide enough to hide it.

slot[name='header-filename-suffix']::slotted(*) { min-width: 0 } in the shared card CSS, letting the truncate chain ellipsize.

4.2A see-through strip above sticky headers

Padding-top on the scroll container let file content show through an 8px band above every pinned card header.

Horizontal inset only on the scroller; sticky headers pin flush.

4.3Collapse-all lost a fight with the scroll hook

The scroll hook keeps its navigation target expanded while sticky tracking is armed, so collapse-all left the last-clicked file open and the toggle never flipped.

Collapsing the sticky target now releases the target in the same pane-data write.

4.4Tree state bled between pane instances

Same-kind panes render through one unkeyed component instance, so a recreated Changes pane inherited the previous pane's manual tree override — a closed pane's "show tree" choice kept the tree open in a fresh 330px pane where it should have auto-hidden.

Render-phase state reset keyed on the pane id (and biome-proof, after the linter quietly gutted the effect version).

05

Then main moved 131 commits

Merging origin/main brought a repo-wide Lingui i18n sweep and a deferred-diff-loading feature straight through the restructured files.

06

Verification

CheckResult
unit tests (touched areas)49 pass — 5 new co-located test files: tree data dedupe, thread ordering, path splitting, diff-stat formatting, collision-safe paths
tsc --noEmit (desktop)pass — verified on the exact merged tree in a fresh worktree; this workspace's local env has a phantom-type quirk that misreports, the code is clean
lingui compile --strictpass — every locale complete
lint / sherifpass
CDP end-to-endpass — tree click-to-navigate, collapse/expand-all, tree toggle + 700px auto-hide with manual override, unified/split sync across surfaces, comment nav force-expanding threads, PR chip → in-app /pull-requests/6882, PR Code tab pixel-unchanged