feat(site/src/pages/AgentsPage): consolidate git panel tab strip into a view switcher dropdown - #27012
Conversation
…her when there is only one view
…plicated inline shapes in git switcher
…es in git switcher
…ain branch row in git panel
|
/coder-agents-review |
|
Chat: Review posted | View chat Review historydeep-review v0.9.0 | Round 2 | Last posted: Round 2, 21 findings (2 P2, 5 P3, 4 P4, 7 Nit, 3 Note), COMMENT. Review Finding inventoryFindings
Round logRound 1Panel review. Netero first pass: 1 P3, 1 Nit, 2 Note. Panel: 14 reviewers (bisky, hisoka, mafu-san, mafuuu, pariston, gon, leorio, nami, ging-react, ging-ts, komugi, robin, zoro, meruem). Ging-react, ging-ts, komugi: no findings. Cross-check produced 13 new findings: 2 P2, 5 P3, 4 P4, 3 Nit, 3 Note. Total: 2 P2, 6 P3, 4 P4, 3 Nit, 3 Note. Reviewed against bfbacd6..4eb29cf. Round 2Churn guard: PROCEED. 17/17 addressed. Netero: 1 Nit (sibling of CRF-4). Panel: 11 reviewers (bisky, hisoka, mafu-san, mafuuu, pariston, nami, komugi, gon, leorio, ging-react, kite). Bisky, komugi: no findings. 1 P3, 4 Nit new. All R1 fixes verified. Reviewed against e5990a9..47cd08b. About deep-reviewCRF = Coder Review Finding (P0-P4, Nit, Note)
|
There was a problem hiding this comment.
The tab-to-dropdown refactor is well-structured. The ViewSwitcher cleanly separates three render paths (empty, single, multi), the ResizeObserver-based truncation detection is correct, and the Storybook updates faithfully track the new component structure. Consolidating PullRequestStateBadge from RemoteDiffPanel into the switcher trigger is a good ownership move.
2 P2, 6 P3, 4 P4, 3 Nit, 3 Note.
The PR description should be updated before merge: it claims a tab-label count feature and countGitPanelViews helper that were implemented and reverted within the branch, and references background tokens that were intentionally removed (details in CRF-5).
CI reports a title check failure (title). The scope site/AgentsPage in the PR title is not a real filesystem path; changed files live under site/src/pages/AgentsPage/components/.
"The description is a chart that says the patient received treatment they didn't receive." Leorio
site/src/pages/AgentsPage/components/GitPanel/GitPanel.stories.tsx:217
P4 [CRF-12] Three of four prStateLabel() branches lack any assertion. PullRequestAndWorkingChanges asserts "Open", but DraftPullRequest (line 217), MergedPullRequest (line 242), and ClosedPullRequest (line 264) render the new ViewSwitcher without play functions. If prStateLabel returned "Open" for every state, all tests would pass. Adding one assertion per story would close it. (Bisky)
🤖
site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx:87
Nit [CRF-16] repoTabLabel still says "Tab" in its name. The function now serves the view switcher (populating triggerIdentifier and itemSecondary), not a tab strip. Consider repoLabel or repoShortName. (Gon)
🤖
site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx:158
Note [CRF-17] localRepos is Array.from(roots).sort(...), which creates a new array reference every render. Since it appears in the useEffect dependency array on line 198, React's Object.is comparison re-fires the effect every render. The correction logic inside is cheap, so this is not a performance concern today. If the component grows heavier, memoizing localRepos with useMemo would tighten it. (Hisoka)
🤖
🤖 This review was automatically generated with Coder Agents.
Response to coder-agents-review feedback (CRF-1 through CRF-17). - Convert ViewItem to a discriminated union so handleSelectItem no longer needs a nullable-repoRoot guard (CRF-7). - Reuse prStateClasses inside PrStateIcon so a fifth state only needs one entry (CRF-8). - Skip the ml-4 nested indent when no remote/PR entry sits above local entries (CRF-6). - When a branch is pushed with no PR, the trigger identifier reads the head branch instead of duplicating 'Branch | Branch' (CRF-9). - Compute effectiveView inline so a repo removal never lands on 'No changes' for a frame before the correction effect runs (CRF-15). - Only render the PR title row when the PR view is active (CRF-14). - Rename repoTabLabel to repoLabel and update stale 'tab / tab strip' comments after the ViewSwitcher refactor (CRF-2, CRF-4, CRF-16). - Drop comments that narrate mechanism already visible in the code (CRF-11). - Memoize repoStats and localRepos to avoid new array identities each render (CRF-17). - Add data-testid to the ViewSwitcher empty state; tighten the CleanRepoFromStart assertion so it no longer passes vacuously (CRF-1). - Add play assertions to Draft/Merged/Closed PR stories to cover each prStateLabel branch (CRF-12). - ViewSwitcherOpen story now clicks a menu item to exercise the view swap path; update its JSDoc to match (CRF-3, CRF-13). - Reword 'closed state' comment in stories to 'collapsed state' to avoid overlap with the ClosedPullRequest story (CRF-10).
|
/coder-agents-review Addressed all 17 review items from the prior pass (CRF-1 through CRF-17). Fixes are in commit
Coder Agent generated on behalf of @tracyjohnsonux. |
|
Note: pixel doesn't have any relevant screenshots to review for this PR. Ignoring for now. |
Drop or reword comments that narrate mechanism already visible from the surrounding code, per CRF-11's spirit. Keep behavioral rationale (nesting invariant, Radix portal note, disabled tooltip workaround, ever-dirty union) and interface JSDoc.
There was a problem hiding this comment.
All 17 R1 findings addressed in a single commit. The fixes target root causes throughout: discriminated union for type safety, shared prStateClasses for dedup, synchronous effectiveView to prevent the flash, conditional indent gating, and test coverage additions for every untested branch. All R1 fixes verified by the panel.
1 P3, 4 Nit.
The CRF-14 fix (scoping the PR title row to the remote view) introduced a new issue: the ResizeObserver for truncation detection depends only on [prTitle], so it doesn't reattach when the span remounts after a view-switch cycle (details in CRF-18). Three reviewers independently traced this sequence.
CI is pending (5 passed, 7 pending, 12 skipped).
"I tried to build a case against the central premise and couldn't." Pariston
site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx:133
Nit [CRF-20] showRemoteTab still says "tab." Every comment and every other name in the file now says "view" or "entry." showRemoteView matches the new vocabulary. Used 9 times, all local to GitPanel. (Gon, Leorio)
🤖
🤖 This review was automatically generated with Coder Agents.
… switch The truncation ResizeObserver effect depended only on [prTitle], so when the PR title span unmounted (switching to a Working view) and remounted (switching back), no observer attached to the new element and isPrTitleTruncated froze at its pre-unmount value (CRF-18). Key the effect on showPrTitleRow instead: it toggles across the unmount/remount cycle, and its truthy value is the title itself, so title changes still re-run the effect.
GitPanel.tsx is in the React Compiler's compilation scope, so the compiler already memoizes these derivations; plain const IIFEs compile to the same output (CRF-22). Also removes the useMemo import this branch introduced.
…her internals
- Replace the prTitleRef/useEffect truncation detection with a ref
callback that returns a cleanup: the observer attaches whenever the
span mounts, and key={prTitle} covers in-place title changes.
ResizeObserver fires once on observe, so no separate initial check.
- Rename ViewSwitcher to GitViewSwitcher, matching the GitView type.
- Inline the trigger class strings instead of hoisted constants.
| // Compute per-repo diff stats from unified diffs. The React | ||
| // Compiler memoizes these derivations. | ||
| const repoStats = (() => { |
There was a problem hiding this comment.
| // Compute per-repo diff stats from unified diffs. The React | |
| // Compiler memoizes these derivations. | |
| const repoStats = (() => { | |
| // Compute per-repo diff stats from unified diffs. | |
| const repoStats = (() => { |
What
Replaces the git panel's tab strip (
[PR #4847] [Working coder] [Working other]) with a single dropdown "view switcher" that lists the PR (when present) and each dirty working repo as items.Also:
Why
The common multi-view states are
PR only,Working only, orPR + one Working repo. The tab strip was fine for one view but crowded the toolbar the moment two showed up. Collapsing to a single trigger + optional dropdown keeps the toolbar quiet in the 80% case and the switcher stays intuitive when there is more than one thing to look at.Screens
Storybook coverage:
PullRequestAndWorkingChanges— collapsed switcher shows the PR state +PR #<n>, PR title below.ViewSwitcherOpen(new) — dropdown open with PR and both working repos, then clicks a working entry to verify the view swaps.DraftPullRequest,MergedPullRequest,ClosedPullRequest— trigger's colored pill reflects state (play assertions added).WorkingChangesOnly,BranchOnly,MultipleRepos,EmptyState,GitNotActive,GitStatusLoading— all pass.EverDirtyRepoGoneClean,CleanRepoFromStart— regression coverage updated to target the new switcher rather than the oldWorkingtab buttons.Decisions and scoping notes
Why a switcher and not a PR-only dropdown
Original design showed multiple PRs in the dropdown, but the server model only tracks one PR per chat (
ChatDiffStatus.pr_numberis a single field). Multi-PR would need a DB / watcher / SDK change out of scope for a UI polish PR.After reviewing frequency of the actual multi-view states (
PR onlyandWorking onlydominate;PR + Workingshows up during review iteration; 3+ views is rare), we scaled back to make the dropdown a view switcher that spans the existing tab strip's data: PR + working repos. Ships today, no backend work.Behavior notes
text-git-*-bright/text-content-warning/text-content-secondary(text color only; no background token).[icon] primary secondarywhere primary/secondary isPR #<n> / titlefor the remote entry andWorking / repofor local entries.Branch | <head-branch>.Coder Agent generated on behalf of @tracyjohnsonux.