authorgravatar for 97427849+flamboh@users.noreply.github.comoliver <97427849+flamboh@users.noreply.github.com> 2026-09-04 00:57:35-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-04 03:57:35-04:00
log706231535ceac8618712913dfdc4a058c2ffb0d8
tree69b14e0d379ad536a6a18d58f2cb86d96f6478ef
parent93c3ab4ffe408a3e06228a33efc8a0745da91178
signature Signed by PGP key B5690EEEBB952194

fix(web): match composer pull request state icons (#9375)


4 files changed, 43 insertions(+), 8 deletions(-)

apps/web/src/components/BranchToolbarBranchSelector.tsx+5-1
......@@ -745,7 +745,11 @@ export function BranchToolbarBranchSelector({
745745 />
746746 }
747747 >
748 <ChangeRequestStatusIcon className="size-3" />
748 <ChangeRequestStatusIcon
749 state={branchPr.state}
750 isDraft={branchPr.isDraft}
751 className="size-3"
752 />
749753 <span
750754 data-composer-label
751755 className="min-w-0 max-w-12 overflow-hidden group-data-[compact]/composer-context:max-w-0"
apps/web/src/components/LegacySidebar.tsx+6-2
......@@ -720,7 +720,7 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr
720720 onContextMenu={handleRowContextMenu}
721721 >
722722 <div className="flex min-w-0 flex-1 items-center gap-1.5 text-left">
723 {prStatus && (
723 {prStatus && pr && (
724724 <Tooltip>
725725 <TooltipTrigger
726726 render={
......@@ -733,7 +733,11 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr
733733 onPointerDown={(event) => event.stopPropagation()}
734734 onClick={handlePrClick}
735735 >
736 <ChangeRequestStatusIcon className="size-3" />
736 <ChangeRequestStatusIcon
737 state={pr.state}
738 isDraft={pr.isDraft}
739 className="size-3"
740 />
737741 </a>
738742 }
739743 />
apps/web/src/components/ThreadStatusIndicators.test.ts+18
......@@ -2,8 +2,15 @@ import { ProjectId, type PullRequestSummary, type VcsStatusResult } from "@t3too
22import { describe, expect, it } from "@effect/vitest";
33import * as Effect from "effect/Effect";
44import { AtomRegistry } from "effect/unstable/reactivity";
5import {
6 GitMergeIcon,
7 GitPullRequestClosedIcon,
8 GitPullRequestDraftIcon,
9 GitPullRequestIcon,
10} from "lucide-react";
511
612import {
13 ChangeRequestStatusIcon,
714 nextThreadChangeRequestSnapshot,
815 prStatusIndicator,
916 resolveDisplayedThreadPr,
......@@ -16,6 +23,17 @@ import {
1623} from "./ThreadStatusIndicators";
1724import { newestPullRequestSummary } from "../state/pullRequests";
1825
26describe("ChangeRequestStatusIcon", () => {
27 it.each([
28 ["open", "open", false, GitPullRequestIcon],
29 ["draft", "open", true, GitPullRequestDraftIcon],
30 ["closed", "closed", false, GitPullRequestClosedIcon],
31 ["merged", "merged", false, GitMergeIcon],
32 ] as const)("uses the %s pull request glyph", (_label, state, isDraft, expectedIcon) => {
33 expect(ChangeRequestStatusIcon({ state, isDraft }).type).toBe(expectedIcon);
34 });
35});
36
1937function status(overrides: Partial<VcsStatusResult> = {}): VcsStatusResult {
2038 return {
2139 isRepo: true,
apps/web/src/components/ThreadStatusIndicators.tsx+14-5
......@@ -11,7 +11,7 @@ import {
1111 type VcsStatusResult,
1212} from "@t3tools/contracts";
1313import { Atom } from "effect/unstable/reactivity";
14import { FolderGit2Icon, GitPullRequestIcon, TerminalIcon } from "lucide-react";
14import { FolderGit2Icon, TerminalIcon } from "lucide-react";
1515import { useMemo } from "react";
1616import { appAtomRegistry } from "../rpc/atomRegistry";
1717import { useEnvironment, usePrimaryEnvironmentId } from "../state/environments";
......@@ -24,6 +24,7 @@ import { vcsEnvironment } from "../state/vcs";
2424import { useUiStateStore } from "../uiStateStore";
2525import { resolveChangeRequestPresentation } from "../sourceControlPresentation";
2626import { resolveThreadStatusPill, type ThreadStatusPill } from "./Sidebar.logic";
27import { resolvePullRequestState } from "./pullRequest/pullRequestPresentation";
2728import type { SidebarThreadSummary } from "../types";
2829import { formatWorktreePathForDisplay } from "../worktreeCleanup";
2930import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";
......@@ -155,8 +156,16 @@ export function prStatusIndicator(
155156 return null;
156157}
157158
158export function ChangeRequestStatusIcon({ className }: { className?: string }) {
159 return <GitPullRequestIcon className={className} />;
159export function ChangeRequestStatusIcon({
160 state,
161 isDraft = false,
162 className,
163}: Pick<NonNullable<ThreadPr>, "state"> & {
164 readonly isDraft?: boolean | undefined;
165 readonly className?: string | undefined;
166}) {
167 const presentation = resolvePullRequestState({ state, isDraft });
168 return <presentation.Icon className={className} />;
160169}
161170
162171export function PrStatusTooltipContent({ status }: { status: PrStatusIndicator }) {
......@@ -585,7 +594,7 @@ export function ThreadRowLeadingStatus({ thread }: { thread: SidebarThreadSummar
585594
586595 return (
587596 <span className="inline-flex shrink-0 items-center gap-1.5">
588 {prStatus ? (
597 {prStatus && pr ? (
589598 <Tooltip>
590599 <TooltipTrigger
591600 render={
......@@ -595,7 +604,7 @@ export function ThreadRowLeadingStatus({ thread }: { thread: SidebarThreadSummar
595604 />
596605 }
597606 >
598 <ChangeRequestStatusIcon className="size-3" />
607 <ChangeRequestStatusIcon state={pr.state} isDraft={pr.isDraft} className="size-3" />
599608 </TooltipTrigger>
600609 <TooltipPopup side="top">
601610 <PrStatusTooltipContent status={prStatus} />