From 4e4a9c667f3bf36aebefe2e98331f4f806dc48c3 Mon Sep 17 00:00:00 2001 From: wangdequan Date: Sun, 14 Jun 2026 21:21:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A8=E8=BF=9B=20INI=20=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=20session=20snapshot=20workflow=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- text10.txt | 160 +++++++++++++----- wasm-port/docs/ui-session-summary-helpers.md | 42 +++++ wasm-port/runtime/ui/ini-panel/app.js | 46 +++-- .../runtime/ui/ini-panel/session-workflow.js | 65 +++++++ .../verify_ini_panel_session_workflow.mjs | 107 ++++++++++++ .../node/verify_ini_panel_session_workflow.sh | 6 + .../tests/ui/node/verify_ui_node_smokes.sh | 1 + 7 files changed, 356 insertions(+), 71 deletions(-) create mode 100644 wasm-port/runtime/ui/ini-panel/session-workflow.js create mode 100644 wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs create mode 100755 wasm-port/tests/ui/node/verify_ini_panel_session_workflow.sh diff --git a/text10.txt b/text10.txt index a4eb710..a3c7388 100644 --- a/text10.txt +++ b/text10.txt @@ -1540,52 +1540,6 @@ browser_interp_smoke=ok 抽取为纯 helper 并接入 `verify_ui_node_smokes.sh`;保持 helper 只描述 host/runtime 边界, 不扩展 CNC 语义。 -二十七、2026-06-14 继续执行记录:browser explicit session readback path helper - -本轮继续沿 OPFS/session/UI boundary 推进,把 browser interpreter smoke 中 ini-named 和 -explicit session 的 saved parameter / backup / tool-table readback path 统一成一个小 helper, -只收拢已有 boundary 返回值的命名,不改变 readback 行为。 - -完成内容: - -- 在 `wasm-port/tests/browser/interp_smoke.html` 新增 - `opfsSessionSavedReadbackPaths(session, savedParameters)`; -- helper 只返回: - - session.parameters.opfsPath; - - savedParameters.backupOpfsPath; - - session.toolTable.opfsPath; -- `opfs_saved_ini_named_parameter_text`、 - `opfs_saved_ini_named_parameter_backup_text`、 - `opfs_saved_ini_named_tool_table_text`、 - `opfs_saved_explicit_parameter_text`、 - `opfs_saved_explicit_parameter_backup_text`、 - `opfs_saved_explicit_tool_table_text` - 改为复用该 helper; -- 未改变参数值、tool-table 值、INI 内容、OPFS/WASM path 字符串、file-service、 - path-model、SDK planner、interpreter、INI、tool、parameter 或 LinuxCNC-owned runtime - semantics。 - -验证已通过: - -```bash -git diff --check -SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_interp_browser.sh -wasm-port/tests/host/verify_host_smokes.sh -``` - -关键输出: - -```text -browser_interp_smoke=ok -host_wasm_opfs_browser_smokes=ok -``` - -下一步建议: - -继续沿 browser/OPFS test glue 推进。优先查看 `verifyOpfsReadback(...)` 周围是否还有 -“路径 + 期望行”成组重复,或者 `saveMachineTextFiles(...)` 相关的 machine text store path -断言是否还能再收一层小 helper;保持只做测试胶水和路径命名,不扩展 CNC 语义。 - 二十二、2026-06-14 继续执行记录:INI panel session load summary helper 本轮继续沿 OPFS/session/UI boundary 推进,把 machine session load 的 OPFS/WASM 映射 @@ -1902,3 +1856,117 @@ host_wasm_opfs_browser_smokes=ok `loadedIniOverrideSession.toolTable.opfsPath`。只处理 browser/OPFS test glue,不改变 参数值、tool-table 值、INI 内容、OPFS/WASM path 字符串、file-service、path-model、SDK planner、interpreter、INI、tool、parameter 或 LinuxCNC-owned runtime semantics。 + +二十七、2026-06-14 继续执行记录:browser explicit session readback path helper + +本轮继续沿 OPFS/session/UI boundary 推进,把 browser interpreter smoke 中 ini-named 和 +explicit session 的 saved parameter / backup / tool-table readback path 统一成一个小 helper, +只收拢已有 boundary 返回值的命名,不改变 readback 行为。 + +完成内容: + +- 在 `wasm-port/tests/browser/interp_smoke.html` 新增 + `opfsSessionSavedReadbackPaths(session, savedParameters)`; +- helper 只返回: + - session.parameters.opfsPath; + - savedParameters.backupOpfsPath; + - session.toolTable.opfsPath; +- `opfs_saved_ini_named_parameter_text`、 + `opfs_saved_ini_named_parameter_backup_text`、 + `opfs_saved_ini_named_tool_table_text`、 + `opfs_saved_explicit_parameter_text`、 + `opfs_saved_explicit_parameter_backup_text`、 + `opfs_saved_explicit_tool_table_text` + 改为复用该 helper; +- 未改变参数值、tool-table 值、INI 内容、OPFS/WASM path 字符串、file-service、 + path-model、SDK planner、interpreter、INI、tool、parameter 或 LinuxCNC-owned runtime + semantics。 + +验证已通过: + +```bash +git diff --check +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_interp_browser.sh +wasm-port/tests/host/verify_host_smokes.sh +``` + +关键输出: + +```text +browser_interp_smoke=ok +host_wasm_opfs_browser_smokes=ok +``` + +下一步建议: + +继续沿 browser/OPFS test glue 推进。优先查看 `verifyOpfsReadback(...)` 周围是否还有 +“路径 + 期望行”成组重复,或者 `saveMachineTextFiles(...)` 相关的 machine text store path +断言是否还能再收一层小 helper;保持只做测试胶水和路径命名,不扩展 CNC 语义。 + +二十八、2026-06-14 继续执行记录:INI panel session snapshot workflow helper + +本轮按“加快实质性推进铁律”转向可复用 UI/session persistence 能力,把 INI panel 的 +save-session-snapshot 按钮流程抽成一个可调用 workflow helper,而不是继续做局部路径 +常量化。 + +完成内容: + +- 新增 `wasm-port/runtime/ui/ini-panel/session-workflow.js`; +- 导出: + - `saveMachineSessionSnapshotWorkflow(input)`; + - `createSessionSnapshotFieldState(summary)`; + - `sessionSnapshotSaveLogLines(summary)`; +- workflow helper 执行完整 host-boundary 保存链路: + - 写入当前 INI/tool/parameter machine text files; + - 写入默认 G-code program; + - 保存 machine session snapshot; + - 返回 snapshot summary、UI field state 和 log lines; +- `wasm-port/runtime/ui/ini-panel/app.js` 的 `Save Session Snapshot` 按钮改为调用该 + workflow helper,按钮处理器只负责 field/log 渲染; +- 新增 `wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs` 和 shell wrapper; +- `wasm-port/tests/ui/node/verify_ui_node_smokes.sh` 纳入 session workflow smoke; +- `wasm-port/docs/ui-session-summary-helpers.md` 增加 session workflow API、返回结构和 + 验证入口; +- 未改变 OPFS bridge、snapshot-store、machine-file-store、interpreter run API、G-code 文本、 + tool-table 文本、parameter 文本或 LinuxCNC-owned runtime semantics。 + +验证已通过: + +```bash +git diff --check +wasm-port/tests/ui/node/verify_ini_panel_session_workflow.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_session_workflow_node_smoke=ok +ini_panel_run_summary_node_smoke=ok +ini_panel_session_summary_node_smoke=ok +ini_panel_machine_file_summary_node_smoke=ok +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 +``` + +下一步建议: + +继续按“实质性能力优先”推进,不再回到零散 path guard。优先把 +`Restore Session Snapshot` 与 `Restore And Load Session` 也抽成 session workflow helper, +让 restore、load、field state、summary/log lines 走同一套可调用 API;完成后浏览器 UI +仍应通过真实 OPFS/session persistence workflow 验证,且不改变 LinuxCNC-owned CNC 语义。 diff --git a/wasm-port/docs/ui-session-summary-helpers.md b/wasm-port/docs/ui-session-summary-helpers.md index d6e9edf..9cef416 100644 --- a/wasm-port/docs/ui-session-summary-helpers.md +++ b/wasm-port/docs/ui-session-summary-helpers.md @@ -8,6 +8,9 @@ for summarizing machine session snapshot state. for machine-session load state. These helpers are pure so browser UI panels, SDK-facing wrappers, and Node smoke tests can share the same data shape without parsing log text. +`runtime/ui/ini-panel/session-workflow.js` contains the reusable UI workflow for +saving the machine text files, default G-code, and machine session snapshot as +one host-boundary operation. The helpers do not implement CNC behavior. G-code execution, canonical events, tool handling, parameters, kinematics, and planner behavior remain owned by the @@ -53,6 +56,42 @@ The returned summary has this shape: } ``` +## `saveMachineSessionSnapshotWorkflow(input)` + +The workflow writes the current INI/tool/parameter text files, writes the +default G-code program, saves the machine session snapshot, and returns the +snapshot summary, field state, and log lines for UI consumers. + +The persistence functions are injected by the caller: + +```js +{ + saveMachineTextFiles, + saveGcodeProgram, + saveMachineSessionSnapshot +} +``` + +The returned object has this shape: + +```js +{ + snapshot: { ... }, + summary: { snapshotLabel: "...", workflow: "save-session-snapshot" }, + fields: { + sessionIni: "linuxcnc/machines/xyzab-tdr/machine.ini", + sessionParameters: "linuxcnc/machines/xyzab-tdr/linuxcnc.var", + sessionToolTable: "linuxcnc/machines/xyzab-tdr/tool.tbl", + sessionGcode: "linuxcnc/gcode/ui-session.ngc", + sessionSnapshot: "ui-machine-session/ui-machine-session.json" + }, + logLines: [ + "Snapshot: ui-machine-session/ui-machine-session.json", + "Workflow: save-session-snapshot" + ] +} +``` + ## Log Helpers - `sessionSnapshotSummaryLogLines(summary)` renders snapshot label, workflow, @@ -61,6 +100,8 @@ The returned summary has this shape: save/restore log summaries. - `machineSessionLoadLogLines(summary)` renders the interpreter/session OPFS-to-WASM mapping and captured result lines. +- `sessionSnapshotSaveLogLines(summary)` renders the save-workflow snapshot + paths used by the INI panel. ## Boundary Rules @@ -76,6 +117,7 @@ Run the focused Node smoke after changing these helpers: ```bash wasm-port/tests/ui/node/verify_ini_panel_session_summary.sh +wasm-port/tests/ui/node/verify_ini_panel_session_workflow.sh ``` The aggregate UI Node smoke is: diff --git a/wasm-port/runtime/ui/ini-panel/app.js b/wasm-port/runtime/ui/ini-panel/app.js index a09f24d..afa70b2 100644 --- a/wasm-port/runtime/ui/ini-panel/app.js +++ b/wasm-port/runtime/ui/ini-panel/app.js @@ -41,6 +41,9 @@ import { sessionSnapshotMetadataLogLines, sessionSnapshotSummaryLogLines, } from "./session-summary.js"; +import { + saveMachineSessionSnapshotWorkflow, +} from "./session-workflow.js"; const SAMPLE_PATH = "../../../vendor/linuxcnc/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini"; @@ -566,35 +569,28 @@ document.getElementById("save-machine-files").addEventListener("click", async () document.getElementById("save-session-snapshot").addEventListener("click", async () => { try { - await saveMachineTextFiles(MACHINE_ID, { - ini: editor.value, - toolTable: DEFAULT_TOOL_TABLE, - parameters: DEFAULT_PARAMETERS, + const workflow = await saveMachineSessionSnapshotWorkflow({ + machineId: MACHINE_ID, + snapshotId: UI_SESSION.snapshotId, + snapshotFilename: UI_SESSION.snapshotFilename, + snapshotLabel: sessionSnapshotLabel(UI_SESSION), + iniText: editor.value, + toolTableText: DEFAULT_TOOL_TABLE, + parameterText: DEFAULT_PARAMETERS, + gcodeFilename: UI_SESSION.defaultGcodeFilename, + gcodeText: DEFAULT_GCODE, + metadata: sessionSnapshotMetadata(), + saveMachineTextFiles, + saveGcodeProgram, + saveMachineSessionSnapshot, }); - await saveGcodeProgram(UI_SESSION.defaultGcodeFilename, DEFAULT_GCODE); - const snapshot = await saveMachineSessionSnapshot( - UI_SESSION.snapshotId, - MACHINE_ID, - { - filename: UI_SESSION.snapshotFilename, - gcodeFilename: UI_SESSION.defaultGcodeFilename, - metadata: sessionSnapshotMetadata(), - }, - ); - setField("sessionIni", snapshot.payload.files.ini); - setField("sessionParameters", snapshot.payload.files.parameters); - setField("sessionToolTable", snapshot.payload.files.toolTable); - setField("sessionGcode", snapshot.payload.files.gcode); - setField("sessionSnapshot", sessionSnapshotLabel(UI_SESSION)); - const summary = createSessionSnapshotSummary(snapshot, sessionSnapshotLabel(UI_SESSION)); + for (const [name, value] of Object.entries(workflow.fields)) { + setField(name, value); + } setLog( [ "Saved machine session snapshot to OPFS.", - ...sessionSnapshotSummaryLogLines(summary), - `INI: ${summary.iniOpfsPath}`, - `Parameter file: ${summary.parameterOpfsPath}`, - `Tool table file: ${summary.toolTableOpfsPath}`, - `G-code: ${summary.gcodeOpfsPath}`, + ...workflow.logLines, ].join("\n"), ); } catch (error) { diff --git a/wasm-port/runtime/ui/ini-panel/session-workflow.js b/wasm-port/runtime/ui/ini-panel/session-workflow.js new file mode 100644 index 0000000..da1e36f --- /dev/null +++ b/wasm-port/runtime/ui/ini-panel/session-workflow.js @@ -0,0 +1,65 @@ +import { + createSessionSnapshotSummary, + sessionSnapshotSummaryLogLines, +} from "./session-summary.js"; + +export function createSessionSnapshotFieldState(summary) { + return { + sessionIni: summary.iniOpfsPath, + sessionParameters: summary.parameterOpfsPath, + sessionToolTable: summary.toolTableOpfsPath, + sessionGcode: summary.gcodeOpfsPath, + sessionSnapshot: summary.snapshotLabel, + }; +} + +export function sessionSnapshotSaveLogLines(summary) { + return [ + ...sessionSnapshotSummaryLogLines(summary), + `INI: ${summary.iniOpfsPath}`, + `Parameter file: ${summary.parameterOpfsPath}`, + `Tool table file: ${summary.toolTableOpfsPath}`, + `G-code: ${summary.gcodeOpfsPath}`, + ]; +} + +export async function saveMachineSessionSnapshotWorkflow({ + machineId, + snapshotId, + snapshotFilename, + snapshotLabel, + iniText, + toolTableText, + parameterText, + gcodeFilename, + gcodeText, + metadata, + saveMachineTextFiles, + saveGcodeProgram, + saveMachineSessionSnapshot, +}) { + await Promise.all([ + saveMachineTextFiles(machineId, { + ini: iniText, + toolTable: toolTableText, + parameters: parameterText, + }), + saveGcodeProgram(gcodeFilename, gcodeText), + ]); + const snapshot = await saveMachineSessionSnapshot( + snapshotId, + machineId, + { + filename: snapshotFilename, + gcodeFilename, + metadata, + }, + ); + const summary = createSessionSnapshotSummary(snapshot, snapshotLabel); + return { + snapshot, + summary, + fields: createSessionSnapshotFieldState(summary), + logLines: sessionSnapshotSaveLogLines(summary), + }; +} diff --git a/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs b/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs new file mode 100644 index 0000000..949ed87 --- /dev/null +++ b/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs @@ -0,0 +1,107 @@ +import assert from "node:assert/strict"; + +import { + saveMachineSessionSnapshotWorkflow, +} from "../../../runtime/ui/ini-panel/session-workflow.js"; + +const calls = []; +const workflow = await saveMachineSessionSnapshotWorkflow({ + machineId: "xyzab-tdr", + snapshotId: "ui-machine-session", + snapshotFilename: "ui-machine-session.json", + snapshotLabel: "ui-machine-session/ui-machine-session.json", + iniText: "[EMC]\nMACHINE = xyzab-tdr\n", + toolTableText: "T2 P7 Z3.125 D1.5 I12 J34 Q4 ;ui session tool\n", + parameterText: "5161 0.0\n", + gcodeFilename: "ui-session.ngc", + gcodeText: "G0 X1.0 Y2.0 (Comment)\nG1 X3.0 Y4.0 F120.0\n", + metadata: { + source: "ini-panel", + workflow: "save-session-snapshot", + snapshotLabel: "ui-machine-session/ui-machine-session.json", + defaultGcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc", + }, + saveMachineTextFiles: async (machineId, files) => { + calls.push(["saveMachineTextFiles", machineId, files]); + }, + saveGcodeProgram: async (filename, text) => { + calls.push(["saveGcodeProgram", filename, text]); + }, + saveMachineSessionSnapshot: async (snapshotId, machineId, options) => { + calls.push(["saveMachineSessionSnapshot", snapshotId, machineId, options]); + return { + sessionId: snapshotId, + metadata: options.metadata, + payload: { + files: { + ini: "linuxcnc/machines/xyzab-tdr/machine.ini", + parameters: "linuxcnc/machines/xyzab-tdr/linuxcnc.var", + toolTable: "linuxcnc/machines/xyzab-tdr/tool.tbl", + gcode: "linuxcnc/gcode/ui-session.ngc", + }, + }, + }; + }, +}); + +assert.deepEqual(calls, [ + [ + "saveMachineTextFiles", + "xyzab-tdr", + { + ini: "[EMC]\nMACHINE = xyzab-tdr\n", + toolTable: "T2 P7 Z3.125 D1.5 I12 J34 Q4 ;ui session tool\n", + parameters: "5161 0.0\n", + }, + ], + [ + "saveGcodeProgram", + "ui-session.ngc", + "G0 X1.0 Y2.0 (Comment)\nG1 X3.0 Y4.0 F120.0\n", + ], + [ + "saveMachineSessionSnapshot", + "ui-machine-session", + "xyzab-tdr", + { + filename: "ui-machine-session.json", + gcodeFilename: "ui-session.ngc", + metadata: { + source: "ini-panel", + workflow: "save-session-snapshot", + snapshotLabel: "ui-machine-session/ui-machine-session.json", + defaultGcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc", + }, + }, + ], +]); + +assert.deepEqual(workflow.summary, { + snapshotLabel: "ui-machine-session/ui-machine-session.json", + workflow: "save-session-snapshot", + defaultGcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc", + iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini", + parameterOpfsPath: "linuxcnc/machines/xyzab-tdr/linuxcnc.var", + toolTableOpfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl", + gcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc", +}); + +assert.deepEqual(workflow.fields, { + sessionIni: "linuxcnc/machines/xyzab-tdr/machine.ini", + sessionParameters: "linuxcnc/machines/xyzab-tdr/linuxcnc.var", + sessionToolTable: "linuxcnc/machines/xyzab-tdr/tool.tbl", + sessionGcode: "linuxcnc/gcode/ui-session.ngc", + sessionSnapshot: "ui-machine-session/ui-machine-session.json", +}); + +assert.deepEqual(workflow.logLines, [ + "Snapshot: ui-machine-session/ui-machine-session.json", + "Workflow: save-session-snapshot", + "Default G-code: linuxcnc/gcode/ui-session.ngc", + "INI: linuxcnc/machines/xyzab-tdr/machine.ini", + "Parameter file: linuxcnc/machines/xyzab-tdr/linuxcnc.var", + "Tool table file: linuxcnc/machines/xyzab-tdr/tool.tbl", + "G-code: linuxcnc/gcode/ui-session.ngc", +]); + +console.log("ini_panel_session_workflow_node_smoke=ok"); diff --git a/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.sh b/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.sh new file mode 100755 index 0000000..9935598 --- /dev/null +++ b/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" + +node "$ROOT_DIR/tests/ui/node/verify_ini_panel_session_workflow.mjs" diff --git a/wasm-port/tests/ui/node/verify_ui_node_smokes.sh b/wasm-port/tests/ui/node/verify_ui_node_smokes.sh index 3fc0ff3..34c95ba 100755 --- a/wasm-port/tests/ui/node/verify_ui_node_smokes.sh +++ b/wasm-port/tests/ui/node/verify_ui_node_smokes.sh @@ -5,6 +5,7 @@ ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" "$ROOT_DIR/tests/ui/node/verify_ini_panel_run_summary.sh" "$ROOT_DIR/tests/ui/node/verify_ini_panel_session_summary.sh" +"$ROOT_DIR/tests/ui/node/verify_ini_panel_session_workflow.sh" "$ROOT_DIR/tests/ui/node/verify_ini_panel_machine_file_summary.sh" "$ROOT_DIR/tests/ui/node/verify_ini_panel_state_summary.sh"