From 46cbf5720da59963767e7d8a10b7bc048255ebbe Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Sat, 22 Aug 2026 02:31:56 -0400 Subject: [PATCH] fix(cmd-j): restore host badges --- .../components/WorktreeJumpPalette.test.tsx | 19 +++++++++++--- .../src/components/WorktreeJumpPalette.tsx | 25 +++++++++++++++++++ .../components/cmd-j/PaletteHostBadgeChip.tsx | 25 +++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 src/renderer/src/components/cmd-j/PaletteHostBadgeChip.tsx diff --git a/src/renderer/src/components/WorktreeJumpPalette.test.tsx b/src/renderer/src/components/WorktreeJumpPalette.test.tsx index e9c560dfc4b..63dbfdcd62a 100644 --- a/src/renderer/src/components/WorktreeJumpPalette.test.tsx +++ b/src/renderer/src/components/WorktreeJumpPalette.test.tsx @@ -8,7 +8,7 @@ import type * as ReactI18Next from 'react-i18next' import { useAppStore } from '@/store' import type { AppState } from '@/store/types' import WorktreeJumpPalette from './WorktreeJumpPalette' -import { makeRepo, makeWorktree } from './worktree-jump-palette-test-fixtures' +import { makeRecentTabState, makeRepo, makeWorktree } from './worktree-jump-palette-test-fixtures' const { activateAndRevealWorktree } = vi.hoisted(() => ({ activateAndRevealWorktree: vi.fn(() => false) @@ -48,9 +48,10 @@ vi.mock('@/components/repo/RepoBadgeLabel', () => ({ RepoBadgeMark: () => })) -vi.mock('@/components/cmd-j/palette-host-badge', () => ({ - getPaletteHostBadge: () => null +const { getPaletteHostBadge } = vi.hoisted(() => ({ + getPaletteHostBadge: vi.fn(() => null as { hostId: 'local'; label: string } | null) })) +vi.mock('@/components/cmd-j/palette-host-badge', () => ({ getPaletteHostBadge })) // Why: activation reaches into window.api and the whole worktree-reveal path; the palette's own // contract is which result it hands over, so stub the boundary and assert on that. @@ -191,6 +192,7 @@ describe('WorktreeJumpPalette', () => { globalThis.IS_REACT_ACT_ENVIRONMENT = true setCommandQuery = null activateAndRevealWorktree.mockClear() + getPaletteHostBadge.mockReturnValue(null) useAppStore.setState(initialAppState, true) testContainer = document.createElement('div') document.body.appendChild(testContainer) @@ -230,6 +232,17 @@ describe('WorktreeJumpPalette', () => { expect(testContainer.textContent).toContain('Folder workspace') }) + it('renders the owning host badge on worktree and tab rows', async () => { + getPaletteHostBadge.mockReturnValue({ hostId: 'local', label: 'Local Mac' }) + await renderPalette(makeRecentTabState()) + + const badge = '[aria-label="Host: Local Mac"]' + expect(testContainer.querySelector(`[data-command-item*="worktree:"] ${badge}`)).not.toBeNull() + expect( + testContainer.querySelector(`[data-command-item*="workspace-tab:"] ${badge}`) + ).not.toBeNull() + }) + it('keeps the explicit default-branch filter authoritative', async () => { const defaultBranch = makeWorktree('default-branch', 'Default branch workspace', { isMainWorktree: true, diff --git a/src/renderer/src/components/WorktreeJumpPalette.tsx b/src/renderer/src/components/WorktreeJumpPalette.tsx index 9a54ed398c7..4f0b4a6bff4 100644 --- a/src/renderer/src/components/WorktreeJumpPalette.tsx +++ b/src/renderer/src/components/WorktreeJumpPalette.tsx @@ -141,6 +141,7 @@ import { import { RepoBadgeMark } from '@/components/repo/RepoBadgeLabel' import { buildSidebarHostOptions } from '@/components/sidebar/sidebar-host-options' import { getPaletteHostBadge } from '@/components/cmd-j/palette-host-badge' +import PaletteHostBadgeChip from '@/components/cmd-j/PaletteHostBadgeChip' import { getWorktreeHostIdentity } from '../../../shared/worktree/host-qualified-identity' import { getRepoHostIdentity } from '@/store/slices/repo-host-identity' import type { Repo } from '../../../shared/repo-types' @@ -3221,6 +3222,7 @@ function WorktreeJumpPaletteContent({ : null const isSshDisconnected = sshStatus != null && sshStatus !== 'connected' const sessionAge = formatPaletteSessionAge(worktree.lastActivityAt, paletteNowMs) + const hostBadge = getPaletteHostBadge(repo, hostOptions, hostFilterActive) return (
+ {repoName && ( @@ -3350,6 +3353,9 @@ function WorktreeJumpPaletteContent({ if (entry.type === 'project-target') { const result = entry.result const isProject = result.kind === 'project' + const hostBadge = isProject + ? getPaletteHostBadge(result.repo, hostOptions, hostFilterActive) + : null const badgeLabel = isProject ? translate('auto.components.WorktreeJumpPalette.projectBadge', 'Project') : translate('auto.components.WorktreeJumpPalette.repoGroupBadge', 'Repo group') @@ -3377,6 +3383,7 @@ function WorktreeJumpPaletteContent({
{isProject ? (
+ {result.repo.displayName} @@ -3434,6 +3441,11 @@ function WorktreeJumpPaletteContent({ ? resolveRepoForWorktree(workspaceTabWorktree) : undefined const workspaceTabRepoName = workspaceTabRepo?.displayName ?? result.repoName + const workspaceTabHostBadge = getPaletteHostBadge( + workspaceTabRepo, + hostOptions, + hostFilterActive + ) const workspaceTabFallback = result.contentType === 'terminal' && result.occupantAgent ? ( + {workspaceTabRepoName && ( @@ -3529,6 +3542,11 @@ function WorktreeJumpPaletteContent({ ? resolveRepoForWorktree(simulatorWorktree) : undefined const simulatorRepoName = simulatorRepo?.displayName ?? result.repoName + const simulatorHostBadge = getPaletteHostBadge( + simulatorRepo, + hostOptions, + hostFilterActive + ) const sessionAge = formatPaletteSessionAge( result.lastActiveAt ?? null, paletteNowMs @@ -3582,6 +3600,7 @@ function WorktreeJumpPaletteContent({ worktree={simulatorWorktree} className="max-w-[280px] truncate text-[12px] font-medium text-muted-foreground" /> + {simulatorRepoName && ( @@ -3610,6 +3629,11 @@ function WorktreeJumpPaletteContent({ ? resolveRepoForWorktree(browserWorktree) : undefined const browserRepoName = browserRepo?.displayName ?? result.repoName + const browserHostBadge = getPaletteHostBadge( + browserRepo, + hostOptions, + hostFilterActive + ) const sessionAge = formatPaletteSessionAge(result.lastActiveAt ?? null, paletteNowMs) return ( @@ -3660,6 +3684,7 @@ function WorktreeJumpPaletteContent({ worktree={browserWorktree} className="max-w-[280px] truncate text-[12px] font-medium text-muted-foreground" /> + {browserRepoName && ( diff --git a/src/renderer/src/components/cmd-j/PaletteHostBadgeChip.tsx b/src/renderer/src/components/cmd-j/PaletteHostBadgeChip.tsx new file mode 100644 index 00000000000..35d60addb36 --- /dev/null +++ b/src/renderer/src/components/cmd-j/PaletteHostBadgeChip.tsx @@ -0,0 +1,25 @@ +import { translate } from '@/i18n/i18n' +import type { PaletteHostBadge } from './palette-host-badge' + +export default function PaletteHostBadgeChip({ + badge +}: { + badge: PaletteHostBadge | null +}): React.JSX.Element | null { + if (!badge) { + return null + } + + return ( + + {badge.label} + + ) +}