feat(awooop): expose execution evidence on incidents
This commit is contained in:
@@ -432,6 +432,10 @@
|
||||
"flowEvidenceKm": "KM {count}",
|
||||
"flowEvidenceRepair": "Repair {count}",
|
||||
"flowMcpDetail": "MCP detail: Gateway success {success} / failed {failed} / blocked {blocked}; first-class {firstClass}; legacy {legacy}; tools {tools}",
|
||||
"flowExecutionDetail": "Execution detail: Executor {executor}; Operation {operation} / {status}; Ansible {ansible}; PlayBook {playbook}",
|
||||
"flowExecutionAnsibleConsidered": "considered ({records} records / {candidates} candidates)",
|
||||
"flowExecutionAnsibleNotUsed": "not used: {reason}",
|
||||
"flowExecutionAnsibleEmpty": "--",
|
||||
"flowTruthChainCurrent": "{stage} / {status}",
|
||||
"flowComplete": "Complete",
|
||||
"flowStages": {
|
||||
|
||||
@@ -433,6 +433,10 @@
|
||||
"flowEvidenceKm": "KM {count}",
|
||||
"flowEvidenceRepair": "修復 {count}",
|
||||
"flowMcpDetail": "MCP 明細:Gateway 成功 {success} / 失敗 {failed} / 阻擋 {blocked};一級治理 {firstClass};Legacy {legacy};工具 {tools}",
|
||||
"flowExecutionDetail": "執行明細:Executor {executor};Operation {operation} / {status};Ansible {ansible};PlayBook {playbook}",
|
||||
"flowExecutionAnsibleConsidered": "已納入 ({records} records / {candidates} candidates)",
|
||||
"flowExecutionAnsibleNotUsed": "未使用:{reason}",
|
||||
"flowExecutionAnsibleEmpty": "--",
|
||||
"flowTruthChainCurrent": "{stage} / {status}",
|
||||
"flowComplete": "已完成",
|
||||
"flowStages": {
|
||||
|
||||
@@ -62,6 +62,32 @@ export interface AwoooPStatusChain {
|
||||
last_error?: string | null;
|
||||
}>;
|
||||
};
|
||||
execution?: {
|
||||
operation_total?: number | null;
|
||||
latest_operation_type?: string | null;
|
||||
latest_status?: string | null;
|
||||
latest_actor?: string | null;
|
||||
latest_action?: string | null;
|
||||
latest_executor?: string | null;
|
||||
playbook_ids?: string[];
|
||||
playbook_paths?: string[];
|
||||
ansible?: {
|
||||
considered?: boolean | null;
|
||||
record_total?: number | null;
|
||||
candidate_count?: number | null;
|
||||
not_used_reason?: string | null;
|
||||
latest_operation_type?: string | null;
|
||||
latest_status?: string | null;
|
||||
latest_playbook_path?: string | null;
|
||||
latest_check_mode?: string | null | boolean;
|
||||
candidate_playbooks?: Array<{
|
||||
catalog_id?: string | null;
|
||||
playbook_path?: string | null;
|
||||
risk_level?: string | null;
|
||||
match_score?: number | null;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function toneClass(chain?: AwoooPStatusChain | null) {
|
||||
|
||||
@@ -137,6 +137,11 @@ function chainValue(value: string | null | undefined, fallback = '--'): string {
|
||||
return normalized || fallback
|
||||
}
|
||||
|
||||
function compactChainPath(value: string | null | undefined, fallback = '--'): string {
|
||||
const normalized = chainValue(value, fallback)
|
||||
return normalized.replace(/^infra\/ansible\/playbooks\//, '')
|
||||
}
|
||||
|
||||
/** 格式化持續時間 */
|
||||
function formatDuration(createdAt: string | undefined): string {
|
||||
if (!createdAt) return '--'
|
||||
@@ -351,6 +356,30 @@ export function IncidentCard({ incident, decision, statusChain, onApprovalChange
|
||||
tools: mcpTopTools || '--',
|
||||
})
|
||||
: null
|
||||
const execution = statusChain?.execution
|
||||
const ansible = execution?.ansible
|
||||
const ansibleSummary = ansible?.considered
|
||||
? t('flowExecutionAnsibleConsidered', {
|
||||
records: ansible.record_total ?? 0,
|
||||
candidates: ansible.candidate_count ?? 0,
|
||||
})
|
||||
: ansible?.not_used_reason
|
||||
? t('flowExecutionAnsibleNotUsed', { reason: String(ansible.not_used_reason).slice(0, 96) })
|
||||
: t('flowExecutionAnsibleEmpty')
|
||||
const executionPlaybook = compactChainPath(
|
||||
execution?.playbook_paths?.[0]
|
||||
?? execution?.playbook_ids?.[0]
|
||||
?? ansible?.candidate_playbooks?.[0]?.playbook_path
|
||||
)
|
||||
const statusChainExecutionDetail = hasTruthChain
|
||||
? t('flowExecutionDetail', {
|
||||
executor: chainValue(execution?.latest_executor),
|
||||
operation: chainValue(execution?.latest_operation_type),
|
||||
status: chainValue(execution?.latest_status),
|
||||
ansible: ansibleSummary,
|
||||
playbook: executionPlaybook,
|
||||
})
|
||||
: null
|
||||
|
||||
const serviceName = incident.affected_services?.[0] ?? '--'
|
||||
const duration = formatDuration(incident.created_at)
|
||||
@@ -626,6 +655,10 @@ export function IncidentCard({ incident, decision, statusChain, onApprovalChange
|
||||
<span data-testid="incident-mcp-evidence" style={{ color: '#555550' }}>
|
||||
{statusChainMcpDetail}
|
||||
</span>
|
||||
<span style={{ color: '#b0ad9f' }}>/</span>
|
||||
<span data-testid="incident-execution-evidence" style={{ color: '#555550' }}>
|
||||
{statusChainExecutionDetail}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user