diff --git a/scripts/qa-scene-controls.mjs b/scripts/qa-scene-controls.mjs
index 223202221..72521d298 100644
--- a/scripts/qa-scene-controls.mjs
+++ b/scripts/qa-scene-controls.mjs
@@ -442,12 +442,13 @@ try {
return '{"scenes":[]}';
},
});
+ // A shot row held across disposal must not act once it is revoked.
+ const retainedLabel = document.querySelector('.scene-shot-label');
const stopping = director.destroy();
const notificationsAtStop = window.__qaSceneState.length;
const stoppedSynchronously =
- controls.destroyed &&
- controls.removers.length === 0 &&
- controls.rowRemovers.length === 0;
+ controls.destroyed && controls.removers.length === 0;
+ retainedLabel?.click();
document.getElementById('scene-new-btn').click();
controls.run('capture');
finish();
@@ -456,6 +457,7 @@ try {
await director.destroy();
return {
stoppedSynchronously,
+ heldRowAction: Boolean(retainedLabel),
stateStopped: window.__qaSceneState.length === notificationsAtStop,
sameProject: director._project === project,
noLateStatus:
@@ -465,7 +467,9 @@ try {
});
check(
'Disposal revokes fixed and row actions before waiting for scene work',
- teardown.stoppedSynchronously && teardown.rowsGone,
+ teardown.stoppedSynchronously &&
+ teardown.heldRowAction &&
+ teardown.rowsGone,
);
check(
'Late import completion cannot replace the disposed project or status',
diff --git a/scripts/qa-visual-input.mjs b/scripts/qa-visual-input.mjs
index 5e3991806..44525e6ab 100644
--- a/scripts/qa-visual-input.mjs
+++ b/scripts/qa-visual-input.mjs
@@ -140,9 +140,11 @@ try {
hudBefore,
),
);
- const displayBefore = await page.evaluate(() => {
+ const displayBefore = await page.evaluate(async () => {
const manager = window.__godsEyeView.styleManager;
manager._setBloomEnabled(true);
+ // The Display view shows the slider row on its next render.
+ await new Promise((resolve) => requestAnimationFrame(resolve));
manager._bloomSlider.value = '80';
manager._bloomSlider.dispatchEvent(new Event('input', { bubbles: true }));
manager._bloomSlider.focus();
diff --git a/src/ui/sceneControls.test.mjs b/src/ui/sceneControls.test.mjs
index 9ab9e6bd5..186713daf 100644
--- a/src/ui/sceneControls.test.mjs
+++ b/src/ui/sceneControls.test.mjs
@@ -459,6 +459,26 @@ test('the scene select follows option renders, as before', async () => {
}
});
+test('an option render restores the published scene after a local pick', async () => {
+ const f = fixture();
+ try {
+ f.state.scenes.push({ id: 'scene-b', title: 'B', shots: [] });
+ f.owner.renderSceneSelect();
+ await nextTick();
+ assert.equal(f.elements.select.value, 'scene-a');
+ // The person picks B; the owner re-renders the shot list only.
+ f.elements.select.value = 'scene-b';
+ f.owner.renderShotList();
+ await nextTick();
+ // Something reloads A and renders the options with the same choice.
+ f.owner.renderSceneSelect();
+ await nextTick();
+ assert.equal(f.elements.select.value, 'scene-a');
+ } finally {
+ f.restore();
+ }
+});
+
test('Scene controls consume current state, preserve rows on progress, and unsubscribe on destruction', async () => {
const f = fixture();
try {
diff --git a/src/ui/stores/scenes.js b/src/ui/stores/scenes.js
index f9d459178..230c3f1ef 100644
--- a/src/ui/stores/scenes.js
+++ b/src/ui/stores/scenes.js
@@ -21,6 +21,9 @@ export const useSceneStore = defineStore('gev-scenes', () => {
const selectedShotId = shallowRef(null);
// The select's choice, updated only when its options are rendered.
const listedSceneId = shallowRef(null);
+ // Counts option renders: each one re-applies the select's choice, which
+ // the person may have changed since.
+ const listedRevision = shallowRef(0);
/** Whether an owner presents the project; until then the list is empty. */
const attached = shallowRef(false);
/** @type {{handlers: SceneRowHandlers}|null} */
@@ -48,6 +51,7 @@ export const useSceneStore = defineStore('gev-scenes', () => {
function publishOptions(state) {
publish(state);
listedSceneId.value = state.selectedSceneId ?? null;
+ listedRevision.value++;
}
/** @param {string|null} id */
@@ -79,6 +83,7 @@ export const useSceneStore = defineStore('gev-scenes', () => {
selectedSceneId,
selectedShotId,
listedSceneId,
+ listedRevision,
attached,
attach,
publish,
diff --git a/src/ui/views/SceneOptions.vue b/src/ui/views/SceneOptions.vue
index 8fe769e40..4cc6bbe77 100644
--- a/src/ui/views/SceneOptions.vue
+++ b/src/ui/views/SceneOptions.vue
@@ -1,9 +1,23 @@