because I got bored of customising my CV for every job
1import { Card, StatusDot } from "@cv/ui";
2import type { WorkerHealthQuery } from "@/generated/graphql";
3
4type Worker = WorkerHealthQuery["workerHealth"][number];
5
6type DotColor = "green" | "yellow" | "red";
7
8const statusColor: Record<string, DotColor> = {
9 healthy: "green",
10 stale: "yellow",
11 dead: "red",
12};
13
14const formatRelativeTime = (isoString: string): string => {
15 const diff = Date.now() - new Date(isoString).getTime();
16 const seconds = Math.floor(diff / 1000);
17
18 if (seconds < 60) return `${seconds}s ago`;
19 const minutes = Math.floor(seconds / 60);
20 if (minutes < 60) return `${minutes}m ago`;
21 const hours = Math.floor(minutes / 60);
22 if (hours < 24) return `${hours}h ago`;
23 return `${Math.floor(hours / 24)}d ago`;
24};
25
26const truncateUuid = (uuid: string): string => uuid.slice(0, 8);
27
28interface WorkerHealthCardProps {
29 workers: Worker[];
30}
31
32export const WorkerHealthCard = ({ workers }: WorkerHealthCardProps) => (
33 <Card>
34 <h3 className="mb-3 text-lg font-medium text-ctp-text">Workers</h3>
35 {workers.length === 0 ? (
36 <p className="text-sm text-ctp-subtext0">No workers registered</p>
37 ) : (
38 <div className="overflow-x-auto">
39 <table className="w-full text-sm">
40 <thead>
41 <tr className="border-b border-ctp-surface1 text-left text-ctp-subtext0">
42 <th className="pb-2 pr-4">Worker ID</th>
43 <th className="pb-2 pr-4">Status</th>
44 <th className="pb-2 pr-4">Started</th>
45 <th className="pb-2 pr-4">Last Seen</th>
46 </tr>
47 </thead>
48 <tbody>
49 {workers.map((w) => (
50 <tr
51 key={w.workerId}
52 className="border-b border-ctp-surface1 last:border-b-0"
53 >
54 <td
55 className="py-1.5 pr-4 font-mono text-xs text-ctp-text"
56 title={w.workerId}
57 >
58 {truncateUuid(w.workerId)}
59 </td>
60 <td className="py-1.5 pr-4">
61 <span className="flex items-center gap-2">
62 <StatusDot color={statusColor[w.status] ?? "gray"} />
63 {w.status}
64 </span>
65 </td>
66 <td className="py-1.5 pr-4 text-ctp-subtext0">
67 {formatRelativeTime(w.startedAt)}
68 </td>
69 <td className="py-1.5 pr-4 text-ctp-subtext0">
70 {formatRelativeTime(w.lastSeenAt)}
71 </td>
72 </tr>
73 ))}
74 </tbody>
75 </table>
76 </div>
77 )}
78 </Card>
79);