From e6f55d775f6617f28ded0c89d60b95d7b70a7b7d Mon Sep 17 00:00:00 2001 From: wangdequan Date: Sun, 14 Jun 2026 22:34:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A8=E8=BF=9B=20INI=20=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=E7=8A=B6=E6=80=81=20bundle=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- text11.txt | 62 ++++++++++++ wasm-port/docs/ui-panel-state-summary.md | 18 ++++ wasm-port/runtime/ui/ini-panel/app.js | 7 ++ .../ui/ini-panel/panel-state-summary.js | 11 +++ wasm-port/tests/browser/ini_panel_smoke.html | 22 +++++ .../node/verify_ini_panel_state_summary.mjs | 96 +++++++++++++++++++ 6 files changed, 216 insertions(+) diff --git a/text11.txt b/text11.txt index 855ddf1..d204322 100644 --- a/text11.txt +++ b/text11.txt @@ -896,3 +896,65 @@ host_wasm_opfs_browser_smokes=ok 继续沿 `window.linuxCncIniPanelApi` 收敛控制面。下一批建议把当前散落的 report/export/ status getter 再包成一个明确的 `getMachineSessionStateBundle()` 或 `getMachineSessionView()` 只读入口,给控制网页界面一个单点轮询对象;仍保持只读,不加按钮,不扩大 CNC 语义边界。 + +九、2026-06-14 继续执行记录:INI panel state bundle helper + +本轮继续沿 `window.linuxCncIniPanelApi` 收敛控制面,把现有 report/export/status 入口 +聚合成一个单点只读 bundle helper,给控制网页界面或上层 SDK 一个更稳的轮询对象。 + +完成内容: + +- `wasm-port/runtime/ui/ini-panel/panel-state-summary.js` 新增 + `createMachineSessionStateBundle(state, options)`; +- bundle helper 返回: + - `report`; + - `export`; + - `workflowStatus`; +- `wasm-port/runtime/ui/ini-panel/app.js` 在 + `window.linuxCncIniPanelApi`、`window.getMachineSessionStateBundle()` 下暴露该 helper; +- `wasm-port/tests/ui/node/verify_ini_panel_state_summary.mjs` 覆盖 bundle 与单项 getter 的 + 结构一致性; +- `wasm-port/tests/browser/ini_panel_smoke.html` 在真实 save、restore-load、run 流程后验证 + bundle,确认其 report/export/status 与单项 getter 一致; +- `wasm-port/docs/ui-panel-state-summary.md` 补充 bundle helper 说明,并明确它是控制页的 +推荐单点只读入口; +- 未新增按钮; +- 未解析 G-code; +- 未改变 OPFS/session persistence、LinuxCNC interpreter、canonical-event 语义、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 +``` + +下一步建议: + +继续沿“单点只读入口”推进,把 `window.linuxCncIniPanelApi` 再收敛成一个更明确的 +`getMachineSessionView()` 或 `getMachineSessionStateBundle()` 的稳定消费者契约,并开始只 +在这个 bundle 上面叠控制页展示逻辑;仍不新增按钮、不把 CNC 语义搬进 JS。 diff --git a/wasm-port/docs/ui-panel-state-summary.md b/wasm-port/docs/ui-panel-state-summary.md index 0a2bf75..6233f51 100644 --- a/wasm-port/docs/ui-panel-state-summary.md +++ b/wasm-port/docs/ui-panel-state-summary.md @@ -21,6 +21,7 @@ shims. 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()`. ## `createIniPanelStateSummary(input)` @@ -124,6 +125,23 @@ This helper derives a lightweight status object for upper-level control pages: It is intended for polling or status panels that need current UI workflow state without parsing logs, DOM nodes, or transient window state. +## `createMachineSessionStateBundle(state, options)` + +This helper packages the current report, export payload, and workflow status +into one read-only object: + +```js +{ + report: { ... }, + export: { filename: "...", mediaType: "application/json", report: { ... }, text: "{...}\n" }, + workflowStatus: { readiness: { ... }, lastAction: "...", error: null, session: { ... }, run: { ... } } +} +``` + +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. + ## 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 ad897f7..5a481ed 100644 --- a/wasm-port/runtime/ui/ini-panel/app.js +++ b/wasm-port/runtime/ui/ini-panel/app.js @@ -47,6 +47,7 @@ import { } from "./session-workflow.js"; import { createMachineSessionStateSnapshot, + createMachineSessionStateBundle, createMachineSessionStateReport, createMachineSessionStateReportExport, createMachineSessionWorkflowStatus, @@ -166,6 +167,10 @@ function getMachineSessionWorkflowStatus() { return createMachineSessionWorkflowStatus(window.linuxCncIniPanelMachineSessionState); } +function getMachineSessionStateBundle() { + return createMachineSessionStateBundle(window.linuxCncIniPanelMachineSessionState); +} + function updatePanelMachineSessionState(patch = {}) { panelMachineSessionState = createMachineSessionStateSnapshot({ ...panelMachineSessionState, @@ -180,10 +185,12 @@ function updatePanelMachineSessionState(patch = {}) { } window.linuxCncIniPanelApi = { + getMachineSessionStateBundle, getMachineSessionStateReport, getMachineSessionStateReportExport, getMachineSessionWorkflowStatus, }; +window.getMachineSessionStateBundle = getMachineSessionStateBundle; window.getMachineSessionStateReport = getMachineSessionStateReport; window.getMachineSessionStateReportExport = getMachineSessionStateReportExport; window.getMachineSessionWorkflowStatus = getMachineSessionWorkflowStatus; 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 f62f0db..f3b89d0 100644 --- a/wasm-port/runtime/ui/ini-panel/panel-state-summary.js +++ b/wasm-port/runtime/ui/ini-panel/panel-state-summary.js @@ -129,3 +129,14 @@ export function createMachineSessionWorkflowStatus(state = {}) { run: report.run, }; } + +export function createMachineSessionStateBundle(state = {}, options = {}) { + const report = createMachineSessionStateReport(state); + const exportPayload = createMachineSessionStateReportExport(state, options); + const workflowStatus = createMachineSessionWorkflowStatus(state); + return { + report, + export: exportPayload, + workflowStatus, + }; +} diff --git a/wasm-port/tests/browser/ini_panel_smoke.html b/wasm-port/tests/browser/ini_panel_smoke.html index 8a1b61d..7189b17 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?.getMachineSessionStateBundle || !uiApi?.getMachineSessionStateReport || !uiApi?.getMachineSessionStateReportExport || !uiApi?.getMachineSessionWorkflowStatus @@ -808,6 +809,27 @@ TOOL_TABLE = browser-tool.tbl 2, "UI machine session workflow status canonical event count", ); + const machineSessionStateBundle = uiApi.getMachineSessionStateBundle(); + assertEqual( + machineSessionStateBundle.report.status.lastAction, + machineSessionStateReport.status.lastAction, + "UI machine session state bundle report last action", + ); + assertEqual( + machineSessionStateBundle.export.text, + machineSessionStateReportExport.text, + "UI machine session state bundle export text", + ); + assertEqual( + machineSessionStateBundle.workflowStatus.run.canonicalEventCount, + machineSessionWorkflowStatus.run.canonicalEventCount, + "UI machine session state bundle workflow status canonical event count", + ); + assertEqual( + uiDocument.defaultView.getMachineSessionStateBundle().workflowStatus.lastAction, + machineSessionStateBundle.workflowStatus.lastAction, + "UI legacy machine session state bundle 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 2701248..6367784 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 @@ -3,6 +3,7 @@ import assert from "node:assert/strict"; import { createIniPanelStateSummary, createMachineSessionStateSnapshot, + createMachineSessionStateBundle, createMachineSessionStateReport, createMachineSessionStateReportExport, createMachineSessionWorkflowStatus, @@ -378,16 +379,111 @@ assert.deepEqual( }, ); +const expectedBundleReport = { + readiness: { + ini: "INI WASM: ready", + interp: "Interpreter WASM: ready", + opfs: "OPFS: ready", + }, + 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", + }, + loaded: { + iniWasmPath: null, + parameterWasmPath: null, + toolTableWasmPath: null, + }, + program: { + source: null, + opfsPath: null, + wasmPath: null, + }, + run: { + status: "ok", + canonicalEventCount: 2, + motionSnapshotCount: 2, + iniWasmPath: null, + }, + status: { + lastAction: "run-gcode", + error: null, + fiveaxisRemap: null, + }, +}; + +assert.deepEqual( + createMachineSessionStateBundle({ + badges: { + ini: "INI WASM: ready", + interp: "Interpreter WASM: ready", + opfs: "OPFS: ready", + }, + fields: { + sessionSnapshot: "ui-machine-session/ui-machine-session.json", + sessionIni: "/work/session-machine.ini", + sessionGcode: "linuxcnc/gcode/ui-session.ngc", + runStatus: "ok", + runWorkflow: "save-session-snapshot", + }, + run: { + runStatus: "ok", + canonicalEventCount: 2, + motionSnapshotCount: 2, + }, + lastAction: "run-gcode", + error: null, + }), + { + 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, + }, + }, + }, +); + assert.deepEqual( { getMachineSessionStateReport: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateReport, getMachineSessionStateReportExport: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateReportExport, getMachineSessionWorkflowStatus: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionWorkflowStatus, + getMachineSessionStateBundle: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateBundle, }, { getMachineSessionStateReport: "undefined", getMachineSessionStateReportExport: "undefined", getMachineSessionWorkflowStatus: "undefined", + getMachineSessionStateBundle: "undefined", }, );