authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-07-24 14:08:39+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-24 14:08:39+02:00
loga7ee3092c3c4383a65a16a51de7e0328d6e027c9
treed1c079654560c866ff9e5296a4089da326864b65
parentf7cc7764887a3c0616973043fa77e12671e3f9ef
signature Signed by PGP key B5690EEEBB952194

Color settled PR labels on hover (#4451)

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 {
117117 sortThreadsForSidebarV2,
118118} from "./Sidebar.logic";
119119import { resolveLocalCheckoutBranchMismatch } from "./BranchToolbar.logic";
120import { prStatusIndicator, resolveThreadPr } from "./ThreadStatusIndicators";
120import {
121 prStatusIndicator,
122 resolveThreadPr,
123 settledPrHoverColorClass,
124} from "./ThreadStatusIndicators";
121125import {
122126 resolveSnoozePresets,
123127 snoozeWakeDescription,
......@@ -498,6 +502,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
498502 hasDedicatedWorktree: thread.worktreePath !== null,
499503 });
500504 const prStatus = prStatusIndicator(pr, gitStatus.data?.sourceControlProvider);
505 const settledPrHoverClass = pr ? settledPrHoverColorClass(pr.state) : undefined;
501506 // Report the PR state up: the parent partitions rows with effectiveSettled,
502507 // and a merged/closed PR auto-settles a thread — data only rows have.
503508 const prState = pr?.state ?? null;
......@@ -714,7 +719,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
714719 variant === "slim" && variantAction === "unsettle"
715720 ? props.isActive
716721 ? "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)
718723 : prStatus.colorClass,
719724 )}
720725 aria-label={prStatus.tooltip}
apps/web/src/components/ThreadStatusIndicators.test.ts+24-1
......@@ -1,7 +1,11 @@
11import type { VcsStatusResult } from "@t3tools/contracts";
22import { describe, expect, it } from "vite-plus/test";
33
4import { prStatusIndicator, resolveThreadPr } from "./ThreadStatusIndicators";
4import {
5 prStatusIndicator,
6 resolveThreadPr,
7 settledPrHoverColorClass,
8} from "./ThreadStatusIndicators";
59
610function status(overrides: Partial<VcsStatusResult> = {}): VcsStatusResult {
711 return {
......@@ -70,4 +74,23 @@ describe("prStatusIndicator", () => {
7074 tooltipTitle: "PR branch",
7175 });
7276 });
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
88describe("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 });
7396});
apps/web/src/components/ThreadStatusIndicators.tsx+12-1
......@@ -35,6 +35,17 @@ export interface TerminalStatusIndicator {
3535
3636export type ThreadPr = VcsStatusResult["pr"];
3737
38export 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
3849export function prStatusIndicator(
3950 pr: ThreadPr,
4051 provider: VcsStatusResult["sourceControlProvider"] | null | undefined,
......@@ -65,7 +76,7 @@ export function prStatusIndicator(
6576 if (pr.state === "closed") {
6677 return {
6778 label: `${presentation.shortName} closed`,
68 colorClass: "text-zinc-500 dark:text-zinc-400/80",
79 colorClass: "text-red-600 dark:text-red-300/90",
6980 tooltip,
7081 tooltipLead,
7182 tooltipTitle: pr.title,