diff --git a/CHANGELOG.md b/CHANGELOG.md index 91de5887f..a2d4f90ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ takes `omitViews` (for example `['provider-settings']`) for views an application leaves out (samehkhamis). +- `./scenes` presents the scene sharing dialogs and the EDIT DETAILS / SHARE + SCENE bar through a store that the scene panels view renders, so a page + that omits `layer-panels` shows neither (samehkhamis). + - `./ui/display`'s `bindDisplayControls` takes the keyhole fade and outside opacity sliders as `fadeSlider` and `outsideOpacitySlider`, and their actions receive whole percentages; `fadeSliders` still works. diff --git a/docs/APPLICATION.md b/docs/APPLICATION.md index 24a7111a9..ceb517133 100644 --- a/docs/APPLICATION.md +++ b/docs/APPLICATION.md @@ -205,8 +205,9 @@ Provider Settings. A page places each Vue view in `src/ui/views` with a host, screen (`#loading-screen` with a `.loader-status` line) as static markup so it paints before any script runs. `createApplication()` renders the views before anything reads the page; `omitViews` names views the application leaves out, -such as `provider-settings`, and their hosts are removed. An unknown view name -is an error. A host that does not initialize Core's locale passes +such as `provider-settings`, and their hosts are removed. Leaving out +`layer-panels` also leaves out the scene sharing dialogs it draws. An unknown +view name is an error. A host that does not initialize Core's locale passes `localePicker: false` to `createApplicationControls` instead of editing the markup. Node tests that import application modules register the component loader with `node --import=/build/register-vue`. diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index ec0d5131b..25e564755 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -28,6 +28,7 @@ "src/ui/views/panels/SdrCard.vue", "src/ui/views/panels/RadioTuner.vue", "src/ui/views/panels/LocalePicker.vue", + "src/ui/views/panels/SceneDialog.vue", "src/ui/localePicker.js", "src/ui/views/panels/PhoneTabBar.vue", "src/ui/views/panels/CockpitBriefing.vue", @@ -76,6 +77,7 @@ "src/ui/stores/cockpit.js", "src/ui/stores/locale.js", "src/ui/stores/providerSettings.js", + "src/ui/stores/sceneSharing.js", "src/ui/stores/location.js", "src/ui/stores/streetLevel.js", "src/ui/rail/RailChips.vue", @@ -84,7 +86,8 @@ "src/ui/rail/rangeValue.js", "src/ui/rail/classToggle.js", "src/ui/rail/focusSafeChildren.js", - "src/ui/rail/fieldValue.js" + "src/ui/rail/fieldValue.js", + "src/ui/rail/statusText.js" ], "external": ["vue", "pinia"] }, @@ -1004,6 +1007,7 @@ "src/ui/stores/cockpit.js", "src/ui/stores/locale.js", "src/ui/stores/providerSettings.js", + "src/ui/stores/sceneSharing.js", "src/ui/stores/location.js", "src/ui/stores/display.js" ], @@ -1118,6 +1122,7 @@ "src/director/authoring.js", "src/scenes/sharing.js", "src/ui/sceneSharing.js", + "src/ui/stores/sceneSharing.js", "src/data/cameraArrival.js", "src/i18n/index.js", "src/i18n/locale.js", @@ -2816,6 +2821,7 @@ "src/director/authoring.js", "src/scenes/sharing.js", "src/ui/sceneSharing.js", + "src/ui/stores/sceneSharing.js", "src/layers/weather/imageryOrder.js", "src/layers/weather/imageryHost.js", "src/layers/cyclones/index.js", @@ -2983,6 +2989,7 @@ "src/ui/stores/cockpit.js", "src/ui/stores/locale.js", "src/ui/stores/providerSettings.js", + "src/ui/stores/sceneSharing.js", "src/ui/stores/location.js", "src/ui/stores/display.js" ], diff --git a/scripts/qa-director-sharing.mjs b/scripts/qa-director-sharing.mjs index bfc76ed93..4a4a93d48 100644 --- a/scripts/qa-director-sharing.mjs +++ b/scripts/qa-director-sharing.mjs @@ -427,6 +427,9 @@ try { shot.interactions = []; fields[0].value = JSON.stringify(scene); fields[1].value = JSON.stringify(shot); + // Typing fires input; the dialog reads its fields from those events. + for (const field of fields) + field.dispatchEvent(new Event('input', { bubbles: true })); }); await page.click('[data-director-apply-details]'); await page.waitForFunction( diff --git a/scripts/qa-scene-dialog-file-drop.mjs b/scripts/qa-scene-dialog-file-drop.mjs index 9b48555ad..d6806ff72 100644 --- a/scripts/qa-scene-dialog-file-drop.mjs +++ b/scripts/qa-scene-dialog-file-drop.mjs @@ -4,7 +4,7 @@ * file dropped from the desktop, proved in a real browser. * * The dialog draws a translated row over the native file input - * (src/ui/sceneSharing.js, fileChooser). The input must still cover the row, + * (src/ui/views/panels/SceneDialog.vue). The input must still cover the row, * or drops miss it. Drops a file on the row's centre via CDP and expects * `input.files` to hold it. * @@ -15,31 +15,34 @@ * drop selects the file, 1 otherwise. */ import http from 'node:http'; -import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { mkdtemp, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; +import vue from '@vitejs/plugin-vue'; import puppeteer from 'puppeteer'; +import { createServer } from 'vite'; +import { VUE_PLUGIN_OPTIONS } from '../build/vueOptions.js'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const TYPES = { - '.js': 'text/javascript', - '.mjs': 'text/javascript', - '.json': 'application/json', - '.html': 'text/html', -}; +// The scene panels view draws the dialog; Vite compiles it for the page. const PAGE = ` +
diff --git a/src/ui/views/ProviderSettingsView.vue b/src/ui/views/ProviderSettingsView.vue index dc575e877..baa13d021 100644 --- a/src/ui/views/ProviderSettingsView.vue +++ b/src/ui/views/ProviderSettingsView.vue @@ -4,6 +4,7 @@ import { computed, onBeforeUnmount, onMounted, shallowRef } from 'vue'; import { t } from '../../i18n/index.js'; import { vClassToggle } from '../rail/classToggle.js'; import { vFieldValue } from '../rail/fieldValue.js'; +import { vStatusText } from '../rail/statusText.js'; import { useLocaleStore } from '../stores/locale.js'; import { useProviderSettingsStore } from '../stores/providerSettings.js'; import LocalePicker from './panels/LocalePicker.vue'; @@ -34,17 +35,7 @@ onMounted(() => { }); onBeforeUnmount(() => themeObserver?.disconnect()); -// The status line is a live region: write each message, even a repeated one, -// so a screen reader announces it again. -const vStatusText = { - mounted(el, { value }) { - el.textContent = value.text; - }, - updated(el, { value, oldValue }) { - if (value.seq !== oldValue?.seq || value.text !== oldValue?.text) - el.textContent = value.text; - }, -}; +// The status line is a live region; vStatusText re-announces repeats. const statusText = computed(() => ({ text: view.value?.status ?? diff --git a/src/ui/views/panels/SceneDialog.vue b/src/ui/views/panels/SceneDialog.vue new file mode 100644 index 000000000..02e1f6918 --- /dev/null +++ b/src/ui/views/panels/SceneDialog.vue @@ -0,0 +1,64 @@ + + +