From 5ede8df52ab1bd4efd0e0627b8775178cf3acdd4 Mon Sep 17 00:00:00 2001 From: weichen Date: Sat, 17 Oct 2026 02:28:47 +0000 Subject: [PATCH 01/13] Fix inverted cancel guard in cockpit project loader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: #102 rewrote the bare-array fallback into a multi-line callback and turned 'if (!c) setProjects(...)' into an early 'if (!c) return', which skips setProjects on the normal (non-cancelled) path — the cockpit then hangs on 加载中 forever, caught by I4 e2e scenario 1. Evidence: tsc clean, vitest 324/324, build green (SELF); seven-scenario browser suite rerun recorded on the Dev I4 card. Impact: cockpit entry only. Refs: rollout I4 --- src/components/DocumentCockpit.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DocumentCockpit.tsx b/src/components/DocumentCockpit.tsx index 8f33889..b3da2b2 100644 --- a/src/components/DocumentCockpit.tsx +++ b/src/components/DocumentCockpit.tsx @@ -66,7 +66,7 @@ export function DocumentCockpit() { setProjects(null); setPid(''); setOverview(null); setSelected(null); setFilter(''); setError('') api.rdmCommand<{ projects?: ProjectView[] } | ProjectView[]>('rdm.project.list') .then(list => { - if (!c) return + if (c) return // rdm.project.list 返回 { projects: [...] };容忍裸数组形态。 const rows = Array.isArray(list) ? list : (list?.projects ?? []) setProjects(rows) From 10f8388bb8c7497a1f6c5f979977e495d15c0fad Mon Sep 17 00:00:00 2001 From: weichen Date: Sat, 17 Oct 2026 02:45:17 +0000 Subject: [PATCH 02/13] Auto-select first visible project on cockpit entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: the cockpit rendered the project dropdown with no project selected and an empty main area — the design's 首屏 default (first visible project drives the overview) was never implemented; caught by I4 e2e scenario 1 which got past the project list but never saw .cockpit-stats. Evidence: tsc clean, vitest green, build green (SELF); seven-scenario rerun to be recorded on the Dev I4 card. Impact: cockpit entry only. Refs: rollout I4 --- src/components/DocumentCockpit.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/DocumentCockpit.tsx b/src/components/DocumentCockpit.tsx index b3da2b2..8a32602 100644 --- a/src/components/DocumentCockpit.tsx +++ b/src/components/DocumentCockpit.tsx @@ -70,6 +70,8 @@ export function DocumentCockpit() { // rdm.project.list 返回 { projects: [...] };容忍裸数组形态。 const rows = Array.isArray(list) ? list : (list?.projects ?? []) setProjects(rows) + // 设计 §6.2:进入驾驶舱默认选中第一个可见项目,驱动概览首屏。 + if (rows.length > 0) setPid(prev => prev || rows[0].id) }) .catch(e => { if (!c) setError(e.message) }) return () => { c = true } From a56ce3e1df18d367718843d2ac6530b2b3fb9dba Mon Sep 17 00:00:00 2001 From: weichen Date: Sat, 17 Oct 2026 03:16:47 +0000 Subject: [PATCH 03/13] Fix cockpit project option field: payload is projectId, not id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: the local ProjectView interface invented 'id'; rdm.project.list returns projectId. Every option value was undefined, so auto-select set pid to undefined and the overview request was never issued — cockpit showed 加载概览… forever after the project list loaded (I4 e2e scenario 1). Evidence: tsc clean, vitest green, build green (SELF); network probe shows rdm.cockpit.overview 200 and .cockpit-stats rendered; seven-scenario rerun to be recorded on the Dev I4 card. Impact: cockpit entry only. Refs: rollout I4 --- src/components/DocumentCockpit.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DocumentCockpit.tsx b/src/components/DocumentCockpit.tsx index 8a32602..c450146 100644 --- a/src/components/DocumentCockpit.tsx +++ b/src/components/DocumentCockpit.tsx @@ -18,7 +18,7 @@ import { } from '../documentCockpit' import { CockpitPanel, CockpitReader } from './CockpitReader' -interface ProjectView { id: string; name: string; canAudit?: boolean } +interface ProjectView { projectId: string; name: string; canAudit?: boolean } function CockpitErrorState({ raw }: { raw: string }) { const c = classifyRdmError(raw) @@ -71,7 +71,7 @@ export function DocumentCockpit() { const rows = Array.isArray(list) ? list : (list?.projects ?? []) setProjects(rows) // 设计 §6.2:进入驾驶舱默认选中第一个可见项目,驱动概览首屏。 - if (rows.length > 0) setPid(prev => prev || rows[0].id) + if (rows.length > 0) setPid(prev => prev || rows[0].projectId) }) .catch(e => { if (!c) setError(e.message) }) return () => { c = true } @@ -130,7 +130,7 @@ export function DocumentCockpit() {
{filter &&