"use client"; import { useEffect, useState } from "react"; import { Table, Box, Icon, Spinner, Text, Badge } from "@chakra-ui/react"; import { FaCheck, FaXmark, FaClock, FaMinus } from "react-icons/fa6"; import type { DagTask, DagTaskStatus } from "../../useWebSockets"; function humanizeTaskName(name: string): string { return name .split("_") .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(" "); } function formatDuration(seconds: number): string { if (seconds < 60) { return `${Math.round(seconds)}s`; } const minutes = Math.floor(seconds / 60); const remainingSeconds = Math.round(seconds % 60); return `${minutes}m ${remainingSeconds}s`; } function StatusIcon({ status }: { status: DagTaskStatus }) { switch (status) { case "completed": return ( ); case "running": return ; case "failed": return ( ); case "queued": return ( ); case "cancelled": return ( ); default: return null; } } function ElapsedTimer({ startedAt }: { startedAt: string }) { const [elapsed, setElapsed] = useState(() => { return (Date.now() - new Date(startedAt).getTime()) / 1000; }); useEffect(() => { const interval = setInterval(() => { setElapsed((Date.now() - new Date(startedAt).getTime()) / 1000); }, 1000); return () => clearInterval(interval); }, [startedAt]); return {formatDuration(elapsed)}; } function DurationCell({ task }: { task: DagTask }) { if (task.status === "completed" && task.duration_seconds !== null) { return {formatDuration(task.duration_seconds)}; } if (task.status === "running" && task.started_at) { return ; } return ( -- ); } function ProgressCell({ task }: { task: DagTask }) { if (task.progress_pct === null && task.children_total === null) { return null; } return ( {task.progress_pct !== null && ( )} {task.children_total !== null && ( {task.children_completed ?? 0}/{task.children_total} )} ); } function TaskRow({ task }: { task: DagTask }) { const [expanded, setExpanded] = useState(false); const hasFailed = task.status === "failed" && task.error; return ( <> setExpanded((prev) => !prev) : undefined} _hover={hasFailed ? { bg: "gray.50" } : undefined} > {humanizeTaskName(task.name)} {hasFailed && expanded && ( {task.error} )} ); } export default function DagProgressTable({ tasks }: { tasks: DagTask[] }) { return ( Task Status Duration Progress {tasks.map((task) => ( ))} ); }