From 463d7dea1ac0cdf04f46a55af24273993dddef46 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Fri, 24 Jul 2026 17:15:20 +0200 Subject: [PATCH] fix(web): scope PR state to the thread branch Co-authored-by: codex --- .../BranchToolbarBranchSelector.tsx | 1 - apps/web/src/components/ChatView.tsx | 1 - apps/web/src/components/Sidebar.tsx | 1 - apps/web/src/components/SidebarV2.tsx | 1 - .../components/ThreadStatusIndicators.test.ts | 24 +++++++++++-------- .../src/components/ThreadStatusIndicators.tsx | 8 +------ 6 files changed, 15 insertions(+), 21 deletions(-) diff --git a/apps/web/src/components/BranchToolbarBranchSelector.tsx b/apps/web/src/components/BranchToolbarBranchSelector.tsx index 763de56d8c4..04baef58237 100644 --- a/apps/web/src/components/BranchToolbarBranchSelector.tsx +++ b/apps/web/src/components/BranchToolbarBranchSelector.tsx @@ -593,7 +593,6 @@ export function BranchToolbarBranchSelector({ const branchPr = resolveThreadPr({ threadBranch: resolvedActiveBranch, gitStatus: branchStatusQuery.data ?? null, - hasDedicatedWorktree: activeWorktreePath !== null, }); const branchPrStatus = prStatusIndicator(branchPr, branchStatusQuery.data?.sourceControlProvider); // Action-oriented tooltip (the pill opens the PR), distinct from the sidebar's diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index ab1256cddb3..32cfe92825f 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -3842,7 +3842,6 @@ function ChatViewContent(props: ChatViewProps) { const activeThreadPr = resolveThreadPr({ threadBranch: activeThread?.branch ?? null, gitStatus: gitStatusQuery.data ?? null, - hasDedicatedWorktree: (activeThread?.worktreePath ?? null) !== null, }); const supportsSettlement = serverConfig?.environment.capabilities.threadSettlement === true; const supportsSnooze = serverConfig?.environment.capabilities.threadSnooze === true; diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index a1d95eaa734..b05b3a39d90 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -452,7 +452,6 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr const pr = resolveThreadPr({ threadBranch: thread.branch, gitStatus: gitStatus.data, - hasDedicatedWorktree: thread.worktreePath !== null, }); const prStatus = prStatusIndicator(pr, gitStatus.data?.sourceControlProvider); const terminalStatus = terminalStatusFromRunningIds(runningTerminalIds); diff --git a/apps/web/src/components/SidebarV2.tsx b/apps/web/src/components/SidebarV2.tsx index 8c5891ebe7e..a5f9eca5f4a 100644 --- a/apps/web/src/components/SidebarV2.tsx +++ b/apps/web/src/components/SidebarV2.tsx @@ -502,7 +502,6 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { const pr = resolveThreadPr({ threadBranch: thread.branch, gitStatus: gitStatus.data, - hasDedicatedWorktree: thread.worktreePath !== null, }); const prStatus = prStatusIndicator(pr, gitStatus.data?.sourceControlProvider); const settledPrHoverClass = pr ? settledPrHoverColorClass(pr.state) : undefined; diff --git a/apps/web/src/components/ThreadStatusIndicators.test.ts b/apps/web/src/components/ThreadStatusIndicators.test.ts index 9fb4535f266..3eb8e4f710f 100644 --- a/apps/web/src/components/ThreadStatusIndicators.test.ts +++ b/apps/web/src/components/ThreadStatusIndicators.test.ts @@ -36,31 +36,35 @@ describe("resolveThreadPr", () => { resolveThreadPr({ threadBranch: "feature/other", gitStatus: status(), - hasDedicatedWorktree: false, }), ).toBeNull(); }); - it("shows PR indicators for dedicated worktree threads even when branch metadata is stale", () => { - const gitStatus = status(); + it("hides PR indicators when a dedicated worktree has switched away from the thread branch", () => { + expect( + resolveThreadPr({ + threadBranch: "stack/base", + gitStatus: status(), + }), + ).toBeNull(); + }); + it("hides PR indicators when thread branch metadata is missing", () => { expect( resolveThreadPr({ - threadBranch: "feature/old-name", - gitStatus, - hasDedicatedWorktree: true, + threadBranch: null, + gitStatus: status(), }), - ).toBe(gitStatus.pr); + ).toBeNull(); }); - it("shows PR indicators for dedicated worktree threads even when branch metadata is missing", () => { + it("shows the PR when the live checkout matches the stored thread branch", () => { const gitStatus = status(); expect( resolveThreadPr({ - threadBranch: null, + threadBranch: "feature/current", gitStatus, - hasDedicatedWorktree: true, }), ).toBe(gitStatus.pr); }); diff --git a/apps/web/src/components/ThreadStatusIndicators.tsx b/apps/web/src/components/ThreadStatusIndicators.tsx index 0d3291a9e28..af53d1a78b2 100644 --- a/apps/web/src/components/ThreadStatusIndicators.tsx +++ b/apps/web/src/components/ThreadStatusIndicators.tsx @@ -113,17 +113,12 @@ export function PrStatusTooltipContent({ status }: { status: PrStatusIndicator } export function resolveThreadPr(input: { threadBranch: string | null; gitStatus: VcsStatusResult | null; - hasDedicatedWorktree: boolean; }): ThreadPr | null { - const { threadBranch, gitStatus, hasDedicatedWorktree } = input; + const { threadBranch, gitStatus } = input; if (gitStatus === null) { return null; } - if (hasDedicatedWorktree) { - return gitStatus.pr ?? null; - } - if (threadBranch === null || gitStatus.refName !== threadBranch) { return null; } @@ -258,7 +253,6 @@ export function ThreadRowLeadingStatus({ thread }: { thread: SidebarThreadSummar const pr = resolveThreadPr({ threadBranch: thread.branch, gitStatus: gitStatus.data, - hasDedicatedWorktree: thread.worktreePath !== null, }); const prStatus = prStatusIndicator(pr, gitStatus.data?.sourceControlProvider); const threadStatus = resolveThreadStatusPill({