fix(telegram): preserve incident history html output
This commit is contained in:
@@ -58,12 +58,31 @@ type SloResponse = {
|
||||
};
|
||||
};
|
||||
|
||||
type RemediationHistoryItem = {
|
||||
work_item_id?: string | null;
|
||||
incident_id?: string | null;
|
||||
verification_result_preview?: string | null;
|
||||
agent_id?: string | null;
|
||||
tool_name?: string | null;
|
||||
required_scope?: string | null;
|
||||
writes_incident_state?: boolean | null;
|
||||
writes_auto_repair_result?: boolean | null;
|
||||
created_at?: string | null;
|
||||
};
|
||||
|
||||
type RemediationHistoryResponse = {
|
||||
schema_version?: string;
|
||||
total?: number;
|
||||
items?: RemediationHistoryItem[];
|
||||
};
|
||||
|
||||
type Telemetry = {
|
||||
quality: AutomationQualitySummary | null;
|
||||
governanceEvents: GovernanceEventsResponse | null;
|
||||
governanceQueue: GovernanceQueueResponse | null;
|
||||
channelEvents: RecentEventsResponse | null;
|
||||
slo: SloResponse | null;
|
||||
remediationHistory: RemediationHistoryResponse | null;
|
||||
};
|
||||
|
||||
type WorkItem = {
|
||||
@@ -74,6 +93,7 @@ type WorkItem = {
|
||||
source: string;
|
||||
gateKey: string;
|
||||
evidence: string;
|
||||
evidenceDetails?: string[];
|
||||
href: string;
|
||||
};
|
||||
|
||||
@@ -119,6 +139,15 @@ function hasGateFailure(summary: AutomationQualitySummary | null, gate: string)
|
||||
return Boolean(summary?.gate_failures?.some((row) => row.gate === gate && row.total > 0));
|
||||
}
|
||||
|
||||
function routeLabel(item?: RemediationHistoryItem | null) {
|
||||
if (!item) return "--";
|
||||
const route = [item.agent_id, item.tool_name, item.required_scope]
|
||||
.filter(Boolean)
|
||||
.map(String)
|
||||
.join("/");
|
||||
return route || "--";
|
||||
}
|
||||
|
||||
function buildWorkItems(
|
||||
telemetry: Telemetry,
|
||||
t: ReturnType<typeof useTranslations>
|
||||
@@ -132,6 +161,8 @@ function buildWorkItems(
|
||||
const remediationTotal = remediationQueue?.total ?? 0;
|
||||
const remediationReadyForAi = remediationQueue?.ready_for_ai ?? 0;
|
||||
const remediationNeedsHuman = remediationQueue?.needs_human ?? 0;
|
||||
const remediationHistoryTotal = telemetry.remediationHistory?.total ?? 0;
|
||||
const latestRemediationHistory = telemetry.remediationHistory?.items?.[0] ?? null;
|
||||
const governanceEventsUnavailable = telemetry.governanceEvents === null;
|
||||
const governanceQueueMissing = telemetry.governanceQueue?.table_pending === true;
|
||||
const governanceDispatchBlocked =
|
||||
@@ -174,13 +205,28 @@ function buildWorkItems(
|
||||
? "in_progress"
|
||||
: "blocked",
|
||||
surfaceKey: "governance",
|
||||
source: "/api/v1/ai/slo remediation_queue",
|
||||
source: "/api/v1/ai/slo remediation_queue + remediation_history",
|
||||
gateKey: "remediationQueue",
|
||||
evidence: t("evidence.remediationQueue", {
|
||||
total: remediationTotal,
|
||||
ready: remediationReadyForAi,
|
||||
human: remediationNeedsHuman,
|
||||
}),
|
||||
evidenceDetails: latestRemediationHistory
|
||||
? [
|
||||
t("evidence.remediationHistory", {
|
||||
count: remediationHistoryTotal,
|
||||
preview: latestRemediationHistory.verification_result_preview ?? "--",
|
||||
}),
|
||||
t("evidence.remediationRoute", {
|
||||
route: routeLabel(latestRemediationHistory),
|
||||
}),
|
||||
t("evidence.remediationWrites", {
|
||||
incident: String(latestRemediationHistory.writes_incident_state ?? "--"),
|
||||
autoRepair: String(latestRemediationHistory.writes_auto_repair_result ?? "--"),
|
||||
}),
|
||||
]
|
||||
: [t("evidence.remediationHistoryEmpty")],
|
||||
href: "/governance",
|
||||
},
|
||||
{
|
||||
@@ -295,6 +341,7 @@ export default function AwoooPWorkItemsPage() {
|
||||
governanceQueue: null,
|
||||
channelEvents: null,
|
||||
slo: null,
|
||||
remediationHistory: null,
|
||||
});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [lastUpdated, setLastUpdated] = useState<Date | null>(null);
|
||||
@@ -306,16 +353,18 @@ export default function AwoooPWorkItemsPage() {
|
||||
const governanceQueueUrl = `${API_BASE}/api/v1/ai/governance/queue?dispatch_status=pending&size=10`;
|
||||
const channelEventsUrl = `${API_BASE}/api/v1/platform/events/recent?project_id=awoooi&provider_prefix=alertmanager&limit=20`;
|
||||
const sloUrl = `${API_BASE}/api/v1/ai/slo`;
|
||||
const remediationHistoryUrl = `${API_BASE}/api/v1/ai/slo/remediation/history?limit=80`;
|
||||
|
||||
const [quality, governanceEvents, governanceQueue, channelEvents, slo] = await Promise.all([
|
||||
const [quality, governanceEvents, governanceQueue, channelEvents, slo, remediationHistory] = await Promise.all([
|
||||
fetchJson<AutomationQualitySummary>(qualityUrl),
|
||||
fetchJson<GovernanceEventsResponse>(governanceEventsUrl),
|
||||
fetchJson<GovernanceQueueResponse>(governanceQueueUrl),
|
||||
fetchJson<RecentEventsResponse>(channelEventsUrl),
|
||||
fetchJson<SloResponse>(sloUrl),
|
||||
fetchJson<RemediationHistoryResponse>(remediationHistoryUrl),
|
||||
]);
|
||||
|
||||
setTelemetry({ quality, governanceEvents, governanceQueue, channelEvents, slo });
|
||||
setTelemetry({ quality, governanceEvents, governanceQueue, channelEvents, slo, remediationHistory });
|
||||
setLastUpdated(new Date());
|
||||
setLoading(false);
|
||||
}, []);
|
||||
@@ -437,6 +486,18 @@ export default function AwoooPWorkItemsPage() {
|
||||
</td>
|
||||
<td className="min-w-[220px] px-4 py-3 text-sm leading-5 text-[#5f5b52]">
|
||||
{item.evidence}
|
||||
{item.evidenceDetails && item.evidenceDetails.length > 0 && (
|
||||
<div className="mt-2 flex flex-col gap-1">
|
||||
{item.evidenceDetails.map((detail) => (
|
||||
<span
|
||||
key={detail}
|
||||
className="inline-flex w-fit max-w-full border border-[#d8d3c7] bg-[#faf9f3] px-2 py-0.5 font-mono text-[11px] leading-5 text-[#5f5b52]"
|
||||
>
|
||||
{detail}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
<td className="min-w-[240px] px-4 py-3">
|
||||
<span className="inline-flex items-start gap-1.5 text-sm leading-5 text-[#5f5b52]">
|
||||
|
||||
Reference in New Issue
Block a user