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 @@