diff --git a/apps/web/src/components/Sidebar.logic.test.ts b/apps/web/src/components/Sidebar.logic.test.ts index fcc0f50e8cb..2f5608a895a 100644 --- a/apps/web/src/components/Sidebar.logic.test.ts +++ b/apps/web/src/components/Sidebar.logic.test.ts @@ -21,7 +21,6 @@ import { getVisibleThreadsForProject, groupSidebarThreadsByWorktree, hasUnseenCompletion, - formatSidebarThreadDisplayTitle, isContextMenuPointerDown, isTrailingDoubleClick, orderItemsByPreferredIds, @@ -1000,35 +999,46 @@ describe("resolveProjectTitleClassName", () => { }); describe("resolveSidebarWorktreeLabelMode", () => { - it("inlines populated non-main worktrees in the native sidebar", () => { + it("shows a compact header for populated non-main worktrees in the native sidebar", () => { expect( resolveSidebarWorktreeLabelMode({ enableNativeMacSidebar: true, isMainCheckout: false, threadGroupingMode: "worktree", - threadCount: 1, + worktreeGroupCount: 1, }), - ).toBe("inline"); + ).toBe("header"); }); - it("hides the redundant main checkout label in the native sidebar", () => { + it("hides the redundant main checkout label when it is the only group", () => { expect( resolveSidebarWorktreeLabelMode({ enableNativeMacSidebar: true, isMainCheckout: true, threadGroupingMode: "worktree", - threadCount: 0, + worktreeGroupCount: 1, }), ).toBe("hidden"); }); + it("shows the main checkout header alongside other worktree groups", () => { + expect( + resolveSidebarWorktreeLabelMode({ + enableNativeMacSidebar: true, + isMainCheckout: true, + threadGroupingMode: "worktree", + worktreeGroupCount: 2, + }), + ).toBe("header"); + }); + it("preserves upstream grouping when the native sidebar is disabled", () => { expect( resolveSidebarWorktreeLabelMode({ enableNativeMacSidebar: false, isMainCheckout: true, threadGroupingMode: "worktree", - threadCount: 1, + worktreeGroupCount: 1, }), ).toBe("header"); }); @@ -1039,7 +1049,7 @@ describe("resolveSidebarWorktreeLabelMode", () => { enableNativeMacSidebar: true, isMainCheckout: false, threadGroupingMode: "worktree", - threadCount: 0, + worktreeGroupCount: 1, }), ).toBe("header"); }); @@ -1065,18 +1075,6 @@ describe("shouldShowSidebarEmptyThreadState", () => { }); }); -describe("formatSidebarThreadDisplayTitle", () => { - it("combines the worktree and thread names", () => { - expect(formatSidebarThreadDisplayTitle("art-15915", "Use historic conversions")).toBe( - "art-15915: Use historic conversions", - ); - }); - - it("keeps standalone thread titles unchanged", () => { - expect(formatSidebarThreadDisplayTitle(null, "General chat")).toBe("General chat"); - }); -}); - describe("resolveProjectStatusIndicator", () => { it("returns null when no threads have a notable status", () => { expect(resolveProjectStatusIndicator([null, null])).toBeNull(); diff --git a/apps/web/src/components/Sidebar.logic.ts b/apps/web/src/components/Sidebar.logic.ts index 5254ba582bf..fdd739fa7d9 100644 --- a/apps/web/src/components/Sidebar.logic.ts +++ b/apps/web/src/components/Sidebar.logic.ts @@ -513,11 +513,10 @@ export function resolveSidebarWorktreeLabelMode(input: { enableNativeMacSidebar: boolean; isMainCheckout: boolean; threadGroupingMode: "separate" | "worktree"; - threadCount: number; -}): "header" | "hidden" | "inline" { + worktreeGroupCount: number; +}): "header" | "hidden" { if (!input.enableNativeMacSidebar || input.threadGroupingMode !== "worktree") return "header"; - if (input.isMainCheckout) return "hidden"; - return input.threadCount > 0 ? "inline" : "header"; + return input.isMainCheckout && input.worktreeGroupCount === 1 ? "hidden" : "header"; } export function shouldShowSidebarEmptyThreadState(input: { @@ -527,13 +526,6 @@ export function shouldShowSidebarEmptyThreadState(input: { return input.showEmptyThreadState && !input.enableNativeMacSidebar; } -export function formatSidebarThreadDisplayTitle( - worktreeLabel: string | null, - threadTitle: string, -): string { - return worktreeLabel ? `${worktreeLabel}: ${threadTitle}` : threadTitle; -} - export function resolveThreadStatusPill(input: { thread: ThreadStatusInput; }): ThreadStatusPill | null { diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 8bf3c13994f..fac9f6ed757 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -154,7 +154,6 @@ import { ProjectFavicon } from "./ProjectFavicon"; import { openDiscoveredPort } from "./preview/openDiscoveredPort"; import { getSidebarThreadIdsToPrewarm, - formatSidebarThreadDisplayTitle, isContextMenuPointerDown, isTrailingDoubleClick, orderItemsByPreferredIds, @@ -347,8 +346,6 @@ function buildThreadJumpLabelMap(input: { interface SidebarThreadRowProps { thread: SidebarThreadSummary; nestedUnderWorktree: boolean; - worktreeLabel: string | null; - onWorktreeContextMenu?: (event: React.MouseEvent) => void; projectCwd: string | null; orderedProjectThreadKeys: readonly string[]; isActive: boolean; @@ -411,8 +408,6 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr openPrLink, thread, nestedUnderWorktree, - worktreeLabel, - onWorktreeContextMenu, } = props; const threadRef = scopeThreadRef(thread.environmentId, thread.id); const threadKey = scopedThreadKey(threadRef); @@ -512,7 +507,6 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr : !isThreadRunning ? "pointer-events-none transition-opacity duration-150 max-sm:pr-6 group-hover/menu-sub-item:opacity-0 group-focus-within/menu-sub-item:opacity-0" : "pointer-events-none"; - const threadDisplayTitle = formatSidebarThreadDisplayTitle(worktreeLabel, thread.title); const clearConfirmingArchive = useCallback(() => { setConfirmingArchiveThreadKey((current) => (current === threadKey ? null : current)); }, [setConfirmingArchiveThreadKey, threadKey]); @@ -712,6 +706,7 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr @@ -731,16 +726,7 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr onKeyDown={handleRowKeyDown} onContextMenu={handleRowContextMenu} > -
- {worktreeLabel ? ( -