feat(awooop): expose execution evidence on incidents
This commit is contained in:
@@ -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