推进 INI 面板会话快照工作流
This commit is contained in:
68
text10.txt
68
text10.txt
@@ -478,3 +478,71 @@ host_wasm_opfs_browser_smokes=ok
|
|||||||
workflow:保存当前 INI、parameter/tool-table path 和可选 G-code snapshot,再通过
|
workflow:保存当前 INI、parameter/tool-table path 和可选 G-code snapshot,再通过
|
||||||
`loadMachineSessionSnapshot(...)` 恢复出待加载文件清单。范围仍限定 OPFS/filesystem/UI
|
`loadMachineSessionSnapshot(...)` 恢复出待加载文件清单。范围仍限定 OPFS/filesystem/UI
|
||||||
workflow,不解析或重写任何 LinuxCNC-owned CNC 语义。
|
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 语义。
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ import {
|
|||||||
import {
|
import {
|
||||||
loadMachineSessionFromOpfs,
|
loadMachineSessionFromOpfs,
|
||||||
} from "../../opfs/linuxcnc-machine-session-bridge.js";
|
} from "../../opfs/linuxcnc-machine-session-bridge.js";
|
||||||
|
import {
|
||||||
|
loadMachineSessionSnapshot,
|
||||||
|
saveMachineSessionSnapshot,
|
||||||
|
} from "../../opfs/snapshot-store.js";
|
||||||
|
|
||||||
const SAMPLE_PATH =
|
const SAMPLE_PATH =
|
||||||
"../../../vendor/linuxcnc/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini";
|
"../../../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_FILENAME = "ui-session.ngc";
|
||||||
const GCODE_WASM_FILE = "/work/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_TOOL_TABLE = "T2 P7 Z3.125 D1.5 I12 J34 Q4 ;ui session tool\n";
|
||||||
const DEFAULT_PARAMETERS = [
|
const DEFAULT_PARAMETERS = [
|
||||||
"5161 0.0",
|
"5161 0.0",
|
||||||
@@ -96,6 +102,7 @@ const fields = {
|
|||||||
sessionParameters: document.getElementById("field-session-parameters"),
|
sessionParameters: document.getElementById("field-session-parameters"),
|
||||||
sessionToolTable: document.getElementById("field-session-tool-table"),
|
sessionToolTable: document.getElementById("field-session-tool-table"),
|
||||||
sessionGcode: document.getElementById("field-session-gcode"),
|
sessionGcode: document.getElementById("field-session-gcode"),
|
||||||
|
sessionSnapshot: document.getElementById("field-session-snapshot"),
|
||||||
runStatus: document.getElementById("field-run-status"),
|
runStatus: document.getElementById("field-run-status"),
|
||||||
fiveaxisRemap: document.getElementById("field-fiveaxis-remap"),
|
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 () => {
|
document.getElementById("load-session").addEventListener("click", async () => {
|
||||||
try {
|
try {
|
||||||
loadedSession = await loadMachineSessionFromOpfs(
|
loadedSession = await loadMachineSessionFromOpfs(
|
||||||
|
|||||||
@@ -228,6 +228,8 @@
|
|||||||
<button id="load-opfs">Load From OPFS</button>
|
<button id="load-opfs">Load From OPFS</button>
|
||||||
<button id="save-machine-files">Save Machine Files</button>
|
<button id="save-machine-files">Save Machine Files</button>
|
||||||
<button id="load-machine-files">Load Machine Files</button>
|
<button id="load-machine-files">Load Machine Files</button>
|
||||||
|
<button id="save-session-snapshot">Save Session Snapshot</button>
|
||||||
|
<button id="restore-session-snapshot">Restore Session Snapshot</button>
|
||||||
<button id="sync-wasm">Sync To WASM FS</button>
|
<button id="sync-wasm">Sync To WASM FS</button>
|
||||||
<button id="query" class="secondary">Query LinuxCNC Fields</button>
|
<button id="query" class="secondary">Query LinuxCNC Fields</button>
|
||||||
<button id="load-session" class="secondary">Load Machine Session</button>
|
<button id="load-session" class="secondary">Load Machine Session</button>
|
||||||
@@ -272,6 +274,8 @@
|
|||||||
<dd id="field-session-tool-table">-</dd>
|
<dd id="field-session-tool-table">-</dd>
|
||||||
<dt>Session G-code</dt>
|
<dt>Session G-code</dt>
|
||||||
<dd id="field-session-gcode">-</dd>
|
<dd id="field-session-gcode">-</dd>
|
||||||
|
<dt>Session Snapshot</dt>
|
||||||
|
<dd id="field-session-snapshot">-</dd>
|
||||||
<dt>Run Status</dt>
|
<dt>Run Status</dt>
|
||||||
<dd id="field-run-status">-</dd>
|
<dd id="field-run-status">-</dd>
|
||||||
<dt>5-Axis Remap</dt>
|
<dt>5-Axis Remap</dt>
|
||||||
|
|||||||
@@ -379,6 +379,40 @@ TOOL_TABLE = browser-tool.tbl
|
|||||||
() => uiDocument.getElementById("log")?.textContent.includes("Saved machine text files"),
|
() => uiDocument.getElementById("log")?.textContent.includes("Saved machine text files"),
|
||||||
"machine file save",
|
"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();
|
uiDocument.getElementById("load-session").click();
|
||||||
await waitFor(
|
await waitFor(
|
||||||
() => uiDocument.getElementById("log")?.textContent.includes("Loaded machine session"),
|
() => uiDocument.getElementById("log")?.textContent.includes("Loaded machine session"),
|
||||||
|
|||||||
Reference in New Issue
Block a user