feat(awooop): show callback evidence capture status
This commit is contained in:
@@ -53,6 +53,11 @@ type CallbackReplyStatus =
|
||||
| "rescue_sent"
|
||||
| "failed"
|
||||
| "observed";
|
||||
type CallbackEvidenceCaptureState =
|
||||
| "captured"
|
||||
| "partial"
|
||||
| "not_captured"
|
||||
| "observed";
|
||||
type RemediationStatus =
|
||||
| "no_evidence"
|
||||
| "mcp_observed"
|
||||
@@ -114,6 +119,18 @@ interface CallbackReplySummary {
|
||||
latest_provider_message_id?: string | null;
|
||||
}
|
||||
|
||||
interface CallbackEvidenceCaptureStatus {
|
||||
schema_version?: string;
|
||||
status?: CallbackEvidenceCaptureState | string | null;
|
||||
reason?: string | null;
|
||||
action?: string | null;
|
||||
captured?: string[];
|
||||
missing?: string[];
|
||||
snapshot_rollout?: string | null;
|
||||
next_action?: string | null;
|
||||
event_at?: string | null;
|
||||
}
|
||||
|
||||
interface Run {
|
||||
run_id: string;
|
||||
project_id: string;
|
||||
@@ -373,6 +390,7 @@ interface CallbackReplyEvent {
|
||||
persisted_awooop_status_chain?: AwoooPStatusChain | null;
|
||||
km_stale_completion_summary?: KmStaleCompletionSummary | null;
|
||||
persisted_km_stale_completion_summary?: KmStaleCompletionSummary | null;
|
||||
evidence_capture_status?: CallbackEvidenceCaptureStatus | null;
|
||||
}
|
||||
|
||||
interface CallbackRepliesResponse {
|
||||
@@ -732,6 +750,19 @@ function normalizeCallbackReplyEventStatus(statusValue?: string | null): Callbac
|
||||
return "observed";
|
||||
}
|
||||
|
||||
function normalizeCallbackEvidenceCaptureStatus(
|
||||
statusValue?: string | null
|
||||
): CallbackEvidenceCaptureState {
|
||||
if (
|
||||
statusValue === "captured" ||
|
||||
statusValue === "partial" ||
|
||||
statusValue === "not_captured"
|
||||
) {
|
||||
return statusValue;
|
||||
}
|
||||
return "observed";
|
||||
}
|
||||
|
||||
function normalizeKmCompletionStatus(statusValue?: string | null) {
|
||||
if (
|
||||
statusValue === "matched_owner_review" ||
|
||||
@@ -744,6 +775,90 @@ function normalizeKmCompletionStatus(statusValue?: string | null) {
|
||||
return "observed";
|
||||
}
|
||||
|
||||
function CallbackEvidenceCaptureStatusPanel({
|
||||
captureStatus,
|
||||
}: {
|
||||
captureStatus?: CallbackEvidenceCaptureStatus | null;
|
||||
}) {
|
||||
const t = useTranslations("awooop.callbackReply.events.capture");
|
||||
if (!captureStatus) return null;
|
||||
|
||||
const state = normalizeCallbackEvidenceCaptureStatus(captureStatus.status);
|
||||
const config = {
|
||||
captured: {
|
||||
className: "border-[#8ec58e] bg-[#edf8ed] text-[#17602a]",
|
||||
icon: ShieldCheck,
|
||||
},
|
||||
partial: {
|
||||
className: "border-[#e1c36a] bg-[#fff7df] text-[#8a5a08]",
|
||||
icon: AlertCircle,
|
||||
},
|
||||
not_captured: {
|
||||
className: "border-[#d8d3c7] bg-[#faf9f3] text-[#5f5b52]",
|
||||
icon: BellOff,
|
||||
},
|
||||
observed: {
|
||||
className: "border-[#9bb6d9] bg-[#eef5ff] text-[#1f5b9b]",
|
||||
icon: SearchCheck,
|
||||
},
|
||||
}[state];
|
||||
const Icon = config.icon;
|
||||
const itemLabels: Record<string, string> = {
|
||||
awooop_status_chain: t("items.awooopStatusChain"),
|
||||
km_stale_completion_summary: t("items.kmCompletionSummary"),
|
||||
};
|
||||
const formatItems = (items?: string[]) => (
|
||||
items && items.length > 0
|
||||
? items.map((item) => itemLabels[item] ?? item).join(" / ")
|
||||
: t("none")
|
||||
);
|
||||
const nextActionRaw = captureStatus.next_action ?? "observed";
|
||||
const nextActionKey = nextActionRaw === "none"
|
||||
|| nextActionRaw === "press_telegram_detail_or_history_after_rollout"
|
||||
? nextActionRaw
|
||||
: "observed";
|
||||
|
||||
return (
|
||||
<div className="mt-3 border-t border-[#e0ddd4] pt-3">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Icon className="h-3.5 w-3.5 text-[#1f5b9b]" aria-hidden="true" />
|
||||
<p className="text-xs font-semibold text-[#141413]">{t("title")}</p>
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex items-center border px-2 py-0.5 text-xs font-semibold",
|
||||
config.className
|
||||
)}
|
||||
>
|
||||
{t(`statuses.${state}` as never)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-2 grid gap-1 text-xs leading-5 text-[#5f5b52]">
|
||||
<p>
|
||||
{t("captured", {
|
||||
items: formatItems(captureStatus.captured),
|
||||
})}
|
||||
</p>
|
||||
<p>
|
||||
{t("missing", {
|
||||
items: formatItems(captureStatus.missing),
|
||||
})}
|
||||
</p>
|
||||
<p>
|
||||
{t("nextAction", {
|
||||
action: t(`nextActions.${nextActionKey}` as never),
|
||||
})}
|
||||
</p>
|
||||
<p className="truncate font-mono text-[#77736a]">
|
||||
{t("reason", {
|
||||
reason: captureStatus.reason ?? "--",
|
||||
rollout: captureStatus.snapshot_rollout ?? "--",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RemediationEvidenceCell({ summary }: { summary?: RemediationSummary | null }) {
|
||||
const t = useTranslations("awooop.listEvidence");
|
||||
const status = normalizeRemediationStatus(summary);
|
||||
@@ -1796,6 +1911,9 @@ function CallbackReplyEvidencePanel({
|
||||
compact
|
||||
className="mt-3"
|
||||
/>
|
||||
<CallbackEvidenceCaptureStatusPanel
|
||||
captureStatus={event.evidence_capture_status}
|
||||
/>
|
||||
<CallbackAwoooPStatusChainSnapshot
|
||||
chain={event.persisted_awooop_status_chain}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user