From 5d3dc2a9c2c7ab3dcdbd0fd9c8d91245441856cb Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 2 Jul 2026 20:08:15 +0800 Subject: [PATCH] feat(awooop): pin manager situation board --- apps/web/messages/en.json | 45 ++++ apps/web/messages/zh-TW.json | 45 ++++ .../app/[locale]/awooop/work-items/page.tsx | 211 +++++++++++++++++- 3 files changed, 296 insertions(+), 5 deletions(-) diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 08861439c..1fb126df7 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -9180,6 +9180,51 @@ "evidenceBoundary": "證據邊界" } }, + "managerSituation": { + "eyebrow": "Manager overview", + "title": "StockPlatform P0", + "subtitle": "Blocker, impact, and next action are pinned to the first screen.", + "loading": "Reading production readback.", + "head": "Deployed source", + "decision": "Decision", + "decisionValue": "Fix P0, no side lane", + "blockingSources": "Blocking sources", + "noSourceNames": "Waiting for source contract readback", + "states": { + "sourceContract": "Source contract blocked", + "preflight": "Recovery preflight blocked", + "publicApi": "Public API blocked", + "ready": "Ready to verify", + "review": "Awaiting readback" + }, + "cards": { + "now": { + "label": "Current blocker", + "detail": "{id}" + }, + "impact": { + "label": "Impact", + "value": "Public API not green", + "detail": "Source trust is not sufficient." + }, + "evidence": { + "label": "Evidence", + "value": "{count} sources failed", + "receipted": "receipt provided", + "missing": "receipt missing" + }, + "next": { + "label": "Next step", + "value": "Repair source contract", + "detail": "Run verifier immediately after repair." + } + }, + "chips": { + "noDbWrite": "no DB write", + "noSecret": "no secret", + "publicVerifier": "public verifier" + } + }, "stockplatformP0Receipt": { "eyebrow": "P0-006 Runtime receipt", "title": "StockPlatform data dependency readback", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 113d53a84..85b06105a 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -9180,6 +9180,51 @@ "evidenceBoundary": "證據邊界" } }, + "managerSituation": { + "eyebrow": "管理者總覽", + "title": "StockPlatform P0", + "subtitle": "卡點、影響、下一步先放第一屏。", + "loading": "正在讀取正式 readback。", + "head": "正式部署", + "decision": "決策", + "decisionValue": "先修 P0,不開支線", + "blockingSources": "阻塞來源", + "noSourceNames": "等待 source contract readback", + "states": { + "sourceContract": "來源合約卡住", + "preflight": "修復預檢卡住", + "publicApi": "公開 API 卡住", + "ready": "已可驗證", + "review": "等待判讀" + }, + "cards": { + "now": { + "label": "目前卡點", + "detail": "{id}" + }, + "impact": { + "label": "影響", + "value": "公開 API 未綠燈", + "detail": "資料來源可信度不足" + }, + "evidence": { + "label": "證據", + "value": "{count} 個來源未通過", + "receipted": "receipt 已收件", + "missing": "receipt 未到" + }, + "next": { + "label": "下一步", + "value": "補來源合約", + "detail": "修完直接跑 verifier" + } + }, + "chips": { + "noDbWrite": "不寫 DB", + "noSecret": "不讀 secret", + "publicVerifier": "公開驗證器" + } + }, "stockplatformP0Receipt": { "eyebrow": "P0-006 Runtime receipt", "title": "StockPlatform 資料依賴回讀", diff --git a/apps/web/src/app/[locale]/awooop/work-items/page.tsx b/apps/web/src/app/[locale]/awooop/work-items/page.tsx index c822ffd67..5927b1ea5 100644 --- a/apps/web/src/app/[locale]/awooop/work-items/page.tsx +++ b/apps/web/src/app/[locale]/awooop/work-items/page.tsx @@ -22,6 +22,7 @@ import { GitPullRequest, ListChecks, Network, + Radar, RefreshCw, SearchCheck, ShieldCheck, @@ -1065,7 +1066,16 @@ type CommanderInsertedRequirementWorkItem = { }; type PriorityWorkOrderResponse = { + current_head?: { + gitea_main_sha?: string | null; + latest_successful_deployed_source_sha?: string | null; + latest_successful_deploy_marker?: string | null; + production_source_truth_available?: boolean | null; + } | null; summary?: { + active_p0_state?: string | null; + next_executable_mainline_workplan_id?: string | null; + next_executable_mainline_state?: string | null; commander_inserted_requirement_work_item_count?: number | null; commander_inserted_requirement_p0_count?: number | null; commander_inserted_requirement_p1_count?: number | null; @@ -1187,6 +1197,11 @@ type PriorityWorkOrderResponse = { stockplatform_source_contract_receipt_provided?: boolean | null; stockplatform_source_contract_ready?: boolean | null; stockplatform_source_contract_non_ok_source_count?: number | null; + stockplatform_source_contract_blocking_sources?: Array<{ + source?: string | null; + category?: string | null; + status?: string | null; + }> | null; } | null; }>; next_execution_order?: string[] | null; @@ -8732,6 +8747,187 @@ function stockplatformCompactTone(value: string | boolean | null | undefined) { return "border-[#c9d8ea] bg-[#eef5ff] text-[#1f5b9b]"; } +function shortSha(value: string | null | undefined) { + return value ? value.slice(0, 10) : "--"; +} + +function stockplatformManagerStateKey(value: string | null | undefined) { + const state = String(value ?? ""); + if (state.includes("source_contract")) return "sourceContract"; + if (state.includes("preflight")) return "preflight"; + if (state.includes("public_api")) return "publicApi"; + if (state.includes("ready")) return "ready"; + return "review"; +} + +function ManagerSituationBoard({ + priority, + loading, +}: { + priority: PriorityWorkOrderResponse | null; + loading: boolean; +}) { + const t = useTranslations("awooop.workItems.managerSituation"); + const summary = priority?.summary; + const evidence = priority?.in_progress_or_blocked_in_priority_order?.find( + (item) => + item.evidence?.stockplatform_source_contract_readback_status || + item.evidence?.stockplatform_public_api_runtime_status + )?.evidence; + const activeWorkplan = + summary?.next_executable_mainline_workplan_id ?? + "P0-006-STOCKPLATFORM-PUBLIC-API-CONTROLLED-RECOVERY-PREFLIGHT"; + const activeState = + summary?.active_p0_state ?? + "blocked_stockplatform_public_api_controlled_recovery_preflight"; + const activeStateLabel = t( + `states.${stockplatformManagerStateKey(activeState)}` as never + ); + const sourceContractStatus = + summary?.stockplatform_source_contract_readback_status ?? + evidence?.stockplatform_source_contract_readback_status ?? + "unknown"; + const nonOkSourceCount = + summary?.stockplatform_source_contract_non_ok_source_count ?? + evidence?.stockplatform_source_contract_non_ok_source_count ?? + 0; + const receiptProvided = + summary?.stockplatform_source_contract_receipt_provided ?? + evidence?.stockplatform_source_contract_receipt_provided ?? + false; + const blockingSources = + evidence?.stockplatform_source_contract_blocking_sources?.slice(0, 3) ?? []; + const sourceNames = blockingSources + .map((source) => source.source) + .filter(Boolean) + .join(" / "); + const deployedSha = + priority?.current_head?.latest_successful_deployed_source_sha ?? + priority?.current_head?.gitea_main_sha; + const managerCards = [ + { + key: "now", + icon: TriangleAlert, + label: t("cards.now.label"), + value: activeStateLabel, + detail: t("cards.now.detail", { + id: activeWorkplan.startsWith("P0-006") ? "P0-006" : activeWorkplan, + }), + tone: "border-[#f0c6a8] bg-[#fff8f1] text-[#9a4d16]", + }, + { + key: "impact", + icon: Database, + label: t("cards.impact.label"), + value: t("cards.impact.value"), + detail: t("cards.impact.detail"), + tone: "border-[#c9d8ea] bg-[#eef5ff] text-[#1f5b9b]", + }, + { + key: "evidence", + icon: SearchCheck, + label: t("cards.evidence.label"), + value: t("cards.evidence.value", { count: nonOkSourceCount }), + detail: receiptProvided ? t("cards.evidence.receipted") : t("cards.evidence.missing"), + tone: stockplatformCompactTone(sourceContractStatus), + }, + { + key: "next", + icon: ArrowRight, + label: t("cards.next.label"), + value: t("cards.next.value"), + detail: t("cards.next.detail"), + tone: "border-[#cbd7bf] bg-[#f4faef] text-[#3d6b24]", + }, + ]; + + return ( +
+
+
+
+
+

+ {t("title")} +

+

+ {loading ? t("loading") : t("subtitle")} +

+
+
+
+ {t("head")} +
+
+ {shortSha(deployedSha)} +
+
+
+
+ {t("decision")} +
+
+ {t("decisionValue")} +
+
+
+
+ +
+
+ {managerCards.map((card) => { + const Icon = card.icon; + return ( +
+
+
{card.label}
+
+
+ {loading ? "--" : card.value} +
+
+ {loading ? "--" : card.detail} +
+
+ ); + })} +
+
+
+
+ {t("blockingSources")} +
+
+ {loading ? "--" : sourceNames || t("noSourceNames")} +
+
+
+ + {t("chips.noDbWrite")} + + + {t("chips.noSecret")} + + + {t("chips.publicVerifier")} + +
+
+
+
+
+ ); +} + function StockPlatformP0ReceiptPanel({ priority, loading, @@ -9607,11 +9803,7 @@ export default function AwoooPWorkItemsPage() { - - - - - @@ -9621,6 +9813,15 @@ export default function AwoooPWorkItemsPage() { loading={priorityWorkOrderLoading && !priorityWorkOrder} /> + + + + + +