authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-09-13 19:27:14-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-13 19:27:14-03:00
logdf7ccc8fd01f5d2a1d8ec21bef8f9c59398fe913
tree5d0390ca3b2657daf32be8c6edc89f69bf581865
parent77bca8b2d76a1f42552e5eee7d277fcb1160347a
signature Signed by PGP key B5690EEEBB952194

feat(web): refine compact thread row badges (#11644)


2 files changed, 83 insertions(+), 28 deletions(-)

apps/web/src/components/Sidebar.tsx+79-27
......@@ -1584,7 +1584,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
15841584 useRightPanelStore.getState().open(threadRef, "pull-requests");
15851585 if (!props.isActive) onThreadActivate(threadRef);
15861586 }, [onThreadActivate, props.isActive, threadRef]);
1587 const prBadge =
1587 const renderPrBadge = (iconOnly: boolean) =>
15881588 prBadgeShape?.kind === "stack" || pr || currentLinkedPr ? (
15891589 <ThreadPullRequestBadgeControl
15901590 variant="underline"
......@@ -1592,10 +1592,12 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
15921592 number={pr?.number ?? currentLinkedPr?.number}
15931593 url={pr?.url ?? currentLinkedPr?.url}
15941594 status={prStatus}
1595 iconOnly={iconOnly}
15951596 onOpenStack={handlePrStackClick}
15961597 onOpenPullRequest={handlePrClick}
15971598 />
15981599 ) : null;
1600 const prBadge = renderPrBadge(false);
15991601 const terminalStatusIcon = terminalStatus ? (
16001602 <span
16011603 role="img"
......@@ -1687,17 +1689,37 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
16871689 />
16881690 }
16891691 >
1690 {props.project ? (
1691 <ProjectFavicon project={props.project} className="size-4 shrink-0" />
1692 ) : driverKind ? (
1693 <ProviderInstanceIcon
1694 driverKind={driverKind}
1695 displayName={providerEntry?.displayName ?? modelInstanceId}
1696 iconClassName="size-4"
1697 />
1698 ) : (
1699 <SquarePenIcon aria-hidden className="size-4" />
1700 )}
1692 <span className="relative inline-flex size-4 shrink-0 items-center justify-center">
1693 {props.project ? (
1694 <ProjectFavicon project={props.project} className="size-4" />
1695 ) : driverKind ? (
1696 <ProviderInstanceIcon
1697 driverKind={driverKind}
1698 displayName={providerEntry?.displayName ?? modelInstanceId}
1699 iconClassName="size-4"
1700 />
1701 ) : (
1702 <SquarePenIcon aria-hidden className="size-4" />
1703 )}
1704 {isRemote ? (
1705 <Tooltip>
1706 <TooltipTrigger
1707 render={
1708 <span
1709 role="img"
1710 aria-label={props.environmentLabel ?? "Remote environment"}
1711 className="absolute -left-1 -bottom-1 inline-flex size-3 items-center justify-center rounded-full bg-sidebar text-sidebar-muted-foreground ring-1 ring-sidebar"
1712 />
1713 }
1714 >
1715 <EnvironmentMachineIcon kind={props.environmentMachine} className="size-2.5" />
1716 </TooltipTrigger>
1717 <TooltipPopup side="right">
1718 {props.environmentLabel ?? "Remote environment"}
1719 </TooltipPopup>
1720 </Tooltip>
1721 ) : null}
1722 </span>
17011723 {topStatus ? (
17021724 <span
17031725 aria-hidden
......@@ -1943,7 +1965,47 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
19431965 <div className="flex h-5 w-full min-w-0 items-center gap-1.5">
19441966 {draftIndicator}
19451967 {props.project ? (
1946 <ProjectFavicon project={props.project} className="size-4 shrink-0" />
1968 <span className="relative inline-flex size-4 shrink-0 items-center justify-center">
1969 <ProjectFavicon project={props.project} className="size-4" />
1970 {compactRows && isRemote ? (
1971 <Tooltip>
1972 <TooltipTrigger
1973 render={
1974 <span
1975 role="img"
1976 aria-label={props.environmentLabel ?? "Remote environment"}
1977 className="absolute -right-1 -bottom-1 inline-flex size-3 items-center justify-center rounded-full bg-sidebar text-sidebar-muted-foreground ring-1 ring-sidebar"
1978 />
1979 }
1980 >
1981 <EnvironmentMachineIcon
1982 kind={props.environmentMachine}
1983 className="size-2.5"
1984 />
1985 </TooltipTrigger>
1986 <TooltipPopup side="top">
1987 {props.environmentLabel ?? "Remote environment"}
1988 </TooltipPopup>
1989 </Tooltip>
1990 ) : null}
1991 </span>
1992 ) : compactRows && isRemote ? (
1993 <Tooltip>
1994 <TooltipTrigger
1995 render={
1996 <span
1997 role="img"
1998 aria-label={props.environmentLabel ?? "Remote environment"}
1999 className="inline-flex size-4 shrink-0 items-center justify-center text-sidebar-muted-foreground/70"
2000 />
2001 }
2002 >
2003 <EnvironmentMachineIcon kind={props.environmentMachine} className="size-3.5" />
2004 </TooltipTrigger>
2005 <TooltipPopup side="top">
2006 {props.environmentLabel ?? "Remote environment"}
2007 </TooltipPopup>
2008 </Tooltip>
19472009 ) : null}
19482010 {compactRows ? (
19492011 title
......@@ -1962,18 +2024,6 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
19622024 {pinIndicator}
19632025 {compactRows ? (
19642026 <>
1965 {isRemote ? (
1966 <span
1967 role="img"
1968 aria-label={props.environmentLabel ?? "Remote environment"}
1969 className="inline-flex shrink-0 text-sidebar-muted-foreground/70"
1970 >
1971 <EnvironmentMachineIcon
1972 kind={props.environmentMachine}
1973 className="size-3.5"
1974 />
1975 </span>
1976 ) : null}
19772027 {terminalStatusIcon}
19782028 {topStatus && CompactStatusIcon ? (
19792029 isWokeStatus ? (
......@@ -2001,7 +2051,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
20012051 </span>
20022052 )
20032053 ) : null}
2004 {prBadge}
2054 {renderPrBadge(true)}
20052055 </>
20062056 ) : null}
20072057 {/* The visible state owns this slot's width: status at rest,
......@@ -2031,7 +2081,9 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
20312081 >
20322082 {compactRows ? (
20332083 status === "working" ? (
2034 <WorkingDuration startedAt={resolveWorkingStartedAt(thread)} />
2084 <span className={topStatus?.className}>
2085 <WorkingDuration startedAt={resolveWorkingStartedAt(thread)} />
2086 </span>
20352087 ) : compactCompletedAt ? (
20362088 <SidebarCompletedTime completedAt={compactCompletedAt} />
20372089 ) : (
apps/web/src/components/ThreadStatusIndicators.tsx+4-1
......@@ -144,6 +144,7 @@ export function ThreadPullRequestBadgeControl({
144144 number,
145145 url,
146146 status,
147 iconOnly = false,
147148 onOpenStack,
148149 onOpenPullRequest,
149150}: {
......@@ -152,6 +153,8 @@ export function ThreadPullRequestBadgeControl({
152153 number?: number | undefined;
153154 url?: string | undefined;
154155 status: PrStatusIndicator | null;
156 /** Dense rows drop the number/layer count and keep only the state glyph. */
157 iconOnly?: boolean;
155158 onOpenStack: () => void;
156159 onOpenPullRequest: (event: MouseEvent<HTMLAnchorElement>) => void;
157160}) {
......@@ -179,7 +182,7 @@ export function ThreadPullRequestBadgeControl({
179182 const content = (
180183 <>
181184 <ThreadPullRequestBadgeIcon icon={badge?.kind ?? "pull-request"} />
182 {isStack ? badge.layers : linkedCount !== null ? `+${linkedCount}` : number}
185 {iconOnly ? null : isStack ? badge.layers : linkedCount !== null ? `+${linkedCount}` : number}
183186 </>
184187 );
185188 return (