refactor: isolate Context controls and layer restoration

This commit is contained in:
Sameh Khamis committed 2026-09-13 01:40:59 -07:00
1 parent 7f70b97536
commit fc369cc65a
26 files changed
+1471 -1271

No files matched your search

+21
View File
@@ -369,5 +369,26 @@
"src/ui/cctvPresentation.js"
],
"external": []
},
"context-controls": {
"exports": [
"./ui/context",
"./ui/context/policy"
],
"modules": [
"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/contextModePolicy.js",
"src/rightRailPolicy.js",
"src/ui/panelRailGeometry.js"
],
"external": []
}
}
+48 -48
View File
@@ -184,21 +184,21 @@ try {
const toasts = [];
styleManager._showToast = (message) => { toasts.push(String(message)); };
try {
if (styleManager._contextMode) await styleManager._selectContextMode(null);
const contactsResult = await styleManager._selectContextMode('flights');
const missionResult = await styleManager._selectContextMode('space-missions');
if (styleManager._contextControls._contextMode) await styleManager._contextControls._selectContextMode(null);
const contactsResult = await styleManager._contextControls._selectContextMode('flights');
const missionResult = await styleManager._contextControls._selectContextMode('space-missions');
const switched = {
contactsResult,
missionResult,
mode: styleManager._contextMode,
mode: styleManager._contextControls._contextMode,
missionsEnabled: dataManager.isEnabled('rocket-launches'),
toasts: [...toasts],
};
const exitResult = await styleManager._selectContextMode(null);
const exitResult = await styleManager._contextControls._selectContextMode(null);
return {
...switched,
exitResult,
modeAfterExit: styleManager._contextMode,
modeAfterExit: styleManager._contextControls._contextMode,
missionsOffAfterExit: !dataManager.isEffectivelyEnabled('rocket-launches'),
};
} finally {
@@ -281,16 +281,16 @@ try {
const deadline = performance.now() + 5_000;
while (performance.now() < deadline) {
if (
styleManager._contextModeEntering === null
&& styleManager._contextSessionSnapshot === null
styleManager._contextControls._contextModeEntering === null
&& styleManager._contextControls._contextSessionSnapshot === null
&& dataManager.isEnabled(siblingId)
&& !dataManager.isEffectivelyEnabled('rocket-launches')
) break;
await new Promise((resolve) => setTimeout(resolve, 20));
}
timedOut = !(
styleManager._contextModeEntering === null
&& styleManager._contextSessionSnapshot === null
styleManager._contextControls._contextModeEntering === null
&& styleManager._contextControls._contextSessionSnapshot === null
&& dataManager.isEnabled(siblingId)
&& !dataManager.isEffectivelyEnabled('rocket-launches')
);
@@ -298,8 +298,8 @@ try {
exercised: true,
transitionResult,
timedOut,
entering: styleManager._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextSessionSnapshot),
entering: styleManager._contextControls._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextControls._contextSessionSnapshot),
siblingRestored: dataManager.isEnabled(siblingId),
missionEffective: dataManager.isEffectivelyEnabled('rocket-launches'),
toasts,
@@ -382,7 +382,7 @@ try {
rocketEntry.module.disable = async () => true;
styleManager._showToast = (message) => { toasts.push(String(message)); };
try {
const entry = styleManager._selectContextMode('space-missions');
const entry = styleManager._contextControls._selectContextMode('space-missions');
await updateStarted;
const replacement = dataManager.setEnabled('rocket-launches', true, { origin: 'programmatic' });
releaseUpdate();
@@ -390,15 +390,15 @@ try {
const committed = {
entryResult,
replacementResult,
mode: styleManager._contextMode,
entering: styleManager._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextSessionSnapshot),
mode: styleManager._contextControls._contextMode,
entering: styleManager._contextControls._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextControls._contextSessionSnapshot),
siblingIsolated: !dataManager.isEffectivelyEnabled(siblingId),
missionEnabled: dataManager.isEnabled('rocket-launches'),
missionEffective: dataManager.isEffectivelyEnabled('rocket-launches'),
toasts: [...toasts],
};
const exitResult = await styleManager._selectContextMode(null);
const exitResult = await styleManager._contextControls._selectContextMode(null);
return {
exercised: true,
...committed,
@@ -482,7 +482,7 @@ try {
styleManager._showToast = (message) => { toasts.push(String(message)); };
try {
const entry = styleManager._runUserFacingContextAction(
(notificationToken) => styleManager._selectContextMode(
(notificationToken) => styleManager._contextControls._selectContextMode(
'space-missions',
{ notificationToken },
),
@@ -498,9 +498,9 @@ try {
exercised: true,
entryResult,
offResult,
mode: styleManager._contextMode,
entering: styleManager._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextSessionSnapshot),
mode: styleManager._contextControls._contextMode,
entering: styleManager._contextControls._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextControls._contextSessionSnapshot),
siblingRestored: dataManager.isEnabled(siblingId),
missionEffective: dataManager.isEffectivelyEnabled('rocket-launches'),
toasts,
@@ -567,35 +567,35 @@ try {
await new Promise((resolve) => setTimeout(resolve, 80));
const voiceState = {
voiceOn,
mode: styleManager._contextMode,
entering: styleManager._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextSessionSnapshot),
mode: styleManager._contextControls._contextMode,
entering: styleManager._contextControls._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextControls._contextSessionSnapshot),
siblingIsolated: !dataManager.isEffectivelyEnabled(siblingId),
};
const snapshotBeforeOff = [...(styleManager._contextSessionSnapshot?.enabledLayerIds || [])];
const snapshotBeforeOff = [...(styleManager._contextControls._contextSessionSnapshot?.enabledLayerIds || [])];
const voiceOff = await dataManager.setEnabled('rocket-launches', false, { origin: 'voice' });
const reactionCountAfterOff = styleManager._contextLayerReactionPromises.size;
const reactionCountAfterOff = styleManager._contextControls._contextLayerReactionPromises.size;
await styleManager._waitForContextLayerSettlement();
const restoredSiblingEntry = dataManager.layers.get(siblingId);
const voiceExit = {
voiceOff,
snapshotBeforeOff,
reactionCountAfterOff,
mode: styleManager._contextMode,
entering: styleManager._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextSessionSnapshot),
mode: styleManager._contextControls._contextMode,
entering: styleManager._contextControls._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextControls._contextSessionSnapshot),
siblingRestored: dataManager.isEffectivelyEnabled(siblingId),
siblingEnabled: restoredSiblingEntry?.enabled,
siblingLifecycle: restoredSiblingEntry?.lifecycleState,
restoreActive: Boolean(styleManager._contextRestoreState),
restoreActive: Boolean(styleManager._contextControls._contextRestoreState),
};
await dataManager.setEnabled('rocket-launches', true, { origin: 'programmatic' });
await new Promise((resolve) => setTimeout(resolve, 40));
const internalState = {
mode: styleManager._contextMode,
entering: styleManager._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextSessionSnapshot),
mode: styleManager._contextControls._contextMode,
entering: styleManager._contextControls._contextModeEntering,
snapshotRetained: Boolean(styleManager._contextControls._contextSessionSnapshot),
missionEnabled: dataManager.isEffectivelyEnabled('rocket-launches'),
};
await dataManager.setEnabled('rocket-launches', false, { origin: 'programmatic' });
@@ -707,7 +707,7 @@ try {
const blockerEntry = dataManager.layers.get(blockerId);
blockerEntry.initialized = true;
await dataManager.setEnabled(blockerId, true, { origin: 'programmatic' });
const transition = styleManager._selectContextMode('flights');
const transition = styleManager._contextControls._selectContextMode('flights');
const disableStart = await settleWithin(disableStarted, gateTimeoutMs);
if (!disableStart.settled) {
releaseDisable();
@@ -725,7 +725,7 @@ try {
styleManager.cockpitView.syncEntry();
const entry = document.getElementById('cockpit-entry');
const pending = {
changing: styleManager._contextModeChanging,
changing: styleManager._contextControls._contextModeChanging,
entryHidden: Boolean(entry?.hidden),
enterResult: styleManager.cockpitView.enter(),
trackerPreserved: viewer.trackedEntity === trackedEntityBefore,
@@ -763,7 +763,7 @@ try {
// probe must not poison the checks that run after it.
releaseDisable();
if (!deferCleanup && dataManager.layers.has(blockerId)) {
if (styleManager._contextSessionSnapshot) await styleManager._selectContextMode(null);
if (styleManager._contextControls._contextSessionSnapshot) await styleManager._contextControls._selectContextMode(null);
await window.__gevQaUnregisterLayer(dataManager, blockerId);
styleManager.cockpitView.syncEntry();
}
@@ -872,7 +872,7 @@ try {
let requestSeen = false;
let transition = null;
try {
await styleManager._selectContextMode(null);
await styleManager._contextControls._selectContextMode(null);
await dataManager.setEnabled('military-installations', false, { origin: 'programmatic' });
// Hold the first Overpass request open, honouring the module's own
@@ -913,7 +913,7 @@ try {
});
};
transition = styleManager._selectContextMode('flights');
transition = styleManager._contextControls._selectContextMode('flights');
// The activation promise stays PENDING while the first fetch is out, and
// the Contacts panel comes up behind it — that is what a deferred
// dependency is for. Verified live on :4272: the panel renders and reads
@@ -984,8 +984,8 @@ try {
released = true;
window.fetch = realFetch;
if (transition) await settleWithin(transition, 20_000);
if (styleManager._contextMode !== 'flights') {
await settleWithin(styleManager._selectContextMode('flights'), 15_000);
if (styleManager._contextControls._contextMode !== 'flights') {
await settleWithin(styleManager._contextControls._selectContextMode('flights'), 15_000);
}
}
});
@@ -1060,7 +1060,7 @@ try {
return {
before: before ? { layerId: before.layerId, id: before.id } : null,
after: after ? { layerId: after.layerId, id: after.id } : null,
mode: styleManager._contextMode,
mode: styleManager._contextControls._contextMode,
released,
refocused,
trackedId: trackedInfo?.icao24 || trackedInfo?.id || null,
@@ -1206,9 +1206,9 @@ try {
// Start from outside both, so activation is a real edge.
cockpit.exit({ restoreTracking: true });
await settle();
await styleManager._selectContextMode(null);
await styleManager._contextControls._selectContextMode(null);
await settle(400);
const cleanupSnapshotCleared = styleManager._contextSessionSnapshot === null;
const cleanupSnapshotCleared = styleManager._contextControls._contextSessionSnapshot === null;
const cleanupBlockerId = '__qa_slow_contacts_sibling__';
const cleanupUnregistered = await window.__gevQaUnregisterLayer(
window.__godsEyeView.dataManager,
@@ -1224,7 +1224,7 @@ try {
const overriddenBeforeContacts = styleManager._detectionUserOverridden;
// 1. Activating Contacts forces the tactical preset on.
const contactsOn = await styleManager._selectContextMode('flights');
const contactsOn = await styleManager._contextControls._selectContextMode('flights');
await settle(400);
const afterContactsOn = mode();
const afterContactsOnDensity = density();
@@ -1254,7 +1254,7 @@ try {
await settle();
// 4. Deactivating Contacts restores the pre-Contacts state.
await styleManager._selectContextMode(null);
await styleManager._contextControls._selectContextMode(null);
await settle(400);
const afterContactsOff = mode();
const afterContactsOffDensity = density();
@@ -1268,7 +1268,7 @@ try {
await settle();
// Leave the session exactly as the following checks expect it.
const restoredContacts = await styleManager._selectContextMode('flights');
const restoredContacts = await styleManager._contextControls._selectContextMode('flights');
await settle(400);
const restoredCockpit = await enterCockpit();
styleManager._detectionUserOverridden = originalOverridden;
@@ -1348,8 +1348,8 @@ try {
step,
cockpitActive: cockpit.active,
bodyCockpit: document.body.classList.contains('cockpit-mode'),
contextMode: styleManager._contextMode,
contextChanging: styleManager._contextModeChanging,
contextMode: styleManager._contextControls._contextMode,
contextChanging: styleManager._contextControls._contextModeChanging,
subject: context?.subject ? `${context.subject.layerId}:${context.subject.id}` : null,
tracked: tracker?.gevTrackedId || null,
density: styleManager.getDetectionState().densityPct,
+2 -2
View File
@@ -87,9 +87,9 @@ try {
result.push([
'native clear activation presents busy state',
ui._clearSelectedLayersBtn.getAttribute('aria-busy') === 'true' &&
!!ui._clearSelectedLayersPromise,
!!ui._contextControls._clearSelectedLayersPromise,
]);
await ui._clearSelectedLayersPromise;
await ui._contextControls._clearSelectedLayersPromise;
result.push([
'clear settles through the existing layer transaction',
!manager.isEnabled(id) &&
+38 -38
View File
@@ -783,10 +783,10 @@ async function main() {
const originalRestoreEnabledLayerIds = dataManager.restoreEnabledLayerIds;
const originalIsEnabled = dataManager.isEnabled;
const originalIsEffectivelyEnabled = dataManager.isEffectivelyEnabled;
const originalClear = styleManager._clearLayersOutsideContextMode;
const originalCapture = styleManager._captureContextSessionSnapshot;
const originalContextMode = styleManager._contextMode;
const originalSnapshot = styleManager._contextSessionSnapshot;
const originalClear = styleManager._contextControls._clearLayersOutsideContextMode;
const originalCapture = styleManager._contextControls._captureContextSessionSnapshot;
const originalContextMode = styleManager._contextControls._contextMode;
const originalSnapshot = styleManager._contextControls._contextSessionSnapshot;
const originalShowToast = styleManager._showToast;
const installations = dataManager.layers.get('military-installations')?.module;
const originalSearchNearby = installations?.searchNearby;
@@ -797,12 +797,12 @@ async function main() {
const semanticFalseMessage = document.getElementById('toast').textContent;
const enabled = new Set();
styleManager._captureContextSessionSnapshot = () => {};
styleManager._contextControls._captureContextSessionSnapshot = () => {};
const runContextFailure = async (mode, phase, outcome) => {
enabled.clear();
enabled.add('local-datacenters');
styleManager._contextMode = null;
styleManager._contextSessionSnapshot = {
styleManager._contextControls._contextMode = null;
styleManager._contextControls._contextSessionSnapshot = {
enabledLayerIds: new Set(enabled),
userAdded: new Set(),
userRemoved: new Set(),
@@ -822,7 +822,7 @@ async function main() {
return true;
};
const result = await styleManager._runUserFacingContextAction(
() => styleManager._selectContextMode(mode),
() => styleManager._contextControls._selectContextMode(mode),
`${mode} QA transition failed`,
);
await new Promise((resolve) => setTimeout(resolve, 0));
@@ -831,8 +831,8 @@ async function main() {
phase,
outcome,
result,
visibleMode: styleManager._contextMode,
snapshotCleared: styleManager._contextSessionSnapshot === null,
visibleMode: styleManager._contextControls._contextMode,
snapshotCleared: styleManager._contextControls._contextSessionSnapshot === null,
priorLayerRestored: enabled.has('local-datacenters'),
entryEnabled: enabled.has(entryLayerId),
flightsButtonDisabled: document.getElementById('global-context-flights-btn').disabled,
@@ -870,8 +870,8 @@ async function main() {
for (const outcome of ['false', 'reject']) {
enabled.clear();
enabled.add('local-datacenters');
styleManager._contextMode = null;
styleManager._contextSessionSnapshot = {
styleManager._contextControls._contextMode = null;
styleManager._contextControls._contextSessionSnapshot = {
enabledLayerIds: new Set(enabled),
userAdded: new Set(),
userRemoved: new Set(),
@@ -886,7 +886,7 @@ async function main() {
dataManager.setEnabled = async (candidateId, shouldEnable, options = {}) => {
if (!failureUsed && candidateId === 'local-datacenters' && !shouldEnable) {
failureUsed = true;
styleManager._handleContextLayerChange({
styleManager._contextControls._handleContextLayerChange({
type: 'visibility-failed',
layerId: candidateId,
enabled: shouldEnable,
@@ -905,7 +905,7 @@ async function main() {
enabled: true,
origin: 'user',
});
styleManager._handleContextLayerChange({
styleManager._contextControls._handleContextLayerChange({
type: 'visibility-blocked',
layerId,
enabled: true,
@@ -925,10 +925,10 @@ async function main() {
reason,
retryReason,
toastMessages,
mode: styleManager._contextMode,
snapshotCleared: styleManager._contextSessionSnapshot === null,
mode: styleManager._contextControls._contextMode,
snapshotCleared: styleManager._contextControls._contextSessionSnapshot === null,
priorLayerRestored,
modeChanging: styleManager._contextModeChanging,
modeChanging: styleManager._contextControls._contextModeChanging,
});
}
}
@@ -937,8 +937,8 @@ async function main() {
const directActivationFailures = [];
for (const layerId of ['military-awareness', 'rocket-launches']) {
enabled.clear();
styleManager._contextMode = null;
styleManager._contextSessionSnapshot = {
styleManager._contextControls._contextMode = null;
styleManager._contextControls._contextSessionSnapshot = {
enabledLayerIds: new Set(['local-datacenters']),
userAdded: new Set(),
userRemoved: new Set(),
@@ -948,7 +948,7 @@ async function main() {
shouldEnable ? enabled.add(candidateId) : enabled.delete(candidateId);
return true;
};
styleManager._handleContextLayerChange({
styleManager._contextControls._handleContextLayerChange({
type: 'visibility-failed',
layerId,
enabled: true,
@@ -957,8 +957,8 @@ async function main() {
await new Promise((resolve) => setTimeout(resolve, 50));
directActivationFailures.push({
layerId,
mode: styleManager._contextMode,
snapshotCleared: styleManager._contextSessionSnapshot === null,
mode: styleManager._contextControls._contextMode,
snapshotCleared: styleManager._contextControls._contextSessionSnapshot === null,
priorLayerRestored: enabled.has('local-datacenters'),
failedLayerDisabled: !enabled.has(layerId),
});
@@ -967,8 +967,8 @@ async function main() {
const directActivationRollbackFailures = [];
for (const layerId of ['military-awareness', 'rocket-launches']) {
enabled.clear();
styleManager._contextMode = null;
styleManager._contextSessionSnapshot = {
styleManager._contextControls._contextMode = null;
styleManager._contextControls._contextSessionSnapshot = {
enabledLayerIds: new Set(['local-datacenters']),
userAdded: new Set(),
userRemoved: new Set(),
@@ -985,7 +985,7 @@ async function main() {
shouldEnable ? enabled.add(candidateId) : enabled.delete(candidateId);
return true;
};
styleManager._handleContextLayerChange({
styleManager._contextControls._handleContextLayerChange({
type: 'visibility-failed',
layerId,
enabled: true,
@@ -996,7 +996,7 @@ async function main() {
directActivationRollbackFailures.push({
layerId,
toastMessages,
retryRetained: styleManager._contextSessionSnapshot?.enabledLayerIds?.has('local-datacenters') === true,
retryRetained: styleManager._contextControls._contextSessionSnapshot?.enabledLayerIds?.has('local-datacenters') === true,
});
}
@@ -1026,8 +1026,8 @@ async function main() {
window.__gevQaRegisterLayer(dataManager, qaLayer);
try {
const enabledBeforeExit = dataManager.getEnabledLayerIds();
styleManager._contextMode = 'flights';
styleManager._contextSessionSnapshot = {
styleManager._contextControls._contextMode = 'flights';
styleManager._contextControls._contextSessionSnapshot = {
enabledLayerIds: new Set([...enabledBeforeExit, layerId]),
userAdded: new Set(),
userRemoved: new Set(),
@@ -1039,13 +1039,13 @@ async function main() {
};
const unhandledBefore = unhandled.length;
const result = await styleManager._runUserFacingContextAction(
(notificationToken) => styleManager._deactivateContextForLayerChange({ notificationToken }),
(notificationToken) => styleManager._contextControls._deactivateContextForLayerChange({ notificationToken }),
`QA Context exit ${outcome} surfaced once`,
);
const retainedForRetry = styleManager._contextSessionSnapshot?.enabledLayerIds?.has(layerId) === true;
const retainedForRetry = styleManager._contextControls._contextSessionSnapshot?.enabledLayerIds?.has(layerId) === true;
enableOutcome = 'success';
const retryResult = await styleManager._runUserFacingContextAction(
(notificationToken) => styleManager._deactivateContextForLayerChange({ notificationToken }),
(notificationToken) => styleManager._contextControls._deactivateContextForLayerChange({ notificationToken }),
`QA Context exit ${outcome} retry failed`,
);
contextExitFailures.push({
@@ -1055,9 +1055,9 @@ async function main() {
toastMessages,
unhandledDelta: unhandled.length - unhandledBefore,
retainedForRetry,
mode: styleManager._contextMode,
modeChanging: styleManager._contextModeChanging,
snapshotClearedAfterRetry: styleManager._contextSessionSnapshot === null,
mode: styleManager._contextControls._contextMode,
modeChanging: styleManager._contextControls._contextModeChanging,
snapshotClearedAfterRetry: styleManager._contextControls._contextSessionSnapshot === null,
enabledAfterRetry: dataManager.isEnabled(layerId),
toastRole: document.getElementById('toast').getAttribute('role'),
toastLive: document.getElementById('toast').getAttribute('aria-live'),
@@ -1163,10 +1163,10 @@ async function main() {
dataManager.restoreEnabledLayerIds = originalRestoreEnabledLayerIds;
dataManager.isEnabled = originalIsEnabled;
dataManager.isEffectivelyEnabled = originalIsEffectivelyEnabled;
styleManager._clearLayersOutsideContextMode = originalClear;
styleManager._captureContextSessionSnapshot = originalCapture;
styleManager._contextMode = originalContextMode;
styleManager._contextSessionSnapshot = originalSnapshot;
styleManager._contextControls._clearLayersOutsideContextMode = originalClear;
styleManager._contextControls._captureContextSessionSnapshot = originalCapture;
styleManager._contextControls._contextMode = originalContextMode;
styleManager._contextControls._contextSessionSnapshot = originalSnapshot;
styleManager._showToast = originalShowToast;
if (installations) installations.searchNearby = originalSearchNearby;
window.removeEventListener('unhandledrejection', onUnhandled);
+10
View File
@@ -58,6 +58,13 @@ try {
counts.cctv++;
return cctvUnsubscribe();
};
const contextFields = ['_contextManagerUnsubscribe', '_dataManagerVisibilityRequestUnsubscribe', '_dataManagerVisibilityGuardUnsubscribe', '_dataManagerBeforeDestroyUnsubscribe'];
const contextConnected = contextFields.every((field) => typeof ui._contextControls[field] === 'function');
for (const field of contextFields) {
const unsubscribe = ui._contextControls[field];
counts[field] = 0;
ui._contextControls[field] = () => { counts[field]++; return unsubscribe?.(); };
}
const resizeHandler = ui._windowResizeHandler;
const removeEventListener = window.removeEventListener;
counts.resize = 0;
@@ -79,6 +86,8 @@ try {
resizeHandler &&
observed.includes('_commandDockTrayObserver'),
),
contextReleased: contextConnected && ui._contextControls.destroyed
&& contextFields.every((field) => counts[field] === 1 && ui._contextControls[field] === null),
observersReleased: observed.every(
(name) => counts[name] === 1 && ui[name] === null,
),
@@ -99,6 +108,7 @@ try {
'real UI has the expected live resources before disposal',
result.connected,
);
check('UI disposal releases all Context subscriptions and stops its controls', result.contextReleased);
check(
'UI disposal disconnects each active panel observer once',
result.observersReleased,