diff --git a/text12.txt b/text12.txt index a5ca4c5..a8263de 100644 --- a/text12.txt +++ b/text12.txt @@ -371,6 +371,87 @@ host_wasm_opfs_browser_smokes=ok `loadMachineSessionIntoWasmWorkflow()`,避免 restore+load 与单独 load 的 field/log 状态模型 分叉;仍保持由 LinuxCNC/OPFS bridge 执行实际语义,不在 JS 中解释 CNC 行为。 +三、2026-06-15 继续执行记录:INI panel run readiness workflow helper + +本轮按“第一原则:加快实质性推进”继续推进 run 前置状态模型,将 run 按钮可执行条件、 +默认/快照 G-code 选择结果与已加载 session 的 WASM 绑定关系抽成可复用 readiness helper, +让 app、state summary、control view 和 Node smoke 共享同一份运行前状态。 + +完成内容: + +- 新增 `wasm-port/runtime/ui/ini-panel/run-workflow.js` 的 + `createRunSessionReadinessState(input)`; +- `runGcodeSessionWorkflow()` 现在先生成 readiness state,再复用其中的选定程序和 loaded + session 信息执行实际 run; +- readiness state 固定返回: + - `phase` + - `canRun` + - `missing` + - `loadedSession` + - `snapshot` + - `defaultProgram` + - `program` + - `runButton` +- `wasm-port/runtime/ui/ini-panel/app.js` 在点击 Run 前先写入 readiness state,并把 + `selectedProgram`、`runReadiness` 和 field state 一起更新到 panel state; +- `wasm-port/runtime/ui/ini-panel/panel-state-summary.js` 新增 `runReadiness` 的 report / + workflowStatus / control-view 映射; +- `createMachineSessionControlView()` 的 Run 区新增 `Ready` 与 `Button` 行,用于 read-only + control page 读取首帧 run 前置状态; +- `wasm-port/tests/ui/node/verify_ini_panel_run_workflow.mjs` 覆盖 readiness helper 与 + workflow readiness 返回值; +- `wasm-port/tests/ui/node/verify_ini_panel_state_summary.mjs` 覆盖 runReadiness 在 report、 + bundle、workflowStatus 和 control view 中的映射; +- `wasm-port/docs/ui-run-summary-helpers.md` 和 `wasm-port/docs/ui-panel-state-summary.md` + 同步说明 readiness helper 与 runReadiness 状态; +- 未新增控制按钮; +- 未解析 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_run_workflow.sh +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_run_workflow_node_smoke=ok +ini_panel_state_summary_node_smoke=ok +ui_node_smokes=ok +browser_ini_opfs_smoke=ok +browser_ini_control_page_smoke=ok +browser_ini_launch_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 +``` + +下一步建议: + +继续推进 OPFS/session persistence 的实质链路。下一批建议将 `load-session` 与 +`restore-load-session` 的 field/log 路径再做一次轻量整合,优先把“已加载 session、快照恢复、 +run readiness、run 结果”汇总成一个更上层的只读工作流状态对象;仍保持只描述 UI/host +boundary facts,不在 JS 中解释 G-code、canonical events 或 CNC 运行语义。 + 三、2026-06-15 继续执行记录:INI panel restore-load workflow 复用 load-session helper 本轮按“第一原则:加快实质性推进”继续推进 OPFS/session persistence 主链路,将 diff --git a/wasm-port/docs/ui-panel-state-summary.md b/wasm-port/docs/ui-panel-state-summary.md index c5ee1fa..dc59754 100644 --- a/wasm-port/docs/ui-panel-state-summary.md +++ b/wasm-port/docs/ui-panel-state-summary.md @@ -49,6 +49,7 @@ For the short page/entry map, see `docs/panel-entry.md`. machineFiles: { iniOpfsPath: "...", toolTableOpfsPath: "...", parameterOpfsPath: "...", gcodeOpfsPath: "..." }, sessionSnapshot: { snapshotLabel: "...", workflow: "save-session-snapshot" }, sessionLoad: { iniOpfsPath: "...", iniWasmPath: "..." }, + runReadiness: { phase: "ready", canRun: true, runButton: { enabled: true } }, run: { runStatus: "ok", programSource: "snapshot" }, fiveaxisRemap: "ok" } @@ -100,6 +101,7 @@ with four sections: session: { snapshotLabel: "...", workflow: "...", ini: "...", parameters: "...", toolTable: "...", gcode: "..." }, loaded: { iniWasmPath: "...", parameterWasmPath: "...", toolTableWasmPath: "..." }, program: { source: "snapshot", opfsPath: "...", wasmPath: "..." }, + runReadiness: { phase: "ready", canRun: true, buttonEnabled: true, programOpfsPath: "..." }, run: { status: "ok", canonicalEventCount: 2, motionSnapshotCount: 2, iniWasmPath: "..." }, status: { lastAction: "run-gcode", error: null, fiveaxisRemap: "ok" } } @@ -130,6 +132,7 @@ This helper derives a lightweight status object for upper-level control pages: ```js { readiness: { ini: "...", interp: "...", opfs: "..." }, + runReadiness: { phase: "ready", canRun: true, buttonEnabled: true }, lastAction: "run-gcode", error: null, session: { snapshotLabel: "...", workflow: "...", gcode: "..." }, @@ -167,7 +170,7 @@ This helper maps a bundle into UI-ready status and sections: 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 }] } + { id: "run", title: "Run", rows: [{ label: "Ready", value: "ready" }] } ] } ``` diff --git a/wasm-port/docs/ui-run-summary-helpers.md b/wasm-port/docs/ui-run-summary-helpers.md index bbbbcd2..715e694 100644 --- a/wasm-port/docs/ui-run-summary-helpers.md +++ b/wasm-port/docs/ui-run-summary-helpers.md @@ -7,7 +7,7 @@ summarizing an INI panel G-code run. `runtime/ui/ini-panel/run-workflow.js` contains the reusable UI workflow for selecting the session/default G-code program, loading it from OPFS, staging it into the interpreter WASM filesystem, invoking the LinuxCNC interpreter, and -returning run field/log state. These helpers are intentionally pure so browser +returning run readiness, field, and log state. These helpers are intentionally pure so browser UI panels, SDK-facing wrappers, and Node smoke tests can share the same summary shape without reading DOM text or parsing log output. @@ -95,8 +95,8 @@ functions: ``` It returns the selected program mapping, raw interpreter result text, run -summary, UI field state, log lines, and optional UI motion snapshots produced -by the injected `summarizeRun` callback: +summary, readiness state, UI field state, log lines, and optional UI motion +snapshots produced by the injected `summarizeRun` callback: ```js { @@ -108,6 +108,7 @@ by the injected `summarizeRun` callback: }, resultText: "canon_event=...", summary: { runStatus: "ok", programSource: "snapshot" }, + readiness: { phase: "ready", canRun: true }, fields: { runStatus: "ok", sessionGcode: "linuxcnc/gcode/ui-session.ngc" }, motionSnapshots: [{ line: 1 }], logLines: ["Program: linuxcnc/gcode/ui-session.ngc -> /work/ui-session.ngc"] @@ -117,6 +118,10 @@ by the injected `summarizeRun` callback: `selectSessionGcodeProgram(input)` is the pure program-selection helper used by the workflow. Invalid snapshot G-code paths fall back to the UI default program. +`createRunSessionReadinessState(input)` is the pure readiness helper used by the +workflow and panel state summary. It reports the selected program, loaded +session path, snapshot metadata, and whether the run button can execute. + ## Boundary Rules - Do not parse G-code text in these helpers. diff --git a/wasm-port/runtime/ui/ini-panel/app.js b/wasm-port/runtime/ui/ini-panel/app.js index 0d167c3..559bdfc 100644 --- a/wasm-port/runtime/ui/ini-panel/app.js +++ b/wasm-port/runtime/ui/ini-panel/app.js @@ -32,6 +32,7 @@ import { summarizeRunResult, } from "./run-summary.js"; import { + createRunSessionReadinessState, runGcodeSessionWorkflow, } from "./run-workflow.js"; import { @@ -772,8 +773,28 @@ document.getElementById("restore-load-session").addEventListener("click", async document.getElementById("run-gcode").addEventListener("click", async () => { try { - if (!loadedSession) { - throw new Error("Load a machine session before running G-code."); + const readiness = createRunSessionReadinessState({ + loadedSession, + snapshot: restoredSessionSnapshot, + defaultFilename: UI_SESSION.defaultGcodeFilename, + defaultOpfsPath: defaultGcodeOpfsPath(), + wasmPath: UI_SESSION.gcodeWasmPath, + gcodeFilenameFromProgramPath, + }); + updatePanelMachineSessionState({ + runReadiness: readiness, + selectedProgram: readiness.program, + fields: { + sessionGcode: readiness.program.opfsPath, + runSource: readiness.program.source, + runOpfsPath: readiness.program.opfsPath, + runWasmPath: readiness.program.wasmPath, + }, + lastAction: "run-gcode-readiness", + error: readiness.runButton.reason, + }); + if (!readiness.canRun) { + throw new Error(readiness.runButton.reason ?? "Load a machine session before running G-code."); } const interp = requireInterpSdk(); clearRunPlayback(); @@ -803,6 +824,7 @@ document.getElementById("run-gcode").addEventListener("click", async () => { setField("runStatus", workflow.fields.runStatus); setLastRunSummary(workflow.summary); updatePanelMachineSessionState({ + runReadiness: workflow.readiness, selectedProgram: { source: workflow.program.source, opfsPath: workflow.program.opfsPath, 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 e139905..7fd2bac 100644 --- a/wasm-port/runtime/ui/ini-panel/panel-state-summary.js +++ b/wasm-port/runtime/ui/ini-panel/panel-state-summary.js @@ -4,6 +4,7 @@ export function createIniPanelStateSummary({ machineFiles = null, sessionSnapshot = null, sessionLoad = null, + runReadiness = null, run = null, fiveaxisRemap = null, } = {}) { @@ -17,6 +18,7 @@ export function createIniPanelStateSummary({ machineFiles, sessionSnapshot, sessionLoad, + runReadiness, run, fiveaxisRemap: fiveaxisRemap ?? null, }; @@ -28,6 +30,7 @@ export function createMachineSessionStateSnapshot({ machineFiles = null, sessionSnapshot = null, sessionLoad = null, + runReadiness = null, selectedProgram = null, run = null, fields = {}, @@ -42,6 +45,7 @@ export function createMachineSessionStateSnapshot({ machineFiles, sessionSnapshot, sessionLoad, + runReadiness, run, fiveaxisRemap, }), @@ -69,6 +73,7 @@ export function createMachineSessionStateReport(state = {}) { const fields = state.fields ?? {}; const sessionSnapshot = state.sessionSnapshot ?? {}; const sessionLoad = state.sessionLoad ?? {}; + const runReadiness = state.runReadiness ?? {}; const selectedProgram = state.selectedProgram ?? {}; const run = state.run ?? {}; return { @@ -95,6 +100,17 @@ export function createMachineSessionStateReport(state = {}) { opfsPath: selectedProgram.opfsPath ?? run.programOpfsPath ?? fields.runOpfsPath ?? null, wasmPath: selectedProgram.wasmPath ?? run.programWasmPath ?? fields.runWasmPath ?? null, }, + runReadiness: { + phase: runReadiness.phase ?? null, + canRun: Boolean(runReadiness.canRun), + missing: Array.isArray(runReadiness.missing) ? runReadiness.missing : [], + buttonEnabled: Boolean(runReadiness.runButton?.enabled), + buttonReason: runReadiness.runButton?.reason ?? null, + programSource: runReadiness.program?.source ?? null, + programOpfsPath: runReadiness.program?.opfsPath ?? null, + programWasmPath: runReadiness.program?.wasmPath ?? null, + iniWasmPath: runReadiness.loadedSession?.iniWasmPath ?? null, + }, run: { status: run.runStatus ?? fields.runStatus ?? null, canonicalEventCount: run.canonicalEventCount ?? 0, @@ -123,6 +139,7 @@ export function createMachineSessionWorkflowStatus(state = {}) { const report = createMachineSessionStateReport(state); return { readiness: report.readiness, + runReadiness: report.runReadiness, lastAction: report.status.lastAction, error: report.status.error, session: report.session, @@ -145,6 +162,7 @@ export function createMachineSessionControlView(bundle = {}) { const report = bundle.report ?? {}; const workflowStatus = bundle.workflowStatus ?? {}; const session = workflowStatus.session ?? report.session ?? {}; + const runReadiness = workflowStatus.runReadiness ?? report.runReadiness ?? {}; const run = workflowStatus.run ?? report.run ?? {}; return { status: { @@ -176,6 +194,8 @@ export function createMachineSessionControlView(bundle = {}) { id: "run", title: "Run", rows: [ + { label: "Ready", value: runReadiness.phase ?? null }, + { label: "Button", value: runReadiness.buttonEnabled ? "enabled" : "disabled" }, { label: "Status", value: run.status ?? null }, { label: "Canonical events", value: run.canonicalEventCount ?? 0 }, { label: "Motion snapshots", value: run.motionSnapshotCount ?? 0 }, diff --git a/wasm-port/runtime/ui/ini-panel/run-workflow.js b/wasm-port/runtime/ui/ini-panel/run-workflow.js index 906e625..4d13ba1 100644 --- a/wasm-port/runtime/ui/ini-panel/run-workflow.js +++ b/wasm-port/runtime/ui/ini-panel/run-workflow.js @@ -34,6 +34,55 @@ export function selectSessionGcodeProgram({ }; } +export function createRunSessionReadinessState({ + loadedSession = null, + snapshot = null, + defaultFilename, + defaultOpfsPath, + wasmPath, + gcodeFilenameFromProgramPath, +}) { + const program = selectSessionGcodeProgram({ + snapshot, + defaultFilename, + defaultOpfsPath, + wasmPath, + gcodeFilenameFromProgramPath, + }); + const missing = []; + if (!loadedSession?.ini?.wasmPath) { + missing.push("loaded-session"); + } + if (!program.filename || !program.opfsPath || !program.wasmPath) { + missing.push("gcode-program"); + } + const canRun = missing.length === 0; + return { + phase: canRun ? "ready" : "blocked", + canRun, + missing, + loadedSession: { + iniWasmPath: loadedSession?.ini?.wasmPath ?? null, + }, + snapshot: { + present: Boolean(snapshot), + label: snapshot?.metadata?.snapshotLabel ?? snapshot?.sessionId ?? null, + workflow: snapshot?.metadata?.workflow ?? null, + gcodeOpfsPath: snapshot?.payload?.files?.gcode ?? null, + }, + defaultProgram: { + filename: defaultFilename ?? null, + opfsPath: defaultOpfsPath ?? null, + wasmPath: wasmPath ?? null, + }, + program, + runButton: { + enabled: canRun, + reason: canRun ? null : `Missing ${missing.join(", ")}.`, + }, + }; +} + export function runSessionContextLogLines(program, snapshot = null, snapshotLabel = null) { const summary = createSessionSnapshotSummary({ metadata: snapshot?.metadata ?? {}, @@ -58,16 +107,18 @@ export async function runGcodeSessionWorkflow({ summarizeRun = () => ({}), snapshotLabel = null, }) { - if (!loadedSession) { - throw new Error("Load a machine session before running G-code."); - } - const program = selectSessionGcodeProgram({ + const readiness = createRunSessionReadinessState({ + loadedSession, snapshot, defaultFilename, defaultOpfsPath, wasmPath, gcodeFilenameFromProgramPath, }); + if (!readiness.canRun) { + throw new Error("Load a machine session before running G-code."); + } + const program = readiness.program; const programText = await loadGcodeProgram(program.filename); interp.writeTextFile(program.wasmPath, programText); const resultText = interp.runFileWithIni(program.wasmPath, loadedSession.ini.wasmPath).trim(); @@ -91,6 +142,7 @@ export async function runGcodeSessionWorkflow({ resultText, motionSnapshots, summary, + readiness, fields: { sessionGcode: program.opfsPath, runStatus: summary.runStatus, diff --git a/wasm-port/tests/ui/node/verify_ini_panel_run_workflow.mjs b/wasm-port/tests/ui/node/verify_ini_panel_run_workflow.mjs index cf6ecd0..6571519 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_run_workflow.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_run_workflow.mjs @@ -1,6 +1,7 @@ import assert from "node:assert/strict"; import { + createRunSessionReadinessState, runGcodeSessionWorkflow, selectSessionGcodeProgram, } from "../../../runtime/ui/ini-panel/run-workflow.js"; @@ -42,6 +43,61 @@ assert.deepEqual(snapshotProgram, { wasmPath: "/work/ui-session.ngc", }); +const readiness = createRunSessionReadinessState({ + loadedSession: { + ini: { + wasmPath: "/work/session-machine.ini", + }, + }, + snapshot: { + sessionId: "ui-machine-session", + metadata: { + workflow: "save-session-snapshot", + snapshotLabel: "ui-machine-session/ui-machine-session.json", + defaultGcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc", + }, + payload: { + files: { + gcode: "linuxcnc/gcode/snapshot-session.ngc", + }, + }, + }, + defaultFilename: "ui-session.ngc", + defaultOpfsPath: "linuxcnc/gcode/ui-session.ngc", + wasmPath: "/work/ui-session.ngc", + gcodeFilenameFromProgramPath: (path) => path.split("/").at(-1), +}); + +assert.deepEqual(readiness, { + phase: "ready", + canRun: true, + missing: [], + loadedSession: { + iniWasmPath: "/work/session-machine.ini", + }, + snapshot: { + present: true, + label: "ui-machine-session/ui-machine-session.json", + workflow: "save-session-snapshot", + gcodeOpfsPath: "linuxcnc/gcode/snapshot-session.ngc", + }, + defaultProgram: { + filename: "ui-session.ngc", + opfsPath: "linuxcnc/gcode/ui-session.ngc", + wasmPath: "/work/ui-session.ngc", + }, + program: { + filename: "snapshot-session.ngc", + opfsPath: "linuxcnc/gcode/snapshot-session.ngc", + source: "snapshot", + wasmPath: "/work/ui-session.ngc", + }, + runButton: { + enabled: true, + reason: null, + }, +}); + const calls = []; const workflow = await runGcodeSessionWorkflow({ interp: { @@ -126,6 +182,7 @@ assert.deepEqual(workflow.fields, { runOpfsPath: "linuxcnc/gcode/snapshot-session.ngc", runWasmPath: "/work/ui-session.ngc", }); +assert.deepEqual(workflow.readiness, readiness); assert.deepEqual(workflow.motionSnapshots, [{ line: 1 }]); 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 aa6247f..f040be1 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 @@ -13,6 +13,60 @@ import { renderMachineSessionControlView, } from "../../../runtime/ui/ini-panel/control-view-renderer.js"; +const runReadinessFixture = { + phase: "ready", + canRun: true, + missing: [], + loadedSession: { + iniWasmPath: "/work/session-machine.ini", + }, + snapshot: { + present: true, + label: "ui-machine-session/ui-machine-session.json", + workflow: "save-session-snapshot", + gcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc", + }, + defaultProgram: { + filename: "ui-session.ngc", + opfsPath: "linuxcnc/gcode/ui-session.ngc", + wasmPath: "/work/ui-session.ngc", + }, + program: { + filename: "ui-session.ngc", + opfsPath: "linuxcnc/gcode/ui-session.ngc", + source: "default", + wasmPath: "/work/ui-session.ngc", + }, + runButton: { + enabled: true, + reason: null, + }, +}; + +const expectedRunReadinessReport = { + phase: "ready", + canRun: true, + missing: [], + buttonEnabled: true, + buttonReason: null, + programSource: "default", + programOpfsPath: "linuxcnc/gcode/ui-session.ngc", + programWasmPath: "/work/ui-session.ngc", + iniWasmPath: "/work/session-machine.ini", +}; + +const expectedEmptyRunReadinessReport = { + phase: null, + canRun: false, + missing: [], + buttonEnabled: false, + buttonReason: null, + programSource: null, + programOpfsPath: null, + programWasmPath: null, + iniWasmPath: null, +}; + const summary = createIniPanelStateSummary({ badges: { ini: "INI WASM: ready", @@ -37,6 +91,7 @@ const summary = createIniPanelStateSummary({ iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini", iniWasmPath: "/work/session-machine.ini", }, + runReadiness: runReadinessFixture, run: { runStatus: "ok", programSource: "snapshot", @@ -68,6 +123,7 @@ assert.deepEqual(summary, { iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini", iniWasmPath: "/work/session-machine.ini", }, + runReadiness: runReadinessFixture, run: { runStatus: "ok", programSource: "snapshot", @@ -87,6 +143,7 @@ assert.deepEqual( machineFiles: null, sessionSnapshot: null, sessionLoad: null, + runReadiness: null, run: null, fiveaxisRemap: null, }, @@ -108,6 +165,7 @@ assert.deepEqual( sessionLoad: { iniWasmPath: "/work/session-machine.ini", }, + runReadiness: runReadinessFixture, selectedProgram: { source: "snapshot", opfsPath: "linuxcnc/gcode/ui-session.ngc", @@ -149,6 +207,7 @@ assert.deepEqual( sessionLoad: { iniWasmPath: "/work/session-machine.ini", }, + runReadiness: runReadinessFixture, run: { runStatus: "ok", programSource: "snapshot", @@ -219,6 +278,7 @@ assert.deepEqual( parameterWasmPath: "/work/session-linuxcnc.var", toolTableWasmPath: "/work/session-tool.tbl", }, + runReadiness: runReadinessFixture, selectedProgram: { source: "snapshot", opfsPath: "linuxcnc/gcode/ui-session.ngc", @@ -261,6 +321,7 @@ assert.deepEqual( opfsPath: "linuxcnc/gcode/ui-session.ngc", wasmPath: "/work/ui-session.ngc", }, + runReadiness: expectedRunReadinessReport, run: { status: "ok", canonicalEventCount: 2, @@ -299,6 +360,7 @@ const expectedExportReport = { opfsPath: null, wasmPath: null, }, + runReadiness: expectedEmptyRunReadinessReport, run: { status: null, canonicalEventCount: 0, @@ -350,6 +412,7 @@ assert.deepEqual( runStatus: "ok", runWorkflow: "save-session-snapshot", }, + runReadiness: runReadinessFixture, run: { runStatus: "ok", canonicalEventCount: 2, @@ -364,6 +427,7 @@ assert.deepEqual( interp: "Interpreter WASM: ready", opfs: "OPFS: ready", }, + runReadiness: expectedRunReadinessReport, lastAction: "run-gcode", error: null, session: { @@ -407,6 +471,7 @@ const expectedBundleReport = { opfsPath: null, wasmPath: null, }, + runReadiness: expectedRunReadinessReport, run: { status: "ok", canonicalEventCount: 2, @@ -434,6 +499,7 @@ assert.deepEqual( runStatus: "ok", runWorkflow: "save-session-snapshot", }, + runReadiness: runReadinessFixture, run: { runStatus: "ok", canonicalEventCount: 2, @@ -458,6 +524,7 @@ assert.deepEqual( }, lastAction: "run-gcode", error: null, + runReadiness: expectedRunReadinessReport, session: { snapshotLabel: "ui-machine-session/ui-machine-session.json", workflow: "save-session-snapshot", @@ -501,6 +568,7 @@ assert.deepEqual( toolTable: null, gcode: "linuxcnc/gcode/ui-session.ngc", }, + runReadiness: expectedRunReadinessReport, run: { status: "ok", canonicalEventCount: 2, @@ -539,6 +607,8 @@ assert.deepEqual( id: "run", title: "Run", rows: [ + { label: "Ready", value: "ready" }, + { label: "Button", value: "enabled" }, { label: "Status", value: "ok" }, { label: "Canonical events", value: 2 }, { label: "Motion snapshots", value: 2 }, @@ -578,6 +648,7 @@ const renderedControlView = renderMachineSessionControlView( lastAction: "run-gcode", error: null, session: expectedBundleReport.session, + runReadiness: expectedBundleReport.runReadiness, run: expectedBundleReport.run, }, }), @@ -588,7 +659,7 @@ assert.equal(renderedControlView.sectionNodes.length, 3); assert.equal(renderedControlView.sectionNodes[2].dataset.sectionId, "run"); assert.equal( renderedControlView.sectionNodes[2].children[1].children[3].textContent, - "2", + "enabled", ); assert.deepEqual(