Fresh-context deep review verdict was SHIP-WITH-FIXES (all hard constraints held: read-only, inert gate panel, XSS posture, no backend, gate-vs-inert semantics). Resolved: - Board columns: replace magic calc(100vh-220px) ScrollArea cap with a proper flex chain (h-full/min-h-0) so card lists size to real column height at any window size / wrapped toolbar. - Valid ARIA: stage row is role=list, each column a role=listitem wrapping a role=listbox of task-card options (no malformed listbox nesting). - TopBar health dot uses status-active/status-failed tokens (no hardcoded Tailwind palette colors). - Stale TaskList reference in badge.tsx comment. Typecheck + 36 tests + build all green.
64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
import * as React from "react";
|
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const badgeVariants = cva(
|
|
"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-semibold leading-none",
|
|
{
|
|
variants: {
|
|
variant: {
|
|
default: "bg-secondary text-secondary-foreground",
|
|
outline: "border border-border text-muted-foreground",
|
|
// Pipeline status variants — tinted surface + bright foreground.
|
|
active: "bg-status-active-bg text-status-active",
|
|
waiting: "bg-status-waiting-bg text-status-waiting",
|
|
parked: "bg-status-parked-bg text-status-parked",
|
|
done: "bg-status-done-bg text-status-done",
|
|
failed: "bg-status-failed-bg text-status-failed",
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
variant: "default",
|
|
},
|
|
},
|
|
);
|
|
|
|
export interface BadgeProps
|
|
extends React.HTMLAttributes<HTMLSpanElement>,
|
|
VariantProps<typeof badgeVariants> {}
|
|
|
|
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
return (
|
|
<span className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Map a backend task status / verdict string to a Badge variant. Centralized so
|
|
* TaskCard, the Board, and TaskDrawer agree on color.
|
|
*/
|
|
export function statusVariant(
|
|
status: string,
|
|
): NonNullable<BadgeProps["variant"]> {
|
|
switch (status) {
|
|
case "active":
|
|
return "active";
|
|
case "waiting_human":
|
|
case "waiting":
|
|
return "waiting";
|
|
case "parked":
|
|
case "request_changes":
|
|
return "parked";
|
|
case "done":
|
|
case "approve":
|
|
case "approved":
|
|
case "pass":
|
|
return status === "done" ? "done" : "active";
|
|
case "failed":
|
|
return "failed";
|
|
default:
|
|
return "outline";
|
|
}
|
|
}
|
|
|
|
export { Badge, badgeVariants };
|