diff --git a/text10.txt b/text10.txt index 0ec5d6a..f6ae877 100644 --- a/text10.txt +++ b/text10.txt @@ -478,3 +478,71 @@ host_wasm_opfs_browser_smokes=ok workflow:保存当前 INI、parameter/tool-table path 和可选 G-code snapshot,再通过 `loadMachineSessionSnapshot(...)` 恢复出待加载文件清单。范围仍限定 OPFS/filesystem/UI workflow,不解析或重写任何 LinuxCNC-owned CNC 语义。 + +五、2026-06-14 继续执行记录:INI panel session snapshot workflow + +本轮继续按“加快实质性推进铁律”推进可直接使用的 browser/UI workflow,把 machine +session snapshot save/load helper 接入 INI panel 的最小会话保存/恢复流程。 + +完成内容: + +- 在 `wasm-port/runtime/ui/ini-panel/app.js` 引入 + `saveMachineSessionSnapshot(...)` 与 `loadMachineSessionSnapshot(...)`; +- 新增固定 UI session snapshot id 与 filename: + `ui-machine-session/ui-machine-session.json`; +- 新增 `Save Session Snapshot` 控件: + - 保存当前编辑器 INI 到 OPFS machine files; + - 保存默认 parameter/tool-table text; + - 保存默认 G-code program; + - 生成并保存 machine session snapshot; + - 回填 INI、parameter、tool-table、G-code 和 snapshot path 字段; +- 新增 `Restore Session Snapshot` 控件: + - 通过 `loadMachineSessionSnapshot(...)` 读取并校验 snapshot; + - 从 OPFS machine files 恢复 INI 到编辑器; + - 回填 snapshot 中的待加载文件清单; +- 在 `wasm-port/runtime/ui/ini-panel/index.html` 增加两个按钮和 + `Session Snapshot` 状态字段; +- 在 browser INI panel smoke 中覆盖保存 snapshot、恢复 snapshot、字段回填和 INI + 文本恢复; +- 未改变 LinuxCNC INI parser、interpreter、parameter restore/save、tool-table load/save + 或 G-code 执行语义; +- 未改变 OPFS path model、generic snapshot envelope、file-service、machine-session + bridge 或 LinuxCNC-owned runtime semantics。 + +验证已通过: + +```bash +git diff --check +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh +wasm-port/tests/opfs/node/verify_file_service.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 +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_ini_opfs_smoke=ok +opfs_file_service_node_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 +browser_interp_smoke=ok +host_wasm_opfs_browser_smokes=ok +``` + +下一步建议: + +继续推进 browser/UI workflow 的实质能力。优先把 `Restore Session Snapshot` 后的文件清单 +与现有 `Load Machine Session` 串联成单个可执行入口,例如新增 +`Restore And Load Session`:先校验 snapshot,再把 OPFS INI/parameter/tool-table 加载到 +interpreter WASM FS,并保持 G-code path 可运行。范围仍限定 OPFS/session/UI 编排,不 +解析或改写任何 CNC 语义。 diff --git a/wasm-port/runtime/ui/ini-panel/app.js b/wasm-port/runtime/ui/ini-panel/app.js index f263f64..b0c033f 100644 --- a/wasm-port/runtime/ui/ini-panel/app.js +++ b/wasm-port/runtime/ui/ini-panel/app.js @@ -17,6 +17,10 @@ import { import { loadMachineSessionFromOpfs, } from "../../opfs/linuxcnc-machine-session-bridge.js"; +import { + loadMachineSessionSnapshot, + saveMachineSessionSnapshot, +} from "../../opfs/snapshot-store.js"; const SAMPLE_PATH = "../../../vendor/linuxcnc/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini"; @@ -44,6 +48,8 @@ const SESSION_WASM_FILES = { }; const GCODE_FILENAME = "ui-session.ngc"; const GCODE_WASM_FILE = "/work/ui-session.ngc"; +const SESSION_SNAPSHOT_ID = "ui-machine-session"; +const SESSION_SNAPSHOT_FILENAME = "ui-machine-session.json"; const DEFAULT_TOOL_TABLE = "T2 P7 Z3.125 D1.5 I12 J34 Q4 ;ui session tool\n"; const DEFAULT_PARAMETERS = [ "5161 0.0", @@ -96,6 +102,7 @@ const fields = { sessionParameters: document.getElementById("field-session-parameters"), sessionToolTable: document.getElementById("field-session-tool-table"), sessionGcode: document.getElementById("field-session-gcode"), + sessionSnapshot: document.getElementById("field-session-snapshot"), runStatus: document.getElementById("field-run-status"), fiveaxisRemap: document.getElementById("field-fiveaxis-remap"), }; @@ -417,6 +424,72 @@ 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, + }); + await saveGcodeProgram(GCODE_FILENAME, DEFAULT_GCODE); + const snapshot = await saveMachineSessionSnapshot( + SESSION_SNAPSHOT_ID, + MACHINE_ID, + { + filename: SESSION_SNAPSHOT_FILENAME, + gcodeFilename: GCODE_FILENAME, + metadata: { source: "ini-panel" }, + }, + ); + 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", `${SESSION_SNAPSHOT_ID}/${SESSION_SNAPSHOT_FILENAME}`); + setLog( + [ + "Saved machine session snapshot to OPFS.", + `Snapshot: ${SESSION_SNAPSHOT_ID}/${SESSION_SNAPSHOT_FILENAME}`, + `INI: ${snapshot.payload.files.ini}`, + `Parameter file: ${snapshot.payload.files.parameters}`, + `Tool table file: ${snapshot.payload.files.toolTable}`, + `G-code: ${snapshot.payload.files.gcode}`, + ].join("\n"), + ); + } catch (error) { + setLog(`Machine session snapshot save failed: ${error.message}`, true); + } +}); + +document.getElementById("restore-session-snapshot").addEventListener("click", async () => { + try { + const snapshot = await loadMachineSessionSnapshot( + SESSION_SNAPSHOT_ID, + MACHINE_ID, + { filename: SESSION_SNAPSHOT_FILENAME }, + ); + const files = await loadMachineTextFiles(MACHINE_ID); + editor.value = files.ini; + 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", `${snapshot.sessionId}/${SESSION_SNAPSHOT_FILENAME}`); + setLog( + [ + "Restored machine session snapshot from OPFS.", + `Snapshot: ${snapshot.sessionId}/${SESSION_SNAPSHOT_FILENAME}`, + `INI: ${snapshot.payload.files.ini}`, + `Parameter file: ${snapshot.payload.files.parameters}`, + `Tool table file: ${snapshot.payload.files.toolTable}`, + `G-code: ${snapshot.payload.files.gcode ?? "-"}`, + ].join("\n"), + ); + } catch (error) { + setLog(`Machine session snapshot restore failed: ${error.message}`, true); + } +}); + document.getElementById("load-session").addEventListener("click", async () => { try { loadedSession = await loadMachineSessionFromOpfs( diff --git a/wasm-port/runtime/ui/ini-panel/index.html b/wasm-port/runtime/ui/ini-panel/index.html index 7620c50..3db7f97 100644 --- a/wasm-port/runtime/ui/ini-panel/index.html +++ b/wasm-port/runtime/ui/ini-panel/index.html @@ -228,6 +228,8 @@ + + @@ -272,6 +274,8 @@
-
Session G-code
-
+
Session Snapshot
+
-
Run Status
-
5-Axis Remap
diff --git a/wasm-port/tests/browser/ini_panel_smoke.html b/wasm-port/tests/browser/ini_panel_smoke.html index a2bc884..a0a8da7 100644 --- a/wasm-port/tests/browser/ini_panel_smoke.html +++ b/wasm-port/tests/browser/ini_panel_smoke.html @@ -379,6 +379,40 @@ TOOL_TABLE = browser-tool.tbl () => uiDocument.getElementById("log")?.textContent.includes("Saved machine text files"), "machine file save", ); + uiDocument.getElementById("save-session-snapshot").click(); + await waitFor( + () => uiDocument.getElementById("log")?.textContent.includes("Saved machine session snapshot"), + "machine session snapshot save", + ); + assertEqual( + uiDocument.getElementById("field-session-snapshot").textContent, + "ui-machine-session/ui-machine-session.json", + "UI session snapshot path", + ); + assertEqual( + uiDocument.getElementById("field-session-ini").textContent, + "linuxcnc/machines/xyzab-tdr/machine.ini", + "UI snapshot INI OPFS path", + ); + assertEqual( + uiDocument.getElementById("field-session-gcode").textContent, + "linuxcnc/gcode/ui-session.ngc", + "UI snapshot G-code OPFS path", + ); + uiDocument.getElementById("ini-editor").value = ""; + uiDocument.getElementById("restore-session-snapshot").click(); + await waitFor( + () => uiDocument.getElementById("log")?.textContent.includes("Restored machine session snapshot"), + "machine session snapshot restore", + ); + assertEqual( + uiDocument.getElementById("field-session-snapshot").textContent, + "ui-machine-session/ui-machine-session.json", + "UI restored session snapshot path", + ); + if (!uiDocument.getElementById("ini-editor").value.includes("MACHINE = browser-smoke")) { + throw new Error("UI restored session snapshot did not reload INI text"); + } uiDocument.getElementById("load-session").click(); await waitFor( () => uiDocument.getElementById("log")?.textContent.includes("Loaded machine session"),