Files
Codewalkers/apps/web/src/components/StatusDot.tsx
Lukas May 8804455c77 Remove task-level approval system
Task-level approval (requiresApproval, mergeRequiresApproval,
pending_approval status) was redundant with executionMode
(yolo vs review_per_phase) and blocked the orchestrator's
phase completion flow. Tasks now complete directly;
phase-level review via executionMode is the right granularity.

Removed: schema columns (left in DB, removed from Drizzle),
TaskPendingApprovalEvent, approveTask/listPendingApprovals
procedures, findPendingApproval repository method, and all
frontend approval UI.
2026-03-05 17:09:48 +01:00

113 lines
2.7 KiB
TypeScript

import { cn } from "@/lib/utils";
export type StatusVariant = "active" | "success" | "warning" | "error" | "neutral" | "urgent";
const dotColors: Record<StatusVariant, string> = {
active: "bg-status-active-dot",
success: "bg-status-success-dot",
warning: "bg-status-warning-dot",
error: "bg-status-error-dot",
neutral: "bg-status-neutral-dot",
urgent: "bg-status-urgent-dot",
};
const glowMap: Record<StatusVariant, string | undefined> = {
active: "0 0 6px 1px hsl(var(--status-active-dot) / 0.5)",
success: "0 0 6px 1px hsl(var(--status-success-dot) / 0.4)",
warning: "0 0 6px 1px hsl(var(--status-warning-dot) / 0.4)",
error: "0 0 6px 1px hsl(var(--status-error-dot) / 0.5)",
neutral: undefined,
urgent: "0 0 6px 1px hsl(var(--status-urgent-dot) / 0.4)",
};
/** Maps raw entity status strings to semantic StatusVariant tokens. */
export function mapEntityStatus(rawStatus: string): StatusVariant {
switch (rawStatus) {
// Active / in-progress
case "running":
case "in_progress":
case "active":
case "building":
case "responded":
return "active";
// Success / completed
case "completed":
case "read":
case "low":
return "success";
// Warning / needs attention
case "waiting_for_input":
case "pending_review":
case "approved":
case "exhausted":
case "medium":
return "warning";
// Error / failed
case "crashed":
case "blocked":
case "failed":
case "high":
return "error";
// Urgent
// (reserved for future use, no current raw statuses map here)
// Neutral / idle
case "pending":
case "idle":
case "stopped":
case "exited":
case "archived":
default:
return "neutral";
}
}
interface StatusDotProps {
status: string;
/** Override the auto-mapped variant with an explicit one. */
variant?: StatusVariant;
size?: "sm" | "md" | "lg";
pulse?: boolean;
label?: string;
className?: string;
}
export function StatusDot({
status,
variant: variantOverride,
size = "md",
pulse = false,
label,
className,
}: StatusDotProps) {
const sizeClasses = {
sm: "h-2 w-2",
md: "h-3 w-3",
lg: "h-4 w-4",
};
const variant = variantOverride ?? mapEntityStatus(status);
const color = dotColors[variant];
const glow = glowMap[variant];
const displayLabel = label ?? status.replace(/_/g, " ").toLowerCase();
return (
<span
role="status"
aria-label={displayLabel}
className={cn(
"inline-block shrink-0 rounded-full",
sizeClasses[size],
color,
pulse && "animate-status-pulse transition-transform",
className,
)}
style={glow ? { boxShadow: glow } : undefined}
/>
);
}