| author | |
| committer | |
| log | 706231535ceac8618712913dfdc4a058c2ffb0d8 |
| tree | 69b14e0d379ad536a6a18d58f2cb86d96f6478ef |
| parent | 93c3ab4ffe408a3e06228a33efc8a0745da91178 |
| signature | Signed by PGP key B5690EEEBB952194 |
4 files changed, 43 insertions(+), 8 deletions(-)
apps/web/src/components/BranchToolbarBranchSelector.tsx+5-1| ... | @@ -745,7 +745,11 @@ export function BranchToolbarBranchSelector({ | ... | @@ -745,7 +745,11 @@ export function BranchToolbarBranchSelector({ |
| 745 | /> | 745 | /> |
| 746 | } | 746 | } |
| 747 | > | 747 | > |
| 748 | <ChangeRequestStatusIcon className="size-3" /> | 748 | <ChangeRequestStatusIcon |
| 749 | state={branchPr.state} | ||
| 750 | isDraft={branchPr.isDraft} | ||
| 751 | className="size-3" | ||
| 752 | /> | ||
| 749 | <span | 753 | <span |
| 750 | data-composer-label | 754 | data-composer-label |
| 751 | className="min-w-0 max-w-12 overflow-hidden group-data-[compact]/composer-context:max-w-0" | 755 | 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 | ... | @@ -720,7 +720,7 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr |
| 720 | onContextMenu={handleRowContextMenu} | 720 | onContextMenu={handleRowContextMenu} |
| 721 | > | 721 | > |
| 722 | <div className="flex min-w-0 flex-1 items-center gap-1.5 text-left"> | 722 | <div className="flex min-w-0 flex-1 items-center gap-1.5 text-left"> |
| 723 | {prStatus && ( | 723 | {prStatus && pr && ( |
| 724 | <Tooltip> | 724 | <Tooltip> |
| 725 | <TooltipTrigger | 725 | <TooltipTrigger |
| 726 | render={ | 726 | render={ |
| ... | @@ -733,7 +733,11 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr | ... | @@ -733,7 +733,11 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr |
| 733 | onPointerDown={(event) => event.stopPropagation()} | 733 | onPointerDown={(event) => event.stopPropagation()} |
| 734 | onClick={handlePrClick} | 734 | onClick={handlePrClick} |
| 735 | > | 735 | > |
| 736 | <ChangeRequestStatusIcon className="size-3" /> | 736 | <ChangeRequestStatusIcon |
| 737 | state={pr.state} | ||
| 738 | isDraft={pr.isDraft} | ||
| 739 | className="size-3" | ||
| 740 | /> | ||
| 737 | </a> | 741 | </a> |
| 738 | } | 742 | } |
| 739 | /> | 743 | /> |
apps/web/src/components/ThreadStatusIndicators.test.ts+18| ... | @@ -2,8 +2,15 @@ import { ProjectId, type PullRequestSummary, type VcsStatusResult } from "@t3too | ... | @@ -2,8 +2,15 @@ import { ProjectId, type PullRequestSummary, type VcsStatusResult } from "@t3too |
| 2 | import { describe, expect, it } from "@effect/vitest"; | 2 | import { describe, expect, it } from "@effect/vitest"; |
| 3 | import * as Effect from "effect/Effect"; | 3 | import * as Effect from "effect/Effect"; |
| 4 | import { AtomRegistry } from "effect/unstable/reactivity"; | 4 | import { AtomRegistry } from "effect/unstable/reactivity"; |
| 5 | import { | ||
| 6 | GitMergeIcon, | ||
| 7 | GitPullRequestClosedIcon, | ||
| 8 | GitPullRequestDraftIcon, | ||
| 9 | GitPullRequestIcon, | ||
| 10 | } from "lucide-react"; | ||
| 5 | 11 | ||
| 6 | import { | 12 | import { |
| 13 | ChangeRequestStatusIcon, | ||
| 7 | nextThreadChangeRequestSnapshot, | 14 | nextThreadChangeRequestSnapshot, |
| 8 | prStatusIndicator, | 15 | prStatusIndicator, |
| 9 | resolveDisplayedThreadPr, | 16 | resolveDisplayedThreadPr, |
| ... | @@ -16,6 +23,17 @@ import { | ... | @@ -16,6 +23,17 @@ import { |
| 16 | } from "./ThreadStatusIndicators"; | 23 | } from "./ThreadStatusIndicators"; |
| 17 | import { newestPullRequestSummary } from "../state/pullRequests"; | 24 | import { newestPullRequestSummary } from "../state/pullRequests"; |
| 18 | 25 | ||
| 26 | describe("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 | |||
| 19 | function status(overrides: Partial<VcsStatusResult> = {}): VcsStatusResult { | 37 | function status(overrides: Partial<VcsStatusResult> = {}): VcsStatusResult { |
| 20 | return { | 38 | return { |
| 21 | isRepo: true, | 39 | isRepo: true, |
apps/web/src/components/ThreadStatusIndicators.tsx+14-5| ... | @@ -11,7 +11,7 @@ import { | ... | @@ -11,7 +11,7 @@ import { |
| 11 | type VcsStatusResult, | 11 | type VcsStatusResult, |
| 12 | } from "@t3tools/contracts"; | 12 | } from "@t3tools/contracts"; |
| 13 | import { Atom } from "effect/unstable/reactivity"; | 13 | import { Atom } from "effect/unstable/reactivity"; |
| 14 | import { FolderGit2Icon, GitPullRequestIcon, TerminalIcon } from "lucide-react"; | 14 | import { FolderGit2Icon, TerminalIcon } from "lucide-react"; |
| 15 | import { useMemo } from "react"; | 15 | import { useMemo } from "react"; |
| 16 | import { appAtomRegistry } from "../rpc/atomRegistry"; | 16 | import { appAtomRegistry } from "../rpc/atomRegistry"; |
| 17 | import { useEnvironment, usePrimaryEnvironmentId } from "../state/environments"; | 17 | import { useEnvironment, usePrimaryEnvironmentId } from "../state/environments"; |
| ... | @@ -24,6 +24,7 @@ import { vcsEnvironment } from "../state/vcs"; | ... | @@ -24,6 +24,7 @@ import { vcsEnvironment } from "../state/vcs"; |
| 24 | import { useUiStateStore } from "../uiStateStore"; | 24 | import { useUiStateStore } from "../uiStateStore"; |
| 25 | import { resolveChangeRequestPresentation } from "../sourceControlPresentation"; | 25 | import { resolveChangeRequestPresentation } from "../sourceControlPresentation"; |
| 26 | import { resolveThreadStatusPill, type ThreadStatusPill } from "./Sidebar.logic"; | 26 | import { resolveThreadStatusPill, type ThreadStatusPill } from "./Sidebar.logic"; |
| 27 | import { resolvePullRequestState } from "./pullRequest/pullRequestPresentation"; | ||
| 27 | import type { SidebarThreadSummary } from "../types"; | 28 | import type { SidebarThreadSummary } from "../types"; |
| 28 | import { formatWorktreePathForDisplay } from "../worktreeCleanup"; | 29 | import { formatWorktreePathForDisplay } from "../worktreeCleanup"; |
| 29 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; | 30 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; |
| ... | @@ -155,8 +156,16 @@ export function prStatusIndicator( | ... | @@ -155,8 +156,16 @@ export function prStatusIndicator( |
| 155 | return null; | 156 | return null; |
| 156 | } | 157 | } |
| 157 | 158 | ||
| 158 | export function ChangeRequestStatusIcon({ className }: { className?: string }) { | 159 | export function ChangeRequestStatusIcon({ |
| 159 | return <GitPullRequestIcon className={className} />; | 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} />; | ||
| 160 | } | 169 | } |
| 161 | 170 | ||
| 162 | export function PrStatusTooltipContent({ status }: { status: PrStatusIndicator }) { | 171 | export function PrStatusTooltipContent({ status }: { status: PrStatusIndicator }) { |
| ... | @@ -585,7 +594,7 @@ export function ThreadRowLeadingStatus({ thread }: { thread: SidebarThreadSummar | ... | @@ -585,7 +594,7 @@ export function ThreadRowLeadingStatus({ thread }: { thread: SidebarThreadSummar |
| 585 | 594 | ||
| 586 | return ( | 595 | return ( |
| 587 | <span className="inline-flex shrink-0 items-center gap-1.5"> | 596 | <span className="inline-flex shrink-0 items-center gap-1.5"> |
| 588 | {prStatus ? ( | 597 | {prStatus && pr ? ( |
| 589 | <Tooltip> | 598 | <Tooltip> |
| 590 | <TooltipTrigger | 599 | <TooltipTrigger |
| 591 | render={ | 600 | render={ |
| ... | @@ -595,7 +604,7 @@ export function ThreadRowLeadingStatus({ thread }: { thread: SidebarThreadSummar | ... | @@ -595,7 +604,7 @@ export function ThreadRowLeadingStatus({ thread }: { thread: SidebarThreadSummar |
| 595 | /> | 604 | /> |
| 596 | } | 605 | } |
| 597 | > | 606 | > |
| 598 | <ChangeRequestStatusIcon className="size-3" /> | 607 | <ChangeRequestStatusIcon state={pr.state} isDraft={pr.isDraft} className="size-3" /> |
| 599 | </TooltipTrigger> | 608 | </TooltipTrigger> |
| 600 | <TooltipPopup side="top"> | 609 | <TooltipPopup side="top"> |
| 601 | <PrStatusTooltipContent status={prStatus} /> | 610 | <PrStatusTooltipContent status={prStatus} /> |