import Link from "next/link"; import { formatDistanceToNowStrict } from "date-fns"; import { cn } from "@/lib/utils"; import { EXPORT_STATUS_STYLES, statusLabel } from "@/app/(dashboard)/pipeline/status-colors"; import type { BlockedExport } from "@/lib/dashboard/ops"; /** * The exception list: exports that have stopped moving and need a person. * * Read by scanning down the left edge โ€” the severity rail says which rows are * dead in the water (a failed state, which nothing retries) versus merely * overdue (still nominally in flight, or waiting on a QC pass). The reason * column exists so the answer to "what happened" doesn't require opening * anything. */ export function BlockedQueue({ blocked }: { blocked: BlockedExport[] }) { const critical = blocked.filter((b) => b.severity === "critical").length; return (

{blocked.length === 0 ? "Nothing blocked" : `${blocked.length} export${blocked.length === 1 ? "" : "s"} stalled`} {critical > 0 && ( {critical} failed )}

Open render queue โ†’
{blocked.length === 0 ? (

Every export is either moving or done.

) : (
{blocked.map((b) => ( {/* The reason can be an aerender error several lines long; it is clamped here and given in full on hover. */} ))}
Shot Status Stuck Why Artist
{b.shotCode}{" "} {b.versionString}
{b.projectCode} {b.episode ? ` ยท ep ${b.episode}` : ""}
{statusLabel(b.status)} {formatDistanceToNowStrict(b.since)} {b.reason} {b.artistName ?? "โ€”"}
)}
); }