refactor: compose UI shell with explicit application operations and component owners

This commit is contained in:
Sameh Khamis committed 2026-09-13 04:26:09 -07:00
1 parent 8a226a2fe3
commit f5ef9091f0
67 files changed
+15799 -15059

No files matched your search

+131
View File
@@ -423,5 +423,136 @@
"src/ui/scenePresentation.js"
],
"external": []
},
"ui-shell": {
"exports": [
"./ui/shell"
],
"modules": [
"src/bloom.js",
"src/cctvFocusPolicy.js",
"src/cctvFocusRequest.js",
"src/cockpitMath.js",
"src/cockpitTracking.js",
"src/cockpitUtilityLayout.js",
"src/cockpitVisionPolicy.js",
"src/contactsDetectionPolicy.js",
"src/contextModePolicy.js",
"src/data/detectionPolicy.js",
"src/data/installationFeedback.js",
"src/data/layerState.js",
"src/data/militaryAwarenessEngine.js",
"src/keySetupCore.mjs",
"src/loadingFeedback.js",
"src/locationStatus.js",
"src/mapStackChips.js",
"src/navigationPolicy.js",
"src/panelStackLayout.js",
"src/rightRailPolicy.js",
"src/splitFlap.js",
"src/styles/anime.js",
"src/styles/noir.js",
"src/styles/retro.js",
"src/styles/snow.js",
"src/styles/surveillance.js",
"src/styles/thermal.js",
"src/ui/applicationShell.js",
"src/ui/applicationShortcuts.js",
"src/ui/cctv.js",
"src/ui/cctvBindings.js",
"src/ui/cctvCalibration.js",
"src/ui/cctvControls.js",
"src/ui/cctvFrames.js",
"src/ui/cctvPresentation.js",
"src/ui/clearLayersControl.js",
"src/ui/cockpit.js",
"src/ui/cockpitBriefing.js",
"src/ui/cockpitCamera.js",
"src/ui/cockpitContext.js",
"src/ui/cockpitController.js",
"src/ui/cockpitDisplayPortal.js",
"src/ui/cockpitInput.js",
"src/ui/cockpitInstruments.js",
"src/ui/cockpitLayout.js",
"src/ui/cockpitPresentation.js",
"src/ui/cockpitSignals.js",
"src/ui/cockpitTrackingController.js",
"src/ui/context.js",
"src/ui/contextActions.js",
"src/ui/contextBindings.js",
"src/ui/contextControls.js",
"src/ui/contextLayerChanges.js",
"src/ui/contextPresentation.js",
"src/ui/contextSession.js",
"src/ui/contextSubscriptions.js",
"src/ui/contextTransactions.js",
"src/ui/displayControls.js",
"src/ui/effects.js",
"src/ui/layerPanel.js",
"src/ui/layers.js",
"src/ui/leftPanelRail.js",
"src/ui/location.js",
"src/ui/locationControls.js",
"src/ui/locationSearch.js",
"src/ui/mapSource.js",
"src/ui/mapSourceControls.js",
"src/ui/panelDisclosure.js",
"src/ui/panelLayoutController.js",
"src/ui/panelMeasurement.js",
"src/ui/panelPositionControls.js",
"src/ui/panelRailGeometry.js",
"src/ui/panelRails.js",
"src/ui/radio.js",
"src/ui/radioBindings.js",
"src/ui/radioControls.js",
"src/ui/radioPresentation.js",
"src/ui/radioTunerModel.js",
"src/ui/recordingControls.js",
"src/ui/rightPanelRail.js",
"src/ui/sceneControls.js",
"src/ui/scenePresentation.js",
"src/ui/scenes.js",
"src/ui/shellElements.js",
"src/ui/shellFeedback.js",
"src/ui/styleParameters.js",
"src/ui/surfaceKeyboard.js",
"src/ui/visualEffects.js",
"src/ui/visualInput.js",
"src/ui/visualPresets.js",
"src/worldFocus.js",
"src/ui/uiLifetime.js"
],
"external": [
"cesium"
]
},
"ui-styles": {
"exports": [
"./ui/styles"
],
"modules": [
"src/ui/styles.js",
"style.css",
"src/ui/styles/foundation.css",
"src/ui/styles/controls.css",
"src/ui/styles/location.css",
"src/ui/styles/status.css",
"src/ui/styles/cockpit.css",
"src/ui/styles/overlays.css",
"src/ui/styles/layers.css",
"src/ui/styles/radio.css",
"src/ui/styles/cctv.css",
"src/ui/styles/scenes.css",
"src/ui/styles/recording.css",
"src/ui/styles/responsive.css",
"src/ui/styles/command-dock.css",
"src/ui/styles/command-dock-compact.css",
"src/ui/styles/command-dock-trays.css",
"src/ui/styles/command-dock-sliding.css",
"src/ui/styles/voice-cost.css",
"src/ui/styles/first-run.css",
"src/ui/styles/provider-settings.css"
],
"external": []
}
}
+3 -3
View File
@@ -918,15 +918,15 @@ try {
});
const waitForQueuedNotice = async (label, timeoutMs = 1000) => {
const deadline = performance.now() + timeoutMs;
while (styleManager._globalStatusNotice?.label !== label
while (styleManager._feedback._globalStatusNotice?.label !== label
&& performance.now() < deadline) {
await new Promise((resolve) => setTimeout(resolve, 16));
}
return styleManager._globalStatusNotice?.label === label;
return styleManager._feedback._globalStatusNotice?.label === label;
};
const baseNow = performance.now();
try {
styleManager._loadingFeedbackState = {
styleManager._feedback._loadingFeedbackState = {
phase: 'idle', visible: false, startedAt: 0, showAt: 0, hideAt: 0,
activeIds: [], batchOutcome: null, terminal: null, operation: null,
};
+28 -28
View File
@@ -1702,8 +1702,8 @@ async function main() {
dataset: { ...stack.dataset },
}];
})),
preferredLeftPanelId: manager._leftStackPreferredPanelId,
preferredRightPanelId: manager._rightStackPreferredPanelId,
preferredLeftPanelId: manager._panelLayout._leftStackPreferredPanelId,
preferredRightPanelId: manager._panelLayout._rightStackPreferredPanelId,
hudMode: manager.hud.getMode(),
hudVariant: manager.hud.getVariant(),
focusId: document.activeElement?.id || null,
@@ -1767,7 +1767,7 @@ async function main() {
const scenePanel = document.getElementById('scene-panel');
const contextPanel = document.getElementById('global-context-panel');
result.tacticalAutoCollapse = {
latestOpenedPanel: manager._leftStackPreferredPanelId,
latestOpenedPanel: manager._panelLayout._leftStackPreferredPanelId,
scenesExpanded: !scenePanel.classList.contains('collapsed'),
dataCollapsed: dataPanel.classList.contains('layout-auto-collapsed'),
dataHiddenWhileScenesOwnsLane: dataPanel.getBoundingClientRect().height === 0
@@ -1814,13 +1814,13 @@ async function main() {
manager.hud.setMode(prior.hudMode);
manager._updateHudButtonState();
await new Promise((resolve) => setTimeout(resolve, 320));
if (manager._leftStackLayoutFrame !== null) {
cancelAnimationFrame(manager._leftStackLayoutFrame);
manager._leftStackLayoutFrame = null;
if (manager._panelLayout._leftStackLayoutFrame !== null) {
cancelAnimationFrame(manager._panelLayout._leftStackLayoutFrame);
manager._panelLayout._leftStackLayoutFrame = null;
}
if (manager._rightStackLayoutFrame !== null) {
cancelAnimationFrame(manager._rightStackLayoutFrame);
manager._rightStackLayoutFrame = null;
if (manager._panelLayout._rightStackLayoutFrame !== null) {
cancelAnimationFrame(manager._panelLayout._rightStackLayoutFrame);
manager._panelLayout._rightStackLayoutFrame = null;
}
for (const [id, state] of Object.entries(prior.panels)) {
const panel = document.getElementById(id);
@@ -1839,18 +1839,18 @@ async function main() {
for (const key of Object.keys(stack.dataset)) delete stack.dataset[key];
Object.assign(stack.dataset, state.dataset);
}
manager._leftStackPreferredPanelId = prior.preferredLeftPanelId;
manager._rightStackPreferredPanelId = prior.preferredRightPanelId;
manager._panelLayout._leftStackPreferredPanelId = prior.preferredLeftPanelId;
manager._panelLayout._rightStackPreferredPanelId = prior.preferredRightPanelId;
localStorage.clear();
for (const [key, value] of Object.entries(prior.storage)) localStorage.setItem(key, value);
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
if (manager._leftStackLayoutFrame !== null) {
cancelAnimationFrame(manager._leftStackLayoutFrame);
manager._leftStackLayoutFrame = null;
if (manager._panelLayout._leftStackLayoutFrame !== null) {
cancelAnimationFrame(manager._panelLayout._leftStackLayoutFrame);
manager._panelLayout._leftStackLayoutFrame = null;
}
if (manager._rightStackLayoutFrame !== null) {
cancelAnimationFrame(manager._rightStackLayoutFrame);
manager._rightStackLayoutFrame = null;
if (manager._panelLayout._rightStackLayoutFrame !== null) {
cancelAnimationFrame(manager._panelLayout._rightStackLayoutFrame);
manager._panelLayout._rightStackLayoutFrame = null;
}
// Disclosure restoration can wake the installed layout observers. Let
// those observers settle, then restore the captured stack presentation
@@ -1880,8 +1880,8 @@ async function main() {
result.restoreDetails = {
panelsRestored,
stacksRestored,
preferredPanelRestored: manager._leftStackPreferredPanelId === prior.preferredLeftPanelId,
preferredRightPanelRestored: manager._rightStackPreferredPanelId === prior.preferredRightPanelId,
preferredPanelRestored: manager._panelLayout._leftStackPreferredPanelId === prior.preferredLeftPanelId,
preferredRightPanelRestored: manager._panelLayout._rightStackPreferredPanelId === prior.preferredRightPanelId,
hudModeRestored: manager.hud.getMode() === prior.hudMode,
hudVariantRestored: manager.hud.getVariant() === prior.hudVariant,
storageRestored: JSON.stringify(Object.fromEntries(Object.entries(localStorage))) === JSON.stringify(prior.storage),
@@ -2055,7 +2055,7 @@ async function main() {
detectionMode: manager.getDetectionState().detectionMode,
models3dEnabled: manager._models3dEnabled,
models3dMode: manager._models3dMode,
preferredLeftPanelId: manager._leftStackPreferredPanelId,
preferredLeftPanelId: manager._panelLayout._leftStackPreferredPanelId,
panels: Object.fromEntries([
'data-panel',
'global-context-panel',
@@ -2371,13 +2371,13 @@ async function main() {
if (prior.utilityTop) hud.style.setProperty('--cockpit-utility-top', prior.utilityTop);
else hud.style.removeProperty('--cockpit-utility-top');
await waitForLayout();
if (manager._leftStackLayoutFrame !== null) {
cancelAnimationFrame(manager._leftStackLayoutFrame);
manager._leftStackLayoutFrame = null;
if (manager._panelLayout._leftStackLayoutFrame !== null) {
cancelAnimationFrame(manager._panelLayout._leftStackLayoutFrame);
manager._panelLayout._leftStackLayoutFrame = null;
}
if (manager._rightStackLayoutFrame !== null) {
cancelAnimationFrame(manager._rightStackLayoutFrame);
manager._rightStackLayoutFrame = null;
if (manager._panelLayout._rightStackLayoutFrame !== null) {
cancelAnimationFrame(manager._panelLayout._rightStackLayoutFrame);
manager._panelLayout._rightStackLayoutFrame = null;
}
for (const [id, state] of Object.entries(prior.panels)) {
const panel = document.getElementById(id);
@@ -2388,7 +2388,7 @@ async function main() {
else panel.setAttribute('aria-hidden', state.ariaHidden);
manager._syncPanelCollapseButton(panel);
}
manager._leftStackPreferredPanelId = prior.preferredLeftPanelId;
manager._panelLayout._leftStackPreferredPanelId = prior.preferredLeftPanelId;
localStorage.clear();
for (const [key, value] of Object.entries(prior.storage)) localStorage.setItem(key, value);
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
@@ -2411,7 +2411,7 @@ async function main() {
&& panel.getAttribute('style') === state.style
&& panel.getAttribute('aria-hidden') === state.ariaHidden;
})
&& manager._leftStackPreferredPanelId === prior.preferredLeftPanelId
&& manager._panelLayout._leftStackPreferredPanelId === prior.preferredLeftPanelId
&& JSON.stringify(Object.fromEntries(Object.entries(localStorage))) === JSON.stringify(prior.storage)
&& (!prior.focusId || document.activeElement?.id === prior.focusId);
}
+5
View File
@@ -208,6 +208,11 @@ try {
!window.__godsEyeView.styleManager.getControlState().recording,
),
);
// Escape can also collapse the Scene accordion. Reopen it through its
// installed disclosure before testing the next visible user action.
if (await page.$eval('#scene-panel', (panel) => panel.classList.contains('collapsed')))
await page.click('[data-collapse-target="scene-panel"]');
await page.waitForSelector('#scene-download-btn', { visible: true });
await page.click('#scene-download-btn');
const metadata = await page.evaluate(async () =>
JSON.parse(await window.__sceneExports.at(-1)),
+6 -1
View File
@@ -33,7 +33,8 @@ try {
const ui = window.__godsEyeView.styleManager;
const counts = {};
const watchObserver = (name) => {
const observer = ui[name];
const owner = name === '_draggableResizeObserver' ? ui._panelPosition : ui._panelLayout;
const observer = owner[name];
if (!observer) return false;
const disconnect = observer.disconnect.bind(observer);
counts[name] = 0;
@@ -113,6 +114,10 @@ try {
const disposal = ui.dispose();
const focusBefore = document.activeElement;
const stoppedBeforeRestoration =
ui._panelLayout.destroyed &&
ui._panelPosition.destroyed &&
ui._feedback.destroyed &&
ui._recording.destroyed &&
cockpit.destroyed &&
portal.stopped &&
cockpit._listenerRemovers.length === 0 &&