n8n: surface real per-workflow evidence on the integration status page
Fleet Ops integration status no longer depends only on a config boolean or the most recent outbox event: N8nIntegrationStatus now reports per-canonical-workflow evidence (last successful outbox delivery for the return workflow, latest service-triggered data_quality_scan_run for the scan workflow, latest n8n_workflow_failure_registered for the error handler, and "not built" for the still-blocked RAGcore sync), plus an error-handler summary (total failures registered, latest failure + which workflow). Automation page renders this as a localized workflow table (EN/NL/FR) with technical workflow names tucked under a "Technical details" disclosure, matching the existing progressive-disclosure pattern. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e39c0a1dd6
commit
4049c0c6b1
@@ -7,7 +7,7 @@ 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 } from "../data/integrationLabels";
|
||||
import { N8N_STATE_META, MCP_STATE_META, N8N_WORKFLOW_SLUGS } from "../data/integrationLabels";
|
||||
|
||||
type ViewFilter = "attention" | "recent" | "succeeded" | "all";
|
||||
|
||||
@@ -218,6 +218,73 @@ export function Automation() {
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<SectionHeading
|
||||
title={t("workflows.title")}
|
||||
description={t("workflows.description", {
|
||||
known: integrationStatus?.n8n.known_workflow_count ?? 0,
|
||||
expected: integrationStatus?.n8n.expected_workflow_count ?? 4,
|
||||
})}
|
||||
/>
|
||||
|
||||
{integrationStatus && (
|
||||
<div className="table-shell">
|
||||
<table className="data-table">
|
||||
<caption className="visually-hidden">{t("workflows.title")}</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{t("workflows.columns.name")}</th>
|
||||
<th scope="col">{t("workflows.columns.status")}</th>
|
||||
<th scope="col">{t("workflows.columns.lastSeen")}</th>
|
||||
<th scope="col">{t("workflows.columns.technicalId")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{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.last_seen_at
|
||||
? { status: "available", label: t("statusLabels.operational") }
|
||||
: { status: "no_events", label: t("workflows.noEvidence") };
|
||||
return (
|
||||
<tr key={w.name}>
|
||||
<td data-label={t("workflows.columns.name")}>{displayName}</td>
|
||||
<td data-label={t("workflows.columns.status")}>
|
||||
<StatusBadge status={badge.status} label={badge.label} />
|
||||
</td>
|
||||
<td data-label={t("workflows.columns.lastSeen")}>
|
||||
{w.last_seen_at ? (
|
||||
<time dateTime={w.last_seen_at}>{formatDateTime(w.last_seen_at)}</time>
|
||||
) : (
|
||||
"—"
|
||||
)}
|
||||
</td>
|
||||
<td data-label={t("workflows.columns.technicalId")}>
|
||||
<details className="evidence-disclosure">
|
||||
<summary>{t("common:actions.technicalDetails")}</summary>
|
||||
<span className="table-subtext">{w.name}</span>
|
||||
</details>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<p className="table-meta">
|
||||
{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")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<SectionHeading title={t("ledger.title")} description={t("ledger.description")} />
|
||||
|
||||
<form className="filters" aria-label={t("ledger.title")}>
|
||||
|
||||
Reference in New Issue
Block a user