import { useEffect, useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { Title, Text, Group, Button, Stack, Paper, Alert, Loader, } from "@mantine/core"; import { IconArrowLeft } from "@tabler/icons-react"; import { getRun } from "../api"; import { StatusBadge } from "../components/StatusBadge"; import { StepTimeline } from "../components/StepTimeline"; import type { RunDetail as RunDetailType } from "../types"; export function RunDetail() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const load = async () => { if (!id) return; try { setData(await getRun(id)); setError(null); } catch (e) { setError((e as Error).message); } finally { setLoading(false); } }; useEffect(() => { load(); // Auto-refresh while running. const interval = setInterval(() => { if (data?.run.Status === "running") { load(); } }, 2000); return () => clearInterval(interval); }, [id, data?.run.Status]); if (loading) return ; if (error) return {error}; if (!data) return Not found; const { run, steps } = data; const duration = run.FinishedAt ? `${Math.round((new Date(run.FinishedAt).getTime() - new Date(run.StartedAt).getTime()) / 1000)}s` : "running..."; return (
Run {run.ID.substring(0, 16)}... {run.DagName} · {run.Trigger} ·{" "} {new Date(run.StartedAt).toLocaleString()}
{duration}
{run.Error && ( {run.Error} )} Steps ({steps?.length || 0}) {steps?.length ? ( ) : ( No steps recorded )}
); }