diff --git a/text12.txt b/text12.txt new file mode 100644 index 0000000..c2f3c91 --- /dev/null +++ b/text12.txt @@ -0,0 +1,307 @@ +项目整体完成情况与后续执行计划 + +生成时间:2026-06-15 CST + +本文件接替 `text11.txt`。后续工作按 `text12.txt` 执行;除非明确要求审计旧记录, +不要再回到 `text1/text2/text3/text4/text5/text6/text7/text8/text9/text10/text11` +扩展进度。`text11.txt` 作为历史归档保留。 + +一、第一原则:加快实质性推进 + +后续批次必须以“实质性能力优先”为第一遵守原则。 + +1. 优先级从高到低: + +- OPFS/session persistence; +- SDK/API surface; +- browser/UI workflow; +- sim config coverage promotion; +- host/runtime boundary proof; +- 文档化可执行工作流。 + +2. 每批默认应产出至少一种可直接复用的能力: + +- 可调用 helper; +- 可复用 API; +- 可验证用户流程; +- 可执行 gate; +- 可提升覆盖面的 runtime boundary proof; +- 能直接指导下一步实现的设计/清单。 + +3. 暂停低收益推进: + +- 不再把“局部常量化、路径变量收敛、断言分组整理”作为主目标; +- 只有当它支撑可复用 workflow/API/gate 时,才允许做测试胶水; +- 禁止为了推进而扩大 CNC 语义边界; +- 禁止启动性能测试,除非已有明确用户流程需要性能基线。 + +4. LinuxCNC 仍是唯一 CNC 语义来源: + +- G-code、remap、tool、parameter、planner、kinematics、user-M、tool DB、Python remap + 等语义必须来自 LinuxCNC upstream 或 vendored LinuxCNC C/C++/配置/脚本源码; +- JS/browser 只允许做 build、source sync、runtime shim、filesystem staging、OPFS、 + WASM/browser boundary、测试胶水、文档和机器可读 gate/artifact; +- 不在 JS 中重写 G-code 或 CNC 语义; +- 不修改 vendored LinuxCNC 源文件来让测试通过; +- 不把 full-process/HAL/UI/Python/tool DB 依赖伪装成 standalone pass; +- 不把 expected failure 硬改成 pass,除非已有 LinuxCNC-owned runtime proof,并且 + native、Node、browser gate 都按顺序通过; +- browser 不能依赖目录枚举。 + +二、续接状态与防重规则 + +1. 当前续接点。 + +`text11.txt` 已推进到: + +```text +二十四、2026-06-15 继续执行记录:INI panel control-page refresh workflow helper +``` + +该批已提交: + +```text +ed5d03e 推进 INI 面板 control-page refresh workflow helper +``` + +本文件从 `text12.txt` 重新开始记录后续进度。 + +2. 每轮开始前必须先执行: + +```bash +git status --short +git log -5 --oneline +tail -n 120 text12.txt +awk '/^[一二三四五六七八九十百]+、/ {print}' text12.txt | sort | uniq -d +``` + +执行规则: + +- 如果 `git status --short` 是 clean,且最新提交已经包含当前建议工作,不要重复追加记录; +- 每轮只追加一个新的中文编号记录; +- 提交前再次检查标题唯一性; +- `text12.txt` 只记录新的后续进度,不复制 `text11.txt` 的长历史; +- 每批完成后,如果要写记录,先写 `text12.txt`,再提交该批代码和记录; +- 如果发现重复记录,先做 dedupe 清理并提交,再继续新功能或新 guard; +- `text11.txt` 不再追加新进度,除非明确要求审计或修正历史记录。 + +三、当前完成情况摘要 + +1. 当前工作树状态。 + +切换到 `text12.txt` 前已确认: + +```text +git status --short: clean +``` + +当前最近提交: + +```text +ed5d03e 推进 INI 面板 control-page refresh workflow helper +213514f 推进 INI 面板 shell view-model helper +b330f7b 推进 INI 面板 launcher link view-model helper +ac46345 推进 INI 面板 entry docs strict gate +ef4769b 推进 INI 面板 entry doc +``` + +2. 关键基线保持稳定。 + +- `linuxcnc/nc_files` native Layer 1: + - `total 107` + - `pass 101` + - `expected_fail 6` + - `unexpected_fail 0` +- `linuxcnc/configs/sim` native Layer 2: + - `total 159` + - `pass 151` + - `expected_fail 8` + - `unexpected_fail 0` +- Node sim-config inventory: + - `executed=28` + - `passed=28` + - `skipped=131` + - `unexpected_fail=0` + +3. blocked runtime family 仍未 promotion。 + +仍 blocked,不允许 promotion: + +- `L4-USER-M-PROCESS` +- `L4-TOOL-DB` +- `L4-PYTHON-REMAP` + +当前 host 仍按缺少 LinuxCNC host runtime 处理,不执行任何: + +```bash +ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1 bash wasm-port/tests/native/probe_millturn_user_m_runtime.sh +ENABLE_TOOL_DB_RUNTIME_PROBE=1 bash wasm-port/tests/native/probe_tool_db_runtime.sh +ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1 bash wasm-port/tests/native/probe_python_remap_runtime.sh +``` + +四、当前实质能力进展 + +1. INI panel/UI helper 能力。 + +当前 UI helper 已覆盖: + +- run summary; +- run workflow; +- session snapshot summary; +- session load summary; +- machine file save/load summary; +- panel state summary; +- session snapshot save/restore workflow; +- entry manifest、launcher link view-model、shell view-model; +- read-only control-page controller; +- read-only control-page refresh workflow。 + +当前聚合验证入口: + +```bash +wasm-port/tests/ui/node/verify_ui_node_smokes.sh +``` + +当前 `verify_ui_node_smokes.sh` 覆盖: + +```text +ini_panel_run_summary_node_smoke=ok +ini_panel_run_workflow_node_smoke=ok +ini_panel_session_summary_node_smoke=ok +ini_panel_session_workflow_node_smoke=ok +ini_panel_machine_file_summary_node_smoke=ok +ini_panel_state_summary_node_smoke=ok +ini_panel_control_page_controller_node_smoke=ok +ini_panel_control_page_refresh_workflow_node_smoke=ok +ini_panel_entry_manifest_node_smoke=ok +ini_panel_ui_shell_node_smoke=ok +ini_panel_entry_docs_node_smoke=ok +ui_node_smokes=ok +``` + +2. Browser/UI workflow 验证。 + +当前 browser INI panel smoke 覆盖真实 OPFS/session persistence workflow: + +```bash +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh +``` + +关键输出: + +```text +browser_ini_opfs_smoke=ok +browser_ini_control_page_smoke=ok +browser_ini_launch_smoke=ok +``` + +五、当前必须保持通过的验证入口 + +每批后续改动至少运行: + +```bash +git diff --check +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_ini_panel_browser.sh +wasm-port/tests/ui/node/verify_ui_node_smokes.sh +wasm-port/tests/host/verify_host_smokes.sh +``` + +如果涉及 browser interpreter smoke,再运行: + +```bash +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_interp_browser.sh +``` + +涉及 native baseline 或大范围 source/staging 改动时,再运行: + +```bash +wasm-port/tests/native/verify_nc_files.sh +wasm-port/tests/native/verify_sim_configs.sh +``` + +六、下一步建议 + +继续推进 OPFS/session persistence 的实质链路。下一批建议抽出 +`loadMachineSessionForControlPageWorkflow()` 或等价 helper,让 read-only control page 能以明确 +状态模型描述 embedded panel API readiness 和首帧 session state;仍保持只读,不新增控制按钮, +不解析 G-code。 + +一、2026-06-15 继续执行记录:INI panel control-page session readiness workflow helper + +本轮按“第一原则:加快实质性推进”切换到 `text12.txt` 续接,并推进 OPFS/session +persistence 相关 browser/UI workflow:新增 read-only control-page session readiness workflow, +让外层页面能以明确状态模型读取 embedded panel API readiness 和首帧 session state。 + +完成内容: + +- 新建 `text12.txt`,接替 `text11.txt`;后续记录从本文件继续; +- 新增 `wasm-port/runtime/ui/ini-panel/control-page-session-workflow.js`; +- 新增 `createControlPageSessionLoadState(input)`,固定 control-page session load 状态结构; +- 新增 `loadMachineSessionForControlPageWorkflow(input)`,统一描述: + - `waiting-panel`:embedded panel frame 尚不可读; + - `waiting-api`:panel window 可读但 API 尚未暴露; + - `waiting-session`:API 已可读但 control view 尚未就绪; + - `ready`:state bundle、workflow status 和 control view 可读取; + - `error`:读取 panel window/API/control view 时失败; +- `createMachineSessionControlPageController()` 新增 `loadSessionState()`; +- `control-page.js` 对浏览器页面暴露 `loadControlPageSessionState`; +- `ui-shell.js` re-export session readiness workflow helper,并在 + `createIniPanelShellViewModel()` 中暴露 `controlPage.loadSessionState`; +- 新增 `wasm-port/tests/ui/node/verify_ini_panel_control_page_session_workflow.mjs` 和 `.sh`; +- `verify_ui_node_smokes.sh` 纳入 session readiness workflow smoke; +- browser control-page smoke 验证 `loadControlPageSessionState().phase === "ready"`; +- `panel-entry.md` 和 entry docs gate 同步记录 session readiness workflow API; +- 未新增控制按钮; +- 未解析 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_control_page_session_workflow.sh +wasm-port/tests/ui/node/verify_ini_panel_control_page_controller.sh +wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh +wasm-port/tests/ui/node/verify_ini_panel_entry_docs.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_control_page_session_workflow_node_smoke=ok +ini_panel_control_page_controller_node_smoke=ok +ini_panel_ui_shell_node_smoke=ok +ini_panel_entry_docs_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` 按钮路径抽成 +`loadMachineSessionIntoWasmWorkflow()`,统一返回 loaded session、load summary、field state 和 +log lines;仍保持由 LinuxCNC/OPFS bridge 执行实际语义,不在 JS 中解释 CNC 行为。 diff --git a/wasm-port/docs/panel-entry.md b/wasm-port/docs/panel-entry.md index 1330706..9375529 100644 --- a/wasm-port/docs/panel-entry.md +++ b/wasm-port/docs/panel-entry.md @@ -15,6 +15,8 @@ import { getIniPanelEntryByHref, getVisibleIniPanelEntries, createMachineSessionControlPageController, + loadMachineSessionForControlPageWorkflow, + createControlPageSessionLoadState, refreshMachineSessionControlPage, controlPageStatusText, renderMachineSessionControlView, @@ -57,6 +59,13 @@ refresh result with `phase`, `statusText`, `view`, `renderResult`, and `error`. the read-only status line, and `createControlPageRefreshState()` is the stable state-shape helper used by the workflow. +The control-page session workflow lives in +`runtime/ui/ini-panel/control-page-session-workflow.js`. Use +`loadMachineSessionForControlPageWorkflow()` when an outer shell needs a +read-only readiness snapshot for the embedded panel API and first control view. +`createControlPageSessionLoadState()` is the stable state-shape helper for +`waiting-panel`, `waiting-api`, `waiting-session`, `ready`, and `error` phases. + ## Boundary The entry shell only links pages and renders already-observed panel state. It diff --git a/wasm-port/runtime/ui/ini-panel/control-page-controller.js b/wasm-port/runtime/ui/ini-panel/control-page-controller.js index e13f3c3..fff1b24 100644 --- a/wasm-port/runtime/ui/ini-panel/control-page-controller.js +++ b/wasm-port/runtime/ui/ini-panel/control-page-controller.js @@ -1,6 +1,9 @@ import { refreshMachineSessionControlPage, } from "./control-page-refresh-workflow.js"; +import { + loadMachineSessionForControlPageWorkflow, +} from "./control-page-session-workflow.js"; export function createMachineSessionControlPageController({ panelFrame, @@ -50,6 +53,14 @@ export function createMachineSessionControlPageController({ }); } + function loadSessionState() { + return loadMachineSessionForControlPageWorkflow({ + getPanelWindow, + getPanelApi, + getControlView, + }); + } + function startPolling() { if (!refreshTimer) { refreshTimer = setIntervalFn(render, pollMs); @@ -72,6 +83,7 @@ export function createMachineSessionControlPageController({ getControlView, getPanelApi, getPanelWindow, + loadSessionState, mount, refresh, render, diff --git a/wasm-port/runtime/ui/ini-panel/control-page-session-workflow.js b/wasm-port/runtime/ui/ini-panel/control-page-session-workflow.js new file mode 100644 index 0000000..60d05c3 --- /dev/null +++ b/wasm-port/runtime/ui/ini-panel/control-page-session-workflow.js @@ -0,0 +1,84 @@ +export function createControlPageSessionLoadState({ + phase, + panelReady = false, + apiReady = false, + controlViewReady = false, + stateBundle = null, + workflowStatus = null, + controlView = null, + error = null, +} = {}) { + return { + phase, + panelReady, + apiReady, + controlViewReady, + stateBundle, + workflowStatus, + controlView, + error, + }; +} + +export function loadMachineSessionForControlPageWorkflow({ + getPanelWindow, + getPanelApi, + getControlView, +} = {}) { + if (typeof getPanelWindow !== "function") { + throw new Error("A panel window getter is required."); + } + if (typeof getPanelApi !== "function") { + throw new Error("A panel API getter is required."); + } + if (typeof getControlView !== "function") { + throw new Error("A control view getter is required."); + } + + let panelWindow = null; + let panelApi = null; + let controlView = null; + try { + panelWindow = getPanelWindow(); + panelApi = getPanelApi(); + controlView = getControlView(); + } catch (error) { + return createControlPageSessionLoadState({ + phase: "error", + error: error.message, + }); + } + + if (!panelWindow) { + return createControlPageSessionLoadState({ + phase: "waiting-panel", + }); + } + + if (!panelApi) { + return createControlPageSessionLoadState({ + phase: "waiting-api", + panelReady: true, + }); + } + + if (!controlView) { + return createControlPageSessionLoadState({ + phase: "waiting-session", + panelReady: true, + apiReady: true, + stateBundle: panelApi.getMachineSessionStateBundle?.() ?? null, + workflowStatus: panelApi.getMachineSessionWorkflowStatus?.() ?? null, + }); + } + + return createControlPageSessionLoadState({ + phase: "ready", + panelReady: true, + apiReady: true, + controlViewReady: true, + stateBundle: panelApi.getMachineSessionStateBundle?.() ?? null, + workflowStatus: panelApi.getMachineSessionWorkflowStatus?.() ?? null, + controlView, + }); +} diff --git a/wasm-port/runtime/ui/ini-panel/control-page.js b/wasm-port/runtime/ui/ini-panel/control-page.js index 63cd918..0c3e07f 100644 --- a/wasm-port/runtime/ui/ini-panel/control-page.js +++ b/wasm-port/runtime/ui/ini-panel/control-page.js @@ -21,6 +21,7 @@ controller.mount(); window.linuxCncIniPanelControlPageApi = { getControlView: controller.getControlView, getPanelApi: controller.getPanelApi, + loadControlPageSessionState: controller.loadSessionState, refreshControlPage: controller.refresh, renderControlPage: controller.render, }; diff --git a/wasm-port/runtime/ui/ini-panel/ui-shell.js b/wasm-port/runtime/ui/ini-panel/ui-shell.js index 23bf643..8736407 100644 --- a/wasm-port/runtime/ui/ini-panel/ui-shell.js +++ b/wasm-port/runtime/ui/ini-panel/ui-shell.js @@ -14,11 +14,19 @@ import { createControlPageRefreshState, refreshMachineSessionControlPage, } from "./control-page-refresh-workflow.js"; +import { + createControlPageSessionLoadState, + loadMachineSessionForControlPageWorkflow, +} from "./control-page-session-workflow.js"; export { controlPageStatusText, createControlPageRefreshState, refreshMachineSessionControlPage, } from "./control-page-refresh-workflow.js"; +export { + createControlPageSessionLoadState, + loadMachineSessionForControlPageWorkflow, +} from "./control-page-session-workflow.js"; export { INI_PANEL_ENTRIES, getIniPanelEntryByHref, @@ -53,6 +61,7 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries launcherLinks: createIniPanelLauncherLinkViewModel(entries), controlPage: { createController: createMachineSessionControlPageController, + loadSessionState: loadMachineSessionForControlPageWorkflow, refresh: refreshMachineSessionControlPage, renderView: renderMachineSessionControlView, }, diff --git a/wasm-port/tests/browser/ini_panel_control_page_smoke.html b/wasm-port/tests/browser/ini_panel_control_page_smoke.html index 04c4a6e..4913650 100644 --- a/wasm-port/tests/browser/ini_panel_control_page_smoke.html +++ b/wasm-port/tests/browser/ini_panel_control_page_smoke.html @@ -64,6 +64,7 @@ TOOL_TABLE = browser-tool.tbl if ( !controlPageApi?.getControlView || !controlPageApi?.getPanelApi || + !controlPageApi?.loadControlPageSessionState || !controlPageApi?.refreshControlPage || !controlPageApi?.renderControlPage ) { @@ -88,6 +89,11 @@ TOOL_TABLE = browser-tool.tbl "rendered", "control page refresh phase", ); + assertEqual( + controlPageApi.loadControlPageSessionState().phase, + "ready", + "control page session load phase", + ); panelDoc.getElementById("ini-editor").value = iniText; panelDoc.getElementById("query").click(); diff --git a/wasm-port/tests/ui/node/verify_ini_panel_control_page_controller.mjs b/wasm-port/tests/ui/node/verify_ini_panel_control_page_controller.mjs index a0700be..72dad85 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_control_page_controller.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_control_page_controller.mjs @@ -39,6 +39,17 @@ const expectedView = { }, ], }; +const expectedStateBundle = { + report: { + readiness: { + ini: "INI WASM: ready", + }, + }, +}; +const expectedWorkflowStatus = { + lastAction: "run-gcode", + error: null, +}; let intervalCallback = null; const panelFrame = createPanelFrame(); @@ -69,11 +80,23 @@ assert.equal(typeof intervalCallback, "function"); const panelApi = { getMachineSessionControlView: () => expectedView, + getMachineSessionStateBundle: () => expectedStateBundle, + getMachineSessionWorkflowStatus: () => expectedWorkflowStatus, }; panelFrame.contentWindow = { linuxCncIniPanelApi: panelApi }; assert.equal(controller.getPanelApi(), panelApi); assert.equal(controller.getControlView(), expectedView); +assert.deepEqual(controller.loadSessionState(), { + phase: "ready", + panelReady: true, + apiReady: true, + controlViewReady: true, + stateBundle: expectedStateBundle, + workflowStatus: expectedWorkflowStatus, + controlView: expectedView, + error: null, +}); const renderResult = controller.render(); assert.deepEqual(renderResult, { statusNode: { textContent: "rendered" } }); assert.equal(statusNode.textContent, "run-gcode | ok | -"); diff --git a/wasm-port/tests/ui/node/verify_ini_panel_control_page_session_workflow.mjs b/wasm-port/tests/ui/node/verify_ini_panel_control_page_session_workflow.mjs new file mode 100644 index 0000000..99d5044 --- /dev/null +++ b/wasm-port/tests/ui/node/verify_ini_panel_control_page_session_workflow.mjs @@ -0,0 +1,121 @@ +import assert from "node:assert/strict"; + +import { + createControlPageSessionLoadState, + loadMachineSessionForControlPageWorkflow, +} from "../../../runtime/ui/ini-panel/control-page-session-workflow.js"; + +const stateBundle = { + report: { + readiness: { + ini: "INI WASM: ready", + interp: "Interpreter WASM: ready", + opfs: "OPFS: ready", + }, + }, +}; +const workflowStatus = { + lastAction: "load-session", + error: null, +}; +const controlView = { + status: { + lastAction: "load-session", + runStatus: null, + error: null, + }, + sections: [], +}; + +assert.deepEqual(createControlPageSessionLoadState({ phase: "waiting-panel" }), { + phase: "waiting-panel", + panelReady: false, + apiReady: false, + controlViewReady: false, + stateBundle: null, + workflowStatus: null, + controlView: null, + error: null, +}); + +assert.deepEqual( + loadMachineSessionForControlPageWorkflow({ + getPanelWindow: () => null, + getPanelApi: () => null, + getControlView: () => null, + }), + createControlPageSessionLoadState({ phase: "waiting-panel" }), +); + +assert.deepEqual( + loadMachineSessionForControlPageWorkflow({ + getPanelWindow: () => ({}), + getPanelApi: () => null, + getControlView: () => null, + }), + createControlPageSessionLoadState({ + phase: "waiting-api", + panelReady: true, + }), +); + +const panelApiWithoutControlView = { + getMachineSessionStateBundle: () => stateBundle, + getMachineSessionWorkflowStatus: () => workflowStatus, +}; +assert.deepEqual( + loadMachineSessionForControlPageWorkflow({ + getPanelWindow: () => ({}), + getPanelApi: () => panelApiWithoutControlView, + getControlView: () => null, + }), + createControlPageSessionLoadState({ + phase: "waiting-session", + panelReady: true, + apiReady: true, + stateBundle, + workflowStatus, + }), +); + +const panelApi = { + ...panelApiWithoutControlView, + getMachineSessionControlView: () => controlView, +}; +assert.deepEqual( + loadMachineSessionForControlPageWorkflow({ + getPanelWindow: () => ({}), + getPanelApi: () => panelApi, + getControlView: () => controlView, + }), + createControlPageSessionLoadState({ + phase: "ready", + panelReady: true, + apiReady: true, + controlViewReady: true, + stateBundle, + workflowStatus, + controlView, + }), +); + +assert.deepEqual( + loadMachineSessionForControlPageWorkflow({ + getPanelWindow: () => { + throw new Error("cross-origin frame"); + }, + getPanelApi: () => null, + getControlView: () => null, + }), + createControlPageSessionLoadState({ + phase: "error", + error: "cross-origin frame", + }), +); + +assert.throws( + () => loadMachineSessionForControlPageWorkflow(), + /panel window getter/, +); + +console.log("ini_panel_control_page_session_workflow_node_smoke=ok"); diff --git a/wasm-port/tests/ui/node/verify_ini_panel_control_page_session_workflow.sh b/wasm-port/tests/ui/node/verify_ini_panel_control_page_session_workflow.sh new file mode 100755 index 0000000..99bdacc --- /dev/null +++ b/wasm-port/tests/ui/node/verify_ini_panel_control_page_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_control_page_session_workflow.mjs" diff --git a/wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs b/wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs index ac41d89..14d5d6e 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs @@ -6,8 +6,10 @@ import { dirname, resolve } from "node:path"; import { INI_PANEL_ENTRIES, controlPageStatusText, + createControlPageSessionLoadState, createIniPanelLauncherLinkViewModel, createIniPanelShellViewModel, + loadMachineSessionForControlPageWorkflow, refreshMachineSessionControlPage, getVisibleIniPanelEntries, } from "../../../runtime/ui/ini-panel/ui-shell.js"; @@ -20,15 +22,21 @@ const refreshWorkflowText = readFileSync( resolve(root, "runtime/ui/ini-panel/control-page-refresh-workflow.js"), "utf8", ); +const sessionWorkflowText = readFileSync( + resolve(root, "runtime/ui/ini-panel/control-page-session-workflow.js"), + "utf8", +); const requiredShellExports = [ "INI_PANEL_ENTRIES", "controlPageStatusText", + "createControlPageSessionLoadState", "createIniPanelLauncherLinkViewModel", "createIniPanelShellViewModel", "getIniPanelEntryByHref", "getVisibleIniPanelEntries", "createMachineSessionControlPageController", + "loadMachineSessionForControlPageWorkflow", "refreshMachineSessionControlPage", "renderMachineSessionControlView", ]; @@ -47,6 +55,14 @@ for (const exportName of [ assert.match(docText, new RegExp(`\\b${exportName}\\b`)); } +for (const exportName of [ + "createControlPageSessionLoadState", + "loadMachineSessionForControlPageWorkflow", +]) { + assert.match(sessionWorkflowText, new RegExp(`\\bexport function ${exportName}\\b`)); + assert.match(docText, new RegExp(`\\b${exportName}\\b`)); +} + const requiredPages = [ ["Launch", "runtime/ui/ini-panel/launch.html"], ["Edit and run", "runtime/ui/ini-panel/index.html"], @@ -69,7 +85,18 @@ assert.deepEqual( assert.deepEqual(createIniPanelShellViewModel().pages, getVisibleIniPanelEntries()); assert.deepEqual(createIniPanelShellViewModel().launcherLinks, createIniPanelLauncherLinkViewModel()); assert.equal(controlPageStatusText({ lastAction: "run-gcode", runStatus: "ok", error: null }), "run-gcode | ok | -"); +assert.deepEqual(createControlPageSessionLoadState({ phase: "waiting-panel" }), { + phase: "waiting-panel", + panelReady: false, + apiReady: false, + controlViewReady: false, + stateBundle: null, + workflowStatus: null, + controlView: null, + error: null, +}); assert.equal(typeof createIniPanelShellViewModel().controlPage.createController, "function"); +assert.equal(createIniPanelShellViewModel().controlPage.loadSessionState, loadMachineSessionForControlPageWorkflow); assert.equal(createIniPanelShellViewModel().controlPage.refresh, refreshMachineSessionControlPage); assert.equal(typeof createIniPanelShellViewModel().controlPage.renderView, "function"); diff --git a/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs b/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs index a5b916a..6df7406 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs @@ -6,10 +6,12 @@ import { createIniPanelLauncherLinkViewModel, createIniPanelShellViewModel, createControlPageRefreshState, + createControlPageSessionLoadState, createMachineSessionControlPageController, getIniPanelEntryByHref, getIniPanelEntryManifest, getVisibleIniPanelEntries, + loadMachineSessionForControlPageWorkflow, refreshMachineSessionControlPage, renderMachineSessionControlView, } from "../../../runtime/ui/ini-panel/ui-shell.js"; @@ -24,8 +26,19 @@ assert.deepEqual(createControlPageRefreshState({ phase: "waiting", statusText: " renderResult: null, error: null, }); +assert.deepEqual(createControlPageSessionLoadState({ phase: "waiting-panel" }), { + phase: "waiting-panel", + panelReady: false, + apiReady: false, + controlViewReady: false, + stateBundle: null, + workflowStatus: null, + controlView: null, + error: null, +}); assert.equal(getIniPanelEntryByHref("./index.html")?.id, "edit-run"); assert.equal(typeof createMachineSessionControlPageController, "function"); +assert.equal(typeof loadMachineSessionForControlPageWorkflow, "function"); assert.equal(typeof refreshMachineSessionControlPage, "function"); assert.equal(typeof renderMachineSessionControlView, "function"); @@ -65,6 +78,7 @@ assert.deepEqual(shellViewModel.pages, [ ]); assert.deepEqual(shellViewModel.launcherLinks, createIniPanelLauncherLinkViewModel()); assert.equal(shellViewModel.controlPage.createController, createMachineSessionControlPageController); +assert.equal(shellViewModel.controlPage.loadSessionState, loadMachineSessionForControlPageWorkflow); assert.equal(shellViewModel.controlPage.refresh, refreshMachineSessionControlPage); assert.equal(shellViewModel.controlPage.renderView, renderMachineSessionControlView); shellViewModel.pages[0].title = "changed"; @@ -102,6 +116,7 @@ const controller = createMachineSessionControlPageController({ assert.deepEqual(controller.render(), { rendered: true }); assert.equal(statusNode.textContent, "run-gcode | ok | -"); assert.equal(renderedView.status.runStatus, "ok"); +assert.equal(controller.loadSessionState().phase, "ready"); assert.equal(controller.refresh().phase, "rendered"); console.log("ini_panel_ui_shell_node_smoke=ok"); 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 3620e72..4865c1c 100755 --- a/wasm-port/tests/ui/node/verify_ui_node_smokes.sh +++ b/wasm-port/tests/ui/node/verify_ui_node_smokes.sh @@ -11,6 +11,7 @@ ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" "$ROOT_DIR/tests/ui/node/verify_ini_panel_state_summary.sh" "$ROOT_DIR/tests/ui/node/verify_ini_panel_control_page_controller.sh" "$ROOT_DIR/tests/ui/node/verify_ini_panel_control_page_refresh_workflow.sh" +"$ROOT_DIR/tests/ui/node/verify_ini_panel_control_page_session_workflow.sh" "$ROOT_DIR/tests/ui/node/verify_ini_panel_entry_manifest.sh" "$ROOT_DIR/tests/ui/node/verify_ini_panel_ui_shell.sh" "$ROOT_DIR/tests/ui/node/verify_ini_panel_entry_docs.sh"