refactor: drive share, location and scene controls through product state

This commit is contained in:
Sameh Khamis committed 2026-09-13 05:42:49 -07:00
1 parent 21a0d0c74e
commit 45d97376d0
21 files changed
+606 -96

No files matched your search

+18 -2
View File
@@ -343,7 +343,8 @@
"src/ui/location.js",
"src/ui/locationControls.js",
"src/ui/locationSearch.js",
"src/locationStatus.js"
"src/locationStatus.js",
"src/app/stateChannel.js"
],
"external": []
},
@@ -518,7 +519,8 @@
"src/ui/visualInput.js",
"src/ui/visualPresets.js",
"src/worldFocus.js",
"src/ui/uiLifetime.js"
"src/ui/uiLifetime.js",
"src/app/stateChannel.js"
],
"external": ["cesium"]
},
@@ -548,5 +550,19 @@
"src/ui/styles/provider-settings.css"
],
"external": []
},
"scenes": {
"exports": ["./scenes"],
"modules": [
"src/scenes/director.js",
"src/scenes/recipes.js",
"src/scenes/scenePolicy.js",
"src/bloom.js",
"src/app/stateChannel.js",
"src/ui/scenes.js",
"src/ui/sceneControls.js",
"src/ui/scenePresentation.js"
],
"external": ["cesium"]
}
}
+10
View File
@@ -87,6 +87,8 @@ try {
await page.evaluate(() => {
const lookup = window.__godsEyeView.styleManager._locationLookup;
window.__qaSearchRequests = [];
window.__qaLocationState = [];
window.__godsEyeView.styleManager.subscribeLocationSearch((notification) => window.__qaLocationState.push(notification));
lookup.search = (query, options) =>
new Promise((resolve) =>
window.__qaSearchRequests.push({ query, options, resolve }),
@@ -139,6 +141,14 @@ try {
);
}),
);
check('Location subscriptions accept only the current result and retain request identities', await page.evaluate(() => {
const seen = window.__qaLocationState;
const started = seen.filter(({ change }) => change?.type === 'started');
const found = seen.filter(({ change }) => change?.type === 'found');
return seen[0].initial && started.length === 2 && found.length === 1 &&
found[0].change.requestId === started[1].change.requestId &&
found[0].state.destination.label === 'Second landmark, Test city' && Object.isFrozen(found[0].state.destination);
}));
check(
'cancelled POI expansion stays closed after a frame',
await page.evaluate(async (id) => {
+14
View File
@@ -39,6 +39,10 @@ try {
document.getElementById('loading-screen')?.classList.contains('hidden'),
{ timeout: 60000 },
);
await page.evaluate(() => {
window.__qaSceneState = [];
window.__godsEyeView.sceneDirector.subscribe((notification) => window.__qaSceneState.push(notification));
});
await page.click('[data-collapse-target="scene-panel"]');
await page.click('#scene-new-btn');
await page.waitForFunction(
@@ -303,6 +307,13 @@ try {
document.querySelectorAll('#scene-select option').length > 0,
),
);
check('Scene subscriptions include current state and the completed native editing actions', await page.evaluate(() => {
const seen = window.__qaSceneState;
const types = new Set(seen.map(({ change }) => change?.type));
return seen[0].initial && Object.isFrozen(seen[0].state) &&
['scene-created', 'shot-captured', 'shot-renamed', 'shot-updated', 'project-exported', 'project-imported', 'shot-deleted', 'scene-deleted', 'run-event'].every((type) => types.has(type)) &&
seen.filter(({ change }) => change?.shot).every(({ change }) => Object.isFrozen(change.shot));
}));
const teardown = await page.evaluate(async () => {
const director = window.__godsEyeView.sceneDirector;
const controls = director._controls;
@@ -320,6 +331,7 @@ try {
},
});
const stopping = director.destroy();
const notificationsAtStop = window.__qaSceneState.length;
const stoppedSynchronously =
controls.destroyed &&
controls.removers.length === 0 &&
@@ -332,6 +344,7 @@ try {
await director.destroy();
return {
stoppedSynchronously,
stateStopped: window.__qaSceneState.length === notificationsAtStop,
sameProject: director._project === project,
noLateStatus:
document.getElementById('scene-status').textContent === previousStatus,
@@ -346,6 +359,7 @@ try {
'Late import completion cannot replace the disposed project or status',
teardown.sameProject && teardown.noLateStatus,
);
check('Scene subscriptions stop before late imports settle', teardown.stateStopped);
check(
'Scene control interaction produces no uncaught browser errors',
errors.length === 0,
+8
View File
@@ -119,6 +119,9 @@ try {
setSplitFlapText(feedbackLabel, 'LOAD COMPLETE');
const permanentText =
feedbackLabel.querySelector('.gev-flap-text')?.firstChild;
let stateNotifications = 0;
ui.subscribeShareState(() => stateNotifications++, { emitCurrent: false });
ui.subscribeLocationSearch(() => stateNotifications++, { emitCurrent: false });
try {
const disposal = ui.dispose();
const focusBefore = document.activeElement;
@@ -139,6 +142,9 @@ try {
const noDeferredFocus = document.activeElement === focusBefore;
releaseRestoration();
await disposal;
ui._syncShareState();
ui.subscribeShareState(() => stateNotifications++);
ui.subscribeLocationSearch(() => stateNotifications++);
const once = JSON.stringify(counts);
await ui.dispose();
window.dispatchEvent(new Event('resize'));
@@ -202,6 +208,7 @@ try {
ui._lifetime.frames.size === 0 &&
ui._lifetime.timers.size === 0 &&
ui._lifetime.removers.size === 0,
stateStopped: stateNotifications === 0,
idempotent: once === JSON.stringify(counts),
};
} finally {
@@ -249,6 +256,7 @@ try {
'shell teardown cancels deferred work and releases listeners',
result.shellWorkReleased,
);
check('state subscriptions stop synchronously with UI disposal', result.stateStopped);
check('repeated UI disposal is inert', result.idempotent);
check(
'disposal and subsequent resize produce no uncaught browser errors',
+6
View File
@@ -152,9 +152,15 @@ try {
'bloom actions, effect state and saved snapshot agree',
await page.evaluate(() => {
const manager = window.__godsEyeView.styleManager;
const states = [];
const unsubscribe = manager.subscribeShareState((value) => states.push(value));
const result = manager.setBloom({ enabled: true, intensityPct: 98 });
unsubscribe();
const published = states.at(-1);
const snapshot = manager.getVisualState();
return (
states[0].initial && states.length > 1 && Object.isFrozen(published.state.options) &&
published.state.bloomEnabled && published.state.options.bloomIntensity === 98 &&
result.ok &&
result.bloom.intensityPct === 98 &&
snapshot.bloom.intensity === 98 &&