| author | |
| committer | |
| log | a7ee3092c3c4383a65a16a51de7e0328d6e027c9 |
| tree | d1c079654560c866ff9e5296a4089da326864b65 |
| parent | f7cc7764887a3c0616973043fa77e12671e3f9ef |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: codex <codex@users.noreply.github.com>3 files changed, 43 insertions(+), 4 deletions(-)
apps/web/src/components/SidebarV2.tsx+7-2| ... | ... | @@ -117,7 +117,11 @@ import { |
| 117 | 117 | sortThreadsForSidebarV2, |
| 118 | 118 | } from "./Sidebar.logic"; |
| 119 | 119 | import { resolveLocalCheckoutBranchMismatch } from "./BranchToolbar.logic"; |
| 120 | import { prStatusIndicator, resolveThreadPr } from "./ThreadStatusIndicators"; | |
| 120 | import { | |
| 121 | prStatusIndicator, | |
| 122 | resolveThreadPr, | |
| 123 | settledPrHoverColorClass, | |
| 124 | } from "./ThreadStatusIndicators"; | |
| 121 | 125 | import { |
| 122 | 126 | resolveSnoozePresets, |
| 123 | 127 | snoozeWakeDescription, |
| ... | ... | @@ -498,6 +502,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 498 | 502 | hasDedicatedWorktree: thread.worktreePath !== null, |
| 499 | 503 | }); |
| 500 | 504 | const prStatus = prStatusIndicator(pr, gitStatus.data?.sourceControlProvider); |
| 505 | const settledPrHoverClass = pr ? settledPrHoverColorClass(pr.state) : undefined; | |
| 501 | 506 | // Report the PR state up: the parent partitions rows with effectiveSettled, |
| 502 | 507 | // and a merged/closed PR auto-settles a thread — data only rows have. |
| 503 | 508 | const prState = pr?.state ?? null; |
| ... | ... | @@ -714,7 +719,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 714 | 719 | variant === "slim" && variantAction === "unsettle" |
| 715 | 720 | ? props.isActive |
| 716 | 721 | ? "text-muted-foreground/70" |
| 717 | : "text-muted-foreground/35 transition-colors group-hover/v2-row:text-muted-foreground/65" | |
| 722 | : cn("text-muted-foreground/35 transition-colors", settledPrHoverClass) | |
| 718 | 723 | : prStatus.colorClass, |
| 719 | 724 | )} |
| 720 | 725 | aria-label={prStatus.tooltip} |
apps/web/src/components/ThreadStatusIndicators.test.ts+24-1| ... | ... | @@ -1,7 +1,11 @@ |
| 1 | 1 | import type { VcsStatusResult } from "@t3tools/contracts"; |
| 2 | 2 | import { describe, expect, it } from "vite-plus/test"; |
| 3 | 3 | |
| 4 | import { prStatusIndicator, resolveThreadPr } from "./ThreadStatusIndicators"; | |
| 4 | import { | |
| 5 | prStatusIndicator, | |
| 6 | resolveThreadPr, | |
| 7 | settledPrHoverColorClass, | |
| 8 | } from "./ThreadStatusIndicators"; | |
| 5 | 9 | |
| 6 | 10 | function status(overrides: Partial<VcsStatusResult> = {}): VcsStatusResult { |
| 7 | 11 | return { |
| ... | ... | @@ -70,4 +74,23 @@ describe("prStatusIndicator", () => { |
| 70 | 74 | tooltipTitle: "PR branch", |
| 71 | 75 | }); |
| 72 | 76 | }); |
| 77 | ||
| 78 | it("uses red for closed pull requests", () => { | |
| 79 | const closedPr = status().pr; | |
| 80 | if (!closedPr) throw new Error("Expected pull request fixture"); | |
| 81 | ||
| 82 | expect(prStatusIndicator({ ...closedPr, state: "closed" }, undefined)?.colorClass).toContain( | |
| 83 | "text-red-600", | |
| 84 | ); | |
| 85 | }); | |
| 86 | }); | |
| 87 | ||
| 88 | describe("settledPrHoverColorClass", () => { | |
| 89 | it.each([ | |
| 90 | ["open", "text-emerald-600"], | |
| 91 | ["merged", "text-violet-600"], | |
| 92 | ["closed", "text-red-600"], | |
| 93 | ] as const)("restores the %s pull request color on row hover", (state, colorClass) => { | |
| 94 | expect(settledPrHoverColorClass(state)).toContain(`group-hover/v2-row:${colorClass}`); | |
| 95 | }); | |
| 73 | 96 | }); |
apps/web/src/components/ThreadStatusIndicators.tsx+12-1| ... | ... | @@ -35,6 +35,17 @@ export interface TerminalStatusIndicator { |
| 35 | 35 | |
| 36 | 36 | export type ThreadPr = VcsStatusResult["pr"]; |
| 37 | 37 | |
| 38 | export function settledPrHoverColorClass(state: NonNullable<ThreadPr>["state"]): string { | |
| 39 | switch (state) { | |
| 40 | case "open": | |
| 41 | return "group-hover/v2-row:text-emerald-600 dark:group-hover/v2-row:text-emerald-300/90"; | |
| 42 | case "merged": | |
| 43 | return "group-hover/v2-row:text-violet-600 dark:group-hover/v2-row:text-violet-300/90"; | |
| 44 | case "closed": | |
| 45 | return "group-hover/v2-row:text-red-600 dark:group-hover/v2-row:text-red-300/90"; | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 38 | 49 | export function prStatusIndicator( |
| 39 | 50 | pr: ThreadPr, |
| 40 | 51 | provider: VcsStatusResult["sourceControlProvider"] | null | undefined, |
| ... | ... | @@ -65,7 +76,7 @@ export function prStatusIndicator( |
| 65 | 76 | if (pr.state === "closed") { |
| 66 | 77 | return { |
| 67 | 78 | label: `${presentation.shortName} closed`, |
| 68 | colorClass: "text-zinc-500 dark:text-zinc-400/80", | |
| 79 | colorClass: "text-red-600 dark:text-red-300/90", | |
| 69 | 80 | tooltip, |
| 70 | 81 | tooltipLead, |
| 71 | 82 | tooltipTitle: pr.title, |