推进 text12 接续和 control-page session readiness workflow
This commit is contained in:
307
text12.txt
Normal file
307
text12.txt
Normal file
@@ -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 行为。
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
@@ -21,6 +21,7 @@ controller.mount();
|
||||
window.linuxCncIniPanelControlPageApi = {
|
||||
getControlView: controller.getControlView,
|
||||
getPanelApi: controller.getPanelApi,
|
||||
loadControlPageSessionState: controller.loadSessionState,
|
||||
refreshControlPage: controller.refresh,
|
||||
renderControlPage: controller.render,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 | -");
|
||||
|
||||
@@ -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");
|
||||
@@ -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"
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user