- Replace statusDotColor + statusColor (35 lines) with STATUS_STYLES config (9 lines) - Single source of truth for both dot and text colors - All 6 statuses explicitly defined with type-safe Record constraint - Use semantic tokens for duration colors (text-destructive/text-primary)
Unified · Split
| @@ -60,22 +60,17 @@ const formatJsonDocument = (value: string | null): string | null => { · 59 unmodified lines | ||
| 60 | 60 | } |
| 61 | 61 | }; |
| 62 | 62 | |
| 63 | −const statusDotColor = (status: ExecutionStatus): string => { | |
| 64 | − switch (status) { | |
| 65 | − case "completed": | |
| 66 | − return "bg-primary"; | |
| 67 | − case "failed": | |
| 68 | − return "bg-destructive"; | |
| 69 | − case "running": | |
| 70 | − return "bg-blue-400 animate-pulse"; | |
| 71 | − case "waiting_for_interaction": | |
| 72 | − return "bg-amber-400 animate-pulse"; | |
| 73 | − case "pending": | |
| 74 | − return "bg-muted"; | |
| 75 | − case "cancelled": | |
| 76 | − return "bg-muted"; | |
| 77 | − } | |
| 78 | −}; | |
| 63 | +const STATUS_STYLES = { | |
| 64 | + completed: { dot: "bg-primary", text: "text-primary" }, | |
| 65 | + failed: { dot: "bg-destructive", text: "text-destructive" }, | |
| 66 | + running: { dot: "bg-blue-400 animate-pulse", text: "text-blue-400" }, | |
| 67 | + waiting_for_interaction: { dot: "bg-amber-400 animate-pulse", text: "text-amber-400" }, | |
| 68 | + pending: { dot: "bg-muted", text: "text-muted-foreground" }, | |
| 69 | + cancelled: { dot: "bg-muted", text: "text-muted-foreground" }, | |
| 70 | +} as const satisfies Record<ExecutionStatus, { dot: string; text: string }>; | |
| 71 | + | |
| 72 | +const statusDot = (status: ExecutionStatus): string => STATUS_STYLES[status].dot; | |
| 73 | +const statusText = (status: ExecutionStatus): string => STATUS_STYLES[status].text; | |
| 79 | 74 | |
| 80 | 75 | const STATUS_OPTIONS: Array<{ value: string; label: string }> = [ |
| 81 | 76 | { value: "all", label: "All" }, |
| @@ -93,21 +88,6 @@ const formatDurationMs = (execution: Execution): string | null => { · 11 unmodified lines | ||
| 93 | 88 | return ms.toLocaleString(); |
| 94 | 89 | }; |
| 95 | 90 | |
| 96 | −const statusColor = (status: ExecutionStatus): string => { | |
| 97 | − switch (status) { | |
| 98 | − case "completed": | |
| 99 | − return "text-primary"; | |
| 100 | − case "failed": | |
| 101 | − return "text-destructive"; | |
| 102 | − case "running": | |
| 103 | − return "text-blue-400"; | |
| 104 | − case "waiting_for_interaction": | |
| 105 | − return "text-amber-400"; | |
| 106 | − default: | |
| 107 | − return "text-muted-foreground"; | |
| 108 | − } | |
| 109 | −}; | |
| 110 | − | |
| 111 | 91 | // ── Execution Row ──────────────────────────────────────────────────────── |
| 112 | 92 | |
| 113 | 93 | const ExecutionRow = (props: { |
| @@ -130,7 +110,7 @@ const ExecutionRow = (props: { · 16 unmodified lines | ||
| 130 | 110 | <span |
| 131 | 111 | className={cn( |
| 132 | 112 | "mt-1.5 size-2 shrink-0 rounded-full", |
| 133 | − statusDotColor(execution.status), | |
| 113 | + statusDot(execution.status), | |
| 134 | 114 | )} |
| 135 | 115 | /> |
| 136 | 116 | <span className="w-[120px] shrink-0 tabular-nums text-muted-foreground"> |
| @@ -138,11 +118,11 @@ const ExecutionRow = (props: { · 1 unmodified line | ||
| 138 | 118 | </span> |
| 139 | 119 | <span className="inline-flex w-[130px] shrink-0"> |
| 140 | 120 | <span className="text-muted-foreground/60">status:</span> |
| 141 | − <span className={statusColor(execution.status)}>{execution.status.replaceAll("_", " ")}</span> | |
| 121 | + <span className={statusText(execution.status)}>{execution.status.replaceAll("_", " ")}</span> | |
| 142 | 122 | </span> |
| 143 | 123 | <span className="inline-flex w-[110px] shrink-0"> |
| 144 | 124 | <span className="text-muted-foreground/60">duration_ms:</span>{" "} |
| 145 | − <span className={durationMs && Number(durationMs.replace(/,/g, "")) > 5000 ? "text-red-400" : "text-emerald-400"}>{durationMs ?? "—"}</span> | |
| 125 | + <span className={durationMs && Number(durationMs.replace(/,/g, "")) > 5000 ? "text-destructive" : "text-primary"}>{durationMs ?? "—"}</span> | |
| 146 | 126 | </span> |
| 147 | 127 | <span className="min-w-0 flex-1 truncate"> |
| 148 | 128 | <span className="text-muted-foreground/60">code:</span>{" "} |
| @@ -186,7 +166,7 @@ const PropertiesTab = (props: { envelope: ExecutionEnvelope }) => { · 37 unmodified lines | ||
| 186 | 166 | Status |
| 187 | 167 | </div> |
| 188 | 168 | <div className="mt-1 flex items-center gap-2"> |
| 189 | − <span className={cn("size-2 rounded-full", statusDotColor(execution.status))} /> | |
| 169 | + <span className={cn("size-2 rounded-full", statusDot(execution.status))} /> | |
| 190 | 170 | <span className="text-sm">{execution.status.replaceAll("_", " ")}</span> |
| 191 | 171 | </div> |
| 192 | 172 | </div> |