Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(site/src/pages/AgentsPage): consolidate git panel tab strip into a view switcher dropdown - #27012

Merged
tracyjohnsonux merged 24 commits into
mainfrom
feat/git-panel-view-dropdown
Aug 11, 2026
Merged

feat(site/src/pages/AgentsPage): consolidate git panel tab strip into a view switcher dropdown#27012
tracyjohnsonux merged 24 commits into
mainfrom
feat/git-panel-view-dropdown

Conversation

@tracyjohnsonux

@tracyjohnsonux tracyjohnsonux commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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:

  • Moves the PR title to a dedicated row below the switcher, truncated with a hover tooltip for the full title. The row only appears while the PR view is active.
  • Removes the redundant PR-state badge from the RemoteDiffPanel sub-header (state is now shown as the colored pill on the switcher trigger).

Why

The common multi-view states are PR only, Working only, or PR + 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 old Working tab 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_number is 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 only and Working only dominate; PR + Working shows 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

  • With a single item the trigger renders as a static pill (no chevron, no dropdown behavior); it becomes an interactive dropdown once there is more than one item.
  • The colored state pill on the trigger uses text-git-*-bright / text-content-warning / text-content-secondary (text color only; no background token).
  • Dropdown items render as [icon] primary secondary where primary/secondary is PR #<n> / title for the remote entry and Working / repo for local entries.
  • Local (Working) entries are visually nested under the remote/PR entry when one is present; otherwise they render flush-left.
  • When the head branch is known but no PR is opened, the trigger reads Branch | <head-branch>.

Coder Agent generated on behalf of @tracyjohnsonux.

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-07-07 16:36 UTC by @tracyjohnsonux
Spend: $48.76 / $100.00

Review history
  • R1 (2026-07-07): 14 reviewers, 3 Nit, 3 Note, 2 P2, 4 P3, 4 P4, COMMENT. Review
  • R2 (2026-07-07): 11 reviewers, 7 Nit, 3 Note, 2 P2, 5 P3, 4 P4, COMMENT. Review

deep-review v0.9.0 | Round 2 | e5990a9..47cd08b

Last posted: Round 2, 21 findings (2 P2, 5 P3, 4 P4, 7 Nit, 3 Note), COMMENT. Review

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P3 Author fixed (47cd08b) GitPanel.stories.tsx:479 CleanRepoFromStart assertion vacuous: empty-state div lacks data-testid so querySelector always returns null R1 Netero, Pariston P4 Yes
CRF-2 Nit Author fixed (47cd08b) GitPanel.tsx:718 Stale comment "for the tab bar" should reference view switcher R1 Netero Yes
CRF-3 Note Author fixed (47cd08b) GitPanel.stories.tsx:167 ViewSwitcherOpen JSDoc overclaims: says it exercises click-swap but only checks text R1 Netero Yes
CRF-4 Note Author fixed (47cd08b) GitPanel.tsx:80 Surviving comments reference "tab" / "tab strip" after refactor (lines 80, 157, 179, 187) R1 Netero Yes
CRF-5 P2 Author fixed (47cd08b) GitPanel.tsx:89 PR description claims two reverted features (countGitPanelViews, tab count) and stale bg-surface-git-* token references R1 Mafu-san P2, Leorio P2, Mafuuu P3, Pariston P3, Meruem P3, Nami Nit, Zoro Note, Bisky Note Yes
CRF-6 P3 Author fixed (47cd08b) GitPanel.tsx:527 Local items indent ml-4 under nothing when no remote/PR item exists; comment references unplanned multi-PR future R1 Hisoka P3, Mafuuu P3, Nami P2, Pariston P4, Zoro P3 Yes
CRF-7 P3 Author fixed (47cd08b) GitPanel.tsx:98 ViewItem uses optional repoRoot where a discriminated union would enforce the local-always-has-repoRoot invariant R1 Zoro P3, Meruem P3 Yes
CRF-8 P3 Author fixed (47cd08b) GitPanel.tsx:704 prStateClasses duplicates color mapping already in PrStateIcon 17 lines below in the same file R1 Robin P3, Zoro P3, Meruem P3 Yes
CRF-9 P3 Author fixed (47cd08b) GitPanel.tsx:265 Branch-only trigger shows "Branch Branch"; head branch name is available but unused R1 Mafuuu P3
CRF-10 P2 Author fixed (47cd08b) GitPanel.stories.tsx:152 "closed state" ambiguous: means "dropdown collapsed" but reads as PR state in a file full of PR states R1 Leorio P2, Gon Note Yes
CRF-11 Nit Author fixed (47cd08b) GitPanel.tsx:224 Several new comments narrate mechanism visible from code (lines 92, 224, 375, 486) R1 Gon P2 Yes
CRF-12 P4 Author fixed (47cd08b) GitPanel.stories.tsx:217 Three of four prStateLabel branches (Draft, Merged, Closed) lack assertions R1 Bisky P4 Yes
CRF-13 P4 Author fixed (47cd08b) GitPanel.stories.tsx:197 No test verifies that clicking a dropdown item switches the view R1 Bisky P4 Yes
CRF-14 P4 Author fixed (47cd08b) GitPanel.tsx:378 PR title row renders in all views including local Working diffs R1 Nami P3, Mafuuu Note Yes
CRF-15 P4 Author fixed (47cd08b) GitPanel.tsx:290 One paint frame of "No changes" when a selected local repo disappears before useEffect corrects R1 Hisoka P3 Yes
CRF-16 Nit Author fixed (47cd08b) GitPanel.tsx:87 repoTabLabel name references tabs; function now serves the view switcher R1 Gon Nit Yes
CRF-17 Note Author fixed (47cd08b) GitPanel.tsx:158 localRepos is a fresh array every render, causing useEffect to fire each time R1 Hisoka Note Yes
CRF-18 P3 Open GitPanel.tsx:231 ResizeObserver for PR title truncation not reattached after span remounts on view switch R2 Hisoka P3, Mafuuu P3, Pariston P3, Kite P4 Yes
CRF-19 Nit Open GitPanel.tsx:75 Stale "tab" in JSDoc at lines 66, 75; sibling of CRF-4 fix sweep R2 Netero Nit, Mafu-san P3, Mafuuu Nit, Nami Nit, Leorio Nit Yes
CRF-20 Nit Open GitPanel.tsx:133 showRemoteTab variable should be showRemoteView R2 Gon Nit, Leorio Nit Yes
CRF-21 Nit Open GitPanel.tsx:403 Recurring comment narration: 7 instances restate what code shows (also lines 294, stories:150, 157, 214, 476, 504) R2 Gon P2 Yes
CRF-22 Nit Open GitPanel.tsx:141 Manual useMemo redundant in React Compiler-compiled component R2 Ging-react Nit Yes

Round log

Round 1

Panel 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 2

Churn 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-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Komugi flake/determinism
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@tracyjohnsonux
tracyjohnsonux requested a review from jaaydenh July 7, 2026 15:54
@tracyjohnsonux tracyjohnsonux changed the title feat(site/AgentsPage): consolidate git panel tab strip into a view switcher dropdown feat(site/src/pages/AgentsPage): consolidate git panel tab strip into a view switcher dropdown Jul 7, 2026

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.stories.tsx
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.stories.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.stories.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.stories.tsx
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx
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).

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

Addressed all 17 review items from the prior pass (CRF-1 through CRF-17). Fixes are in commit 47cd08bf64 and I have resolved the 14 threads I addressed. Summary:

  • Discriminated union for ViewItem (CRF-7)
  • PrStateIcon reuses prStateClasses (CRF-8)
  • Conditional ml-4 nesting only when a remote entry exists (CRF-6)
  • Branch-only trigger uses head_branch as identifier (CRF-9)
  • Inline effectiveView prevents the "No changes" flash (CRF-15)
  • PR title row scoped to the PR view (CRF-14)
  • repoTabLabel -> repoLabel; stale "tab" comments removed (CRF-2, CRF-4, CRF-16)
  • Deleted mechanism-narrating comments (CRF-11)
  • useMemo for repoStats and localRepos (CRF-17)
  • data-testid on empty state; tightened CleanRepoFromStart assertion (CRF-1)
  • Play assertions added to Draft/Merged/Closed PR stories (CRF-12)
  • ViewSwitcherOpen now clicks a menu item to exercise the swap; JSDoc rewritten (CRF-3, CRF-13)
  • Story comment rewords "closed state" -> "collapsed state" (CRF-10)
  • PR description rewritten to drop the reverted count-decoration and background-token claims (CRF-5)

Coder Agent generated on behalf of @tracyjohnsonux.

@tracyjohnsonux

Copy link
Copy Markdown
Contributor Author

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.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
@github-actions github-actions Bot added the stale This issue is like stale bread. label Jul 21, 2026
@github-actions github-actions Bot closed this Jul 25, 2026
… 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.
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/GitPanel/GitPanel.tsx Outdated
…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.
Comment on lines +134 to 136
// Compute per-repo diff stats from unified diffs. The React
// Compiler memoizes these derivations.
const repoStats = (() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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 = (() => {

@tracyjohnsonux
tracyjohnsonux merged commit f7f840a into main Aug 11, 2026
26 checks passed
@tracyjohnsonux
tracyjohnsonux deleted the feat/git-panel-view-dropdown branch August 11, 2026 19:25
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

stale This issue is like stale bread.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants