358 lines
11 KiB
JavaScript
358 lines
11 KiB
JavaScript
import {
|
|
INI_PANEL_ENTRIES,
|
|
getIniPanelEntryByHref,
|
|
getIniPanelEntryManifest,
|
|
} from "./entry-manifest.js";
|
|
import {
|
|
createMachineSessionControlPageController,
|
|
} from "./control-page-controller.js";
|
|
import {
|
|
renderMachineSessionControlView,
|
|
} from "./control-view-renderer.js";
|
|
import {
|
|
controlPageStatusText,
|
|
createControlPageRefreshState,
|
|
refreshMachineSessionControlPage,
|
|
} from "./control-page-refresh-workflow.js";
|
|
import {
|
|
createControlPageSessionLoadState,
|
|
loadMachineSessionForControlPageWorkflow,
|
|
} from "./control-page-session-workflow.js";
|
|
import {
|
|
createMachineSessionReadonlyStatus,
|
|
createMachineSessionReadonlyStatusApiManifest,
|
|
readMachineSessionReadonlyStatus,
|
|
} from "./readonly-status-api.js";
|
|
export {
|
|
controlPageStatusText,
|
|
createControlPageRefreshState,
|
|
refreshMachineSessionControlPage,
|
|
} from "./control-page-refresh-workflow.js";
|
|
export {
|
|
createControlPageSessionLoadState,
|
|
loadMachineSessionForControlPageWorkflow,
|
|
} from "./control-page-session-workflow.js";
|
|
export {
|
|
createMachineSessionReadonlyStatus,
|
|
createMachineSessionReadonlyStatusApiManifest,
|
|
readMachineSessionReadonlyStatus,
|
|
} from "./readonly-status-api.js";
|
|
export {
|
|
INI_PANEL_ENTRIES,
|
|
getIniPanelEntryByHref,
|
|
getIniPanelEntryManifest,
|
|
} from "./entry-manifest.js";
|
|
export {
|
|
createMachineSessionControlPageController,
|
|
} from "./control-page-controller.js";
|
|
export {
|
|
renderMachineSessionControlView,
|
|
} from "./control-view-renderer.js";
|
|
|
|
export function getVisibleIniPanelEntries() {
|
|
return getIniPanelEntryManifest();
|
|
}
|
|
|
|
export function createIniPanelLauncherLinkViewModel(entries = getVisibleIniPanelEntries()) {
|
|
return entries.map(({ id, href, title }) => ({
|
|
entryId: id,
|
|
href,
|
|
label: title,
|
|
}));
|
|
}
|
|
|
|
export function createIniPanelLaunchApiSchema() {
|
|
return {
|
|
apiName: "ini-panel-launch",
|
|
manifestVersion: 1,
|
|
fields: [
|
|
"apiName",
|
|
"manifestVersion",
|
|
"methods",
|
|
"visibleEntries",
|
|
"targetPages",
|
|
"controlPageApiMethods",
|
|
"persistenceCapabilities",
|
|
],
|
|
};
|
|
}
|
|
|
|
export function isSupportedIniPanelLaunchApiManifest(manifest, schema = createIniPanelLaunchApiSchema()) {
|
|
if (!manifest || typeof manifest !== "object") {
|
|
return false;
|
|
}
|
|
if (manifest.apiName !== schema.apiName || manifest.manifestVersion !== schema.manifestVersion) {
|
|
return false;
|
|
}
|
|
return schema.fields.every((fieldName) => Object.hasOwn(manifest, fieldName));
|
|
}
|
|
|
|
export function createControlPageBrowserApiSchema() {
|
|
return {
|
|
apiName: "ini-panel-control-page",
|
|
manifestVersion: 1,
|
|
fields: [
|
|
"apiName",
|
|
"manifestVersion",
|
|
"methods",
|
|
"contract",
|
|
"readonlyStatusApiManifest",
|
|
],
|
|
};
|
|
}
|
|
|
|
export function isSupportedIniPanelControlPageApiManifest(
|
|
manifest,
|
|
schema = createControlPageBrowserApiSchema(),
|
|
) {
|
|
if (!manifest || typeof manifest !== "object") {
|
|
return false;
|
|
}
|
|
if (manifest.apiName !== schema.apiName || manifest.manifestVersion !== schema.manifestVersion) {
|
|
return false;
|
|
}
|
|
return schema.fields.every((fieldName) => Object.hasOwn(manifest, fieldName));
|
|
}
|
|
|
|
export function createIniPanelLaunchApiManifest(entries = getVisibleIniPanelEntries()) {
|
|
const schema = createIniPanelLaunchApiSchema();
|
|
return {
|
|
apiName: schema.apiName,
|
|
manifestVersion: schema.manifestVersion,
|
|
methods: [
|
|
"isSupportedLaunchApiManifest",
|
|
"getLaunchApiSchema",
|
|
"getLaunchApiManifest",
|
|
"getShellIntegrationSchema",
|
|
"getShellIntegrationManifest",
|
|
"getShellIntegrationReadiness",
|
|
"getLauncherLinks",
|
|
"getControlPageApiMethods",
|
|
],
|
|
visibleEntries: entries.map(({ id, href, title }) => ({
|
|
id,
|
|
href,
|
|
title,
|
|
})),
|
|
targetPages: entries.map(({ id, href }) => ({
|
|
entryId: id,
|
|
href,
|
|
})),
|
|
controlPageApiMethods: createControlPageBrowserApiMethods(),
|
|
persistenceCapabilities: [
|
|
{
|
|
id: "machine-files",
|
|
label: "Machine text files",
|
|
scope: "opfs",
|
|
},
|
|
{
|
|
id: "session-snapshot",
|
|
label: "Machine session snapshot",
|
|
scope: "opfs",
|
|
},
|
|
{
|
|
id: "readonly-status",
|
|
label: "Read-only machine session status",
|
|
scope: "control-page",
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
export function createIniPanelShellControlPageContract() {
|
|
const readonlyStatusApiManifest = createMachineSessionReadonlyStatusApiManifest();
|
|
return {
|
|
methodNames: [
|
|
"createController",
|
|
"loadSessionState",
|
|
"readStatus",
|
|
"refresh",
|
|
"renderView",
|
|
],
|
|
readonlyStatusApiManifest,
|
|
readonlyStatusApiMethodNames: Object.keys(readonlyStatusApiManifest.methods),
|
|
readonlyStatusApiStatusFields: readonlyStatusApiManifest.statusFields,
|
|
relatedControlPageMethods: readonlyStatusApiManifest.relatedControlPageMethods,
|
|
};
|
|
}
|
|
|
|
export function createControlPageBrowserApiMethods() {
|
|
return [
|
|
"isSupportedControlPageApiManifest",
|
|
"getControlPageApiSchema",
|
|
"getControlPageApiManifest",
|
|
"getControlPageApiMethods",
|
|
"getControlPageContract",
|
|
"getControlView",
|
|
"getPanelApi",
|
|
"loadControlPageSessionState",
|
|
"readControlPageStatus",
|
|
"refreshControlPage",
|
|
"renderControlPage",
|
|
];
|
|
}
|
|
|
|
export function createControlPageBrowserApiManifest() {
|
|
const schema = createControlPageBrowserApiSchema();
|
|
const contract = createIniPanelShellControlPageContract();
|
|
return {
|
|
apiName: schema.apiName,
|
|
manifestVersion: schema.manifestVersion,
|
|
methods: createControlPageBrowserApiMethods(),
|
|
contract,
|
|
readonlyStatusApiManifest: contract.readonlyStatusApiManifest,
|
|
};
|
|
}
|
|
|
|
export function createIniPanelShellIntegrationSchema() {
|
|
return {
|
|
apiName: "ini-panel-shell-integration",
|
|
manifestVersion: 1,
|
|
fields: [
|
|
"apiName",
|
|
"manifestVersion",
|
|
"pages",
|
|
"launcherLinks",
|
|
"launchApiSchema",
|
|
"launchApiManifest",
|
|
"controlPageApiSchema",
|
|
"controlPageApiManifest",
|
|
"compatibility",
|
|
"persistenceCapabilities",
|
|
],
|
|
};
|
|
}
|
|
|
|
export function isSupportedIniPanelShellIntegrationManifest(
|
|
manifest,
|
|
schema = createIniPanelShellIntegrationSchema(),
|
|
) {
|
|
if (!manifest || typeof manifest !== "object") {
|
|
return false;
|
|
}
|
|
if (manifest.apiName !== schema.apiName || manifest.manifestVersion !== schema.manifestVersion) {
|
|
return false;
|
|
}
|
|
return schema.fields.every((fieldName) => Object.hasOwn(manifest, fieldName));
|
|
}
|
|
|
|
export function createIniPanelShellIntegrationManifest(entries = getVisibleIniPanelEntries()) {
|
|
const schema = createIniPanelShellIntegrationSchema();
|
|
const launchApiSchema = createIniPanelLaunchApiSchema();
|
|
const launchApiManifest = createIniPanelLaunchApiManifest(entries);
|
|
const controlPageApiSchema = createControlPageBrowserApiSchema();
|
|
const controlPageApiManifest = createControlPageBrowserApiManifest();
|
|
return {
|
|
apiName: schema.apiName,
|
|
manifestVersion: schema.manifestVersion,
|
|
pages: entries.map(({ id, href, title }) => ({
|
|
id,
|
|
href,
|
|
title,
|
|
})),
|
|
launcherLinks: createIniPanelLauncherLinkViewModel(entries),
|
|
launchApiSchema,
|
|
launchApiManifest,
|
|
controlPageApiSchema,
|
|
controlPageApiManifest,
|
|
compatibility: {
|
|
launchApiManifest: isSupportedIniPanelLaunchApiManifest(launchApiManifest, launchApiSchema),
|
|
controlPageApiManifest: isSupportedIniPanelControlPageApiManifest(
|
|
controlPageApiManifest,
|
|
controlPageApiSchema,
|
|
),
|
|
},
|
|
persistenceCapabilities: launchApiManifest.persistenceCapabilities,
|
|
};
|
|
}
|
|
|
|
export function createIniPanelShellIntegrationReadiness(
|
|
manifest = createIniPanelShellIntegrationManifest(),
|
|
) {
|
|
const integrationManifestSupported = isSupportedIniPanelShellIntegrationManifest(manifest);
|
|
const launchApiManifestSupported = integrationManifestSupported
|
|
&& isSupportedIniPanelLaunchApiManifest(manifest.launchApiManifest, manifest.launchApiSchema);
|
|
const controlPageApiManifestSupported = integrationManifestSupported
|
|
&& isSupportedIniPanelControlPageApiManifest(
|
|
manifest.controlPageApiManifest,
|
|
manifest.controlPageApiSchema,
|
|
);
|
|
const compatibility = integrationManifestSupported && manifest.compatibility
|
|
? {
|
|
launchApiManifest: Boolean(manifest.compatibility.launchApiManifest),
|
|
controlPageApiManifest: Boolean(manifest.compatibility.controlPageApiManifest),
|
|
}
|
|
: {
|
|
launchApiManifest: false,
|
|
controlPageApiManifest: false,
|
|
};
|
|
const checks = {
|
|
integrationManifestSupported,
|
|
launchApiManifestSupported,
|
|
controlPageApiManifestSupported,
|
|
launchCompatibility: compatibility.launchApiManifest,
|
|
controlPageCompatibility: compatibility.controlPageApiManifest,
|
|
};
|
|
const missing = Object.entries(checks)
|
|
.filter(([, passed]) => !passed)
|
|
.map(([name]) => name);
|
|
const ready = missing.length === 0;
|
|
|
|
return {
|
|
phase: ready ? "ready" : "blocked",
|
|
ready,
|
|
checks,
|
|
missing,
|
|
counts: {
|
|
pages: Array.isArray(manifest?.pages) ? manifest.pages.length : 0,
|
|
launcherLinks: Array.isArray(manifest?.launcherLinks) ? manifest.launcherLinks.length : 0,
|
|
launchMethods: Array.isArray(manifest?.launchApiManifest?.methods)
|
|
? manifest.launchApiManifest.methods.length
|
|
: 0,
|
|
controlPageMethods: Array.isArray(manifest?.controlPageApiManifest?.methods)
|
|
? manifest.controlPageApiManifest.methods.length
|
|
: 0,
|
|
persistenceCapabilities: Array.isArray(manifest?.persistenceCapabilities)
|
|
? manifest.persistenceCapabilities.length
|
|
: 0,
|
|
},
|
|
apiNames: {
|
|
integration: manifest?.apiName ?? null,
|
|
launch: manifest?.launchApiManifest?.apiName ?? null,
|
|
controlPage: manifest?.controlPageApiManifest?.apiName ?? null,
|
|
},
|
|
};
|
|
}
|
|
|
|
export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries()) {
|
|
const shellIntegrationManifest = createIniPanelShellIntegrationManifest(entries);
|
|
return {
|
|
pages: entries.map(({ id, href, title }) => ({
|
|
id,
|
|
href,
|
|
title,
|
|
})),
|
|
launcherLinks: createIniPanelLauncherLinkViewModel(entries),
|
|
shellIntegrationSchema: createIniPanelShellIntegrationSchema(),
|
|
shellIntegrationManifest,
|
|
shellIntegrationReadiness: createIniPanelShellIntegrationReadiness(shellIntegrationManifest),
|
|
launchApiSchema: createIniPanelLaunchApiSchema(),
|
|
launchApiManifest: createIniPanelLaunchApiManifest(entries),
|
|
isSupportedShellIntegrationManifest: isSupportedIniPanelShellIntegrationManifest,
|
|
createShellIntegrationReadiness: createIniPanelShellIntegrationReadiness,
|
|
controlPage: {
|
|
browserApiSchema: createControlPageBrowserApiSchema(),
|
|
browserApiManifest: createControlPageBrowserApiManifest(),
|
|
browserApiMethods: createControlPageBrowserApiMethods(),
|
|
contract: createIniPanelShellControlPageContract(),
|
|
createController: createMachineSessionControlPageController,
|
|
isSupportedBrowserApiManifest: isSupportedIniPanelControlPageApiManifest,
|
|
loadSessionState: loadMachineSessionForControlPageWorkflow,
|
|
readonlyStatusApiManifest: createMachineSessionReadonlyStatusApiManifest(),
|
|
readStatus: readMachineSessionReadonlyStatus,
|
|
refresh: refreshMachineSessionControlPage,
|
|
renderView: renderMachineSessionControlView,
|
|
},
|
|
};
|
|
}
|