fix(awooop): collapse work item blocker details
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 57s
CD Pipeline / build-and-deploy (push) Failing after 46s
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
Your Name
2026-07-03 16:02:29 +08:00
parent ea6e4c2819
commit 889507ff9d
3 changed files with 91 additions and 20 deletions

View File

@@ -9300,6 +9300,9 @@
"decisionValue": "Fix P0, no side lane",
"decisionParallel": "P0 waits for data; advance {id}",
"blockingSources": "Blocking sources",
"blockingSourcesSummary": "shown {shown} / collapsed {hidden}",
"details": "Details",
"hiddenCount": "+{count}",
"noSourceNames": "Waiting for source contract readback",
"states": {
"rebootSlo": "10-minute recovery SLO not proven",
@@ -9433,6 +9436,7 @@
"blockerLanes": {
"label": "Blocker lanes",
"count": "{count}",
"summary": "{lanes} lanes / {count}",
"hostBoot": "Host / reboot event",
"windows99": "Windows99 / VMware",
"serviceData": "Service data",

View File

@@ -9300,6 +9300,9 @@
"decisionValue": "先修 P0不開支線",
"decisionParallel": "P0 等資料;並行推進 {id}",
"blockingSources": "阻塞來源",
"blockingSourcesSummary": "顯示 {shown} / 收合 {hidden}",
"details": "明細",
"hiddenCount": "+{count}",
"noSourceNames": "等待 source contract readback",
"states": {
"rebootSlo": "10 分鐘恢復 SLO 未證明",
@@ -9433,6 +9436,7 @@
"blockerLanes": {
"label": "卡點分群",
"count": "{count} 個",
"summary": "{lanes} 類 / {count} 個",
"hostBoot": "Host / reboot event",
"windows99": "Windows99 / VMware",
"serviceData": "Service data",

View File

@@ -9576,29 +9576,26 @@ function ManagerSituationBoard({
summary?.stockplatform_source_contract_receipt_provided ??
evidence?.stockplatform_source_contract_receipt_provided ??
true;
const blockingSources =
const allBlockingSources =
isRebootP0
? activeBlockers.slice(0, 4).map((source) => ({ source }))
? activeBlockers.map((source) => ({ source }))
: (
evidence?.stockplatform_source_contract_blocking_sources?.slice(0, 3) ??
evidence?.stockplatform_source_contract_blocking_sources ??
STOCKPLATFORM_SOURCE_CONTRACT_FALLBACK_SOURCES.map((source) => ({ source }))
);
const blockingSources = allBlockingSources.slice(0, 3);
const sourceNames = blockingSources
.map((source) => source.source)
.filter(Boolean)
.join(" / ");
const visibleBlockers = (
isRebootP0
? activeBlockers.map((source) => ({ source }))
: blockingSources
)
const blockerSourceRows = allBlockingSources
.filter((source) => source.source)
.slice(0, 5);
const hiddenBlockerCount = Math.max(
0,
(isRebootP0 ? activeBlockers.length : blockingSources.length) -
visibleBlockers.length
);
const visibleBlockers = blockerSourceRows.slice(0, 3);
const hiddenBlockers = blockerSourceRows.slice(3);
const hiddenBlockerCount = hiddenBlockers.length;
const visibleBlockerLanes = rebootBlockerLanes.slice(0, 3);
const hiddenBlockerLanes = rebootBlockerLanes.slice(3);
const hiddenBlockerLaneCount = hiddenBlockerLanes.length;
const deployedSha =
priority?.current_head?.latest_successful_deployed_source_sha ??
priority?.current_head?.gitea_main_sha;
@@ -10007,12 +10004,22 @@ function ManagerSituationBoard({
</span>
</div>
) : null}
<div className="text-[11px] font-semibold text-[#77736a]">
{t("blockerLanes.label")}
<div className="mt-2 flex flex-wrap items-center justify-between gap-2">
<div className="text-[11px] font-semibold text-[#77736a]">
{t("blockerLanes.label")}
</div>
{rebootBlockerLanes.length ? (
<div className="font-mono text-[11px] font-semibold text-[#5f5b52]">
{t("blockerLanes.summary", {
lanes: rebootBlockerLanes.length,
count: activeBlockerCount,
})}
</div>
) : null}
</div>
<div className="mt-1 flex flex-wrap gap-1.5">
{rebootBlockerLanes.length ? (
rebootBlockerLanes.map((lane) => (
visibleBlockerLanes.map((lane) => (
<span
key={lane.key}
className="inline-flex items-center gap-1.5 border border-[#d8d3c7] bg-white px-2 py-0.5 text-[11px] font-semibold text-[#38352e]"
@@ -10028,13 +10035,48 @@ function ManagerSituationBoard({
{t("noSourceNames")}
</span>
)}
{hiddenBlockerLaneCount > 0 ? (
<span className="inline-flex items-center border border-[#d8d3c7] bg-white px-2 py-0.5 font-mono text-[11px] font-semibold text-[#5f5b52]">
{t("hiddenCount", { count: hiddenBlockerLaneCount })}
</span>
) : null}
</div>
{hiddenBlockerLaneCount > 0 ? (
<details className="mt-1 text-[11px] text-[#5f5b52]">
<summary className="inline-flex cursor-pointer items-center gap-1 border border-[#d8d3c7] bg-white px-2 py-0.5 font-semibold">
{t("details")}
</summary>
<div className="mt-1 flex flex-wrap gap-1.5">
{hiddenBlockerLanes.map((lane) => (
<span
key={lane.key}
className="inline-flex items-center gap-1.5 border border-[#d8d3c7] bg-white px-2 py-0.5 font-semibold text-[#38352e]"
>
<span>{t(`blockerLanes.${lane.key}` as never)}</span>
<span className="font-mono text-[#9a4d16]">
{t("blockerLanes.count", { count: lane.count })}
</span>
</span>
))}
</div>
</details>
) : null}
</div>
) : null}
<div className="mt-2 grid gap-2 border border-[#d8d3c7] bg-[#faf9f3] p-2 lg:grid-cols-[minmax(0,1fr)_auto]">
<div className="min-w-0">
<div className="text-[11px] font-semibold text-[#77736a]">
{t("blockingSources")}
<div className="flex flex-wrap items-center justify-between gap-2">
<div className="text-[11px] font-semibold text-[#77736a]">
{t("blockingSources")}
</div>
{hiddenBlockerCount > 0 ? (
<div className="font-mono text-[11px] font-semibold text-[#5f5b52]">
{t("blockingSourcesSummary", {
shown: visibleBlockers.length,
hidden: hiddenBlockerCount,
})}
</div>
) : null}
</div>
<div className="mt-1 flex flex-wrap gap-1.5">
{loading ? (
@@ -10057,7 +10099,7 @@ function ManagerSituationBoard({
})}
{hiddenBlockerCount > 0 ? (
<span className="border border-[#d8d3c7] bg-white px-2 py-0.5 font-mono text-[11px] font-semibold text-[#5f5b52]">
+{hiddenBlockerCount}
{t("hiddenCount", { count: hiddenBlockerCount })}
</span>
) : null}
</>
@@ -10067,6 +10109,27 @@ function ManagerSituationBoard({
</span>
)}
</div>
{hiddenBlockerCount > 0 ? (
<details className="mt-1 text-[11px] text-[#5f5b52]">
<summary className="inline-flex cursor-pointer items-center gap-1 border border-[#d8d3c7] bg-white px-2 py-0.5 font-semibold">
{t("details")}
</summary>
<div className="mt-1 flex flex-wrap gap-1.5">
{hiddenBlockers.map((blocker, index) => {
const source = blocker.source ?? `unknown_blocker_${index + 1}`;
return (
<span
key={`${source}-hidden-${index}`}
title={source}
className="border border-[#f0c6a8] bg-white px-2 py-0.5 font-mono font-semibold text-[#9a4d16]"
>
{compactBlockerLabel(source)}
</span>
);
})}
</div>
</details>
) : null}
</div>
<div className="flex flex-wrap items-center gap-1.5 text-[11px] font-semibold">
<span className="border border-[#d8d3c7] bg-white px-2 py-1 text-[#5f5b52]">