fix(web): avoid ai loop zero-state readback flash
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
This commit is contained in:
@@ -11578,8 +11578,10 @@
|
||||
"title": "AI Controlled Execution Loop",
|
||||
"refresh": "Refresh",
|
||||
"completion": "{percent}% complete",
|
||||
"completionLoading": "Completion reading",
|
||||
"detail": "Incident {incident} / op {op} / {catalog}",
|
||||
"states": {
|
||||
"loading": "Reading production readback",
|
||||
"closed": "Loop closed",
|
||||
"open": "Loop open",
|
||||
"degraded": "Read degraded",
|
||||
|
||||
@@ -11578,8 +11578,10 @@
|
||||
"title": "AI 受控執行閉環",
|
||||
"refresh": "重新整理",
|
||||
"completion": "完成 {percent}%",
|
||||
"completionLoading": "完成度讀取中",
|
||||
"detail": "Incident {incident} / op {op} / {catalog}",
|
||||
"states": {
|
||||
"loading": "讀取正式 readback",
|
||||
"closed": "閉環完成",
|
||||
"open": "閉環中",
|
||||
"degraded": "讀取降級",
|
||||
|
||||
@@ -275,6 +275,16 @@ function toNumber(value: unknown): number {
|
||||
return Number.isFinite(numeric) ? numeric : 0;
|
||||
}
|
||||
|
||||
function readbackNumber(value: unknown, ready: boolean): string {
|
||||
if (!ready) return "--";
|
||||
return numberValue(value);
|
||||
}
|
||||
|
||||
function readbackRatio(done: unknown, total: unknown, ready: boolean): string {
|
||||
if (!ready) return "-- / --";
|
||||
return `${numberValue(done)} / ${numberValue(total)}`;
|
||||
}
|
||||
|
||||
function shortRef(value?: string | null): string {
|
||||
if (!value) return "--";
|
||||
return value.length > 12 ? `${value.slice(0, 8)}...` : value;
|
||||
@@ -397,6 +407,9 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
return () => window.clearInterval(timer);
|
||||
}, [refresh]);
|
||||
|
||||
const hasRuntimeReadback = payload !== null;
|
||||
const hasPriorityReadback = priorityPayload !== null;
|
||||
const hasConsumerReadback = consumerPayload !== null;
|
||||
const readback = payload?.runtime_receipt_readback;
|
||||
const ledger = readback?.autonomous_execution_loop_ledger;
|
||||
const traceLedger = readback?.trace_ledger;
|
||||
@@ -428,8 +441,11 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
?? ledger?.missing_stage_ids
|
||||
?? latestFlow?.missing
|
||||
?? [];
|
||||
const tone: Tone = error || !dbOk ? "warn" : closed ? "ok" : "neutral";
|
||||
const stateLabel = closed
|
||||
const initialRuntimeReadInFlight = loading && !hasRuntimeReadback && !error;
|
||||
const tone: Tone = initialRuntimeReadInFlight ? "neutral" : error || !dbOk ? "warn" : closed ? "ok" : "neutral";
|
||||
const stateLabel = initialRuntimeReadInFlight
|
||||
? t("states.loading")
|
||||
: closed
|
||||
? t("states.closed")
|
||||
: error
|
||||
? t("states.unavailable")
|
||||
@@ -633,102 +649,136 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
const deployedSourceShortSha = prioritySummary?.latest_successful_deployed_source_short_sha
|
||||
?? (deployedSourceSha ? deployedSourceSha.slice(0, 10) : null);
|
||||
const deployReadbackResolved = prioritySummary?.ai_loop_current_blocker_deploy_marker_resolved_by_production_readback === true;
|
||||
const deployCardTone: Tone = !hasPriorityReadback ? "neutral" : deployReadbackResolved ? "ok" : "warn";
|
||||
const runtimeCardTone: Tone = !hasRuntimeReadback ? "neutral" : dbOk ? "ok" : "warn";
|
||||
const workCardTone: Tone = !hasRuntimeReadback ? "neutral" : workTotal > 0 && workCompleted === workTotal ? "ok" : "warn";
|
||||
const sourceCardTone: Tone = !hasRuntimeReadback
|
||||
? "neutral"
|
||||
: toNumber(rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count) > 0
|
||||
? "ok"
|
||||
: "warn";
|
||||
const eventCardTone: Tone = !hasRuntimeReadback
|
||||
? "neutral"
|
||||
: toNumber(rollups.live_log_classified_event_total ?? logRollups.classified_event_total) > 0
|
||||
? "ok"
|
||||
: "neutral";
|
||||
const consumerCardTone: Tone = !hasConsumerReadback ? "neutral" : consumerReady ? "ok" : "warn";
|
||||
const proofCards = [
|
||||
{
|
||||
key: "deploy",
|
||||
label: t("proof.deploy"),
|
||||
value: deployedSourceShortSha ?? "--",
|
||||
detail: t("proof.deployDetail", {
|
||||
status: mainlineState?.current_main_cd_run_status ?? priorityPayload?.status ?? "--",
|
||||
status: hasPriorityReadback
|
||||
? mainlineState?.current_main_cd_run_status ?? priorityPayload?.status ?? "--"
|
||||
: t("states.loading"),
|
||||
}),
|
||||
icon: Rocket,
|
||||
tone: deployReadbackResolved ? "ok" as Tone : "warn" as Tone,
|
||||
tone: deployCardTone,
|
||||
},
|
||||
{
|
||||
key: "runtime",
|
||||
label: t("proof.runtime"),
|
||||
value: dbOk ? t("proof.ok") : t("proof.degraded"),
|
||||
value: !hasRuntimeReadback ? t("states.loading") : dbOk ? t("proof.ok") : t("proof.degraded"),
|
||||
detail: t("proof.runtimeDetail", {
|
||||
marker: shortRef(payload?.program_status?.deploy_readback_marker),
|
||||
}),
|
||||
icon: Database,
|
||||
tone: dbOk ? "ok" as Tone : "warn" as Tone,
|
||||
tone: runtimeCardTone,
|
||||
},
|
||||
{
|
||||
key: "work",
|
||||
label: t("proof.workItems"),
|
||||
value: `${numberValue(workCompleted)}/${numberValue(workTotal)}`,
|
||||
value: readbackRatio(workCompleted, workTotal, hasRuntimeReadback),
|
||||
detail: t("proof.workItemsDetail", {
|
||||
percent: numberValue(workCompletionPercent),
|
||||
percent: readbackNumber(workCompletionPercent, hasRuntimeReadback),
|
||||
}),
|
||||
icon: ListChecks,
|
||||
tone: workTotal > 0 && workCompleted === workTotal ? "ok" as Tone : "warn" as Tone,
|
||||
tone: workCardTone,
|
||||
},
|
||||
{
|
||||
key: "sources",
|
||||
label: t("proof.sources"),
|
||||
value: `${numberValue(rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count)}/${numberValue(rollups.live_log_source_family_count ?? logRollups.source_family_count)}`,
|
||||
value: readbackRatio(
|
||||
rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count,
|
||||
rollups.live_log_source_family_count ?? logRollups.source_family_count,
|
||||
hasRuntimeReadback
|
||||
),
|
||||
detail: t("proof.sourcesDetail"),
|
||||
icon: Bot,
|
||||
tone: toNumber(rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count) > 0 ? "ok" as Tone : "warn" as Tone,
|
||||
tone: sourceCardTone,
|
||||
},
|
||||
{
|
||||
key: "events",
|
||||
label: t("proof.events"),
|
||||
value: numberValue(rollups.live_log_classified_event_total ?? logRollups.classified_event_total),
|
||||
value: readbackNumber(
|
||||
rollups.live_log_classified_event_total ?? logRollups.classified_event_total,
|
||||
hasRuntimeReadback
|
||||
),
|
||||
detail: t("proof.eventsDetail", {
|
||||
recent: numberValue(rollups.live_log_recent_classified_event_total ?? logRollups.recent_classified_event_total),
|
||||
recent: readbackNumber(
|
||||
rollups.live_log_recent_classified_event_total ?? logRollups.recent_classified_event_total,
|
||||
hasRuntimeReadback
|
||||
),
|
||||
}),
|
||||
icon: Activity,
|
||||
tone: toNumber(rollups.live_log_classified_event_total ?? logRollups.classified_event_total) > 0 ? "ok" as Tone : "neutral" as Tone,
|
||||
tone: eventCardTone,
|
||||
},
|
||||
{
|
||||
key: "consumer",
|
||||
label: t("proof.consumer"),
|
||||
value: `${numberValue(
|
||||
value: readbackRatio(
|
||||
rollups.live_log_controlled_writeback_consumer_apply_receipt_count
|
||||
?? consumerRollups.consumer_apply_receipt_row_count
|
||||
)}/${numberValue(
|
||||
?? consumerRollups.consumer_apply_receipt_row_count,
|
||||
rollups.live_log_controlled_writeback_consumer_dispatch_ledger_count
|
||||
?? consumerRollups.dispatch_ledger_row_count
|
||||
)}`,
|
||||
?? consumerRollups.dispatch_ledger_row_count,
|
||||
hasConsumerReadback || hasRuntimeReadback
|
||||
),
|
||||
detail: t("proof.consumerDetail", {
|
||||
targets: numberValue(consumerRollups.ready_target_count),
|
||||
targets: readbackNumber(consumerRollups.ready_target_count, hasConsumerReadback),
|
||||
}),
|
||||
icon: Database,
|
||||
tone: consumerReady ? "ok" as Tone : "warn" as Tone,
|
||||
tone: consumerCardTone,
|
||||
},
|
||||
];
|
||||
const writebackCards = [
|
||||
{
|
||||
key: "dispatch",
|
||||
label: t("writeback.dispatch"),
|
||||
value: numberValue(
|
||||
value: readbackNumber(
|
||||
rollups.live_log_controlled_writeback_consumer_dispatch_ledger_count
|
||||
?? consumerRollups.dispatch_ledger_row_count
|
||||
?? consumerRollups.dispatch_ledger_row_count,
|
||||
hasConsumerReadback || hasRuntimeReadback
|
||||
),
|
||||
detail: t("writeback.dispatchDetail"),
|
||||
icon: Send,
|
||||
tone: consumerReady ? "ok" as Tone : "warn" as Tone,
|
||||
tone: consumerCardTone,
|
||||
},
|
||||
{
|
||||
key: "apply",
|
||||
label: t("writeback.apply"),
|
||||
value: numberValue(
|
||||
value: readbackNumber(
|
||||
rollups.live_log_controlled_writeback_consumer_apply_receipt_count
|
||||
?? consumerRollups.consumer_apply_receipt_row_count
|
||||
?? consumerRollups.consumer_apply_receipt_row_count,
|
||||
hasConsumerReadback || hasRuntimeReadback
|
||||
),
|
||||
detail: t("writeback.applyDetail"),
|
||||
icon: CheckCircle2,
|
||||
tone: runtimeTargetWritePerformed ? "ok" as Tone : "neutral" as Tone,
|
||||
tone: !hasConsumerReadback && !hasRuntimeReadback ? "neutral" as Tone : runtimeTargetWritePerformed ? "ok" as Tone : "neutral" as Tone,
|
||||
},
|
||||
{
|
||||
key: "bindings",
|
||||
label: t("writeback.bindings"),
|
||||
value: `${numberValue(consumerRollups.ready_consumer_binding_count)}/${numberValue(consumerRollups.consumer_binding_count)}`,
|
||||
value: readbackRatio(
|
||||
consumerRollups.ready_consumer_binding_count,
|
||||
consumerRollups.consumer_binding_count,
|
||||
hasConsumerReadback
|
||||
),
|
||||
detail: t("writeback.bindingsDetail"),
|
||||
icon: Bot,
|
||||
tone: toNumber(consumerRollups.ready_consumer_binding_count) === toNumber(consumerRollups.consumer_binding_count)
|
||||
tone: !hasConsumerReadback
|
||||
? "neutral" as Tone
|
||||
: toNumber(consumerRollups.ready_consumer_binding_count) === toNumber(consumerRollups.consumer_binding_count)
|
||||
&& toNumber(consumerRollups.consumer_binding_count) > 0
|
||||
? "ok" as Tone
|
||||
: "warn" as Tone,
|
||||
@@ -736,26 +786,34 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
{
|
||||
key: "targets",
|
||||
label: t("writeback.targets"),
|
||||
value: numberValue(consumerRollups.ready_target_count),
|
||||
value: readbackNumber(consumerRollups.ready_target_count, hasConsumerReadback),
|
||||
detail: t("writeback.targetsDetail"),
|
||||
icon: ListChecks,
|
||||
tone: toNumber(consumerRollups.ready_target_count) >= 6 ? "ok" as Tone : "warn" as Tone,
|
||||
tone: !hasConsumerReadback
|
||||
? "neutral" as Tone
|
||||
: toNumber(consumerRollups.ready_target_count) >= 6 ? "ok" as Tone : "warn" as Tone,
|
||||
},
|
||||
{
|
||||
key: "context",
|
||||
label: t("writeback.contextWrites"),
|
||||
value: numberValue(consumerRollups.target_context_receipt_write_count),
|
||||
value: readbackNumber(consumerRollups.target_context_receipt_write_count, hasConsumerReadback),
|
||||
detail: t("writeback.contextWritesDetail"),
|
||||
icon: BookOpenCheck,
|
||||
tone: runtimeTargetWritePerformed ? "ok" as Tone : "neutral" as Tone,
|
||||
tone: !hasConsumerReadback
|
||||
? "neutral" as Tone
|
||||
: runtimeTargetWritePerformed ? "ok" as Tone : "neutral" as Tone,
|
||||
},
|
||||
{
|
||||
key: "blockers",
|
||||
label: t("writeback.blockers"),
|
||||
value: numberValue(consumerBlockers.length),
|
||||
detail: consumerBlockers.length > 0 ? consumerBlockers[0] : t("writeback.noBlockers"),
|
||||
value: readbackNumber(consumerBlockers.length, hasConsumerReadback),
|
||||
detail: !hasConsumerReadback
|
||||
? t("states.loading")
|
||||
: consumerBlockers.length > 0 ? consumerBlockers[0] : t("writeback.noBlockers"),
|
||||
icon: TriangleAlert,
|
||||
tone: consumerBlockers.length > 0 ? "warn" as Tone : "ok" as Tone,
|
||||
tone: !hasConsumerReadback
|
||||
? "neutral" as Tone
|
||||
: consumerBlockers.length > 0 ? "warn" as Tone : "ok" as Tone,
|
||||
},
|
||||
];
|
||||
const targetWritebackCards = [
|
||||
@@ -835,9 +893,11 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
{stateLabel}
|
||||
</span>
|
||||
<span className="font-mono text-xs text-[#77736a]">
|
||||
{t("completion", {
|
||||
percent: numberValue(payload?.program_status?.implementation_completion_percent ?? 0),
|
||||
})}
|
||||
{hasRuntimeReadback
|
||||
? t("completion", {
|
||||
percent: numberValue(payload?.program_status?.implementation_completion_percent ?? 0),
|
||||
})
|
||||
: t("completionLoading")}
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
||||
@@ -931,9 +991,9 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-[#77736a]">{card.label}</p>
|
||||
<p className="mt-2 font-mono text-lg font-semibold text-[#141413]">
|
||||
{numberValue(writeCount)}
|
||||
{readbackNumber(writeCount, hasConsumerReadback)}
|
||||
{" / "}
|
||||
{numberValue(bindingCount)}
|
||||
{readbackNumber(bindingCount, hasConsumerReadback)}
|
||||
</p>
|
||||
</div>
|
||||
<Icon className="h-4 w-4 text-[#87867f]" aria-hidden="true" />
|
||||
@@ -951,17 +1011,21 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
<div className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("metrics.loop")}</p>
|
||||
<div className="mt-2 flex items-center gap-2">
|
||||
{closed ? (
|
||||
{!hasRuntimeReadback ? (
|
||||
<RefreshCw className="h-4 w-4 animate-spin text-[#87867f]" aria-hidden="true" />
|
||||
) : closed ? (
|
||||
<CheckCircle2 className="h-4 w-4 text-[#17602a]" aria-hidden="true" />
|
||||
) : (
|
||||
<TriangleAlert className="h-4 w-4 text-[#8a5a08]" aria-hidden="true" />
|
||||
)}
|
||||
<span className="font-mono text-lg font-semibold text-[#141413]">
|
||||
{closed ? "1" : "0"}
|
||||
{!hasRuntimeReadback ? "--" : closed ? "1" : "0"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
||||
{missingStages.length > 0
|
||||
{!hasRuntimeReadback
|
||||
? t("states.loading")
|
||||
: missingStages.length > 0
|
||||
? t("missing", { count: missingStages.length })
|
||||
: t("closedDetail")}
|
||||
</p>
|
||||
@@ -974,13 +1038,15 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-[#77736a]">{metric.label}</p>
|
||||
<div className="mt-2 font-mono text-lg font-semibold text-[#141413]">
|
||||
{numberValue(metric.value)}
|
||||
{readbackNumber(metric.value, hasRuntimeReadback)}
|
||||
</div>
|
||||
</div>
|
||||
<Icon className="h-4 w-4 text-[#87867f]" aria-hidden="true" />
|
||||
</div>
|
||||
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
||||
{"caption" in metric && metric.caption
|
||||
{!hasRuntimeReadback
|
||||
? t("states.loading")
|
||||
: "caption" in metric && metric.caption
|
||||
? metric.caption
|
||||
: t("recent", { count: numberValue(metric.recent) })}
|
||||
</p>
|
||||
@@ -993,33 +1059,43 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
<div className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.sources")}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
||||
{numberValue(rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count)}
|
||||
{readbackNumber(
|
||||
rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count,
|
||||
hasRuntimeReadback
|
||||
)}
|
||||
{" / "}
|
||||
{numberValue(rollups.live_log_source_family_count ?? logRollups.source_family_count)}
|
||||
{readbackNumber(
|
||||
rollups.live_log_source_family_count ?? logRollups.source_family_count,
|
||||
hasRuntimeReadback
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.products")}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
||||
{numberValue(
|
||||
{readbackNumber(
|
||||
rollups.live_multi_product_taxonomy_contract_ready_count
|
||||
?? multiProductRollups.contract_ready_product_scope_count
|
||||
?? multiProductRollups.contract_ready_product_scope_count,
|
||||
hasRuntimeReadback
|
||||
)}
|
||||
{" / "}
|
||||
{numberValue(
|
||||
{readbackNumber(
|
||||
rollups.live_multi_product_taxonomy_product_scope_count
|
||||
?? multiProductRollups.product_scope_count
|
||||
?? multiProductRollups.product_scope_count,
|
||||
hasRuntimeReadback
|
||||
)}
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
||||
{t("taxonomy.productsDetail", {
|
||||
active: numberValue(
|
||||
active: readbackNumber(
|
||||
rollups.live_multi_product_taxonomy_runtime_adapter_active_count
|
||||
?? multiProductRollups.runtime_adapter_active_count
|
||||
?? multiProductRollups.runtime_adapter_active_count,
|
||||
hasRuntimeReadback
|
||||
),
|
||||
missing: numberValue(
|
||||
missing: readbackNumber(
|
||||
rollups.live_multi_product_taxonomy_missing_dimension_count
|
||||
?? multiProductRollups.missing_required_dimension_count
|
||||
?? multiProductRollups.missing_required_dimension_count,
|
||||
hasRuntimeReadback
|
||||
),
|
||||
})}
|
||||
</p>
|
||||
@@ -1027,33 +1103,54 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
<div className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.labels")}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
||||
{numberValue(rollups.live_log_label_dimension_count ?? logRollups.label_dimension_count)}
|
||||
{readbackNumber(
|
||||
rollups.live_log_label_dimension_count ?? logRollups.label_dimension_count,
|
||||
hasRuntimeReadback
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.events")}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
||||
{numberValue(rollups.live_log_classified_event_total ?? logRollups.classified_event_total)}
|
||||
{readbackNumber(
|
||||
rollups.live_log_classified_event_total ?? logRollups.classified_event_total,
|
||||
hasRuntimeReadback
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.learning")}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
||||
{numberValue(logRollups.learning_source_family_count)}
|
||||
{readbackNumber(logRollups.learning_source_family_count, hasRuntimeReadback)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.workItems")}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
||||
{numberValue(rollups.live_work_item_completed_count ?? workItemRollups.completed_count)}
|
||||
{readbackNumber(
|
||||
rollups.live_work_item_completed_count ?? workItemRollups.completed_count,
|
||||
hasRuntimeReadback
|
||||
)}
|
||||
{" / "}
|
||||
{numberValue(rollups.live_work_item_count ?? workItemRollups.work_item_count)}
|
||||
{readbackNumber(
|
||||
rollups.live_work_item_count ?? workItemRollups.work_item_count,
|
||||
hasRuntimeReadback
|
||||
)}
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
||||
{t("taxonomy.workItemsDetail", {
|
||||
active: numberValue(rollups.live_work_item_in_progress_count ?? workItemRollups.in_progress_count),
|
||||
pending: numberValue(rollups.live_work_item_pending_count ?? workItemRollups.pending_count),
|
||||
blocked: numberValue(rollups.live_work_item_blocked_count ?? workItemRollups.blocked_count),
|
||||
active: readbackNumber(
|
||||
rollups.live_work_item_in_progress_count ?? workItemRollups.in_progress_count,
|
||||
hasRuntimeReadback
|
||||
),
|
||||
pending: readbackNumber(
|
||||
rollups.live_work_item_pending_count ?? workItemRollups.pending_count,
|
||||
hasRuntimeReadback
|
||||
),
|
||||
blocked: readbackNumber(
|
||||
rollups.live_work_item_blocked_count ?? workItemRollups.blocked_count,
|
||||
hasRuntimeReadback
|
||||
),
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
@@ -1098,15 +1195,17 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
<div className="min-w-[180px]">
|
||||
<div className="flex items-center justify-between gap-3 text-xs font-semibold text-[#5f5b52]">
|
||||
<span>{t("workBoard.completedOfTotal", {
|
||||
completed: numberValue(workCompleted),
|
||||
total: numberValue(workTotal),
|
||||
completed: readbackNumber(workCompleted, hasRuntimeReadback),
|
||||
total: readbackNumber(workTotal, hasRuntimeReadback),
|
||||
})}</span>
|
||||
<span className="font-mono text-[#141413]">{workCompletionPercent}%</span>
|
||||
<span className="font-mono text-[#141413]">
|
||||
{hasRuntimeReadback ? `${workCompletionPercent}%` : "--"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-2 h-2 border border-[#d8d3c7] bg-[#faf9f3]">
|
||||
<div
|
||||
className="h-full bg-[#17602a]"
|
||||
style={{ width: `${workCompletionPercent}%` }}
|
||||
style={{ width: hasRuntimeReadback ? `${workCompletionPercent}%` : "0%" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1130,7 +1229,7 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
>
|
||||
<Icon className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
<span>{t(`workBoard.filters.${filter.key}` as never)}</span>
|
||||
<span className="font-mono">{numberValue(filter.count)}</span>
|
||||
<span className="font-mono">{readbackNumber(filter.count, hasRuntimeReadback)}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -1139,7 +1238,7 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
<div className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("workBoard.sourceCoverage")}</p>
|
||||
<p className="mt-2 font-mono text-lg font-semibold text-[#141413]">
|
||||
{numberValue(sourceFamilyTotal)}
|
||||
{readbackNumber(sourceFamilyTotal, hasRuntimeReadback)}
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
||||
{t("workBoard.sourceCoverageDetail")}
|
||||
@@ -1173,7 +1272,7 @@ export function AutonomousRuntimeReceiptPanel({
|
||||
</div>
|
||||
)) : (
|
||||
<div className="bg-white px-4 py-6 text-sm font-semibold text-[#5f5b52]">
|
||||
{t("workBoard.empty")}
|
||||
{hasRuntimeReadback ? t("workBoard.empty") : t("states.loading")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user