From c81ac40d4c0447a459b5e429518a410121da8bd2 Mon Sep 17 00:00:00 2001 From: Rafael Audibert <32079912+rafaeelaudibert@users.noreply.github.com> Date: Thu, 28 May 2026 17:48:03 -0300 Subject: [PATCH] Add PR badge to sidebar task list Tasks in the sidebar with a linked pull request now show a small clickable badge on the right side of the row. The badge displays the PR number (e.g. `#123`) when it can be extracted from the URL and falls back to `PR` otherwise; clicking it opens the PR in the user's browser via `openUrlInBrowser`. The URL is sourced from the existing `TaskData.cloudPrUrl` field (populated from `task.latest_run.output.pr_url`), so no new data plumbing is needed. Generated-By: PostHog Code Task-Id: ba55cf1b-c69e-4b32-b689-9a00d3831b64 --- .../sidebar/components/TaskListView.tsx | 1 + .../sidebar/components/items/TaskItem.tsx | 50 ++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx b/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx index 7fea8db2c5..82487858cd 100644 --- a/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx +++ b/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx @@ -131,6 +131,7 @@ function TaskRow({ slackThreadUrl={task.slackThreadUrl} prState={prState} hasDiff={hasDiff} + prUrl={task.cloudPrUrl} timestamp={timestamp} onClick={onClick} onDoubleClick={onDoubleClick} diff --git a/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx b/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx index a5ee2a5b49..3c5b2c66db 100644 --- a/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx +++ b/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx @@ -1,13 +1,54 @@ import { Tooltip } from "@components/ui/Tooltip"; import type { SidebarPrState } from "@features/sidebar/hooks/useTaskPrStatus"; import type { WorkspaceMode } from "@main/services/workspace/schemas"; -import { Archive, PushPin } from "@phosphor-icons/react"; +import { Archive, GitPullRequest, PushPin } from "@phosphor-icons/react"; import type { TaskRunStatus } from "@shared/types"; +import { openUrlInBrowser } from "@utils/browser"; import { formatRelativeTimeShort } from "@utils/time"; import { useCallback, useEffect, useRef, useState } from "react"; import { SidebarItem } from "../SidebarItem"; import { TaskIcon } from "./TaskIcon"; +function extractPrNumber(url: string): string | null { + const match = url.match( + /\/(?:pull|pulls|merge_requests|pull-requests)\/(\d+)/, + ); + return match ? match[1] : null; +} + +function PrBadge({ url }: { url: string }) { + const number = extractPrNumber(url); + const open = () => { + void openUrlInBrowser(url); + }; + return ( + + {/* biome-ignore lint/a11y/useSemanticElements: nested clickable inside SidebarItem button */} + { + e.stopPropagation(); + open(); + }} + onDoubleClick={(e) => e.stopPropagation()} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + e.stopPropagation(); + open(); + } + }} + > + + {number ? `#${number}` : "PR"} + + + ); +} + interface TaskItemProps { depth?: number; taskId: string; @@ -27,6 +68,7 @@ interface TaskItemProps { slackThreadUrl?: string; prState?: SidebarPrState; hasDiff?: boolean; + prUrl?: string | null; timestamp?: number; isEditing?: boolean; onClick: (e: React.MouseEvent) => void; @@ -123,6 +165,7 @@ export function TaskItem({ slackThreadUrl, prState, hasDiff, + prUrl, timestamp, isEditing = false, onClick, @@ -149,6 +192,8 @@ export function TaskItem({ /> ); + const prBadge = prUrl ? : null; + const timestampNode = timestamp ? ( {formatRelativeTimeShort(timestamp)} @@ -165,8 +210,9 @@ export function TaskItem({ ) : null; const endContent = - timestampNode || toolbar ? ( + prBadge || timestampNode || toolbar ? ( <> + {prBadge} {timestampNode} {toolbar}