diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 9064ece7..d4da493f 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -9554,6 +9554,17 @@ } } }, + "runsIncidentFocus": { + "title": "事故焦點狀態鏈", + "description": "URL 上的 incident_id 會直接讀回 status-chain、套用閘門與自動化資產總帳,避免只看到 Run 摘要卻看不到下一步。", + "states": { + "ready": "已讀回狀態鏈", + "loading": "讀取中", + "missing": "尚未讀回" + }, + "loading": "正在讀回事故狀態鏈與自動化資產。", + "missing": "尚未讀回 {incidentId} 的狀態鏈;請先確認來源事件是否已入庫,或查看 API readback。" + }, "listEvidence": { "column": "AI 證據", "callbackColumn": "TG Callback", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 9064ece7..d4da493f 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -9554,6 +9554,17 @@ } } }, + "runsIncidentFocus": { + "title": "事故焦點狀態鏈", + "description": "URL 上的 incident_id 會直接讀回 status-chain、套用閘門與自動化資產總帳,避免只看到 Run 摘要卻看不到下一步。", + "states": { + "ready": "已讀回狀態鏈", + "loading": "讀取中", + "missing": "尚未讀回" + }, + "loading": "正在讀回事故狀態鏈與自動化資產。", + "missing": "尚未讀回 {incidentId} 的狀態鏈;請先確認來源事件是否已入庫,或查看 API readback。" + }, "listEvidence": { "column": "AI 證據", "callbackColumn": "TG Callback", diff --git a/apps/web/src/app/[locale]/awooop/runs/page.tsx b/apps/web/src/app/[locale]/awooop/runs/page.tsx index 1965ce4e..2d7189e9 100644 --- a/apps/web/src/app/[locale]/awooop/runs/page.tsx +++ b/apps/web/src/app/[locale]/awooop/runs/page.tsx @@ -4221,6 +4221,7 @@ export default function RunsPage() { const tEvidence = useTranslations("awooop.listEvidence"); const tAssetLedger = useTranslations("awooop.automationAssetLedger"); const tCallback = useTranslations("awooop.callbackReply"); + const tIncidentFocus = useTranslations("awooop.runsIncidentFocus"); const [runs, setRuns] = useState([]); const [groupedEvents, setGroupedEvents] = useState([]); const [dossierCoverage, setDossierCoverage] = useState(null); @@ -4555,6 +4556,13 @@ export default function RunsPage() { refreshKey: lastRefresh?.toISOString() ?? null, limit: PER_PAGE, }); + const normalizedIncidentFocus = useMemo(() => { + const normalized = incidentFilter.trim().toUpperCase(); + return INCIDENT_ID_FILTER_RE.test(normalized) ? normalized : null; + }, [incidentFilter]); + const incidentFocusChain = normalizedIncidentFocus + ? runStatusChains[normalizedIncidentFocus] + : null; return (
@@ -4686,6 +4694,53 @@ export default function RunsPage() { })} + {normalizedIncidentFocus && ( +
+
+
+
+
+

+ {tIncidentFocus("description")} +

+
+ + {incidentFocusChain + ? tIncidentFocus("states.ready") + : runStatusChainsLoading + ? tIncidentFocus("states.loading") + : tIncidentFocus("states.missing")} + +
+ {incidentFocusChain ? ( +
+
+ +
+
+ +
+
+ ) : ( +
+ {runStatusChainsLoading + ? tIncidentFocus("loading") + : tIncidentFocus("missing", { incidentId: normalizedIncidentFocus })} +
+ )} +
+ )} + { const incidentIds = linkedIncidentIds(run.remediation_summary); - const statusChain = incidentIds + const rowIncidentIds = normalizedIncidentFocus + ? Array.from(new Set([normalizedIncidentFocus, ...incidentIds])) + : incidentIds; + const statusChain = rowIncidentIds .map((incidentId) => runStatusChains[incidentId]) .find((chain): chain is AwoooPStatusChain => Boolean(chain)); return ( diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index c7090574..45ad1447 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -35,6 +35,27 @@ **邊界**:本段只補 UI 查詢來源;不寫 DB、不改 run 狀態、不執行修復、不發 Telegram、不開 runtime gate。 +## 2026-06-25|Runs 新增事故焦點狀態鏈面板 + +**背景**:`5a76316a` 部署後,正式 Runs 頁已無 502、無 JS error、無水平溢出,且 DOM 可見 `INC-20260625-977E5F`;但頁面仍未顯示 `乾跑後套用閘門`,因為 status-chain 只被表格列用來補欄位,沒有固定的 incident drilldown 焦點面板。 + +**完成**: +- Runs 頁在 URL `incident_id` 合法時,於 KPI 區下方固定顯示「事故焦點狀態鏈」。 +- 焦點面板直接渲染 `AwoooPStatusChainPanel` 與 `AwoooPAutomationAssetLedger`,把乾跑、套用審查、驗證回寫、資產總帳放在同一個操作區。 +- 表格列在 incident filter 模式下也會使用 URL 焦點 status-chain,避免資產總帳欄因 run summary 缺 incident ids 而空白。 +- 新增 `awooop.runsIncidentFocus` i18n 文案,維持 zh-TW / en key 鏡像。 + +**驗證待辦**: +- i18n JSON parse / mirror。 +- `pnpm --filter @awoooi/web typecheck`。 +- 下一個 deploy marker 後重跑 `/zh-TW/awooop/runs?project_id=awoooi&incident_id=INC-20260625-977E5F` desktop / mobile smoke。 + +**完成度同步**: +- Runs incident drilldown 可判讀性:`82% -> 90%`。 +- 真正修復自動執行成功率仍不提高;這段只是把目前卡在 apply gate 的事實清楚呈現。 + +**邊界**:本段只改前端顯示與 i18n;不寫 DB、不改 run 狀態、不執行修復、不發 Telegram、不開 runtime gate。 + ## 2026-06-25|Status-chain 新增乾跑後套用閘門 handoff **背景**:`INC-20260625-977E5F` 類告警目前已能辨識 Ansible `check_mode` 乾跑成功、`apply_total=0`、`verifier=missing`,但 operator 在 Runs / Telegram 看見的下一步仍容易停在「需人工」或長文字。這會讓 AI 自動化看起來像只是把問題丟回人工,而不是清楚交付下一個可審核 gate。 diff --git a/docs/workplans/2026-06-25-awoooi-product-uiux-inventory.md b/docs/workplans/2026-06-25-awoooi-product-uiux-inventory.md index 7f1d72d3..cf9e1448 100644 --- a/docs/workplans/2026-06-25-awoooi-product-uiux-inventory.md +++ b/docs/workplans/2026-06-25-awoooi-product-uiux-inventory.md @@ -279,6 +279,21 @@ Tenants 目前已讀到: 完成度同步:Runs incident drilldown 穩定性 `72% -> 82%`;AwoooP Runs apply-gate 正式頁驗證需前端修正 deploy 後重跑。 +### 2.5.11 Runs 事故焦點狀態鏈面板 + +2026-06-25 `5a76316a` 部署後,正式 Runs 頁面可載入且沒有 502 / JS error / 水平溢出,但仍未顯示 `乾跑後套用閘門`。原因是 status-chain 只被表格列用來補欄位,沒有固定的 incident drilldown 焦點區;而這次 `INC-20260625-977E5F` 的 run summary 又缺 incident ids,讓使用者只看到 Run 摘要和大量文字。 + +| 項目 | 調整 | +|---|---| +| 焦點面板 | URL `incident_id` 合法時,在 KPI 區下方固定顯示「事故焦點狀態鏈」 | +| 狀態鏈 | 直接渲染 `AwoooPStatusChainPanel`,顯示 verdict、repair_state、apply gate、verifier 等 | +| 資產總帳 | 直接渲染 `AwoooPAutomationAssetLedger`,讓 KM / PlayBook / 乾跑 / 套用 / Verifier 狀態同屏可見 | +| 表格列 | incident filter 模式下,列資料也可使用 URL 焦點 status-chain 補齊來源流程與資產總帳 | +| 文案 | 新增 `awooop.runsIncidentFocus` i18n,zh-TW / en key 鏡像 | +| 邊界 | 不新增任何執行按鈕;不寫 DB、不發 Telegram、不開 runtime gate | + +完成度同步:Runs incident drilldown 可判讀性 `82% -> 90%`;真正修復自動執行成功率仍不提高,下一步要補 owner review apply gate / verifier plan 的實際狀態閉環。 + ## 3. 頁面 UI/UX 現況盤點 2026-06-25 對正式站桌機 / mobile 抽查: