"use client"; import { useCallback, useEffect, useState } from "react"; import Link from "next/link"; import { api, type RunWithPipeline } from "@/components/api"; import { StatusBadge } from "@/components/status-badge"; import { fmtTime, fmtDuration } from "@/components/format"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; export default function RunsPage() { const [runs, setRuns] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const load = useCallback(() => { api("/api/runs") .then(setRuns) .catch((e) => setError(e instanceof Error ? e.message : "加载失败")) .finally(() => setLoading(false)); }, []); useEffect(load, [load]); // 有运行中的任务时轮询刷新 const hasActive = runs.some( (r) => r.status === "running" || r.status === "queued" ); useEffect(() => { if (!hasActive) return; const t = setInterval(load, 4000); return () => clearInterval(t); }, [hasActive, load]); return (

Runs

{loading ? (
加载中…
) : error ? (
加载失败:{error}
) : runs.length === 0 ? (
还没有运行记录。
) : (
ID 流水线 状态 开始时间 耗时 操作 {runs.map((r) => ( #{r.id} {r.pipeline_name ?? `(已删除 #${r.pipeline_id})`} {fmtTime(r.started_at)} {fmtDuration(r.started_at, r.finished_at)} ))}
)}
); }