收口 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

@@ -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",