From 4133d202f01e74e59500ac21e13d92c6a6c1ab6f Mon Sep 17 00:00:00 2001 From: wangdequan Date: Sun, 14 Jun 2026 22:40:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A8=E8=BF=9B=20INI=20=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=20control=20view=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- text11.txt | 61 ++++++++++++++ wasm-port/docs/ui-panel-state-summary.md | 19 +++++ wasm-port/runtime/ui/ini-panel/app.js | 7 ++ .../ui/ini-panel/panel-state-summary.js | 45 +++++++++++ wasm-port/tests/browser/ini_panel_smoke.html | 27 +++++++ .../node/verify_ini_panel_state_summary.mjs | 80 ++++++++++++++++++- 6 files changed, 237 insertions(+), 2 deletions(-) diff --git a/text11.txt b/text11.txt index d204322..5859f9c 100644 --- a/text11.txt +++ b/text11.txt @@ -958,3 +958,64 @@ host_wasm_opfs_browser_smokes=ok 继续沿“单点只读入口”推进,把 `window.linuxCncIniPanelApi` 再收敛成一个更明确的 `getMachineSessionView()` 或 `getMachineSessionStateBundle()` 的稳定消费者契约,并开始只 在这个 bundle 上面叠控制页展示逻辑;仍不新增按钮、不把 CNC 语义搬进 JS。 + +十、2026-06-14 继续执行记录:INI panel control view helper + +本轮按“加快实质性推进”继续往控制网页界面的只读展示层推进,在 bundle 之上新增 +control view helper,让上层 UI 可以直接渲染 status 与 sections/rows。 + +完成内容: + +- `wasm-port/runtime/ui/ini-panel/panel-state-summary.js` 新增 + `createMachineSessionControlView(bundle)`; +- control view 返回: + - `status`; + - `sections`; + - readiness/session/run 三组 rows; +- `wasm-port/runtime/ui/ini-panel/app.js` 在 + `window.linuxCncIniPanelApi`、`window.getMachineSessionControlView()` 下暴露该 helper; +- `wasm-port/tests/ui/node/verify_ini_panel_state_summary.mjs` 覆盖 view model 输出结构; +- `wasm-port/tests/browser/ini_panel_smoke.html` 在真实 save、restore-load、run 流程后验证 + control view 的 status、section id、workflow row 和 canonical-event row; +- `wasm-port/docs/ui-panel-state-summary.md` 补充 control view helper 说明; +- 未新增按钮; +- 未解析 G-code; +- 未解释 canonical events; +- 未改变 OPFS/session persistence、LinuxCNC interpreter、tool、parameter、planner 或 + LinuxCNC-owned runtime semantics。 + +验证已通过: + +```bash +git diff --check +wasm-port/tests/ui/node/verify_ini_panel_state_summary.sh +wasm-port/tests/ui/node/verify_ui_node_smokes.sh +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh +wasm-port/tools/verify_vendor_sync.sh +wasm-port/tools/verify_no_standalone_cnc_semantics.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh +SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh +wasm-port/tests/host/verify_host_smokes.sh +``` + +关键输出: + +```text +ini_panel_state_summary_node_smoke=ok +ui_node_smokes=ok +browser_ini_opfs_smoke=ok +vendor sync up to date +standalone CNC semantics guard complete +interp_wasm_node_smoke=ok +sim_configs_wasm_node_inventory_executed=28 +sim_configs_wasm_node_inventory_passed=28 +sim_configs_wasm_node_inventory_skipped=131 +sim_configs_wasm_node_inventory_unexpected_fail=0 +host_wasm_opfs_browser_smokes=ok +``` + +下一步建议: + +继续推进实际控制网页界面的只读展示层。下一批建议新增一个极薄的 browser smoke 或 +文档化控制页消费示例,直接读取 `window.linuxCncIniPanelApi.getMachineSessionControlView()` +并渲染 sections;仍保持只读,不加控制按钮,不解析 G-code。 diff --git a/wasm-port/docs/ui-panel-state-summary.md b/wasm-port/docs/ui-panel-state-summary.md index 6233f51..557055c 100644 --- a/wasm-port/docs/ui-panel-state-summary.md +++ b/wasm-port/docs/ui-panel-state-summary.md @@ -22,6 +22,7 @@ For control-page polling, use `window.linuxCncIniPanelApi.getMachineSessionWorkflowStatus()`. It returns a smaller workflow-facing object derived from the same report data. For a single read call, use `window.linuxCncIniPanelApi.getMachineSessionStateBundle()`. +For direct rendering, use `window.linuxCncIniPanelApi.getMachineSessionControlView()`. ## `createIniPanelStateSummary(input)` @@ -142,6 +143,24 @@ It is the preferred single-entry helper for control-page polling and other upper-level UI consumers that want one stable read instead of stitching the three views together themselves. +## `createMachineSessionControlView(bundle)` + +This helper maps a bundle into UI-ready status and sections: + +```js +{ + status: { lastAction: "run-gcode", error: null, runStatus: "ok" }, + sections: [ + { id: "readiness", title: "Readiness", rows: [{ label: "INI", value: "..." }] }, + { id: "session", title: "Session", rows: [{ label: "Workflow", value: "..." }] }, + { id: "run", title: "Run", rows: [{ label: "Canonical events", value: 2 }] } + ] +} +``` + +It is a presentation mapping over the bundle only. It does not parse G-code, +canonical events, or LinuxCNC-owned runtime content. + ## Boundary Rules - Do not parse G-code text in this helper. diff --git a/wasm-port/runtime/ui/ini-panel/app.js b/wasm-port/runtime/ui/ini-panel/app.js index 5a481ed..83947d7 100644 --- a/wasm-port/runtime/ui/ini-panel/app.js +++ b/wasm-port/runtime/ui/ini-panel/app.js @@ -46,6 +46,7 @@ import { saveMachineSessionSnapshotWorkflow, } from "./session-workflow.js"; import { + createMachineSessionControlView, createMachineSessionStateSnapshot, createMachineSessionStateBundle, createMachineSessionStateReport, @@ -171,6 +172,10 @@ function getMachineSessionStateBundle() { return createMachineSessionStateBundle(window.linuxCncIniPanelMachineSessionState); } +function getMachineSessionControlView() { + return createMachineSessionControlView(getMachineSessionStateBundle()); +} + function updatePanelMachineSessionState(patch = {}) { panelMachineSessionState = createMachineSessionStateSnapshot({ ...panelMachineSessionState, @@ -185,11 +190,13 @@ function updatePanelMachineSessionState(patch = {}) { } window.linuxCncIniPanelApi = { + getMachineSessionControlView, getMachineSessionStateBundle, getMachineSessionStateReport, getMachineSessionStateReportExport, getMachineSessionWorkflowStatus, }; +window.getMachineSessionControlView = getMachineSessionControlView; window.getMachineSessionStateBundle = getMachineSessionStateBundle; window.getMachineSessionStateReport = getMachineSessionStateReport; window.getMachineSessionStateReportExport = getMachineSessionStateReportExport; diff --git a/wasm-port/runtime/ui/ini-panel/panel-state-summary.js b/wasm-port/runtime/ui/ini-panel/panel-state-summary.js index f3b89d0..e139905 100644 --- a/wasm-port/runtime/ui/ini-panel/panel-state-summary.js +++ b/wasm-port/runtime/ui/ini-panel/panel-state-summary.js @@ -140,3 +140,48 @@ export function createMachineSessionStateBundle(state = {}, options = {}) { workflowStatus, }; } + +export function createMachineSessionControlView(bundle = {}) { + const report = bundle.report ?? {}; + const workflowStatus = bundle.workflowStatus ?? {}; + const session = workflowStatus.session ?? report.session ?? {}; + const run = workflowStatus.run ?? report.run ?? {}; + return { + status: { + lastAction: workflowStatus.lastAction ?? report.status?.lastAction ?? null, + error: workflowStatus.error ?? report.status?.error ?? null, + runStatus: run.status ?? null, + }, + sections: [ + { + id: "readiness", + title: "Readiness", + rows: [ + { label: "INI", value: workflowStatus.readiness?.ini ?? report.readiness?.ini ?? null }, + { label: "Interpreter", value: workflowStatus.readiness?.interp ?? report.readiness?.interp ?? null }, + { label: "OPFS", value: workflowStatus.readiness?.opfs ?? report.readiness?.opfs ?? null }, + ], + }, + { + id: "session", + title: "Session", + rows: [ + { label: "Snapshot", value: session.snapshotLabel ?? null }, + { label: "Workflow", value: session.workflow ?? null }, + { label: "INI", value: session.ini ?? null }, + { label: "G-code", value: session.gcode ?? null }, + ], + }, + { + id: "run", + title: "Run", + rows: [ + { label: "Status", value: run.status ?? null }, + { label: "Canonical events", value: run.canonicalEventCount ?? 0 }, + { label: "Motion snapshots", value: run.motionSnapshotCount ?? 0 }, + { label: "INI WASM", value: run.iniWasmPath ?? null }, + ], + }, + ], + }; +} diff --git a/wasm-port/tests/browser/ini_panel_smoke.html b/wasm-port/tests/browser/ini_panel_smoke.html index 7189b17..8d28245 100644 --- a/wasm-port/tests/browser/ini_panel_smoke.html +++ b/wasm-port/tests/browser/ini_panel_smoke.html @@ -369,6 +369,7 @@ TOOL_TABLE = browser-tool.tbl ); const uiApi = uiDocument.defaultView.linuxCncIniPanelApi; if ( + !uiApi?.getMachineSessionControlView || !uiApi?.getMachineSessionStateBundle || !uiApi?.getMachineSessionStateReport || !uiApi?.getMachineSessionStateReportExport || @@ -830,6 +831,32 @@ TOOL_TABLE = browser-tool.tbl machineSessionStateBundle.workflowStatus.lastAction, "UI legacy machine session state bundle getter matches API namespace", ); + const machineSessionControlView = uiApi.getMachineSessionControlView(); + assertEqual( + machineSessionControlView.status.runStatus, + "ok", + "UI machine session control view run status", + ); + assertEqual( + machineSessionControlView.sections[0].id, + "readiness", + "UI machine session control view readiness section", + ); + assertEqual( + machineSessionControlView.sections[1].rows[1].value, + "save-session-snapshot", + "UI machine session control view session workflow row", + ); + assertEqual( + machineSessionControlView.sections[2].rows[1].value, + 2, + "UI machine session control view canonical event row", + ); + assertEqual( + uiDocument.defaultView.getMachineSessionControlView().status.lastAction, + machineSessionControlView.status.lastAction, + "UI legacy machine session control view getter matches API namespace", + ); assertEqual( uiDocument.defaultView.getMachineSessionStateReport().status.lastAction, machineSessionStateReport.status.lastAction, diff --git a/wasm-port/tests/ui/node/verify_ini_panel_state_summary.mjs b/wasm-port/tests/ui/node/verify_ini_panel_state_summary.mjs index 6367784..5dd551f 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_state_summary.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_state_summary.mjs @@ -2,6 +2,7 @@ import assert from "node:assert/strict"; import { createIniPanelStateSummary, + createMachineSessionControlView, createMachineSessionStateSnapshot, createMachineSessionStateBundle, createMachineSessionStateReport, @@ -473,17 +474,92 @@ assert.deepEqual( ); assert.deepEqual( + createMachineSessionControlView({ + report: expectedBundleReport, + export: { + filename: "machine-session-state-report.json", + mediaType: "application/json", + report: expectedBundleReport, + text: `${JSON.stringify(expectedBundleReport, null, 2)}\n`, + }, + workflowStatus: { + readiness: { + ini: "INI WASM: ready", + interp: "Interpreter WASM: ready", + opfs: "OPFS: ready", + }, + lastAction: "run-gcode", + error: null, + session: { + snapshotLabel: "ui-machine-session/ui-machine-session.json", + workflow: "save-session-snapshot", + ini: "/work/session-machine.ini", + parameters: null, + toolTable: null, + gcode: "linuxcnc/gcode/ui-session.ngc", + }, + run: { + status: "ok", + canonicalEventCount: 2, + motionSnapshotCount: 2, + iniWasmPath: null, + }, + }, + }), { + status: { + lastAction: "run-gcode", + error: null, + runStatus: "ok", + }, + sections: [ + { + id: "readiness", + title: "Readiness", + rows: [ + { label: "INI", value: "INI WASM: ready" }, + { label: "Interpreter", value: "Interpreter WASM: ready" }, + { label: "OPFS", value: "OPFS: ready" }, + ], + }, + { + id: "session", + title: "Session", + rows: [ + { label: "Snapshot", value: "ui-machine-session/ui-machine-session.json" }, + { label: "Workflow", value: "save-session-snapshot" }, + { label: "INI", value: "/work/session-machine.ini" }, + { label: "G-code", value: "linuxcnc/gcode/ui-session.ngc" }, + ], + }, + { + id: "run", + title: "Run", + rows: [ + { label: "Status", value: "ok" }, + { label: "Canonical events", value: 2 }, + { label: "Motion snapshots", value: 2 }, + { label: "INI WASM", value: null }, + ], + }, + ], + }, +); + +assert.deepEqual( + { + getMachineSessionControlView: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionControlView, + getMachineSessionStateBundle: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateBundle, getMachineSessionStateReport: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateReport, getMachineSessionStateReportExport: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateReportExport, getMachineSessionWorkflowStatus: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionWorkflowStatus, - getMachineSessionStateBundle: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateBundle, }, { + getMachineSessionControlView: "undefined", + getMachineSessionStateBundle: "undefined", getMachineSessionStateReport: "undefined", getMachineSessionStateReportExport: "undefined", getMachineSessionWorkflowStatus: "undefined", - getMachineSessionStateBundle: "undefined", }, );