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

@@ -46,6 +46,9 @@ import {
} from "./session-workflow.js";
import {
createMachineSessionControlView,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionStateSnapshot,
createMachineSessionStateBundle,
createMachineSessionStateReport,
@@ -171,6 +174,25 @@ function getMachineSessionWorkflowStatus() {
return createMachineSessionWorkflowStatus(window.linuxCncIniPanelMachineSessionState);
}
function getMachineSessionPersistenceSummary(options = {}) {
return createMachineSessionPersistenceSummary({
state: window.linuxCncIniPanelMachineSessionState,
...options,
});
}
function getMachineSessionPersistenceDisplayViewModel(options = {}) {
return createMachineSessionPersistenceDisplayViewModel(
getMachineSessionPersistenceSummary(options),
);
}
function getMachineSessionPersistenceRenderState(options = {}) {
return createMachineSessionPersistenceRenderState(
getMachineSessionPersistenceDisplayViewModel(options),
);
}
function getMachineSessionStateBundle() {
return createMachineSessionStateBundle(window.linuxCncIniPanelMachineSessionState);
}
@@ -203,6 +225,9 @@ window.linuxCncIniPanelApi = {
getMachineSessionStateReport,
getMachineSessionStateReportExport,
getMachineSessionWorkflowStatus,
getMachineSessionPersistenceSummary,
getMachineSessionPersistenceDisplayViewModel,
getMachineSessionPersistenceRenderState,
renderMachineSessionControlView: renderCurrentMachineSessionControlView,
};
window.getMachineSessionControlView = getMachineSessionControlView;
@@ -210,6 +235,9 @@ window.getMachineSessionStateBundle = getMachineSessionStateBundle;
window.getMachineSessionStateReport = getMachineSessionStateReport;
window.getMachineSessionStateReportExport = getMachineSessionStateReportExport;
window.getMachineSessionWorkflowStatus = getMachineSessionWorkflowStatus;
window.getMachineSessionPersistenceSummary = getMachineSessionPersistenceSummary;
window.getMachineSessionPersistenceDisplayViewModel = getMachineSessionPersistenceDisplayViewModel;
window.getMachineSessionPersistenceRenderState = getMachineSessionPersistenceRenderState;
window.renderMachineSessionControlView = renderCurrentMachineSessionControlView;
window.linuxCncIniPanelMachineSessionState = panelMachineSessionState;
renderCurrentMachineSessionControlView();

View File

@@ -116,6 +116,7 @@
mountIniPanelShellSessionHandoff,
mountIniPanelShellSessionHandoffFromControlPage,
readIniPanelShellSessionHandoffStatusFromControlPage,
createMachineSessionPersistenceSummary,
createIniPanelShellSessionHandoffWorkflowSummary,
createIniPanelShellSessionReadinessWorkflowReport,
createIniPanelShellSessionHandoffWorkflowDisplayViewModel,
@@ -229,6 +230,9 @@
...(options ?? {}),
})
),
getMachineSessionPersistenceSummary: (options) => (
createMachineSessionPersistenceSummary(options)
),
getShellSessionHandoffWorkflowSummary: (options) => (
createIniPanelShellSessionHandoffWorkflowSummary(options ?? {
mountWorkflow: {

View File

@@ -156,6 +156,156 @@ export function createMachineSessionWorkflowStatus(state = {}) {
};
}
export function createMachineSessionPersistenceSummary({
state = {},
report = createMachineSessionStateReport(state),
workflowStatus = createMachineSessionWorkflowStatus(state),
readonlyStatus = null,
handoffSummary = null,
handoffWorkflowSummary = null,
} = {}) {
const readiness = report.readiness ?? {};
const machineFiles = state.machineFiles ?? {};
const session = report.session ?? {};
const loaded = report.loaded ?? {};
const sessionReadiness = report.sessionReadiness ?? workflowStatus.sessionReadiness ?? null;
const opfsReady = String(readiness.opfs ?? "").toLowerCase().includes("ready");
const machineFileLabels = [
machineFiles.iniOpfsPath || session.ini ? "ini" : null,
machineFiles.parameterOpfsPath || session.parameters ? "parameters" : null,
machineFiles.toolTableOpfsPath || session.toolTable ? "tool-table" : null,
machineFiles.gcodeOpfsPath || session.gcode ? "g-code" : null,
].filter(Boolean);
const machineFilesReady = machineFileLabels.length > 0;
const snapshotReady = Boolean(session.snapshotLabel);
const sessionReadinessReady = sessionReadiness?.ready === true;
const sessionLoadReady = Boolean(loaded.iniWasmPath);
const readonlyStatusValue = readonlyStatus
? (readonlyStatus.ready === true ? "ready" : readonlyStatus.phase ?? "available")
: "not-provided";
const handoffValue = handoffWorkflowSummary
? (handoffWorkflowSummary.ready === true ? "ready" : handoffWorkflowSummary.phase ?? "blocked")
: (
handoffSummary
? (handoffSummary.ready === true ? "ready" : handoffSummary.phase ?? "blocked")
: "not-provided"
);
const checks = {
opfs: opfsReady,
machineFiles: machineFilesReady,
sessionSnapshot: snapshotReady,
sessionReadiness: sessionReadinessReady,
sessionLoad: sessionLoadReady,
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "machine-session-persistence-summary",
summaryVersion: 1,
phase: ready ? "ready" : "waiting",
ready,
checks,
missing,
counts: {
machineFiles: machineFileLabels.length,
missing: missing.length,
},
rows: [
{
id: "opfs",
label: "OPFS",
value: readiness.opfs ?? "missing",
},
{
id: "machine-files",
label: "Machine files",
value: machineFileLabels.length > 0 ? machineFileLabels.join(", ") : "missing",
},
{
id: "session-snapshot",
label: "Session snapshot",
value: session.snapshotLabel ?? "missing",
},
{
id: "session-readiness",
label: "Session readiness",
value: sessionReadiness
? (sessionReadiness.ready ? "ready" : `blocked: ${sessionReadiness.missing?.join(", ") || "unknown"}`)
: "missing",
},
{
id: "session-load",
label: "Session load",
value: loaded.iniWasmPath ? `loaded: ${loaded.iniWasmPath}` : "missing",
},
{
id: "readonly-status",
label: "Readonly status",
value: readonlyStatusValue,
},
{
id: "handoff-readiness",
label: "Handoff readiness",
value: handoffValue,
},
],
};
}
export function createMachineSessionPersistenceDisplayViewModel(
summary = createMachineSessionPersistenceSummary(),
) {
const missing = Array.isArray(summary?.missing) ? summary.missing : [];
const rows = Array.isArray(summary?.rows)
? summary.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
return {
phase: summary?.phase === "ready" ? "ready" : "waiting",
title: "OPFS/session persistence",
statusText: summary?.ready ? "Ready" : "Waiting",
detailText: missing.length > 0 ? missing.join(", ") : "No missing persistence requirements",
rows,
};
}
export function createMachineSessionPersistenceRenderState(
displayViewModel = createMachineSessionPersistenceDisplayViewModel(),
) {
const rows = Array.isArray(displayViewModel?.rows)
? displayViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = displayViewModel?.phase === "ready" && displayViewModel?.statusText === "Ready";
const statusText = displayViewModel?.statusText ?? (ready ? "Ready" : "Waiting");
const detailText = displayViewModel?.detailText ?? "No missing persistence requirements";
return {
apiName: "machine-session-persistence-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "waiting",
ready,
title: displayViewModel?.title ?? "OPFS/session persistence",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
persistencePhase: ready ? "ready" : "waiting",
persistenceReady: ready ? "true" : "false",
persistenceScope: "opfs-session",
},
};
}
export function createMachineSessionWorkflowOverview(report = {}) {
const readiness = report.readiness ?? {};
const loaded = report.loaded ?? {};

View File

@@ -28,6 +28,9 @@ import {
createMachineSessionReadonlyStatusApiManifest,
readMachineSessionReadonlyStatus,
} from "./readonly-status-api.js";
import {
createMachineSessionPersistenceSummary,
} from "./panel-state-summary.js";
export {
controlPageStatusText,
createControlPageRefreshState,
@@ -58,6 +61,17 @@ export {
export {
renderMachineSessionControlView,
} from "./control-view-renderer.js";
export {
createMachineSessionControlView,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionStateBundle,
createMachineSessionStateReport,
createMachineSessionStateReportExport,
createMachineSessionWorkflowOverview,
createMachineSessionWorkflowStatus,
} from "./panel-state-summary.js";
export function getVisibleIniPanelEntries() {
return getIniPanelEntryManifest();
@@ -159,6 +173,7 @@ export function createIniPanelLaunchApiManifest(entries = getVisibleIniPanelEntr
"mountShellSessionHandoff",
"mountShellSessionHandoffFromControlPage",
"readShellSessionHandoffStatusFromControlPage",
"getMachineSessionPersistenceSummary",
"getShellSessionHandoffWorkflowSummary",
"getShellSessionReadinessWorkflowReport",
"getShellApiSurfaceInventory",
@@ -1428,6 +1443,8 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({
statusLine: "Blocked: readonly status unavailable",
missingStatusFields: [],
},
persistenceSummary = null,
apiSurfaceInventory = null,
} = {}) {
const sessionReadiness = readonlyStatusResult?.readonlyStatus?.sessionReadiness ?? null;
const sessionReadinessMissing = Array.isArray(sessionReadiness?.missing)
@@ -1456,6 +1473,32 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({
blockingReasons.push(`readonly-status:${readonlyDetail}`);
}
const ready = blockingReasons.length === 0;
const apiSurfaceRows = Array.isArray(apiSurfaceInventory?.rows)
? apiSurfaceInventory.rows
: [];
const apiSurfaceValue = apiSurfaceInventory
? (
apiSurfaceInventory.ready
? `ready: ${apiSurfaceRows.length} rows`
: `blocked: ${apiSurfaceInventory.phase ?? "unknown"}`
)
: "missing";
const apiSurfaceCounts = apiSurfaceInventory?.counts && typeof apiSurfaceInventory.counts === "object"
? { ...apiSurfaceInventory.counts }
: null;
const persistenceRows = Array.isArray(persistenceSummary?.rows)
? persistenceSummary.rows
: [];
const persistenceMissing = Array.isArray(persistenceSummary?.missing)
? persistenceSummary.missing
: [];
const persistenceValue = persistenceSummary
? (
persistenceSummary.ready
? `ready: ${persistenceRows.length} rows`
: `${persistenceSummary.phase ?? "waiting"}: ${persistenceMissing.length} missing`
)
: "missing";
return {
apiName: "ini-panel-shell-session-handoff-workflow-summary",
@@ -1490,6 +1533,22 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({
missing: sessionReadinessMissing,
}
: null,
apiSurfaceInventory: apiSurfaceInventory
? {
phase: apiSurfaceInventory.phase ?? (apiSurfaceInventory.ready ? "ready" : "blocked"),
ready: apiSurfaceInventory.ready === true,
counts: apiSurfaceCounts,
apiNames: apiSurfaceInventory.apiNames ? { ...apiSurfaceInventory.apiNames } : null,
}
: null,
persistenceSummary: persistenceSummary
? {
phase: persistenceSummary.phase ?? (persistenceSummary.ready ? "ready" : "waiting"),
ready: persistenceSummary.ready === true,
counts: persistenceSummary.counts ? { ...persistenceSummary.counts } : null,
missing: persistenceMissing,
}
: null,
blockingReasons,
rows: [
{
@@ -1520,6 +1579,16 @@ export function createIniPanelShellSessionHandoffWorkflowSummary({
? readonlyStatusResult.missingStatusFields.join(", ")
: "none",
},
{
id: "persistence-summary",
label: "Persistence summary",
value: persistenceValue,
},
{
id: "api-surface-inventory",
label: "API surface inventory",
value: apiSurfaceValue,
},
{
id: "blocking-reasons",
label: "Blocking reasons",
@@ -1609,6 +1678,7 @@ export function createIniPanelShellApiSurfaceInventory({
controlPageApiManifest = createControlPageBrowserApiManifest(),
workflowOverviewContract = createIniPanelShellWorkflowOverviewContract(),
sessionReadinessWorkflowReport = createIniPanelShellSessionReadinessWorkflowReport(),
persistenceSummary = createMachineSessionPersistenceSummary(),
} = {}) {
const launchMethods = Array.isArray(launchApiManifest?.methods) ? launchApiManifest.methods : [];
const controlPageMethods = Array.isArray(controlPageApiManifest?.methods) ? controlPageApiManifest.methods : [];
@@ -1621,11 +1691,15 @@ export function createIniPanelShellApiSurfaceInventory({
const sessionReadinessRows = Array.isArray(sessionReadinessWorkflowReport?.rows)
? sessionReadinessWorkflowReport.rows
: [];
const persistenceSummaryRows = Array.isArray(persistenceSummary?.rows)
? persistenceSummary.rows
: [];
const ready = Boolean(
launchApiManifest?.apiName
&& controlPageApiManifest?.apiName
&& workflowOverviewContract?.apiName
&& sessionReadinessWorkflowReport?.apiName,
&& sessionReadinessWorkflowReport?.apiName
&& persistenceSummary?.apiName,
);
return {
@@ -1639,12 +1713,14 @@ export function createIniPanelShellApiSurfaceInventory({
workflowOverviewMethods: workflowOverviewMethods.length,
persistenceCapabilities: persistenceCapabilities.length,
sessionReadinessRows: sessionReadinessRows.length,
persistenceSummaryRows: persistenceSummaryRows.length,
},
apiNames: {
launch: launchApiManifest?.apiName ?? null,
controlPage: controlPageApiManifest?.apiName ?? null,
workflowOverview: workflowOverviewContract?.apiName ?? null,
sessionReadinessReport: sessionReadinessWorkflowReport?.apiName ?? null,
persistenceSummary: persistenceSummary?.apiName ?? null,
},
entries: [
{
@@ -1671,6 +1747,12 @@ export function createIniPanelShellApiSurfaceInventory({
apiName: sessionReadinessWorkflowReport?.apiName ?? null,
count: sessionReadinessRows.length,
},
{
id: "persistence-summary",
label: "Persistence summary",
apiName: persistenceSummary?.apiName ?? null,
count: persistenceSummaryRows.length,
},
{
id: "persistence-capabilities",
label: "Persistence capabilities",
@@ -1699,6 +1781,11 @@ export function createIniPanelShellApiSurfaceInventory({
label: "Session readiness report",
value: sessionReadinessWorkflowReport?.apiName ?? "missing",
},
{
id: "persistence-summary",
label: "Persistence summary",
value: persistenceSummary?.apiName ?? "missing",
},
{
id: "persistence-capabilities",
label: "Persistence capabilities",
@@ -1777,6 +1864,7 @@ export function createIniPanelShellWorkflowOverviewContract() {
"getWorkflowOverviewSummary",
"getWorkflowOverviewSessionReadinessReport",
"getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
@@ -2668,7 +2756,10 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
shellSessionHandoffPackageMountDisplayViewModel,
);
const shellSessionHandoffMountDomContract = createIniPanelShellSessionHandoffMountDomContract();
const shellSessionHandoffWorkflowSummary = createIniPanelShellSessionHandoffWorkflowSummary({
const shellSessionHandoffReadonlyStatusResult = readIniPanelShellSessionHandoffStatusFromControlPage({
handoffSummary: shellSessionHandoffSummary,
});
const baseShellSessionHandoffWorkflowSummary = createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow: {
phase: shellSessionHandoffPackageMountRenderState.phase,
ready: shellSessionHandoffPackageMountRenderState.ready,
@@ -2679,12 +2770,27 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
ready: shellSessionHandoffPackageMountState.ready,
statusLine: shellSessionHandoffPackageMountState.statusLine,
},
readonlyStatusResult: readIniPanelShellSessionHandoffStatusFromControlPage({
handoffSummary: shellSessionHandoffSummary,
}),
readonlyStatusResult: shellSessionHandoffReadonlyStatusResult,
});
const shellSessionHandoffWorkflowDomContract = createIniPanelShellSessionHandoffWorkflowDomContract();
const shellWorkflowOverviewContract = createIniPanelShellWorkflowOverviewContract();
const shellSessionReadinessWorkflowReport = createIniPanelShellSessionReadinessWorkflowReport({
workflowSummary: shellSessionHandoffWorkflowSummary,
workflowSummary: baseShellSessionHandoffWorkflowSummary,
});
const shellPersistenceSummary = createMachineSessionPersistenceSummary();
const shellApiSurfaceInventory = createIniPanelShellApiSurfaceInventory({
launchApiManifest: shellIntegrationManifest.launchApiManifest,
controlPageApiManifest: shellIntegrationManifest.controlPageApiManifest,
workflowOverviewContract: shellWorkflowOverviewContract,
sessionReadinessWorkflowReport: shellSessionReadinessWorkflowReport,
persistenceSummary: shellPersistenceSummary,
});
const shellSessionHandoffWorkflowSummary = createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow: baseShellSessionHandoffWorkflowSummary.mountWorkflow,
controlPageMountWorkflow: baseShellSessionHandoffWorkflowSummary.controlPageMountWorkflow,
readonlyStatusResult: shellSessionHandoffReadonlyStatusResult,
persistenceSummary: shellPersistenceSummary,
apiSurfaceInventory: shellApiSurfaceInventory,
});
const shellSessionHandoffWorkflowDisplayViewModel = createIniPanelShellSessionHandoffWorkflowDisplayViewModel(
shellSessionHandoffWorkflowSummary,
@@ -2692,14 +2798,6 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
const shellSessionHandoffWorkflowRenderState = createIniPanelShellSessionHandoffWorkflowRenderState(
shellSessionHandoffWorkflowDisplayViewModel,
);
const shellSessionHandoffWorkflowDomContract = createIniPanelShellSessionHandoffWorkflowDomContract();
const shellWorkflowOverviewContract = createIniPanelShellWorkflowOverviewContract();
const shellApiSurfaceInventory = createIniPanelShellApiSurfaceInventory({
launchApiManifest: shellIntegrationManifest.launchApiManifest,
controlPageApiManifest: shellIntegrationManifest.controlPageApiManifest,
workflowOverviewContract: shellWorkflowOverviewContract,
sessionReadinessWorkflowReport: shellSessionReadinessWorkflowReport,
});
return {
pages: entries.map(({ id, href, title }) => ({
id,
@@ -2734,6 +2832,7 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
shellSessionHandoffWorkflowRenderState,
shellSessionHandoffWorkflowDomContract,
shellWorkflowOverviewContract,
shellPersistenceSummary,
shellApiSurfaceInventory,
launchApiSchema: createIniPanelLaunchApiSchema(),
launchApiManifest: createIniPanelLaunchApiManifest(entries),
@@ -2764,6 +2863,7 @@ export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries
mountShellSessionHandoffFromControlPage: mountIniPanelShellSessionHandoffFromControlPage,
readShellSessionHandoffStatusFromControlPage: readIniPanelShellSessionHandoffStatusFromControlPage,
createShellSessionHandoffWorkflowSummary: createIniPanelShellSessionHandoffWorkflowSummary,
createMachineSessionPersistenceSummary,
createShellSessionReadinessWorkflowReport: createIniPanelShellSessionReadinessWorkflowReport,
createShellApiSurfaceInventory: createIniPanelShellApiSurfaceInventory,
createShellSessionHandoffWorkflowDisplayViewModel: createIniPanelShellSessionHandoffWorkflowDisplayViewModel,

View File

@@ -96,6 +96,7 @@
createIniPanelShellWorkflowOverviewEmbeddingDomContract,
createIniPanelShellWorkflowOverviewEmbeddingDomReadiness,
mountIniPanelShellWorkflowOverviewEmbedding,
createMachineSessionPersistenceSummary,
renderIniPanelShellWorkflowOverviewEmbeddingState,
mountIniPanelShellWorkflowOverviewEmbeddingState,
createIniPanelShellWorkflowOverviewEmbeddingMountDisplayViewModel,
@@ -129,6 +130,9 @@
sessionReadinessWorkflowReport: shellViewModel.shellSessionReadinessWorkflowReport,
})
),
getWorkflowOverviewPersistenceSummary: (options) => (
createMachineSessionPersistenceSummary(options)
),
getWorkflowOverviewDomContract: (options) => (
createIniPanelShellSessionHandoffWorkflowDomContract(options)
),