import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { api } from "../api/client"; import { describeApiError, type ApiErrorInfo } from "../api/errorMessages"; import type { AutomationRun, IntegrationStatus, KnowledgeHealth } from "../api/types"; import { StatusBadge } from "../components/Badge"; import { useAuth } from "../context/AuthContext"; import { useLocaleFormat } from "../i18n/format"; import { ApiErrorNotice, ErrorState, IntegrationMark, LoadingState, PageHeader, SectionHeading } from "../components/PageChrome"; import { N8N_STATE_META, MCP_STATE_META, N8N_WORKFLOW_SLUGS } from "../data/integrationLabels"; type ViewFilter = "attention" | "recent" | "succeeded" | "all"; function deriveDisplayRef(run: AutomationRun): string { const digits = run.aggregate_ref.match(/(\d+)$/)?.[1]; if (digits) return `AUT-RET-${digits}`; return `AUT-${run.event_id.slice(0, 4).toUpperCase()}`; } export function Automation() { const { t } = useTranslation(["integrations", "common"]); const { formatDateTime } = useLocaleFormat(); const { user } = useAuth(); const [runs, setRuns] = useState(null); const [error, setError] = useState(null); const [status, setStatus] = useState(""); const [view, setView] = useState("attention"); const [expandSucceeded, setExpandSucceeded] = useState(false); const [retryError, setRetryError] = useState(null); const [retrying, setRetrying] = useState(null); const [knowledge, setKnowledge] = useState(null); const [integrationStatus, setIntegrationStatus] = useState(null); const load = useCallback(() => { setRuns(null); setError(null); const params = new URLSearchParams(); if (status) params.set("status", status); api .get(`/api/v1/workflows?${params.toString()}`) .then(setRuns) .catch(() => setError(user?.role === "operations_manager" ? t("ledger.unavailable") : t("ledger.managerOnly")), ); }, [status, user, t]); useEffect(() => { load(); }, [load]); useEffect(() => { api.get("/api/v1/knowledge/status").then(setKnowledge).catch(() => setKnowledge(null)); }, []); const loadIntegrationStatus = useCallback(() => { api .get("/api/v1/integrations/status") .then(setIntegrationStatus) .catch(() => setIntegrationStatus(null)); }, []); useEffect(() => { loadIntegrationStatus(); }, [loadIntegrationStatus]); async function handleRetry(eventId: string) { setRetryError(null); setRetrying(eventId); try { await api.post(`/api/v1/workflows/${eventId}/retry`); load(); loadIntegrationStatus(); } catch (err) { setRetryError(describeApiError(t, err, "ledger.retryFailed")); } finally { setRetrying(null); } } const visibleRuns = useMemo(() => { if (!runs) return null; switch (view) { case "attention": return runs.filter((r) => r.status === "failed" || r.status === "pending" || r.status === "delivering"); case "recent": return runs.slice(0, 5); case "succeeded": return runs.filter((r) => r.status === "succeeded"); default: return runs; } }, [runs, view]); const succeededRuns = useMemo(() => (visibleRuns ?? []).filter((r) => r.status === "succeeded"), [visibleRuns]); const otherRuns = useMemo(() => (visibleRuns ?? []).filter((r) => r.status !== "succeeded"), [visibleRuns]); const groupSucceeded = view !== "succeeded" && succeededRuns.length > 3; if (user?.role !== "operations_manager") { return (

{t("ledger.managerOnly")}

); } function renderRow(r: AutomationRun) { return (
{deriveDisplayRef(r)} {r.event_id}
{t(`ledger.eventTypes.${r.event_type}`, { defaultValue: r.event_type })} {r.aggregate_ref} {r.is_demo_scenario && ( )} {r.attempts} {r.last_error_code ? ( <> {t(`ledger.errorCodes.${r.last_error_code}`, { defaultValue: r.last_error ?? r.last_error_code })} {r.is_demo_scenario &&

{t("ledger.demoScenarioExplanation")}

} {r.last_error && (
{t("common:actions.technicalDetails")}
{r.last_error}
)} ) : ( "—" )} {r.status === "failed" ? ( ) : ( t("ledger.noAction") )} ); } return (
{t("cards.orchestrationKicker")}

{t("cards.n8nTitle")}

{integrationStatus ? t("cards.n8nSummary", { succeeded: integrationStatus.n8n.succeeded, failed: integrationStatus.n8n.unexpected_failed, pending: integrationStatus.n8n.pending, delivering: integrationStatus.n8n.delivering, }) : t("cards.n8nFallback")}

{/* Prepared demo failures are stated separately and never folded into the health count above, so the badge and the numbers tell the same story. */} {integrationStatus && integrationStatus.n8n.demo_scenario_failed > 0 && (

{t("cards.n8nDemoScenario", { count: integrationStatus.n8n.demo_scenario_failed })}

)}
{(() => { const meta = integrationStatus ? N8N_STATE_META[integrationStatus.n8n.state] : null; return ( ); })()}
{t("cards.knowledgeKicker")}

{t("cards.knowledgeTitle")}

{knowledge ? knowledge.document_count === null ? t("cards.knowledgeSummaryIndexUnknown", { collection: knowledge.collection }) : t(knowledge.provider === "ragcore" ? "cards.knowledgeSummaryRagcore" : "cards.knowledgeSummaryDemo", { count: knowledge.document_count, collection: knowledge.collection, }) : t("cards.knowledgeUnavailable")}

{t("cards.gatewayKicker")}

{t("cards.mcpTitle")}

{(() => { const hub = integrationStatus?.mcp_hub; if (!hub?.registration_enabled) return t("cards.mcpNotConnected"); if (hub.total_calls > 0) { return t("cards.mcpEvidence", { tool: hub.last_tool, client: hub.last_client, count: hub.total_calls }); } return t("cards.mcpNoEvidence"); })()}

{integrationStatus?.mcp_hub.last_called_at && ( {formatDateTime(integrationStatus.mcp_hub.last_called_at)} )}
{(() => { const meta = integrationStatus ? MCP_STATE_META[integrationStatus.mcp_hub.state] : null; return ; })()} {integrationStatus?.mcp_hub.hub_reachable !== null && integrationStatus?.mcp_hub.hub_reachable !== undefined && ( )}
{integrationStatus && (
{integrationStatus.n8n.workflows.map((w) => { const slug = N8N_WORKFLOW_SLUGS[w.name] ?? ""; const displayName = slug ? t(`workflows.names.${slug}`) : w.name; const badge = !w.built ? { status: "not_configured", label: t("workflows.notBuilt") } : w.state === "healthy" ? { status: "available", label: t("workflows.healthy") } : w.state === "stale" ? { status: "degraded", label: t("workflows.stale") } : w.state === "failed" ? { status: "failed", label: t("workflows.failed") } : { status: "no_events", label: t("workflows.noEvidence") }; return ( ); })}
{t("workflows.title")}
{t("workflows.columns.name")} {t("workflows.columns.status")} {t("workflows.columns.lastSeen")} {t("workflows.columns.technicalId")}
{displayName} {w.last_seen_at ? ( ) : ( "—" )}
{t("common:actions.technicalDetails")} {w.name}{w.last_execution_id ? ` · ${t("workflows.executionId")}: ${w.last_execution_id}` : ""}

{integrationStatus.n8n.error_handler.total_failures_registered > 0 ? t("workflows.errorHandler.summary", { count: integrationStatus.n8n.error_handler.total_failures_registered, workflow: integrationStatus.n8n.error_handler.latest_failure_workflow ?? "", when: integrationStatus.n8n.error_handler.latest_failure_at ? formatDateTime(integrationStatus.n8n.error_handler.latest_failure_at) : "", }) : t("workflows.errorHandler.summaryEmpty")}

)}
{error && } {!error && !runs && } {visibleRuns && visibleRuns.length === 0 &&

{t("ledger.empty")}

} {visibleRuns && visibleRuns.length > 0 && (
{t("ledger.count", { count: visibleRuns.length })}{t("ledger.boundedRetries")}
{otherRuns.map(renderRow)} {groupSucceeded ? ( <> {expandSucceeded && succeededRuns.map(renderRow)} ) : ( succeededRuns.map(renderRow) )}
{t("ledger.title")}
{t("ledger.columns.event")} {t("ledger.columns.type")} {t("ledger.columns.booking")} {t("ledger.columns.status")} {t("ledger.columns.attempts")} {t("ledger.columns.lastError")} {t("ledger.columns.when")} {t("ledger.columns.action")}
)}
); }