From 9d621e97066af6e8ec6d0cf1ad781a2d5bcd2bea Mon Sep 17 00:00:00 2001 From: Tim Bradgate Date: Sat, 6 Jun 2026 21:40:36 +0100 Subject: [PATCH 1/3] Fix script page changes not propagating to other connected clients (#1151) * Broadcast SCRIPT_PAGE_CHANGED after script saves so other clients update in real-time When one client saved script changes, other connected clients did not see the updates without a manual refresh. The backend was missing a WebSocket broadcast after the save commit in both the POST and PATCH handlers. Adds ws_send_to_all("NOOP", "SCRIPT_PAGE_CHANGED", {"page": page}) to both handlers, and adds matching action handlers in the Vue 2 Vuex store (SCRIPT_PAGE_CHANGED) and Vue 3 Pinia store (scriptPageChanged) that reload the changed page into both the script store and tmpScript (the data source the editor template renders from) when the page is loaded. Fixes #1149. Co-Authored-By: Claude Sonnet 4.6 * Use Object.hasOwn() instead of Object.prototype.hasOwnProperty.call() Addresses SonarCloud warnings on PR #1151. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- client-v3/src/stores/script.ts | 12 ++++++++++++ client/src/store/modules/script.ts | 7 +++++++ server/controllers/api/show/script/script.py | 7 +++++++ 3 files changed, 26 insertions(+) diff --git a/client-v3/src/stores/script.ts b/client-v3/src/stores/script.ts index e16c3f192..1e8fb89ac 100644 --- a/client-v3/src/stores/script.ts +++ b/client-v3/src/stores/script.ts @@ -2,6 +2,7 @@ import { defineStore } from 'pinia'; import log from 'loglevel'; import { makeURL } from '@/js/utils'; import { toast } from '@/js/toast'; +import { useScriptConfigStore } from '@/stores/scriptConfig'; import type { ScriptLine, StageDirectionStyle, @@ -47,6 +48,17 @@ export const useScriptStore = defineStore('script', { } }, + async scriptPageChanged(data: { page: number }): Promise { + const pageStr = String(data.page); + if (Object.hasOwn(this.script, pageStr)) { + await this.loadScriptPage(data.page); + const scriptConfigStore = useScriptConfigStore(); + if (Object.hasOwn(scriptConfigStore.tmpScript, pageStr)) { + scriptConfigStore.addPage(data.page, this.getScriptPage(data.page)); + } + } + }, + async saveNewPage(page: number, lines: ScriptLine[]): Promise { const params = new URLSearchParams({ page: String(page) }); const response = await fetch(`${makeURL('/api/v1/show/script')}?${params}`, { diff --git a/client/src/store/modules/script.ts b/client/src/store/modules/script.ts index cb7e453d9..740f9c9a1 100644 --- a/client/src/store/modules/script.ts +++ b/client/src/store/modules/script.ts @@ -145,6 +145,13 @@ const module: Module = { await context.dispatch('LOAD_CUES'); await context.dispatch('GET_CUTS'); }, + async SCRIPT_PAGE_CHANGED(context, msg: { DATA: { page: number } }) { + const page = String(msg.DATA.page); + if (Object.hasOwn(context.state.script, page)) { + await context.dispatch('LOAD_SCRIPT_PAGE', page); + await context.dispatch('ADD_BLANK_PAGE', page); + } + }, async LOAD_SCRIPT_PAGE(context, page: string | number) { const searchParams = new URLSearchParams({ page: String(page) }); const response = await fetch(`${makeURL('/api/v1/show/script')}?${searchParams}`, { diff --git a/server/controllers/api/show/script/script.py b/server/controllers/api/show/script/script.py index cd61959ac..cb9b62129 100644 --- a/server/controllers/api/show/script/script.py +++ b/server/controllers/api/show/script/script.py @@ -269,6 +269,9 @@ async def post(self): CompiledScript.compile_script, self.application, revision.id ) ) + await self.application.ws_send_to_all( + "NOOP", "SCRIPT_PAGE_CHANGED", {"page": page} + ) else: self.set_status(404) await self.finish({"message": ERROR_SHOW_NOT_FOUND}) @@ -663,11 +666,15 @@ async def patch(self): (revision.id, line["id"]), ) # Spawn a callback to create a compiled version of the script + session.commit() IOLoop.current().add_callback( partial( CompiledScript.compile_script, self.application, revision.id ) ) + await self.application.ws_send_to_all( + "NOOP", "SCRIPT_PAGE_CHANGED", {"page": page} + ) else: self.set_status(404) await self.finish({"message": ERROR_SHOW_NOT_FOUND}) From f61fd30087ac64e3de51a88edbfedc9a1f698ab4 Mon Sep 17 00:00:00 2001 From: Tim Bradgate Date: Sat, 6 Jun 2026 22:10:54 +0100 Subject: [PATCH 2/3] Fix BVN modal props: rename hide-footer/hide-header-close to no-footer/no-header-close (#1150) (#1152) Bootstrap Vue Next renamed these props from BV2. The old names were silently ignored, causing modal footers and close buttons to remain visible/enabled when they should be hidden (e.g. during an in-progress save). Co-authored-by: Claude Sonnet 4.6 --- client-v3/src/App.vue | 4 ++-- client-v3/src/components/config/ConfigUsers.vue | 8 ++++---- client-v3/src/components/show/config/cues/CueEditor.vue | 4 ++-- .../src/components/show/config/cues/JumpToCueModal.vue | 4 ++-- .../components/show/config/mics/MicAutoPopulateModal.vue | 2 +- .../src/components/show/config/script/ScriptEditor.vue | 9 +++++---- .../components/show/config/sessions/SessionTagList.vue | 2 +- client-v3/src/views/show/config/ConfigCues.vue | 2 +- 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/client-v3/src/App.vue b/client-v3/src/App.vue index e2009da23..78d0877df 100644 --- a/client-v3/src/App.vue +++ b/client-v3/src/App.vue @@ -158,8 +158,8 @@ ref="goToPageModal" title="Go to Page" size="sm" - :hide-header-close="changingPage" - :hide-footer="changingPage" + :no-header-close="changingPage" + :no-footer="changingPage" :no-close-on-backdrop="changingPage" :no-close-on-esc="changingPage" @ok.prevent="goToLivePage" diff --git a/client-v3/src/components/config/ConfigUsers.vue b/client-v3/src/components/config/ConfigUsers.vue index 1082a688f..62b3fa836 100644 --- a/client-v3/src/components/config/ConfigUsers.vue +++ b/client-v3/src/components/config/ConfigUsers.vue @@ -52,11 +52,11 @@ - + - + - + - + diff --git a/client-v3/src/components/show/config/mics/MicAutoPopulateModal.vue b/client-v3/src/components/show/config/mics/MicAutoPopulateModal.vue index cd2b89173..8b942c681 100644 --- a/client-v3/src/components/show/config/mics/MicAutoPopulateModal.vue +++ b/client-v3/src/components/show/config/mics/MicAutoPopulateModal.vue @@ -3,7 +3,7 @@ ref="modalRef" size="xl" title="Auto-Populate Microphones" - :hide-footer="true" + no-footer @show="resetState" @hidden="resetState" > diff --git a/client-v3/src/components/show/config/script/ScriptEditor.vue b/client-v3/src/components/show/config/script/ScriptEditor.vue index ba84c0a0f..44d98c963 100644 --- a/client-v3/src/components/show/config/script/ScriptEditor.vue +++ b/client-v3/src/components/show/config/script/ScriptEditor.vue @@ -138,8 +138,9 @@ ref="saveModal" title="Saving Script" size="md" - :hide-header-close="savingInProgress" - :hide-footer="savingInProgress" + :no-header-close="savingInProgress" + :no-footer="savingInProgress" + :ok-disabled="savingInProgress" :no-close-on-backdrop="savingInProgress" :no-close-on-esc="savingInProgress" ok-only @@ -174,8 +175,8 @@ ref="goToPageModal" title="Go to Page" size="sm" - :hide-header-close="changingPage" - :hide-footer="changingPage" + :no-header-close="changingPage" + :no-footer="changingPage" :no-close-on-backdrop="changingPage" :no-close-on-esc="changingPage" @ok.prevent="goToPage" diff --git a/client-v3/src/components/show/config/sessions/SessionTagList.vue b/client-v3/src/components/show/config/sessions/SessionTagList.vue index 231cb33aa..40a43ad20 100644 --- a/client-v3/src/components/show/config/sessions/SessionTagList.vue +++ b/client-v3/src/components/show/config/sessions/SessionTagList.vue @@ -138,7 +138,7 @@ ref="importTagModal" title="Import Session Tag" size="xl" - hide-footer + no-footer @hide="resetImportState" >
diff --git a/client-v3/src/views/show/config/ConfigCues.vue b/client-v3/src/views/show/config/ConfigCues.vue index 14382160a..9326a1e2c 100644 --- a/client-v3/src/views/show/config/ConfigCues.vue +++ b/client-v3/src/views/show/config/ConfigCues.vue @@ -163,7 +163,7 @@ ref="importCueTypeModal" title="Import Cue Type" size="xl" - hide-footer + no-footer @hide="resetImportState" >
From b4ace219aa9bd112c663b06dcbd79f82a9d1f1ef Mon Sep 17 00:00:00 2001 From: Tim Bradgate Date: Sat, 6 Jun 2026 22:12:35 +0100 Subject: [PATCH 3/3] Bump version to 0.30.8 --- client-v3/package-lock.json | 4 ++-- client-v3/package.json | 2 +- client/package-lock.json | 4 ++-- client/package.json | 2 +- electron/package-lock.json | 4 ++-- electron/package.json | 2 +- server/pyproject.toml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client-v3/package-lock.json b/client-v3/package-lock.json index 669302055..54e746017 100644 --- a/client-v3/package-lock.json +++ b/client-v3/package-lock.json @@ -1,12 +1,12 @@ { "name": "client-v3", - "version": "0.30.7", + "version": "0.30.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "client-v3", - "version": "0.30.7", + "version": "0.30.8", "dependencies": { "@vuelidate/core": "^2.0.3", "@vuelidate/validators": "^2.0.4", diff --git a/client-v3/package.json b/client-v3/package.json index 370c6fd81..540895fb4 100644 --- a/client-v3/package.json +++ b/client-v3/package.json @@ -1,6 +1,6 @@ { "name": "client-v3", - "version": "0.30.7", + "version": "0.30.8", "description": "DigiScript front end (Vue 3)", "author": "DreamTeamProd", "private": true, diff --git a/client/package-lock.json b/client/package-lock.json index ee485dd01..517441328 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "client", - "version": "0.30.7", + "version": "0.30.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "client", - "version": "0.30.7", + "version": "0.30.8", "dependencies": { "bootstrap": "4.6.2", "bootstrap-vue": "2.23.1", diff --git a/client/package.json b/client/package.json index a12b6a7ee..f580b7f65 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "client", - "version": "0.30.7", + "version": "0.30.8", "description": "DigiScript front end", "author": "DreamTeamProd", "private": true, diff --git a/electron/package-lock.json b/electron/package-lock.json index a91394182..9e7de4797 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "digiscript-electron", - "version": "0.30.7", + "version": "0.30.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digiscript-electron", - "version": "0.30.7", + "version": "0.30.8", "license": "GPL-3.0", "dependencies": { "bonjour-service": "^1.4.0", diff --git a/electron/package.json b/electron/package.json index dea7d20c7..54c1430f0 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,6 +1,6 @@ { "name": "digiscript-electron", - "version": "0.30.7", + "version": "0.30.8", "description": "DigiScript Electron Desktop Application", "author": "DreamTeamProd", "license": "GPL-3.0", diff --git a/server/pyproject.toml b/server/pyproject.toml index 7e2bbe0e5..518e552b6 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -11,7 +11,7 @@ build-backend = "setuptools.build_meta" [project] name = "digiscript-server" -version = "0.30.7" +version = "0.30.8" description = "DigiScript server - Digital script management for theatrical shows" readme = "../README.md" requires-python = ">=3.13"