import { Button } from "@heroui/react"; import { useMemo } from "react"; import { Link } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { useI18n } from "../../i18n"; import { fetchOpsTasks, type OpsTaskItem } from "../../services/api"; import { formatSystemTime } from "../../utils/time"; const POLL_MS = 4000; function statusTone(status: string): string { const s = status.toLowerCase(); if (s === "collecting" || s === "running" || s === "connecting" || s === "testing") return "running"; if (s === "ready" || s === "idle") return "ok"; if (s === "paused" || s === "pending" || s === "detached") return "paused"; if (s === "failed" || s === "error") return "stopped"; return "other"; } function kindLabel(kind: string, t: (k: string, vars?: Record) => string): string { const key = `audit.tasks.kind.${kind}`; const tr = t(key); return tr === key ? kind : tr; } function statusLabel(status: string, t: (k: string, vars?: Record) => string): string { const key = `audit.tasks.status.${status}`; const tr = t(key); return tr === key ? status : tr; } function triggerLabel(trigger: string, t: (k: string, vars?: Record) => string): string { const raw = String(trigger || "").trim(); if (!raw || raw === "—") return "—"; const key = `audit.tasks.trigger.${raw}`; const tr = t(key); return tr === key ? raw : tr; } function runtimeTaskSubject( taskId: string, t: (k: string, vars?: Record) => string, ): string { const key = `ume.tasks.runtimeTask.${taskId}`; const label = t(key); return label === key ? taskId : label; } function taskTitle(row: OpsTaskItem, t: (k: string, vars?: Record) => string): string { const kind = kindLabel(row.kind, t); const subjectRaw = String(row.title || row.id || "").trim(); const subject = row.kind === "ume_runtime" && subjectRaw ? runtimeTaskSubject(subjectRaw, t) : subjectRaw; if (!subject) return kind; // Avoid "Kind · Kind · x" if an old backend still prefixed the localized kind. if (subject === kind || subject.startsWith(`${kind} · `) || subject.startsWith(`${kind}·`)) { return subject; } return `${kind} · ${subject}`; } function progressLabel(row: OpsTaskItem, t: (k: string, vars?: Record) => string): string { const base = String(row.progress || "").trim(); const inflight = Number(row.inflight || 0); if (inflight > 0) { const extra = t("audit.tasks.inflight", { n: inflight }); return base ? `${base} · ${extra}` : extra; } return base || "—"; } export function TaskOverviewPage() { const { t } = useI18n(); const query = useQuery({ queryKey: ["opsTasks"], queryFn: fetchOpsTasks, refetchInterval: POLL_MS, staleTime: 1500, }); const data = query.data; const items = useMemo(() => data?.items || [], [data]); const byKind = data?.by_kind || {}; const byStatus = data?.by_status || {}; return (

{t("audit.tasks.title")}

{t("audit.tasks.hint")}

{t("audit.tasks.kpiActive")}
{data?.active ?? "—"}
{t("audit.tasks.kpiTotal")}
{data?.total ?? "—"}
{t("audit.tasks.kpiKinds")}
{Object.keys(byKind).length ? Object.entries(byKind) .map(([k, n]) => `${kindLabel(k, t)} ${n}`) .join(" · ") : "—"}
{t("audit.tasks.kpiStatuses")}
{Object.keys(byStatus).length ? Object.entries(byStatus) .map(([k, n]) => `${statusLabel(k, t)} ${n}`) .join(" · ") : "—"}
{query.isLoading ?

{t("common.refreshing")}

: null} {!items.length && !query.isLoading ? (

{t("audit.tasks.empty")}

) : (
{items.map((row) => ( ))}
{t("audit.tasks.colKind")} {t("audit.tasks.colTitle")} {t("audit.tasks.colStatus")} {t("audit.tasks.colActor")} {t("audit.tasks.colTrigger")} {t("audit.tasks.colProgress")} {t("audit.tasks.colStarted")} {t("audit.tasks.colUpdated")} {t("audit.tasks.colLink")}
{kindLabel(row.kind, t)}
{taskTitle(row, t)}
{row.detail ? (
{row.detail}
) : null}
{statusLabel(row.status, t)} {row.actor || "—"} {triggerLabel(row.trigger, t)} {progressLabel(row, t)} {formatSystemTime(row.started_at) || "—"} {formatSystemTime(row.updated_at) || "—"} {row.href ? ( {t("audit.tasks.open")} ) : ( "—" )}
)}
); }