"use client"; import { CheckCircle2, AlertCircle, Clock, XCircle, Loader2 } from "lucide-react"; import type { CronStatusResponse } from "@/api/generated/model"; import { DashboardSection } from "./DashboardSection"; import { DashboardEmptyState } from "./DashboardEmptyState"; interface GatewayCronPanelProps { cron: CronStatusResponse | null; isLoading?: boolean; hasGateways: boolean; } type StatusKey = "ok" | "error" | "running" | "pending" | "disabled" | "unknown"; const STATUS_META: Record = { ok: { icon: CheckCircle2, cls: "text-[color:var(--success)]", label: "OK" }, error: { icon: AlertCircle, cls: "text-[color:var(--danger)]", label: "Error" }, running: { icon: Loader2, cls: "text-[color:var(--accent)] animate-spin", label: "Running" }, pending: { icon: Clock, cls: "text-muted", label: "Pending" }, disabled: { icon: XCircle, cls: "text-muted opacity-40", label: "Disabled" }, unknown: { icon: Clock, cls: "text-muted", label: "Unknown" }, }; function fmtMs(ms: number | null | undefined): string { if (ms == null) return ""; if (ms < 1000) return `${ms}ms`; return `${(ms / 1000).toFixed(1)}s`; } function relativeTime(iso: string | null | undefined): string { if (!iso) return "never"; try { const diff = Date.now() - new Date(iso).getTime(); if (diff < 60_000) return "just now"; if (diff < 3_600_000) return `${Math.floor(diff / 60_000)}m ago`; if (diff < 86_400_000) return `${Math.floor(diff / 3_600_000)}h ago`; return `${Math.floor(diff / 86_400_000)}d ago`; } catch { return "—"; } } export function GatewayCronPanel({ cron, isLoading = false, hasGateways, }: GatewayCronPanelProps) { if (!hasGateways) return null; const jobs = cron?.jobs ?? []; return ( 0 ? { label: `${jobs.length}`, href: "#" } : undefined} > {isLoading && !cron ? (
{[0, 1].map((i) => (
))}
) : jobs.length === 0 ? ( ) : (
{jobs.map((job) => { const meta = STATUS_META[(job.status as StatusKey) ?? "unknown"] ?? STATUS_META.unknown; const Icon = meta.icon; return (

{job.name}

{job.schedule && ( {job.schedule} )}
Last: {relativeTime(job.last_run)} {job.next_run && Next: {relativeTime(job.next_run)}} {job.last_duration_ms != null && ( {fmtMs(job.last_duration_ms)} )} {job.last_error && ( {job.last_error} )}
{meta.label}
); })}
)} ); }