import type { LedKind } from "@unlocalhosted/metalui";
import type { CommitStatus, JobStatus, RunStatus, StepStatus } from "@/lib/runs";
// Run, job and step states, drawn like the issue status glyphs (MetalUI's 24 grid, 1.7 stroke) and
// coloured like its LEDs: green passed, red failed, amber working or waiting, unlit (ink3) the rest.
export type AnyStatus = RunStatus | JobStatus | StepStatus | CommitStatus;
const AMBER = "text-[#c98a18]";
const COLORS: Record<AnyStatus, string> = {
success: "text-green-deep",
failure: "text-red",
in_progress: AMBER,
queued: AMBER,
pending: "text-ink3",
waiting: "text-ink3",
cancelled: "text-ink3",
skipped: "text-ink3",
};
const LABELS: Record<AnyStatus, string> = {
success: "Success",
failure: "Failure",
in_progress: "In progress",
queued: "Queued",
pending: "Pending",
waiting: "Waiting",
cancelled: "Cancelled",
skipped: "Skipped",
};
export const statusText = (status: AnyStatus) => LABELS[status];
/** The LED for a status beside its words (StatusBadge). */
export function statusLed(status: AnyStatus): LedKind {
if (status === "success") return "live";
if (status === "failure") return "failed";
if (status === "in_progress" || status === "queued") return "waiting";
return "off";
}
const R = 9.15;
export function RunStatusIcon({ status, size = 16, className = "" }: { status: AnyStatus; size?: number; className?: string }) {
return (
<svg
viewBox="0 0 24 24"
width={size}
height={size}
className={`shrink-0 ${COLORS[status]} ${className}`}
role="img"
aria-label={LABELS[status]}
>
<title>{LABELS[status]}</title>
{status === "success" && (
<>
<circle cx="12" cy="12" r="10" fill="currentColor" />
<path d="m7.6 12.3 3.1 3.1 5.7-6.2" fill="none" stroke="var(--canvas)" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" />
</>
)}
{status === "failure" && (
<>
<circle cx="12" cy="12" r="10" fill="currentColor" />
<path d="m8.7 8.7 6.6 6.6m0-6.6-6.6 6.6" fill="none" stroke="var(--canvas)" strokeWidth="1.9" strokeLinecap="round" />
</>
)}
{status === "in_progress" && (
<>
<circle cx="12" cy="12" r={R} fill="none" stroke="currentColor" strokeWidth="1.7" opacity="0.3" />
<path
d={`M12 ${12 - R}a${R} ${R} 0 0 1 ${R} ${R}`}
fill="none"
stroke="currentColor"
strokeWidth="1.9"
strokeLinecap="round"
className="origin-center animate-spin"
/>
<circle cx="12" cy="12" r="3" fill="currentColor" />
</>
)}
{(status === "queued" || status === "waiting" || status === "pending") && (
<>
<circle cx="12" cy="12" r={R} fill="none" stroke="currentColor" strokeWidth="1.7" strokeDasharray="2.6 2.19" />
{status === "queued" && <circle cx="12" cy="12" r="3" fill="currentColor" />}
</>
)}
{status === "cancelled" && (
<>
<circle cx="12" cy="12" r={R} fill="none" stroke="currentColor" strokeWidth="1.7" />
<path d="m5.6 18.4 12.8-12.8" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" />
</>
)}
{status === "skipped" && (
<>
<circle cx="12" cy="12" r={R} fill="none" stroke="currentColor" strokeWidth="1.7" opacity="0.6" />
<path d="M8 12h8" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" />
</>
)}
</svg>
);
}