收口 INI 面板 persistence summary 发布门禁

This commit is contained in:
2026-06-16 09:00:29 +08:00
parent 65e95327b3
commit d3ee5d49ff
21 changed files with 1458 additions and 46 deletions

View File

@@ -101,6 +101,7 @@
!launchApi?.getShellSessionHandoffPackageMountRenderState ||
!launchApi?.getShellSessionReadinessWorkflowReport ||
!launchApi?.getShellApiSurfaceInventory ||
!launchApi?.getMachineSessionPersistenceSummary ||
!launchApi?.renderShellSessionHandoffMountState ||
!launchApi?.getWorkflowOverviewContract ||
!launchApi?.getWorkflowOverviewReadiness ||
@@ -182,6 +183,7 @@
const shellSessionHandoffPackageMountRenderState = launchApi.getShellSessionHandoffPackageMountRenderState();
const shellSessionReadinessWorkflowReport = launchApi.getShellSessionReadinessWorkflowReport();
const shellApiSurfaceInventory = launchApi.getShellApiSurfaceInventory();
const launchPersistenceSummary = launchApi.getMachineSessionPersistenceSummary();
const workflowOverviewContract = launchApi.getWorkflowOverviewContract();
assertEqual(
shellIntegrationSchema.manifestVersion,
@@ -448,6 +450,21 @@
3,
"shell API surface inventory session readiness rows",
);
assertEqual(
shellApiSurfaceInventory.counts.persistenceSummaryRows,
7,
"shell API surface inventory persistence summary rows",
);
assertEqual(
launchPersistenceSummary.apiName,
"machine-session-persistence-summary",
"launch API persistence summary API",
);
assertEqual(
launchPersistenceSummary.rows.length,
7,
"launch API persistence summary rows",
);
assertEqual(
workflowOverviewContract.pageHref,
"./workflow-overview.html",
@@ -709,12 +726,12 @@
assertEqual(workflowOverviewEmbedding.pageHref, "./workflow-overview.html", "workflow overview embedding page");
assertEqual(workflowOverviewEmbedding.ready, false, "workflow overview embedding default readiness");
assertEqual(workflowOverviewEmbedding.renderState.dataset.handoffScope, "workflow", "workflow overview embedding scope");
assertEqual(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 5, "workflow overview embedding rows");
assertEqual(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 8, "workflow overview embedding rows");
assertEqual(workflowOverviewEmbedding.error, null, "workflow overview embedding error");
assertEqual(workflowOverviewEmbeddingReport.apiName, "ini-panel-shell-workflow-overview-embedding-report", "workflow overview embedding report API name");
assertEqual(workflowOverviewEmbeddingReport.ready, false, "workflow overview embedding report readiness");
assertEqual(workflowOverviewEmbeddingReport.missingMethods.join(","), "", "workflow overview embedding report missing methods");
assertEqual(workflowOverviewEmbeddingReport.renderRowCount, 5, "workflow overview embedding report row count");
assertEqual(workflowOverviewEmbeddingReport.renderRowCount, 8, "workflow overview embedding report row count");
assertEqual(workflowOverviewEmbeddingReport.rows.length, 6, "workflow overview embedding report rows");
assertEqual(workflowOverviewEmbeddingDisplay.title, "Workflow overview embedding", "workflow overview embedding display title");
assertEqual(workflowOverviewEmbeddingDisplay.statusText, "Blocked", "workflow overview embedding display status");

View File

@@ -372,11 +372,11 @@ TOOL_TABLE = browser-shell-tool.tbl
assertEqual(workflowOverviewReadiness.missing.join(","), "", "shell workflow overview iframe missing methods");
assertEqual(workflowOverviewEmbedding.apiName, "ini-panel-shell-workflow-overview-embedding", "shell workflow overview embedding API");
assertEqual(workflowOverviewEmbedding.renderState.dataset.handoffScope, "workflow", "shell workflow overview embedding scope");
assertEqual(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 5, "shell workflow overview embedding rows");
assertEqual(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 8, "shell workflow overview embedding rows");
assertEqual(workflowOverviewEmbedding.error, null, "shell workflow overview embedding error");
assertEqual(workflowOverviewEmbeddingReport.ready, false, "shell workflow overview embedding report readiness");
assertEqual(workflowOverviewEmbeddingReport.rows.length, 6, "shell workflow overview embedding report rows");
assertEqual(workflowOverviewEmbeddingReport.renderRowCount, 5, "shell workflow overview embedding report row count");
assertEqual(workflowOverviewEmbeddingReport.renderRowCount, 8, "shell workflow overview embedding report row count");
assertEqual(workflowOverviewEmbeddingReport.error, null, "shell workflow overview embedding report error");
assertEqual(workflowOverviewEmbeddingDisplay.statusText, "Blocked", "shell workflow overview embedding display status");
assertEqual(workflowOverviewEmbeddingDisplay.rows.length, 6, "shell workflow overview embedding display rows");
@@ -508,16 +508,27 @@ TOOL_TABLE = browser-shell-tool.tbl
const readonlyStatusResult = launchApi.readShellSessionHandoffStatusFromControlPage({
controlPageApi,
});
const workflowSummaryResult = launchApi.getShellSessionHandoffWorkflowSummary({
const baseWorkflowSummaryResult = launchApi.getShellSessionHandoffWorkflowSummary({
mountWorkflow: readyMountWorkflow,
controlPageMountWorkflow: readyControlPageMountWorkflow,
readonlyStatusResult,
});
const sessionReadinessWorkflowReport = launchApi.getShellSessionReadinessWorkflowReport({
workflowSummary: workflowSummaryResult,
workflowSummary: baseWorkflowSummaryResult,
});
const shellApiSurfaceInventory = launchApi.getShellApiSurfaceInventory({
sessionReadinessWorkflowReport,
persistenceSummary: panelDoc.defaultView.linuxCncIniPanelApi.getMachineSessionPersistenceSummary(),
});
const persistenceSummary = panelDoc.defaultView.linuxCncIniPanelApi.getMachineSessionPersistenceSummary({
readonlyStatus,
});
const workflowSummaryResult = launchApi.getShellSessionHandoffWorkflowSummary({
mountWorkflow: readyMountWorkflow,
controlPageMountWorkflow: readyControlPageMountWorkflow,
readonlyStatusResult,
persistenceSummary,
apiSurfaceInventory: shellApiSurfaceInventory,
});
const workflowDisplayResult = launchApi.getShellSessionHandoffWorkflowDisplayViewModel(
workflowSummaryResult,
@@ -576,6 +587,21 @@ TOOL_TABLE = browser-shell-tool.tbl
3,
"shell handoff API surface inventory session readiness rows",
);
assertEqual(
shellApiSurfaceInventory.counts.persistenceSummaryRows,
7,
"shell handoff API surface inventory persistence summary rows",
);
assertEqual(
workflowSummaryResult.rows.some((row) => row.id === "persistence-summary" && row.value === "ready: 7 rows"),
true,
"shell handoff workflow summary persistence summary row",
);
assertEqual(
workflowSummaryResult.rows.some((row) => row.id === "api-surface-inventory" && row.value === "ready: 6 rows"),
true,
"shell handoff workflow summary API surface inventory row",
);
assertEqual(
workflowSummaryResult.sessionReadiness.ready,
true,
@@ -595,7 +621,7 @@ TOOL_TABLE = browser-shell-tool.tbl
assertEqual(workflowRenderState.dataset.handoffScope, "workflow", "shell handoff workflow render-state scope");
assertEqual(externalWorkflowDomReadiness.ready, true, "shell handoff workflow DOM readiness");
assertEqual(workflowDomMountResult.phase, "ready", "shell handoff workflow DOM mount phase");
assertEqual(workflowDomMountResult.renderResult.rowCount, 6, "shell handoff workflow DOM mount rows");
assertEqual(workflowDomMountResult.renderResult.rowCount, 8, "shell handoff workflow DOM mount rows");
assertEqual(
document.querySelector("[data-external-shell-workflow]").dataset.handoffScope,
"workflow",

View File

@@ -376,6 +376,9 @@ TOOL_TABLE = browser-tool.tbl
!uiApi?.getMachineSessionStateReport ||
!uiApi?.getMachineSessionStateReportExport ||
!uiApi?.getMachineSessionWorkflowStatus ||
!uiApi?.getMachineSessionPersistenceSummary ||
!uiApi?.getMachineSessionPersistenceDisplayViewModel ||
!uiApi?.getMachineSessionPersistenceRenderState ||
!uiApi?.renderMachineSessionControlView
) {
throw new Error("INI panel API namespace did not expose state getters");
@@ -813,6 +816,44 @@ TOOL_TABLE = browser-tool.tbl
2,
"UI machine session workflow status canonical event count",
);
const machineSessionPersistenceSummary = uiApi.getMachineSessionPersistenceSummary();
assertEqual(
machineSessionPersistenceSummary.apiName,
"machine-session-persistence-summary",
"UI machine session persistence summary API name",
);
assertEqual(
machineSessionPersistenceSummary.ready,
true,
"UI machine session persistence summary readiness",
);
assertEqual(
machineSessionPersistenceSummary.rows.find((row) => row.id === "machine-files")?.value,
"ini, parameters, tool-table, g-code",
"UI machine session persistence summary machine files",
);
assertEqual(
machineSessionPersistenceSummary.rows.find((row) => row.id === "session-load")?.value,
"loaded: /work/session-machine.ini",
"UI machine session persistence summary session load",
);
const machineSessionPersistenceDisplay = uiApi.getMachineSessionPersistenceDisplayViewModel();
assertEqual(
machineSessionPersistenceDisplay.statusText,
"Ready",
"UI machine session persistence display status",
);
const machineSessionPersistenceRenderState = uiApi.getMachineSessionPersistenceRenderState();
assertEqual(
machineSessionPersistenceRenderState.statusLine,
"Ready: No missing persistence requirements",
"UI machine session persistence render-state status",
);
assertEqual(
machineSessionPersistenceRenderState.dataset.persistenceScope,
"opfs-session",
"UI machine session persistence render-state scope",
);
const machineSessionStateBundle = uiApi.getMachineSessionStateBundle();
assertEqual(
machineSessionStateBundle.report.status.lastAction,

View File

@@ -33,6 +33,7 @@
!workflowApi?.getWorkflowOverviewSummary ||
!workflowApi?.getWorkflowOverviewSessionReadinessReport ||
!workflowApi?.getWorkflowOverviewApiSurfaceInventory ||
!workflowApi?.getWorkflowOverviewPersistenceSummary ||
!workflowApi?.getWorkflowOverviewDomContract ||
!workflowApi?.getWorkflowOverviewDomReadiness ||
!workflowApi?.renderWorkflowOverview ||
@@ -60,6 +61,7 @@
const summary = workflowApi.getWorkflowOverviewSummary();
const sessionReadinessReport = workflowApi.getWorkflowOverviewSessionReadinessReport();
const apiSurfaceInventory = workflowApi.getWorkflowOverviewApiSurfaceInventory();
const persistenceSummary = workflowApi.getWorkflowOverviewPersistenceSummary();
const domContract = workflowApi.getWorkflowOverviewDomContract();
const domReadiness = workflowApi.getWorkflowOverviewDomReadiness();
const renderResult = workflowApi.renderWorkflowOverview();
@@ -93,19 +95,30 @@
"ini-panel-shell-api-surface-inventory",
"workflow overview API surface inventory API name",
);
assertEqual(apiSurfaceInventory.rows.length, 5, "workflow overview API surface inventory rows");
assertEqual(apiSurfaceInventory.rows.length, 6, "workflow overview API surface inventory rows");
assertEqual(
apiSurfaceInventory.counts.persistenceSummaryRows,
7,
"workflow overview API surface inventory persistence summary rows",
);
assertEqual(
persistenceSummary.apiName,
"machine-session-persistence-summary",
"workflow overview persistence summary API name",
);
assertEqual(persistenceSummary.rows.length, 7, "workflow overview persistence summary rows");
assertEqual(displayViewModel.title, "Shell handoff workflow", "workflow overview display title");
assertEqual(renderState.renderStateVersion, 1, "workflow overview render-state version");
assertEqual(renderState.dataset.handoffScope, "workflow", "workflow overview render-state scope");
assertEqual(domContract.selectors.mount, "[data-handoff-workflow]", "workflow overview DOM contract mount selector");
assertEqual(domReadiness.ready, true, "workflow overview DOM readiness");
assertEqual(renderResult.rendered, true, "workflow overview render result");
assertEqual(renderResult.rowCount, 5, "workflow overview render row count");
assertEqual(renderResult.rowCount, 8, "workflow overview render row count");
assertEqual(mountResult.ready, false, "workflow overview mount result readiness");
assertEqual(mountResult.renderResult.rendered, true, "workflow overview mount result rendered");
assertEqual(embeddingReport.apiName, "ini-panel-shell-workflow-overview-embedding-report", "workflow overview embedding report API name");
assertEqual(embeddingReport.ready, false, "workflow overview embedding report readiness");
assertEqual(embeddingReport.renderRowCount, 5, "workflow overview embedding report row count");
assertEqual(embeddingReport.renderRowCount, 8, "workflow overview embedding report row count");
assertEqual(embeddingReport.rows.length, 6, "workflow overview embedding report rows");
assertEqual(embeddingDisplay.title, "Workflow overview embedding", "workflow overview embedding display title");
assertEqual(embeddingDisplay.statusText, "Blocked", "workflow overview embedding display status");
@@ -191,6 +204,16 @@
true,
"workflow overview DOM blocking reasons row",
);
assertEqual(
workflowDoc.querySelector('[data-handoff-workflow-value="api-surface-inventory"]').textContent,
"ready: 6 rows",
"workflow overview DOM API surface inventory row",
);
assertEqual(
workflowDoc.querySelector('[data-handoff-workflow-value="persistence-summary"]').textContent,
"waiting: 5 missing",
"workflow overview DOM persistence summary row",
);
document.getElementById("status").textContent = "browser_ini_workflow_overview_smoke=ok";
console.log("browser_ini_workflow_overview_smoke=ok");

View File

@@ -4,22 +4,41 @@ import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import {
INI_PANEL_ENTRIES,
analyzeIniRuntimeBoundaries,
createControlPageBrowserApiManifest,
createControlPageBrowserApiMethods,
createControlPageBrowserApiSchema,
createIniPanelLaunchApiManifest,
createIniPanelLauncherLinkViewModel,
createIniPanelShellApiSurfaceInventory,
createIniPanelShellControlPageContract,
createIniPanelShellIntegrationManifest,
createIniPanelShellIntegrationReadiness,
createIniPanelShellIntegrationSchema,
createIniPanelShellIntegrationWorkflowPlan,
createIniPanelShellSessionReadinessWorkflowReport,
createIniPanelShellViewModel,
createIniPanelShellWorkflowOverviewContract,
createIniPanelShellWorkflowOverviewEmbeddingMountDomContract,
createIniPanelShellWorkflowOverviewEmbeddingMountDomReadiness,
createLinuxCncIniSdk,
createLinuxCncInterpSdk,
createMachineSessionSnapshotPayload,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createSessionSnapshot,
defaultMachinePaths,
gcodeFilenameFromProgramPath,
gcodeProgramPath,
getIniPanelEntryByHref,
getIniPanelEntryManifest,
getOpfsRoot,
getVisibleIniPanelEntries,
isSupportedIniPanelControlPageApiManifest,
isSupportedIniPanelLaunchApiManifest,
isSupportedIniPanelShellIntegrationManifest,
loadMachineSessionFromOpfs,
loadMachineSessionSnapshot,
loadMachineTextFiles,
@@ -56,6 +75,13 @@ const requiredExports = [
["planIniFileContextStaging", planIniFileContextStaging],
["planSimConfigStaging", planSimConfigStaging],
["analyzeIniRuntimeBoundaries", analyzeIniRuntimeBoundaries],
["getIniPanelEntryManifest", getIniPanelEntryManifest],
["getIniPanelEntryByHref", getIniPanelEntryByHref],
["getVisibleIniPanelEntries", getVisibleIniPanelEntries],
["createIniPanelLauncherLinkViewModel", createIniPanelLauncherLinkViewModel],
["createMachineSessionPersistenceDisplayViewModel", createMachineSessionPersistenceDisplayViewModel],
["createMachineSessionPersistenceRenderState", createMachineSessionPersistenceRenderState],
["createMachineSessionPersistenceSummary", createMachineSessionPersistenceSummary],
["getOpfsRoot", getOpfsRoot],
["saveTextFile", saveTextFile],
["loadTextFile", loadTextFile],
@@ -80,11 +106,22 @@ const requiredExports = [
["loadMachineToolTableFromOpfs", loadMachineToolTableFromOpfs],
["loadMachineSessionFromOpfs", loadMachineSessionFromOpfs],
["readMachineSessionReadiness", readMachineSessionReadiness],
["createControlPageBrowserApiSchema", createControlPageBrowserApiSchema],
["createControlPageBrowserApiManifest", createControlPageBrowserApiManifest],
["createControlPageBrowserApiMethods", createControlPageBrowserApiMethods],
["createIniPanelShellControlPageContract", createIniPanelShellControlPageContract],
["isSupportedIniPanelControlPageApiManifest", isSupportedIniPanelControlPageApiManifest],
["createIniPanelLaunchApiManifest", createIniPanelLaunchApiManifest],
["isSupportedIniPanelLaunchApiManifest", isSupportedIniPanelLaunchApiManifest],
["createIniPanelShellIntegrationSchema", createIniPanelShellIntegrationSchema],
["createIniPanelShellIntegrationManifest", createIniPanelShellIntegrationManifest],
["createIniPanelShellIntegrationReadiness", createIniPanelShellIntegrationReadiness],
["createIniPanelShellIntegrationWorkflowPlan", createIniPanelShellIntegrationWorkflowPlan],
["isSupportedIniPanelShellIntegrationManifest", isSupportedIniPanelShellIntegrationManifest],
["createIniPanelShellViewModel", createIniPanelShellViewModel],
["createIniPanelShellApiSurfaceInventory", createIniPanelShellApiSurfaceInventory],
["createIniPanelShellSessionReadinessWorkflowReport", createIniPanelShellSessionReadinessWorkflowReport],
["createIniPanelShellWorkflowOverviewContract", createIniPanelShellWorkflowOverviewContract],
[
"createIniPanelShellWorkflowOverviewEmbeddingMountDomContract",
createIniPanelShellWorkflowOverviewEmbeddingMountDomContract,
@@ -116,12 +153,80 @@ assert.equal(sessionSnapshotPath("sdk-session"), "linuxcnc/sessions/sdk-session/
assert.equal(normalizeOpfsPath("linuxcnc/machines/sdk-mill/tool.tbl"), "linuxcnc/machines/sdk-mill/tool.tbl");
assert.equal(gcodeFilenameFromProgramPath("linuxcnc/gcode/demo.ngc"), "demo.ngc");
assert.deepEqual(getIniPanelEntryManifest(), INI_PANEL_ENTRIES);
assert.deepEqual(getVisibleIniPanelEntries(), INI_PANEL_ENTRIES);
assert.deepEqual(getIniPanelEntryByHref("./control-page.html"), {
id: "control-view",
title: "Open read-only control view",
href: "./control-page.html",
});
assert.deepEqual(createIniPanelLauncherLinkViewModel(), [
{
entryId: "edit-run",
href: "./index.html",
label: "Open edit and run panel",
},
{
entryId: "control-view",
href: "./control-page.html",
label: "Open read-only control view",
},
{
entryId: "workflow-overview",
href: "./workflow-overview.html",
label: "Open shell handoff overview",
},
]);
assert.equal(
createMachineSessionPersistenceSummary({
state: {
badges: { opfs: "OPFS: ready" },
fields: { sessionSnapshot: "sdk-session/snapshot.json", sessionIni: "/work/session-machine.ini" },
sessionLoad: { iniWasmPath: "/work/session-machine.ini" },
sessionReadiness: { phase: "ready", ready: true, missing: [] },
},
}).rows.find(({ id }) => id === "session-load")?.value,
"loaded: /work/session-machine.ini",
);
assert.equal(
createMachineSessionPersistenceRenderState(
createMachineSessionPersistenceDisplayViewModel(createMachineSessionPersistenceSummary()),
).apiName,
"machine-session-persistence-render-state",
);
const controlPageApiSchema = createControlPageBrowserApiSchema();
const controlPageApiManifest = createControlPageBrowserApiManifest();
assert.equal(controlPageApiSchema.apiName, "ini-panel-control-page");
assert.equal(isSupportedIniPanelControlPageApiManifest(controlPageApiManifest), true);
assert.deepEqual(controlPageApiManifest.methods, createControlPageBrowserApiMethods());
assert.equal(
createIniPanelShellControlPageContract().readonlyStatusApiManifest.apiName,
"machine-session-readonly-status",
);
const launchManifest = createIniPanelLaunchApiManifest();
assert.equal(isSupportedIniPanelLaunchApiManifest(launchManifest), true);
assert.equal(
launchManifest.methods.includes("mountWorkflowOverviewEmbeddingMountState"),
true,
);
assert.deepEqual(
launchManifest.visibleEntries,
getVisibleIniPanelEntries().map(({ id, href, title }) => ({ id, href, title })),
);
const shellIntegrationManifest = createIniPanelShellIntegrationManifest();
assert.equal(createIniPanelShellIntegrationSchema().apiName, "ini-panel-shell-integration");
assert.equal(isSupportedIniPanelShellIntegrationManifest(shellIntegrationManifest), true);
assert.equal(createIniPanelShellIntegrationReadiness(shellIntegrationManifest).ready, true);
assert.equal(createIniPanelShellIntegrationWorkflowPlan({
manifest: shellIntegrationManifest,
}).ready, true);
assert.equal(
createIniPanelShellWorkflowOverviewContract().methodNames.includes("getWorkflowOverviewApiSurfaceInventory"),
true,
);
const shellViewModel = createIniPanelShellViewModel();
assert.equal(
@@ -140,6 +245,19 @@ assert.equal(
createIniPanelShellApiSurfaceInventory().apiName,
"ini-panel-shell-api-surface-inventory",
);
assert.equal(shellViewModel.shellApiSurfaceInventory.ready, true);
assert.equal(
shellViewModel.shellSessionHandoffWorkflowSummary.rows.find(
({ id }) => id === "persistence-summary",
)?.value,
"waiting: 5 missing",
);
assert.equal(
shellViewModel.shellSessionHandoffWorkflowSummary.rows.find(
({ id }) => id === "api-surface-inventory",
)?.value,
"ready: 6 rows",
);
assert.equal(
shellViewModel.mountWorkflowOverviewEmbeddingMountState,
mountIniPanelShellWorkflowOverviewEmbeddingMountState,

View File

@@ -167,6 +167,9 @@ const requiredShellExports = [
"createIniPanelShellViewModel",
"getIniPanelEntryByHref",
"getVisibleIniPanelEntries",
"createMachineSessionPersistenceDisplayViewModel",
"createMachineSessionPersistenceRenderState",
"createMachineSessionPersistenceSummary",
"isSupportedIniPanelControlPageApiManifest",
"isSupportedIniPanelLaunchApiManifest",
"isSupportedIniPanelShellIntegrationManifest",

View File

@@ -69,6 +69,7 @@ assert.deepEqual(manifest, {
"mountShellSessionHandoff",
"mountShellSessionHandoffFromControlPage",
"readShellSessionHandoffStatusFromControlPage",
"getMachineSessionPersistenceSummary",
"getShellSessionHandoffWorkflowSummary",
"getShellSessionReadinessWorkflowReport",
"getShellApiSurfaceInventory",
@@ -227,6 +228,7 @@ assert.match(launchText, /\brenderShellSessionHandoffMountState\b/);
assert.match(launchText, /\bmountShellSessionHandoff\b/);
assert.match(launchText, /\bmountShellSessionHandoffFromControlPage\b/);
assert.match(launchText, /\breadShellSessionHandoffStatusFromControlPage\b/);
assert.match(launchText, /\bgetMachineSessionPersistenceSummary\b/);
assert.match(launchText, /\bgetShellSessionHandoffWorkflowSummary\b/);
assert.match(launchText, /\bgetShellSessionReadinessWorkflowReport\b/);
assert.match(launchText, /\bgetShellApiSurfaceInventory\b/);

View File

@@ -179,7 +179,7 @@ assert.deepEqual(readiness, {
counts: {
pages: 3,
launcherLinks: 3,
launchMethods: 57,
launchMethods: 58,
controlPageMethods: 11,
persistenceCapabilities: 3,
},
@@ -242,7 +242,7 @@ assert.deepEqual(handoffSummary, {
counts: {
pages: 3,
launcherLinks: 3,
launchMethods: 57,
launchMethods: 58,
controlPageMethods: 11,
persistenceCapabilities: 3,
},
@@ -779,6 +779,7 @@ assert.deepEqual(createIniPanelShellWorkflowOverviewContract(), {
"getWorkflowOverviewSummary",
"getWorkflowOverviewSessionReadinessReport",
"getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
@@ -827,6 +828,7 @@ assert.deepEqual(
[
"getWorkflowOverviewDisplayViewModel",
"getWorkflowOverviewSummary",
"getWorkflowOverviewPersistenceSummary",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
@@ -1246,7 +1248,7 @@ assert.deepEqual(createIniPanelShellIntegrationReadiness(blockedManifest), {
counts: {
pages: 3,
launcherLinks: 3,
launchMethods: 57,
launchMethods: 58,
controlPageMethods: 11,
persistenceCapabilities: 3,
},

View File

@@ -3,6 +3,9 @@ import assert from "node:assert/strict";
import {
createIniPanelStateSummary,
createMachineSessionControlView,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionStateSnapshot,
createMachineSessionStateBundle,
createMachineSessionStateReport,
@@ -566,6 +569,145 @@ const expectedBundleReport = {
},
};
const readyPersistenceSummary = createMachineSessionPersistenceSummary({
state: {
badges: {
ini: "INI WASM: ready",
interp: "Interpreter WASM: ready",
opfs: "OPFS: ready",
},
machineFiles: {
iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini",
parameterOpfsPath: "linuxcnc/machines/xyzab-tdr/linuxcnc.var",
toolTableOpfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl",
gcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc",
},
fields: {
sessionSnapshot: "ui-machine-session/ui-machine-session.json",
sessionIni: "/work/session-machine.ini",
sessionParameters: "/work/session-linuxcnc.var",
sessionToolTable: "/work/session-tool.tbl",
sessionGcode: "linuxcnc/gcode/ui-session.ngc",
},
sessionLoad: {
iniWasmPath: "/work/session-machine.ini",
parameterWasmPath: "/work/session-linuxcnc.var",
toolTableWasmPath: "/work/session-tool.tbl",
},
sessionReadiness: sessionReadinessFixture,
},
readonlyStatus: {
phase: "ready",
ready: true,
},
handoffWorkflowSummary: {
phase: "ready",
ready: true,
},
});
assert.deepEqual(
readyPersistenceSummary,
{
apiName: "machine-session-persistence-summary",
summaryVersion: 1,
phase: "ready",
ready: true,
checks: {
opfs: true,
machineFiles: true,
sessionSnapshot: true,
sessionReadiness: true,
sessionLoad: true,
},
missing: [],
counts: {
machineFiles: 4,
missing: 0,
},
rows: [
{
id: "opfs",
label: "OPFS",
value: "OPFS: ready",
},
{
id: "machine-files",
label: "Machine files",
value: "ini, parameters, tool-table, g-code",
},
{
id: "session-snapshot",
label: "Session snapshot",
value: "ui-machine-session/ui-machine-session.json",
},
{
id: "session-readiness",
label: "Session readiness",
value: "ready",
},
{
id: "session-load",
label: "Session load",
value: "loaded: /work/session-machine.ini",
},
{
id: "readonly-status",
label: "Readonly status",
value: "ready",
},
{
id: "handoff-readiness",
label: "Handoff readiness",
value: "ready",
},
],
},
);
assert.deepEqual(
createMachineSessionPersistenceSummary().missing,
["opfs", "machineFiles", "sessionSnapshot", "sessionReadiness", "sessionLoad"],
);
assert.deepEqual(
createMachineSessionPersistenceDisplayViewModel(readyPersistenceSummary),
{
phase: "ready",
title: "OPFS/session persistence",
statusText: "Ready",
detailText: "No missing persistence requirements",
rows: readyPersistenceSummary.rows,
},
);
assert.deepEqual(
createMachineSessionPersistenceRenderState(
createMachineSessionPersistenceDisplayViewModel(readyPersistenceSummary),
),
{
apiName: "machine-session-persistence-render-state",
renderStateVersion: 1,
phase: "ready",
ready: true,
title: "OPFS/session persistence",
statusText: "Ready",
detailText: "No missing persistence requirements",
statusLine: "Ready: No missing persistence requirements",
rows: readyPersistenceSummary.rows,
dataset: {
persistencePhase: "ready",
persistenceReady: "true",
persistenceScope: "opfs-session",
},
},
);
assert.equal(
createMachineSessionPersistenceRenderState().statusLine,
"Waiting: opfs, machineFiles, sessionSnapshot, sessionReadiness, sessionLoad",
);
assert.deepEqual(
createMachineSessionWorkflowOverview(expectedBundleReport),
expectedWorkflowOverview,

View File

@@ -67,6 +67,9 @@ import {
createControlPageRefreshState,
createControlPageSessionLoadState,
createMachineSessionControlPageController,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
getIniPanelEntryByHref,
getIniPanelEntryManifest,
getVisibleIniPanelEntries,
@@ -104,6 +107,9 @@ assert.deepEqual(createControlPageSessionLoadState({ phase: "waiting-panel" }),
});
assert.equal(getIniPanelEntryByHref("./index.html")?.id, "edit-run");
assert.equal(typeof createMachineSessionControlPageController, "function");
assert.equal(typeof createMachineSessionPersistenceDisplayViewModel, "function");
assert.equal(typeof createMachineSessionPersistenceRenderState, "function");
assert.equal(typeof createMachineSessionPersistenceSummary, "function");
assert.equal(typeof createMachineSessionReadonlyStatus, "function");
assert.equal(typeof createMachineSessionReadonlyStatusApiManifest, "function");
assert.equal(typeof createControlPageBrowserApiManifest, "function");
@@ -667,6 +673,7 @@ assert.deepEqual(shellViewModel.shellWorkflowOverviewContract, {
"getWorkflowOverviewSummary",
"getWorkflowOverviewSessionReadinessReport",
"getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
@@ -1113,13 +1120,17 @@ assert.equal(workflowSummaryResult.apiName, "ini-panel-shell-session-handoff-wor
assert.equal(workflowSummaryResult.summaryVersion, 1);
assert.equal(workflowSummaryResult.phase, "blocked");
assert.equal(workflowSummaryResult.ready, false);
assert.deepEqual(workflowSummaryResult.apiSurfaceInventory, null);
assert.deepEqual(workflowSummaryResult.persistenceSummary, null);
assert.deepEqual(workflowSummaryResult.sessionReadiness, {
phase: "ready",
ready: true,
missing: [],
});
assert.equal(workflowSummaryResult.rows.find(({ id }) => id === "session-readiness")?.value, "ready");
assert.equal(workflowSummaryResult.rows.length, 6);
assert.equal(workflowSummaryResult.rows.find(({ id }) => id === "persistence-summary")?.value, "missing");
assert.equal(workflowSummaryResult.rows.find(({ id }) => id === "api-surface-inventory")?.value, "missing");
assert.equal(workflowSummaryResult.rows.length, 8);
assert.equal(workflowSummaryResult.blockingReasons[0], "mount:blocked");
const sessionReadinessWorkflowReport = createIniPanelShellSessionReadinessWorkflowReport({
workflowSummary: workflowSummaryResult,
@@ -1137,7 +1148,18 @@ assert.equal(shellViewModel.shellSessionReadinessWorkflowReport.rows.length, 3);
assert.equal(shellViewModel.shellApiSurfaceInventory.apiName, "ini-panel-shell-api-surface-inventory");
assert.equal(shellViewModel.shellApiSurfaceInventory.ready, true);
assert.equal(shellViewModel.shellApiSurfaceInventory.counts.sessionReadinessRows, 3);
assert.equal(shellViewModel.shellApiSurfaceInventory.rows.length, 5);
assert.equal(shellViewModel.shellApiSurfaceInventory.counts.persistenceSummaryRows, 7);
assert.equal(shellViewModel.shellApiSurfaceInventory.rows.length, 6);
assert.equal(shellViewModel.shellPersistenceSummary.ready, false);
assert.equal(
shellViewModel.shellSessionHandoffWorkflowSummary.rows.find(({ id }) => id === "persistence-summary")?.value,
"waiting: 5 missing",
);
assert.equal(shellViewModel.shellSessionHandoffWorkflowSummary.apiSurfaceInventory.ready, true);
assert.equal(
shellViewModel.shellSessionHandoffWorkflowSummary.rows.find(({ id }) => id === "api-surface-inventory")?.value,
"ready: 6 rows",
);
const readyWorkflowSummaryResult = createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow: {
phase: "ready",
@@ -1157,7 +1179,7 @@ assert.equal(workflowDisplayViewModel.phase, "blocked");
assert.equal(workflowDisplayViewModel.title, "Shell handoff workflow");
assert.equal(workflowDisplayViewModel.statusText, "Blocked");
assert.equal(workflowDisplayViewModel.detailText, "mount:blocked");
assert.equal(workflowDisplayViewModel.rows.length, 6);
assert.equal(workflowDisplayViewModel.rows.length, 8);
const readyWorkflowDisplayViewModel = createIniPanelShellSessionHandoffWorkflowDisplayViewModel(
readyWorkflowSummaryResult,
);
@@ -1172,7 +1194,7 @@ assert.equal(workflowRenderState.renderStateVersion, 1);
assert.equal(workflowRenderState.phase, "blocked");
assert.equal(workflowRenderState.statusLine, "Blocked: mount:blocked");
assert.equal(workflowRenderState.dataset.handoffScope, "workflow");
assert.equal(workflowRenderState.rows.length, 6);
assert.equal(workflowRenderState.rows.length, 8);
const readyWorkflowRenderState = createIniPanelShellSessionHandoffWorkflowRenderState(
readyWorkflowDisplayViewModel,
);
@@ -1215,13 +1237,15 @@ assert.deepEqual(
{
rendered: true,
statusLine: "Blocked: mount:blocked",
rowCount: 6,
rowCount: 8,
rowIds: [
"mount-workflow",
"control-page-mount-workflow",
"readonly-status-workflow",
"session-readiness",
"readonly-status-missing-fields",
"persistence-summary",
"api-surface-inventory",
"blocking-reasons",
],
dataset: {
@@ -1242,7 +1266,7 @@ assert.equal(workflowDomMountResult.apiName, "ini-panel-shell-session-handoff-wo
assert.equal(workflowDomMountResult.workflowVersion, 1);
assert.equal(workflowDomMountResult.phase, "blocked");
assert.equal(workflowDomMountResult.ready, false);
assert.equal(workflowDomMountResult.renderResult.rowCount, 6);
assert.equal(workflowDomMountResult.renderResult.rowCount, 8);
assert.equal(workflowDomMountResult.renderResult.dataset.handoffScope, "workflow");
assert.deepEqual(createIniPanelShellWorkflowOverviewContract(), shellViewModel.shellWorkflowOverviewContract);
assert.deepEqual(createIniPanelShellWorkflowOverviewReadiness(), {
@@ -1259,6 +1283,7 @@ const workflowOverviewApi = {
getWorkflowOverviewSummary: () => workflowSummaryResult,
getWorkflowOverviewSessionReadinessReport: () => sessionReadinessWorkflowReport,
getWorkflowOverviewApiSurfaceInventory: () => shellViewModel.shellApiSurfaceInventory,
getWorkflowOverviewPersistenceSummary: () => shellViewModel.shellPersistenceSummary,
getWorkflowOverviewDomContract: createIniPanelShellSessionHandoffWorkflowDomContract,
getWorkflowOverviewDomReadiness: createIniPanelShellSessionHandoffWorkflowDomReadiness,
renderWorkflowOverview: renderIniPanelShellSessionHandoffWorkflowState,
@@ -1291,7 +1316,7 @@ assert.equal(workflowOverviewEmbedding.apiName, "ini-panel-shell-workflow-overvi
assert.equal(workflowOverviewEmbedding.embeddingVersion, 1);
assert.equal(workflowOverviewEmbedding.ready, false);
assert.equal(workflowOverviewEmbedding.renderState.statusLine, "Blocked: mount:blocked");
assert.equal(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 6);
assert.equal(workflowOverviewEmbedding.mountResult.renderResult.rowCount, 8);
assert.equal(workflowOverviewEmbedding.error, null);
const workflowOverviewEmbeddingReport = createIniPanelShellWorkflowOverviewEmbeddingReport(workflowOverviewEmbedding);
assert.deepEqual(workflowOverviewEmbeddingReport, {
@@ -1307,7 +1332,7 @@ assert.deepEqual(workflowOverviewEmbeddingReport, {
contract: shellViewModel.shellWorkflowOverviewContract,
missingMethods: [],
mountPhase: "blocked",
renderRowCount: 6,
renderRowCount: 8,
error: null,
blockingReasons: ["embedding:blocked", "mount:blocked"],
rows: [
@@ -1334,7 +1359,7 @@ assert.deepEqual(workflowOverviewEmbeddingReport, {
{
id: "render-row-count",
label: "Render row count",
value: "6",
value: "8",
},
{
id: "error",