feat(demo): add reset UI and wire truthful integration status into pages
Add a "Reset demo data" action to the sidebar (Operations Manager only, explicit confirmation, progress, error handling) -- POST /api/v1/demo/reset already existed and was already role-gated server-side, but had no UI trigger. Reset invalidates the acting session server-side, so the flow signs the user out and returns them to login afterward. Wire the new GET /api/v1/integrations/status into Automation.tsx and Dashboard.tsx so both show the aggregate n8n state instead of the most recent event's status, and the MCP Hub card reflects the actual registration_enabled setting instead of a hardcoded "not configured" label.
This commit is contained in:
@@ -1,10 +1,18 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { api, ApiError } from "../api/client";
|
||||
import type { AutomationRun, KnowledgeHealth } from "../api/types";
|
||||
import type { AutomationRun, IntegrationStatus, KnowledgeHealth } from "../api/types";
|
||||
import { StatusBadge } from "../components/Badge";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import { ErrorState, IntegrationMark, LoadingState, PageHeader, SectionHeading } from "../components/PageChrome";
|
||||
|
||||
const N8N_STATE_LABEL: Record<IntegrationStatus["n8n"]["state"], string> = {
|
||||
disabled: "disabled",
|
||||
unavailable: "unavailable",
|
||||
degraded: "degraded",
|
||||
operational: "available",
|
||||
no_evidence: "no_events",
|
||||
};
|
||||
|
||||
export function Automation() {
|
||||
const { user } = useAuth();
|
||||
const [runs, setRuns] = useState<AutomationRun[] | null>(null);
|
||||
@@ -13,6 +21,7 @@ export function Automation() {
|
||||
const [retryError, setRetryError] = useState<string | null>(null);
|
||||
const [retrying, setRetrying] = useState<string | null>(null);
|
||||
const [knowledge, setKnowledge] = useState<KnowledgeHealth | null>(null);
|
||||
const [integrationStatus, setIntegrationStatus] = useState<IntegrationStatus | null>(null);
|
||||
|
||||
const load = useCallback(() => {
|
||||
setRuns(null);
|
||||
@@ -39,12 +48,24 @@ export function Automation() {
|
||||
api.get<KnowledgeHealth>("/api/v1/knowledge/status").then(setKnowledge).catch(() => setKnowledge(null));
|
||||
}, []);
|
||||
|
||||
const loadIntegrationStatus = useCallback(() => {
|
||||
api
|
||||
.get<IntegrationStatus>("/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(err instanceof ApiError ? err.message : "Could not retry this delivery.");
|
||||
} finally {
|
||||
@@ -66,9 +87,33 @@ export function Automation() {
|
||||
<PageHeader eyebrow="Assurance / Integrations" title="Integration control" description="Monitor delivery health, graceful degradation and retryable workflow events." />
|
||||
|
||||
<section className="integration-cards" aria-label="Integration health">
|
||||
<article><IntegrationMark kind="n8n" /><div><span className="integration-kicker">Orchestration</span><h2>n8n delivery</h2><p>Return events are committed locally first and then delivered through the outbox.</p></div><StatusBadge status={runs?.[0]?.status ?? "no_events"} /></article>
|
||||
<article>
|
||||
<IntegrationMark kind="n8n" />
|
||||
<div>
|
||||
<span className="integration-kicker">Orchestration</span>
|
||||
<h2>n8n delivery</h2>
|
||||
<p>
|
||||
{integrationStatus
|
||||
? `${integrationStatus.n8n.succeeded} succeeded · ${integrationStatus.n8n.failed} failed · ${integrationStatus.n8n.pending} pending · ${integrationStatus.n8n.delivering} delivering.`
|
||||
: "Return events are committed locally first and then delivered through the outbox."}
|
||||
</p>
|
||||
</div>
|
||||
<StatusBadge status={integrationStatus ? N8N_STATE_LABEL[integrationStatus.n8n.state] : (runs?.[0]?.status ?? "no_events")} />
|
||||
</article>
|
||||
<article><IntegrationMark kind="rag" /><div><span className="integration-kicker">Knowledge</span><h2>RAGcore</h2><p>{knowledge ? `${knowledge.document_count} procedures indexed in ${knowledge.collection}.` : "Health evidence is currently unavailable."}</p></div><StatusBadge status={knowledge?.available ? "available" : "unavailable"} /></article>
|
||||
<article><IntegrationMark kind="mcp" /><div><span className="integration-kicker">Tool gateway</span><h2>MCP Hub</h2><p>No active MobilityOps adapter is configured in this proof of concept.</p></div><StatusBadge status="not_configured" /></article>
|
||||
<article>
|
||||
<IntegrationMark kind="mcp" />
|
||||
<div>
|
||||
<span className="integration-kicker">Tool gateway</span>
|
||||
<h2>MCP Hub</h2>
|
||||
<p>
|
||||
{integrationStatus?.mcp_hub.registration_enabled
|
||||
? "Registration is enabled for this deployment."
|
||||
: "No active MobilityOps adapter is configured in this proof of concept."}
|
||||
</p>
|
||||
</div>
|
||||
<StatusBadge status={integrationStatus?.mcp_hub.state ?? "not_configured"} />
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<SectionHeading title="Delivery ledger" description="Persisted outbox attempts with the latest failure evidence." />
|
||||
|
||||
Reference in New Issue
Block a user