From b8e987bde417b9c57a2087403d02ddc4c78b0337 Mon Sep 17 00:00:00 2001 From: ogt Date: Fri, 10 Jul 2026 09:49:22 +0800 Subject: [PATCH] fix(work-items): surface mainline progress order --- apps/web/messages/en.json | 54 +++-- apps/web/messages/zh-TW.json | 18 ++ .../app/[locale]/awooop/work-items/page.tsx | 216 ++++++++++++++++++ 3 files changed, 270 insertions(+), 18 deletions(-) diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 8437b6612..a193ee3ee 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -9531,31 +9531,49 @@ "noSecret": "no secret read" } }, + "mainlineProgress": { + "eyebrow": "Mainline Work Progress", + "title": "All Work Items And Priority Order", + "subtitle": "Reads the production priority work-order readback and surfaces totals, completion, current P0, next action, and the first 8 ordered items before the deeper automation / ledger views.", + "loading": "Reading production work-order", + "completion": "Overall completion", + "currentP0": "Current P0", + "primaryBlocker": "Primary blocker", + "blockerCount": "{count} blockers", + "nextAction": "Next ordered action", + "statuses": { + "done": "Completed", + "in_progress": "In progress", + "pending": "Not started", + "blocked": "Blocked", + "deferred": "Deferred" + } + }, "commanderInsertedRequirements": { - "eyebrow": "主線優先序", - "title": "統帥插入需求工作項", - "subtitle": "把本輪中途插入的要求收成正式工作項,依 P0/P1/P2/P3 排序,並顯示狀態、驗收條件與下一步。", - "total": "總工作項", - "next": "目前優先項", - "nextAction": "下一步", - "acceptance": "驗收條件", - "rowNextAction": "下一步", - "spotlight": "主線焦點", - "spotlightSubtitle": "直接露出目前 P0、OpenClaw Live Ops 與非文字牆 UX,避免工作項藏在長清單裡。", - "fullLedger": "完整總帳 {count} 項", - "loading": "讀取插入需求工作項", - "empty": "尚未讀回插入需求工作項。", + "eyebrow": "Mainline priority", + "title": "Commander Inserted Requirement Work Items", + "subtitle": "Turns midstream requirements into ordered P0/P1/P2/P3 work items with status, acceptance, and next action.", + "total": "Total work items", + "next": "Current priority", + "nextAction": "Next action", + "acceptance": "Acceptance", + "rowNextAction": "Next action", + "spotlight": "Mainline spotlight", + "spotlightSubtitle": "Pins current P0, OpenClaw Live Ops, and UI work so they do not hide in a long ledger.", + "fullLedger": "Full ledger {count} items", + "loading": "Reading inserted requirement work items", + "empty": "No inserted requirement work items read back yet.", "order": "order={order}", "source": "source={source}", "metrics": { "active": "active" }, "statuses": { - "done": "已完成", - "inProgress": "進行中", - "pending": "未開始", - "blocked": "阻塞", - "deferred": "延後" + "done": "Completed", + "inProgress": "In progress", + "pending": "Not started", + "blocked": "Blocked", + "deferred": "Deferred" } }, "operatorSop": { diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index c547fa54f..37c766e21 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -9531,6 +9531,24 @@ "noSecret": "no secret read" } }, + "mainlineProgress": { + "eyebrow": "主線工作進度", + "title": "全部工作項目與優先順序", + "subtitle": "直接讀正式 priority work-order readback,先看總數、完成度、目前 P0、下一步與前 8 個 ordered items;細節再下鑽 automation / ledger。", + "loading": "讀取正式 work-order", + "completion": "整體完成度", + "currentP0": "目前 P0", + "primaryBlocker": "主要阻擋", + "blockerCount": "{count} 個 blocker", + "nextAction": "下一個 ordered action", + "statuses": { + "done": "已完成", + "in_progress": "進行中", + "pending": "未開始", + "blocked": "阻塞", + "deferred": "延後" + } + }, "commanderInsertedRequirements": { "eyebrow": "主線優先序", "title": "統帥插入需求工作項", 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 72120e046..59b2273fb 100644 --- a/apps/web/src/app/[locale]/awooop/work-items/page.tsx +++ b/apps/web/src/app/[locale]/awooop/work-items/page.tsx @@ -1091,6 +1091,7 @@ type PriorityWorkOrderResponse = { active_p0_state?: string | null; active_p0_workplan_id?: string | null; active_p0_readiness_percent?: number | null; + active_p0_primary_blocker?: string | null; active_p0_live_active_blockers?: string[] | null; next_executable_mainline_workplan_id?: string | null; next_executable_mainline_state?: string | null; @@ -11065,6 +11066,216 @@ function commanderStatusTone(status: string) { } } +function MainlineWorkProgressStrip({ + priority, + loading, +}: { + priority: PriorityWorkOrderResponse | null; + loading: boolean; +}) { + const t = useTranslations("awooop.workItems.mainlineProgress"); + const summary = priority?.summary; + const items = (priority?.commander_inserted_requirement_work_items ?? []) + .slice() + .sort((left, right) => (left.order ?? 0) - (right.order ?? 0)); + const total = toCount( + summary?.commander_inserted_requirement_work_item_count ?? items.length + ); + const done = toCount(summary?.commander_inserted_requirement_done_count); + const inProgress = toCount( + summary?.commander_inserted_requirement_in_progress_count + ); + const pending = toCount(summary?.commander_inserted_requirement_pending_count); + const blocked = toCount(summary?.commander_inserted_requirement_blocked_count); + const deferred = toCount(summary?.commander_inserted_requirement_deferred_count); + const completion = total > 0 ? Math.round((done / total) * 100) : 0; + const readiness = toCount(summary?.active_p0_readiness_percent); + const nextId = + summary?.commander_inserted_requirement_next_id ?? items[0]?.id ?? "--"; + const nextPriority = + summary?.commander_inserted_requirement_next_priority ?? + items[0]?.priority ?? + "--"; + const nextAction = + summary?.commander_inserted_requirement_next_action ?? + items[0]?.next_action ?? + "--"; + const currentP0 = summary?.active_p0_workplan_id ?? "--"; + const currentState = summary?.active_p0_state ?? "--"; + const activeBlockers = summary?.active_p0_live_active_blockers ?? []; + const primaryBlocker = + summary?.active_p0_primary_blocker ?? activeBlockers[0] ?? "--"; + const visibleItems = items.slice(0, 8); + const statusMetrics = [ + { + key: "done", + label: t("statuses.done"), + value: done, + tone: commanderStatusTone("done"), + }, + { + key: "inProgress", + label: t("statuses.in_progress"), + value: inProgress, + tone: commanderStatusTone("in_progress"), + }, + { + key: "pending", + label: t("statuses.pending"), + value: pending, + tone: commanderStatusTone("pending"), + }, + { + key: "blocked", + label: t("statuses.blocked"), + value: blocked, + tone: commanderStatusTone("blocked"), + }, + { + key: "deferred", + label: t("statuses.deferred"), + value: deferred, + tone: commanderStatusTone("deferred"), + }, + ]; + + return ( +
+
+
+
+
+
+ + + + {loading ? t("loading") : `${nextPriority}:${nextId}`} + +
+

+ {t("title")} +

+

+ {t("subtitle")} +

+
+
+
+ {t("completion")} + + {loading ? "--" : `${completion}% · ${done}/${total}`} + +
+
+
+
+
+
+ +
+ {statusMetrics.map((metric) => ( +
+
{metric.label}
+
+ {loading ? "--" : metric.value} +
+
+ ))} +
+ +
+ {visibleItems.map((item) => { + const itemPriority = String(item.priority ?? "--"); + const itemStatus = String(item.status ?? "pending"); + return ( +
+
+ + {itemPriority} + + + {t(`statuses.${itemStatus}` as never)} + +
+
+ {item.id} +
+
+ {item.normalized_work_item ?? item.request} +
+
+ ); + })} +
+
+ +
+
+
+
+
+ {t("currentP0")} +
+ + {loading ? "--" : currentP0} + +
+
+ {loading ? "--" : `${readiness}%`} +
+
+ {currentState} +
+
+ +
+
+ {t("primaryBlocker")} +
+
+ {loading ? "--" : primaryBlocker} +
+
+ {t("blockerCount", { count: activeBlockers.length })} +
+
+ +
+
+ {t("nextAction")} +
+
+ {loading ? "--" : nextAction} +
+
+
+
+
+
+ ); +} + function CommanderInsertedRequirementsPanel({ priority, loading, @@ -11775,6 +11986,11 @@ export default function AwoooPWorkItemsPage() { + +