feat(web): split Runs dry-run and apply ledger
Some checks failed
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / tests (push) Successful in 1m35s
CD Pipeline / build-and-deploy (push) Successful in 5m28s
CD Pipeline / post-deploy-checks (push) Successful in 1m35s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-25 21:10:22 +08:00
parent 24ad757844
commit b297b013ac
7 changed files with 100 additions and 16 deletions

View File

@@ -22,6 +22,10 @@ function countLabel(value: number) {
return value > 0 ? String(value) : "--";
}
function valueLabel(value: number, fallback: string) {
return value > 0 ? String(value) : fallback;
}
export function AwoooPAutomationAssetLedger({
chain,
remediationSummary,
@@ -36,9 +40,16 @@ export function AwoooPAutomationAssetLedger({
const playbookCount = (chain?.execution?.playbook_ids?.length ?? 0)
+ (chain?.execution?.playbook_paths?.length ?? 0);
const ansible = chain?.execution?.ansible;
const scriptCount = (ansible?.candidate_count ?? 0)
+ (ansible?.check_mode_total ?? 0)
+ (ansible?.apply_total ?? 0);
const ansibleCandidates = ansible?.candidate_count ?? 0;
const dryRunCount = (ansible?.check_mode_total ?? 0) + (ansible?.pending_check_mode_total ?? 0);
const applyCount = ansible?.apply_total ?? 0;
const ansibleDryRunOnly = Boolean(chain?.evidence?.ansible_dry_run_only)
|| (
dryRunCount > 0
&& applyCount === 0
&& ansible?.applied !== true
&& ansible?.controlled_apply !== true
);
const correlation = chain?.source_refs?.correlation;
const scheduleCount = (correlation?.provider_event_total ?? 0)
+ (correlation?.direct_ref_total ?? 0)
@@ -64,13 +75,24 @@ export function AwoooPAutomationAssetLedger({
value: countLabel(playbookCount),
},
{
key: "script",
tone: scriptCount > 0
key: "dryRun",
tone: dryRunCount > 0
? "ready"
: remediationSummary?.has_mcp_investigation || (chain?.mcp?.gateway?.total ?? 0) > 0
: ansibleCandidates > 0
? "pending"
: "blocked",
value: countLabel(scriptCount),
value: valueLabel(dryRunCount, ansibleCandidates > 0 ? t("values.pending") : "--"),
},
{
key: "apply",
tone: applyCount > 0 || ansible?.applied === true
? "ready"
: ansibleDryRunOnly || chain?.needs_human
? "blocked"
: dryRunCount > 0 || ansibleCandidates > 0
? "pending"
: "blocked",
value: applyCount > 0 ? String(applyCount) : ansible?.applied === true ? t("values.ready") : t("values.notApplied"),
},
{
key: "schedule",
@@ -79,8 +101,8 @@ export function AwoooPAutomationAssetLedger({
},
{
key: "verifier",
tone: verifierReady ? "ready" : verifierBlocked ? "blocked" : "pending",
value: verifierReady ? t("values.ready") : verifierBlocked ? t("values.blocked") : t("values.pending"),
tone: verifierReady ? "ready" : verifierBlocked || ansibleDryRunOnly ? "blocked" : "pending",
value: verifierReady ? t("values.ready") : verifierBlocked || ansibleDryRunOnly ? t("values.blocked") : t("values.pending"),
},
] satisfies Array<{ key: string; tone: AutomationAssetTone; value: string }>;
const readyCount = items.filter((item) => item.tone === "ready").length;

View File

@@ -55,6 +55,7 @@ export interface AwoooPStatusChain {
latest_mode?: string | null;
latest_at?: string | null;
latest_preview?: string | null;
ansible_dry_run_only?: boolean | null;
};
writes?: {
incident?: boolean | null;