From 0fcd5f90611451cca842689faea53b5450c022da Mon Sep 17 00:00:00 2001
From: oliver <97427849+flamboh@users.noreply.github.com>
Date: Tue, 29 Sep 2026 17:40:55 -0700
Subject: [PATCH] fix(web): multi-PR badges open the linked pull requests panel
(#13211)
---
.../BranchToolbarBranchSelector.tsx | 2 +-
apps/web/src/components/Sidebar.tsx | 7 +++---
.../src/components/ThreadStatusIndicators.tsx | 25 ++++++++++---------
docs/user/source-control.md | 2 +-
4 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/apps/web/src/components/BranchToolbarBranchSelector.tsx b/apps/web/src/components/BranchToolbarBranchSelector.tsx
index 17199bbf33746c5090dfbae999021b08f1783a22..c28bb475281172a61409edddaffcda160f7475ea 100644
--- a/apps/web/src/components/BranchToolbarBranchSelector.tsx
+++ b/apps/web/src/components/BranchToolbarBranchSelector.tsx
@@ -793,7 +793,7 @@ export function BranchToolbarBranchSelector({
number={prNumber}
url={prUrl}
status={displayedPrStatus}
- onOpenStack={() => useRightPanelStore.getState().open(threadRef, "pull-requests")}
+ onOpenList={() => useRightPanelStore.getState().open(threadRef, "pull-requests")}
onOpenPullRequest={(event) => {
if (prUrl) openPrLink(event, prUrl);
}}
diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx
index 90f65ea2b941788d9be7c6fdcabd26865952cb42..7b9e0e545d56f00494ec170a7c79a17ce1732a02 100644
--- a/apps/web/src/components/Sidebar.tsx
+++ b/apps/web/src/components/Sidebar.tsx
@@ -1515,11 +1515,12 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
const accessibleTitle = isRenaming ? null : {thread.title};
// Stacks show their layer count; multiple unrelated links show their total count.
- // Plain clicks open T3; individual PR links also support opening the host in a new tab.
+ // Either opens the thread's pull requests tab; a single PR link opens that PR and still
+ // supports opening the host in a new tab.
const prBadgeShape = supportsMultiplePullRequests
? resolveThreadPullRequestBadge(thread.pullRequests)
: null;
- const handlePrStackClick = useCallback(() => {
+ const handlePrListClick = useCallback(() => {
useRightPanelStore.getState().open(threadRef, "pull-requests");
if (!props.isActive) onThreadActivate(threadRef);
}, [onThreadActivate, props.isActive, threadRef]);
@@ -1531,7 +1532,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
number={pr?.number ?? currentLinkedPr?.number}
url={pr?.url ?? currentLinkedPr?.url}
status={prStatus}
- onOpenStack={handlePrStackClick}
+ onOpenList={handlePrListClick}
onOpenPullRequest={handlePrClick}
/>
) : null;
diff --git a/apps/web/src/components/ThreadStatusIndicators.tsx b/apps/web/src/components/ThreadStatusIndicators.tsx
index 859650ca0a9f4867e3ba387983c246c963fde8a4..6ca601653f301f54952cfa381af74b012371c98c 100644
--- a/apps/web/src/components/ThreadStatusIndicators.tsx
+++ b/apps/web/src/components/ThreadStatusIndicators.tsx
@@ -195,7 +195,8 @@ export function resolveThreadPullRequestBadgePresentation({
* The linked-PR badge shared by the sidebar and composer footer. The badge owns what it shows:
* the state glyph and number at the meta size, in the state's color. The caller owns the control
* it sits in through `render` (an inline link in a sidebar row, a toolbar control in the
- * composer), and the badge fills in the link or stack button behavior.
+ * composer), and the badge fills in the behavior: a single PR is a link to it, while a stack or
+ * several linked PRs is a button that opens the thread's pull requests tab.
*/
export function ThreadPullRequestBadgeControl({
render,
@@ -203,7 +204,7 @@ export function ThreadPullRequestBadgeControl({
number,
url,
status,
- onOpenStack,
+ onOpenList,
onOpenPullRequest,
}: {
render: ReactElement<{ render?: useRender.RenderProp }>;
@@ -211,7 +212,7 @@ export function ThreadPullRequestBadgeControl({
number?: number | undefined;
url?: string | undefined;
status: PrStatusIndicator | null;
- onOpenStack: () => void;
+ onOpenList: () => void;
onOpenPullRequest: (event: MouseEvent) => void;
}) {
const presentation = resolveThreadPullRequestBadgePresentation({ badge, number, url, status });
@@ -220,9 +221,9 @@ export function ThreadPullRequestBadgeControl({
0)}
url={url}
- onOpenStack={onOpenStack}
+ onOpenList={onOpenList}
onOpenPullRequest={onOpenPullRequest}
/>
);
@@ -231,26 +232,26 @@ export function ThreadPullRequestBadgeControl({
function PullRequestBadge({
render,
presentation,
- isStack,
+ opensList,
url,
- onOpenStack,
+ onOpenList,
onOpenPullRequest,
}: {
render: ReactElement<{ render?: useRender.RenderProp }>;
presentation: NonNullable>;
- isStack: boolean;
+ opensList: boolean;
url: string | undefined;
- onOpenStack: () => void;
+ onOpenList: () => void;
onOpenPullRequest: (event: MouseEvent) => void;
}) {
- const onClick = isStack
+ const onClick = opensList
? (event: MouseEvent) => {
event.preventDefault();
event.stopPropagation();
- onOpenStack();
+ onOpenList();
}
: onOpenPullRequest;
- const element = isStack ? (
+ const element = opensList ? (
) : (
diff --git a/docs/user/source-control.md b/docs/user/source-control.md
index 0427f143c7d5a683cce9c3b6a87177c9b6dd83d9..306632d9ca64483e3ff5e013fe83e1ea1763347b 100644
--- a/docs/user/source-control.md
+++ b/docs/user/source-control.md
@@ -164,7 +164,7 @@ on the Pull Requests page, **Link to thread** lets you search for an active thre
also lists the threads that link to it, including archived threads, so you can return to their context.
Thread badges show a stack's layer count or the current review number with a count of additional
-links. On mobile, the Git overview lists linked reviews and their stacks; tap a review to open it.
+links. Clicking a badge with more than one review opens the **Linked pull requests** panel. On mobile, the Git overview lists linked reviews and their stacks; tap a review to open it.
Linking and unlinking are available in the web and desktop clients.
The **Linked pull requests** panel lists every review and groups stacks. Unlink a review from its
--
2.54.0