Skip to content

Commit b589918

Browse files
ravwojdyla-agentravwojdylaclaude
authored
[status-page] Stripe cancelled ferry runs as gray/red (#4785)
Cancelled runs already count against the ferry success rate (anything not "success" lowers it), but the UI rendered them in plain slate — visually indistinguishable from an unknown state. Render cancelled runs with a diagonal slate/rose stripe in both the latest-status dot and the history strip so the "failed, distinct cause" reading is visible at a glance. Co-authored-by: Rafal Wojdyla <ravwojdyla@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 461787b commit b589918

File tree

1 file changed

+32
-17
lines changed

1 file changed

+32
-17
lines changed

infra/status-page/web/src/components/FerryPanel.tsx

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
1+
import type { CSSProperties } from "react";
12
import { useFerry } from "../hooks/useFerry";
23
import type { FerryRun, FerryWorkflowStatus } from "../api";
34

4-
function runColor(run: FerryRun): string {
5-
if (run.status !== "completed") return "bg-amber-400";
5+
// Diagonal gray/red stripe marks cancelled runs — they count as failures
6+
// for success-rate math but carry a distinct cause worth surfacing.
7+
const CANCELLED_STRIPE: CSSProperties = {
8+
backgroundImage:
9+
"repeating-linear-gradient(45deg, #64748b 0, #64748b 3px, #f43f5e 3px, #f43f5e 6px)",
10+
};
11+
12+
function runAppearance(run: FerryRun): { className: string; style?: CSSProperties } {
13+
if (run.status !== "completed") return { className: "bg-amber-400" };
614
switch (run.conclusion) {
715
case "success":
8-
return "bg-emerald-500";
16+
return { className: "bg-emerald-500" };
917
case "failure":
10-
return "bg-rose-500";
18+
return { className: "bg-rose-500" };
1119
case "cancelled":
12-
return "bg-slate-500";
20+
return { className: "", style: CANCELLED_STRIPE };
1321
default:
14-
return "bg-slate-600";
22+
return { className: "bg-slate-600" };
1523
}
1624
}
1725

@@ -66,7 +74,10 @@ function WorkflowCard({ wf }: { wf: FerryWorkflowStatus }) {
6674
rel="noreferrer"
6775
className="inline-flex items-center gap-2 text-slate-200 hover:text-emerald-300"
6876
>
69-
<span className={`h-3 w-3 rounded-full ${runColor(latest)}`} />
77+
{(() => {
78+
const a = runAppearance(latest);
79+
return <span className={`h-3 w-3 rounded-full ${a.className}`} style={a.style} />;
80+
})()}
7081
<span className="font-mono text-xs">{latest.shaShort}</span>
7182
<span className="text-slate-400">{formatRelative(latest.startedAt)}</span>
7283
<span className="text-slate-500">({formatDuration(latest.durationSeconds)})</span>
@@ -85,16 +96,20 @@ function WorkflowCard({ wf }: { wf: FerryWorkflowStatus }) {
8596
so all 30 fit on a ~340px phone content area without
8697
wrapping to a second row. */}
8798
<div className="mt-3 flex gap-px sm:gap-1">
88-
{wf.history.map((run) => (
89-
<a
90-
key={run.id}
91-
href={run.url}
92-
target="_blank"
93-
rel="noreferrer"
94-
title={`${run.shaShort} · ${run.conclusion ?? run.status} · ${formatRelative(run.startedAt)}`}
95-
className={`h-5 w-2 rounded-sm sm:w-2.5 ${runColor(run)} hover:ring-2 hover:ring-slate-400`}
96-
/>
97-
))}
99+
{wf.history.map((run) => {
100+
const a = runAppearance(run);
101+
return (
102+
<a
103+
key={run.id}
104+
href={run.url}
105+
target="_blank"
106+
rel="noreferrer"
107+
title={`${run.shaShort} · ${run.conclusion ?? run.status} · ${formatRelative(run.startedAt)}`}
108+
className={`h-5 w-2 rounded-sm sm:w-2.5 ${a.className} hover:ring-2 hover:ring-slate-400`}
109+
style={a.style}
110+
/>
111+
);
112+
})}
98113
</div>
99114
</>
100115
)}

0 commit comments

Comments
 (0)