feat(governance): 新增 release decision readback
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
Archive,
|
||||
BellOff,
|
||||
BellRing,
|
||||
BookOpenCheck,
|
||||
Boxes,
|
||||
CalendarClock,
|
||||
Database,
|
||||
@@ -86,6 +87,7 @@ import {
|
||||
type AiAgentResultCaptureReleaseAuthorizationHoldSnapshot,
|
||||
type AiAgentResultCaptureReleaseAuthorizationReadbackGateSnapshot,
|
||||
type AiAgentResultCaptureReleaseDecisionHoldSnapshot,
|
||||
type AiAgentResultCaptureReleaseDecisionReadbackSnapshot,
|
||||
type AiAgentResultCaptureReleaseVerifierPreflightGateSnapshot,
|
||||
type AiAgentResultCaptureReleaseVerifierOwnerReviewPacketSnapshot,
|
||||
type AiAgentResultCaptureWriterImplementationReviewSnapshot,
|
||||
@@ -497,6 +499,7 @@ export function AutomationInventoryTab() {
|
||||
const [resultCaptureReleaseVerifierPreflightGate, setResultCaptureReleaseVerifierPreflightGate] = useState<AiAgentResultCaptureReleaseVerifierPreflightGateSnapshot | null>(null)
|
||||
const [resultCaptureReleaseVerifierOwnerReviewPacket, setResultCaptureReleaseVerifierOwnerReviewPacket] = useState<AiAgentResultCaptureReleaseVerifierOwnerReviewPacketSnapshot | null>(null)
|
||||
const [resultCaptureReleaseDecisionHold, setResultCaptureReleaseDecisionHold] = useState<AiAgentResultCaptureReleaseDecisionHoldSnapshot | null>(null)
|
||||
const [resultCaptureReleaseDecisionReadback, setResultCaptureReleaseDecisionReadback] = useState<AiAgentResultCaptureReleaseDecisionReadbackSnapshot | null>(null)
|
||||
const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState<AiAgentReportTruthActionabilityReviewSnapshot | null>(null)
|
||||
const [ownerDryRunPackage, setOwnerDryRunPackage] = useState<AiAgentOwnerApprovedFixtureDryRunSnapshot | null>(null)
|
||||
const [hostStatefulInventory, setHostStatefulInventory] = useState<AiAgentHostStatefulVersionInventorySnapshot | null>(null)
|
||||
@@ -572,6 +575,7 @@ export function AutomationInventoryTab() {
|
||||
apiClient.getAiAgentResultCaptureReleaseVerifierPreflightGate(),
|
||||
apiClient.getAiAgentResultCaptureReleaseVerifierOwnerReviewPacket(),
|
||||
apiClient.getAiAgentResultCaptureReleaseDecisionHold(),
|
||||
apiClient.getAiAgentResultCaptureReleaseDecisionReadback(),
|
||||
apiClient.getAiAgentReportTruthActionabilityReview(),
|
||||
apiClient.getAiAgentOwnerApprovedFixtureDryRun(),
|
||||
apiClient.getAiAgentHostStatefulVersionInventory(),
|
||||
@@ -646,6 +650,7 @@ export function AutomationInventoryTab() {
|
||||
resultCaptureReleaseVerifierPreflightGateResult,
|
||||
resultCaptureReleaseVerifierOwnerReviewPacketResult,
|
||||
resultCaptureReleaseDecisionHoldResult,
|
||||
resultCaptureReleaseDecisionReadbackResult,
|
||||
reportTruthActionabilityReviewResult,
|
||||
ownerDryRunPackageResult,
|
||||
hostStatefulInventoryResult,
|
||||
@@ -717,6 +722,7 @@ export function AutomationInventoryTab() {
|
||||
setResultCaptureReleaseVerifierPreflightGate(resultCaptureReleaseVerifierPreflightGateResult.status === 'fulfilled' ? resultCaptureReleaseVerifierPreflightGateResult.value : null)
|
||||
setResultCaptureReleaseVerifierOwnerReviewPacket(resultCaptureReleaseVerifierOwnerReviewPacketResult.status === 'fulfilled' ? resultCaptureReleaseVerifierOwnerReviewPacketResult.value : null)
|
||||
setResultCaptureReleaseDecisionHold(resultCaptureReleaseDecisionHoldResult.status === 'fulfilled' ? resultCaptureReleaseDecisionHoldResult.value : null)
|
||||
setResultCaptureReleaseDecisionReadback(resultCaptureReleaseDecisionReadbackResult.status === 'fulfilled' ? resultCaptureReleaseDecisionReadbackResult.value : null)
|
||||
setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null)
|
||||
setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null)
|
||||
setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null)
|
||||
@@ -786,6 +792,7 @@ export function AutomationInventoryTab() {
|
||||
resultCaptureReleaseVerifierPreflightGateResult,
|
||||
resultCaptureReleaseVerifierOwnerReviewPacketResult,
|
||||
resultCaptureReleaseDecisionHoldResult,
|
||||
resultCaptureReleaseDecisionReadbackResult,
|
||||
reportTruthActionabilityReviewResult,
|
||||
ownerDryRunPackageResult,
|
||||
hostStatefulInventoryResult,
|
||||
@@ -2028,7 +2035,7 @@ export function AutomationInventoryTab() {
|
||||
)
|
||||
}
|
||||
|
||||
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !resultCaptureOwnerPromotionReview || !resultCaptureOwnerApprovedExecutionRehearsal || !resultCaptureOwnerAcceptanceMaintenanceGate || !resultCaptureOwnerAcceptanceReadbackPreflightHold || !resultCaptureOwnerApprovedPreflightReleasePackage || !resultCaptureOwnerApprovedReleaseReadinessReadback || !resultCaptureOwnerReleaseApprovalGate || !resultCapturePostReleaseVerifierRollbackGate || !resultCaptureFinalReleaseCandidateReadback || !resultCaptureReleaseAuthorizationHold || !resultCaptureReleaseAuthorizationReadbackGate || !resultCaptureReleaseVerifierPreflightGate || !resultCaptureReleaseVerifierOwnerReviewPacket || !resultCaptureReleaseDecisionHold || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !resultCaptureOwnerPromotionReview || !resultCaptureOwnerApprovedExecutionRehearsal || !resultCaptureOwnerAcceptanceMaintenanceGate || !resultCaptureOwnerAcceptanceReadbackPreflightHold || !resultCaptureOwnerApprovedPreflightReleasePackage || !resultCaptureOwnerApprovedReleaseReadinessReadback || !resultCaptureOwnerReleaseApprovalGate || !resultCapturePostReleaseVerifierRollbackGate || !resultCaptureFinalReleaseCandidateReadback || !resultCaptureReleaseAuthorizationHold || !resultCaptureReleaseAuthorizationReadbackGate || !resultCaptureReleaseVerifierPreflightGate || !resultCaptureReleaseVerifierOwnerReviewPacket || !resultCaptureReleaseDecisionHold || !resultCaptureReleaseDecisionReadback || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<GlassCard variant="subtle" padding="lg">
|
||||
@@ -3353,6 +3360,46 @@ export function AutomationInventoryTab() {
|
||||
+ resultCaptureReleaseDecisionHold.rollups.playbook_trust_write_count
|
||||
+ resultCaptureReleaseDecisionHold.rollups.production_write_count
|
||||
)
|
||||
const resultCaptureReleaseDecisionReadbackOverall = resultCaptureReleaseDecisionReadback.program_status.overall_completion_percent
|
||||
const resultCaptureReleaseDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.release_decision_readback_count
|
||||
const resultCaptureReleaseOwnerDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.owner_decision_readback_count
|
||||
const resultCaptureReleaseVerifierDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.verifier_decision_readback_count
|
||||
const resultCaptureReleaseRollbackDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.rollback_decision_readback_count
|
||||
const resultCaptureReleaseMaintenanceDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.maintenance_window_decision_readback_count
|
||||
const resultCaptureReleaseLiveApplyDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.live_apply_decision_readback_count
|
||||
const resultCaptureReleaseDecisionReadbackBlockedTransitions = resultCaptureReleaseDecisionReadback.rollups.blocked_readback_transition_count
|
||||
const resultCaptureReleaseDecisionReadbackActions = resultCaptureReleaseDecisionReadback.rollups.operator_action_count
|
||||
const resultCaptureReleaseDecisionReadbackApprovalRequired = (
|
||||
resultCaptureReleaseDecisionReadback.rollups.approval_required_release_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.approval_required_owner_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.approval_required_verifier_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.approval_required_rollback_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.approval_required_maintenance_window_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.approval_required_live_apply_decision_count
|
||||
)
|
||||
const resultCaptureReleaseDecisionReadbackBlocked = (
|
||||
resultCaptureReleaseDecisionReadback.rollups.blocked_release_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.blocked_owner_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.blocked_verifier_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.blocked_rollback_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.blocked_maintenance_window_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.blocked_live_apply_decision_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.critical_blocker_count
|
||||
)
|
||||
const resultCaptureReleaseDecisionReadbackLiveWrites = (
|
||||
resultCaptureReleaseDecisionReadback.rollups.writer_apply_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.execution_apply_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.receipt_write_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.reviewer_queue_write_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.gateway_queue_write_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.telegram_send_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.bot_api_call_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.report_receipt_write_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.result_capture_write_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.learning_write_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.playbook_trust_write_count
|
||||
+ resultCaptureReleaseDecisionReadback.rollups.production_write_count
|
||||
)
|
||||
const reportTruthOverall = reportTruthActionabilityReview.program_status.overall_completion_percent
|
||||
const reportTruthFindings = reportTruthActionabilityReview.rollups.zero_signal_finding_count
|
||||
const reportTruthCritical = reportTruthActionabilityReview.rollups.critical_finding_count
|
||||
@@ -8087,6 +8134,160 @@ export function AutomationInventoryTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#f8fbff', display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>
|
||||
<BookOpenCheck size={14} style={{ color: '#275e9c' }} />
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
|
||||
{t('resultCaptureReleaseDecisionReadback.title')}
|
||||
</span>
|
||||
</div>
|
||||
<Chip
|
||||
value={t('resultCaptureReleaseDecisionReadback.source', {
|
||||
generated: formatDateTime(resultCaptureReleaseDecisionReadback.generated_at),
|
||||
current: resultCaptureReleaseDecisionReadback.program_status.current_task_id,
|
||||
next: resultCaptureReleaseDecisionReadback.program_status.next_task_id,
|
||||
})}
|
||||
muted
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(128px, 1fr))', gap: 10 }} className="automation-inventory-live-read-kpi-grid">
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.overall')} value={`${resultCaptureReleaseDecisionReadbackOverall}%`} tone="ok" icon={<Gauge size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.releaseReadbacks')} value={resultCaptureReleaseDecisionReadbacks} tone="warn" icon={<BookOpenCheck size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.ownerReadbacks')} value={resultCaptureReleaseOwnerDecisionReadbacks} tone="warn" icon={<ShieldCheck size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.verifierReadbacks')} value={resultCaptureReleaseVerifierDecisionReadbacks} tone="warn" icon={<ShieldAlert size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.rollbackReadbacks')} value={resultCaptureReleaseRollbackDecisionReadbacks} tone="warn" icon={<Undo2 size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.maintenanceReadbacks')} value={resultCaptureReleaseMaintenanceDecisionReadbacks} tone="warn" icon={<CalendarClock size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.liveApplyReadbacks')} value={resultCaptureReleaseLiveApplyDecisionReadbacks} tone="warn" icon={<Lock size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.blockers')} value={resultCaptureReleaseDecisionReadbackBlockedTransitions} tone="danger" icon={<AlertTriangle size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.actions')} value={resultCaptureReleaseDecisionReadbackActions} tone="warn" icon={<Target size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.approvalRequired')} value={resultCaptureReleaseDecisionReadbackApprovalRequired} tone="warn" icon={<ShieldAlert size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.blocked')} value={resultCaptureReleaseDecisionReadbackBlocked} tone="danger" icon={<ShieldAlert size={16} />} />
|
||||
<MetricCard label={t('resultCaptureReleaseDecisionReadback.metrics.liveWrites')} value={resultCaptureReleaseDecisionReadbackLiveWrites} tone={resultCaptureReleaseDecisionReadbackLiveWrites === 0 ? 'ok' : 'danger'} icon={<BellOff size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 10 }}>
|
||||
<div style={{ padding: 10, border: '0.5px solid #d7c7a1', borderRadius: 7, background: '#fff', minWidth: 0 }}>
|
||||
<SmallLabel>{t('resultCaptureReleaseDecisionReadback.priorTitle')}</SmallLabel>
|
||||
<p style={{ margin: '6px 0 8px', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.5, color: '#5c5a55', overflowWrap: 'anywhere' }}>
|
||||
{resultCaptureReleaseDecisionReadback.prior_release_decision_hold.readiness_note}
|
||||
</p>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={resultCaptureReleaseDecisionReadback.prior_release_decision_hold.schema_version} />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.metrics.releaseReadbacks') + ` ${resultCaptureReleaseDecisionReadbacks}`} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.metrics.liveWrites') + ` ${resultCaptureReleaseDecisionReadback.prior_release_decision_hold.result_capture_write_count}`} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 10, border: '0.5px solid #d7c7a1', borderRadius: 7, background: '#fff', minWidth: 0 }}>
|
||||
<SmallLabel>{t('resultCaptureReleaseDecisionReadback.truthTitle')}</SmallLabel>
|
||||
<p style={{ margin: '6px 0 8px', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.5, color: '#5c5a55', overflowWrap: 'anywhere' }}>
|
||||
{resultCaptureReleaseDecisionReadback.release_decision_readback_truth.truth_note}
|
||||
</p>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.flags.p2Loaded', { value: String(resultCaptureReleaseDecisionReadback.release_decision_readback_truth.p2_138_release_decision_hold_loaded) })} />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.flags.readbackReady', { value: String(resultCaptureReleaseDecisionReadback.release_decision_readback_truth.release_decision_readback_ready) })} />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.flags.maintenanceStillRequired', { value: String(resultCaptureReleaseDecisionReadback.release_decision_readback_truth.maintenance_window_decision_still_required) })} />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.flags.liveApplyStillRequired', { value: String(resultCaptureReleaseDecisionReadback.release_decision_readback_truth.live_apply_decision_still_required) })} />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.ownerReleaseAuthorized', { value: String(resultCaptureReleaseDecisionReadback.rollups.owner_release_authorized_count) })} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.decisionPassed', { value: String(resultCaptureReleaseDecisionReadback.rollups.release_decision_pass_count) })} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.gatewayWrites', { value: String(resultCaptureReleaseDecisionReadback.rollups.gateway_queue_write_count) })} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.telegramSends', { value: String(resultCaptureReleaseDecisionReadback.rollups.telegram_send_count) })} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.productionWrites', { value: String(resultCaptureReleaseDecisionReadback.rollups.production_write_count) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{resultCaptureReleaseDecisionReadback.release_decision_readbacks.slice(0, 5).map(readback => (
|
||||
<div key={readback.readback_id} style={{ padding: 10, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{readback.display_name}
|
||||
</span>
|
||||
<Chip value={readback.readback_status} muted={readback.readback_status === 'readback_complete'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{readback.readback_summary}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', readback.owner_agent)} muted />
|
||||
<Chip value={readback.readback_mode} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.decisionPassed', { value: String(readback.release_decision_passed) })} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.authorizationGranted', { value: String(readback.release_authorization_granted) })} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.telegramSendAllowed', { value: String(readback.telegram_send_allowed) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{[
|
||||
...resultCaptureReleaseDecisionReadback.owner_decision_readbacks.slice(0, 2),
|
||||
...resultCaptureReleaseDecisionReadback.verifier_decision_readbacks.slice(0, 2),
|
||||
...resultCaptureReleaseDecisionReadback.rollback_decision_readbacks.slice(0, 2),
|
||||
...resultCaptureReleaseDecisionReadback.maintenance_window_decision_readbacks.slice(0, 2),
|
||||
...resultCaptureReleaseDecisionReadback.live_apply_decision_readbacks.slice(0, 2),
|
||||
].map(readback => (
|
||||
<div key={readback.readback_id} style={{ padding: 10, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{readback.display_name}
|
||||
</span>
|
||||
<Chip value={readback.readback_status} muted={readback.readback_status === 'readback_complete'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{readback.readback_summary}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', readback.owner_agent)} muted />
|
||||
<Chip value={readback.readback_mode} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.runtimeWriteAllowed', { value: String(readback.runtime_write_allowed) })} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.telegramSendAllowed', { value: String(readback.telegram_send_allowed) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{resultCaptureReleaseDecisionReadback.blocked_readback_transitions.slice(0, 6).map(transition => (
|
||||
<div key={transition.transition_id} style={{ padding: 10, border: '0.5px solid #e0b4a3', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{transition.transition_id}
|
||||
</span>
|
||||
<Chip value={transition.status} muted />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{transition.reason}
|
||||
</span>
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.runtimeWriteAllowed', { value: String(transition.runtime_write_allowed) })} muted />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{resultCaptureReleaseDecisionReadback.operator_actions.slice(0, 5).map(action => (
|
||||
<div key={action.action_id} style={{ padding: 10, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{action.action_id}
|
||||
</span>
|
||||
<Chip value={action.status} muted={action.status === 'ready_for_operator_review'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{action.operator_instruction}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', action.owner_agent)} muted />
|
||||
<Chip value={t('resultCaptureReleaseDecisionReadback.labels.runtimeWriteAllowed', { value: String(action.runtime_write_allowed) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#f8fbff', display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>
|
||||
|
||||
Reference in New Issue
Block a user