From fe8b60b11c4cbe987fe70b2749742d0468aab878 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:17:28 -0700 Subject: [PATCH] Show branch cues in experimental worktree cards (#5737) --- .../src/components/sidebar/WorktreeCard.tsx | 1 + .../sidebar/WorktreeCardStatusSlot.test.tsx | 51 +++++++++++++++++-- .../sidebar/WorktreeCardStatusSlot.tsx | 49 ++++++++++++++++-- src/renderer/src/i18n/locales/en.json | 1 + src/renderer/src/i18n/locales/es.json | 1 + src/renderer/src/i18n/locales/ja.json | 3 +- src/renderer/src/i18n/locales/ko.json | 3 +- src/renderer/src/i18n/locales/zh.json | 3 +- 8 files changed, 102 insertions(+), 10 deletions(-) diff --git a/src/renderer/src/components/sidebar/WorktreeCard.tsx b/src/renderer/src/components/sidebar/WorktreeCard.tsx index 454367f3b..dbb74f9e7 100644 --- a/src/renderer/src/components/sidebar/WorktreeCard.tsx +++ b/src/renderer/src/components/sidebar/WorktreeCard.tsx @@ -1209,6 +1209,7 @@ const WorktreeCard = React.memo(function WorktreeCard({ onToggleUnread={handleToggleUnreadQuick} prDisplay={hoverReview} newCardStyle={newCardStyle} + hasBranchIdentity={!isFolder && branch.length > 0} /> ) : null} diff --git a/src/renderer/src/components/sidebar/WorktreeCardStatusSlot.test.tsx b/src/renderer/src/components/sidebar/WorktreeCardStatusSlot.test.tsx index 1bc33db2c..d916b12e5 100644 --- a/src/renderer/src/components/sidebar/WorktreeCardStatusSlot.test.tsx +++ b/src/renderer/src/components/sidebar/WorktreeCardStatusSlot.test.tsx @@ -148,6 +148,46 @@ describe('WorktreeCardStatusSlot', () => { expect(markup).not.toContain('bg-neutral-500/40') }) + it('uses a branch icon instead of the quiet active dot when new card style has no review', () => { + const markup = renderToStaticMarkup( + + ) + + expect(markup).toContain('Branch') + expect(markup).toContain('lucide-git-branch') + expect(markup).toContain('text-muted-foreground/70') + expect(markup).not.toContain('bg-emerald-500') + }) + + it('keeps the quiet dot when the row has no branch identity', () => { + const markup = renderToStaticMarkup( + + ) + + expect(markup).toContain('Active') + expect(markup).toContain('bg-emerald-500') + expect(markup).not.toContain('lucide-git-branch') + }) + it('keeps working activity ahead of PR status in new card style', () => { mocks.status = 'working' const markup = renderToStaticMarkup( @@ -237,23 +277,26 @@ describe('WorktreeCardStatusSlot', () => { expect(markup).not.toContain('bg-emerald-500') }) - it('keeps the new style unread status dot in the stable lane footprint', () => { + it('overlays unread on the no-review branch icon in new card style', () => { const markup = renderToStaticMarkup( ) - expect(markup).toContain('Active · Mark as unread') + expect(markup).toContain('Branch · Mark as read') expect(markup).toContain( 'group/unread relative flex cursor-pointer items-center justify-center rounded transition-all size-5' ) + expect(markup).toContain('lucide-git-branch') + expect(markup).toContain('absolute -right-1 -top-1 size-[13px] text-amber-500') + expect(markup).not.toContain('bg-emerald-500') }) }) diff --git a/src/renderer/src/components/sidebar/WorktreeCardStatusSlot.tsx b/src/renderer/src/components/sidebar/WorktreeCardStatusSlot.tsx index 82b6fd2f2..e15a41cda 100644 --- a/src/renderer/src/components/sidebar/WorktreeCardStatusSlot.tsx +++ b/src/renderer/src/components/sidebar/WorktreeCardStatusSlot.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { Bell } from 'lucide-react' +import { Bell, GitBranch } from 'lucide-react' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' import { cn } from '@/lib/utils' import { getWorktreeStatusLabel, type WorktreeStatus } from '@/lib/worktree-status' @@ -19,10 +19,15 @@ type WorktreeCardStatusSlotProps = { onPointerDown: React.PointerEventHandler prDisplay?: WorktreeCardPrDisplay | null newCardStyle?: boolean + hasBranchIdentity?: boolean className?: string } const QUIET_REVIEW_REPLACEABLE_STATUSES = new Set(['active', 'done', 'inactive']) +// Why: a missing review display can also mean provider state is unavailable, +// so the passive label names the branch cue without claiming no review exists. +const BRANCH_STATUS_LABEL = 'Branch' +const branchStatusIconClassName = 'size-4 text-muted-foreground/70' function getReviewStatusTooltip(review: WorktreeCardPrDisplay): string { const label = getReviewLabel(review) @@ -57,6 +62,7 @@ export function WorktreeCardStatusSlot({ onPointerDown, prDisplay = null, newCardStyle = false, + hasBranchIdentity = true, className }: WorktreeCardStatusSlotProps): React.JSX.Element | null { const status = useWorktreeActivityStatus(worktreeId) @@ -66,9 +72,20 @@ export function WorktreeCardStatusSlot({ showStatus && prDisplay !== null && QUIET_REVIEW_REPLACEABLE_STATUSES.has(status) + const canShowBranchStatus = + newCardStyle && + showStatus && + hasBranchIdentity && + prDisplay === null && + QUIET_REVIEW_REPLACEABLE_STATUSES.has(status) const passiveStatusLabel = - canShowReviewStatus && prDisplay ? getReviewStatusTooltip(prDisplay) : statusLabel + canShowReviewStatus && prDisplay + ? getReviewStatusTooltip(prDisplay) + : canShowBranchStatus + ? BRANCH_STATUS_LABEL + : statusLabel const reviewStatusIconClassName = 'size-4' + const branchStatusIcon =