fix(ui): keep the scene select on the published scene after a local pick

Re-apply the published scene to the select after every option render, as the imperative renderer did. The scene and visual-input QA scripts click a held shot label after disposal and wait a frame for the bloom row.
This commit is contained in:
Sameh Khamis committed 2026-10-30 23:56:20 -07:00
1 parent b870df4199
commit 54b8060f71
5 files changed
+51 -6

No files matched your search

+8 -4
View File
@@ -442,12 +442,13 @@ try {
return '{"scenes":[]}'; 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 stopping = director.destroy();
const notificationsAtStop = window.__qaSceneState.length; const notificationsAtStop = window.__qaSceneState.length;
const stoppedSynchronously = const stoppedSynchronously =
controls.destroyed && controls.destroyed && controls.removers.length === 0;
controls.removers.length === 0 && retainedLabel?.click();
controls.rowRemovers.length === 0;
document.getElementById('scene-new-btn').click(); document.getElementById('scene-new-btn').click();
controls.run('capture'); controls.run('capture');
finish(); finish();
@@ -456,6 +457,7 @@ try {
await director.destroy(); await director.destroy();
return { return {
stoppedSynchronously, stoppedSynchronously,
heldRowAction: Boolean(retainedLabel),
stateStopped: window.__qaSceneState.length === notificationsAtStop, stateStopped: window.__qaSceneState.length === notificationsAtStop,
sameProject: director._project === project, sameProject: director._project === project,
noLateStatus: noLateStatus:
@@ -465,7 +467,9 @@ try {
}); });
check( check(
'Disposal revokes fixed and row actions before waiting for scene work', 'Disposal revokes fixed and row actions before waiting for scene work',
teardown.stoppedSynchronously && teardown.rowsGone, teardown.stoppedSynchronously &&
teardown.heldRowAction &&
teardown.rowsGone,
); );
check( check(
'Late import completion cannot replace the disposed project or status', 'Late import completion cannot replace the disposed project or status',
+3 -1
View File
@@ -140,9 +140,11 @@ try {
hudBefore, hudBefore,
), ),
); );
const displayBefore = await page.evaluate(() => { const displayBefore = await page.evaluate(async () => {
const manager = window.__godsEyeView.styleManager; const manager = window.__godsEyeView.styleManager;
manager._setBloomEnabled(true); 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.value = '80';
manager._bloomSlider.dispatchEvent(new Event('input', { bubbles: true })); manager._bloomSlider.dispatchEvent(new Event('input', { bubbles: true }));
manager._bloomSlider.focus(); manager._bloomSlider.focus();
+20
View File
@@ -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 () => { test('Scene controls consume current state, preserve rows on progress, and unsubscribe on destruction', async () => {
const f = fixture(); const f = fixture();
try { try {
+5
View File
@@ -21,6 +21,9 @@ export const useSceneStore = defineStore('gev-scenes', () => {
const selectedShotId = shallowRef(null); const selectedShotId = shallowRef(null);
// The select's choice, updated only when its options are rendered. // The select's choice, updated only when its options are rendered.
const listedSceneId = shallowRef(null); 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. */ /** Whether an owner presents the project; until then the list is empty. */
const attached = shallowRef(false); const attached = shallowRef(false);
/** @type {{handlers: SceneRowHandlers}|null} */ /** @type {{handlers: SceneRowHandlers}|null} */
@@ -48,6 +51,7 @@ export const useSceneStore = defineStore('gev-scenes', () => {
function publishOptions(state) { function publishOptions(state) {
publish(state); publish(state);
listedSceneId.value = state.selectedSceneId ?? null; listedSceneId.value = state.selectedSceneId ?? null;
listedRevision.value++;
} }
/** @param {string|null} id */ /** @param {string|null} id */
@@ -79,6 +83,7 @@ export const useSceneStore = defineStore('gev-scenes', () => {
selectedSceneId, selectedSceneId,
selectedShotId, selectedShotId,
listedSceneId, listedSceneId,
listedRevision,
attached, attached,
attach, attach,
publish, publish,
+15 -1
View File
@@ -1,9 +1,23 @@
<script setup> <script setup>
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { getCurrentInstance, watch } from 'vue';
import { useSceneStore } from '../stores/scenes.js'; import { useSceneStore } from '../stores/scenes.js';
// The Scene select's options; selecting one stays with SceneControls. // The Scene select's options; selecting one stays with SceneControls.
const { scenes, listedSceneId } = storeToRefs(useSceneStore()); const { scenes, listedSceneId, listedRevision } = storeToRefs(useSceneStore());
// Every option render shows the published scene, as the select did before:
// `selected` alone is written only when it changes, so it would leave a
// person's later pick standing.
const instance = getCurrentInstance();
watch(
listedRevision,
() => {
const select = instance.proxy.$el?.parentNode;
if (select && listedSceneId.value) select.value = listedSceneId.value;
},
{ flush: 'post' },
);
</script> </script>
<template> <template>