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.
113 lines
2.7 KiB
TypeScript
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}
|
|
/>
|
|
);
|
|
}
|