feat(ui): render the page toast from the status store

ShellFeedback and the scene director show toasts through createToast(),
each on its own timer as before, and the scene chrome renders the toast.
Every show rewrites the text, so a repeated message is announced again.
This commit is contained in:
Sameh Khamis committed 2026-10-31 19:58:59 -07:00
1 parent 3c391482f6
commit f846aaed4c
13 files changed
+203 -43

No files matched your search

+4 -14
View File
@@ -17,6 +17,7 @@ import { resolveCameraPose, resolveCameraMove } from '../director/camera.js';
import { createCameraMotion } from './cameraMotion.js';
import { createStateChannel } from '../app/stateChannel.js';
import { SceneControls } from '../ui/scenes.js';
import { createToast } from '../ui/toast.js';
import { buildPlaybackQueue, playSceneQueue } from '../director/playback.js';
import { createScenePlaybackAdapter } from './playbackAdapter.js';
import * as Cesium from 'cesium';
@@ -252,7 +253,7 @@ export class SceneDirector {
this._loadAbort?.abort();
this._loadGeneration++;
this.viewer.camera.cancelFlight();
clearTimeout(this._storageToastTimer);
this._storageToast?.cancel();
await Promise.allSettled(this._pendingWork || []);
this._clock.destroy();
this._cancelActiveSceneTravel();
@@ -365,19 +366,8 @@ export class SceneDirector {
message = t('Scene not saved — browser storage unavailable'),
) {
this._updateStatus(message);
try {
const toast = document.getElementById('toast');
if (toast) {
toast.textContent = message;
toast.classList.add('visible');
clearTimeout(this._storageToastTimer);
this._storageToastTimer = setTimeout(() => {
toast.classList.remove('visible');
}, 2600);
}
} catch {
/* toast is best-effort */
}
this._storageToast ??= createToast({ durationMs: 2600 });
this._storageToast.show(message);
}
/** Immutable playback snapshots and completed editing actions. */
+5
View File
@@ -1,4 +1,6 @@
import { readShellSource } from '../testSupport/readShellSource.mjs';
import { useStatusStore } from '../ui/stores/status.js';
import { applicationPinia } from '../ui/vueRuntime.js';
// Director-level pins for scene playback.
//
// scenePolicy.test.mjs pins the pure decisions; these pin the wiring, which is
@@ -1995,6 +1997,9 @@ test('a capture, update or import that cannot be saved keeps the "Scene not save
{ prepared: { project: structuredClone(PROJECT_FIXTURE), assets: [] } },
), true);
assert.match(status, /^Scene not saved/, 'failed import keeps the save failure');
const toast = useStatusStore(applicationPinia()).toast;
assert.equal(toast.visible, true);
assert.match(toast.text, /^Scene not saved/, 'the page toast says so too');
} finally { console.warn = warn; await director.destroy(); restore(); }
});