From a9a1d53caa4b4aad0daaa23e9443383de52bd16b Mon Sep 17 00:00:00 2001 From: Tim Bradgate Date: Fri, 8 May 2026 18:21:12 +0100 Subject: [PATCH 1/2] Add bulk act/scene edit mode to script editor (#998) (#999) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces a 'Bulk Edit' toggle in the script editor toolbar that lets the user select a start and end line (across multiple pages) and apply a new act/scene assignment to all lines in between. Changes are written into TMP_SCRIPT via SET_LINE and saved through the normal per-page PATCH flow — no new backend endpoint required. - BulkActSceneModal.vue: new modal with act/scene selects constrained to the valid range (same nextActs/nextScenes algorithm as ScriptLineEditor) - ScriptLineViewer.vue: Start/End selection buttons replace the Edit dropdown while bulk edit mode is active - ScriptEditor.vue: bulk edit state, toolbar button, boundary page loading, and SET_LINE application across all pages in the selected range Co-authored-by: Claude Sonnet 4.6 --- .../show/config/script/BulkActSceneModal.vue | 134 +++++++++++++++++ .../show/config/script/ScriptEditor.vue | 135 +++++++++++++++++- .../show/config/script/ScriptLineViewer.vue | 32 ++++- 3 files changed, 299 insertions(+), 2 deletions(-) create mode 100644 client/src/vue_components/show/config/script/BulkActSceneModal.vue diff --git a/client/src/vue_components/show/config/script/BulkActSceneModal.vue b/client/src/vue_components/show/config/script/BulkActSceneModal.vue new file mode 100644 index 00000000..49b5ccd9 --- /dev/null +++ b/client/src/vue_components/show/config/script/BulkActSceneModal.vue @@ -0,0 +1,134 @@ + + + diff --git a/client/src/vue_components/show/config/script/ScriptEditor.vue b/client/src/vue_components/show/config/script/ScriptEditor.vue index 6df5713d..d9cce962 100644 --- a/client/src/vue_components/show/config/script/ScriptEditor.vue +++ b/client/src/vue_components/show/config/script/ScriptEditor.vue @@ -50,6 +50,13 @@ > Save + + {{ bulkEditMode ? 'Exit Bulk Edit' : 'Bulk Edit' }} + @@ -98,6 +105,9 @@ :line-part-cuts="linePartCuts" :stage-direction-styles="STAGE_DIRECTION_STYLES" :stage-direction-style-overrides="STAGE_DIRECTION_STYLE_OVERRIDES" + :bulk-edit-mode="bulkEditMode" + :is-bulk-start="isBulkStart(index)" + :is-bulk-end="isBulkEnd(index)" @editLine="beginEditingLine(currentEditPage, index)" @cutLinePart="cutLinePart" @insertDialogue="insertDialogueAt(currentEditPage, index)" @@ -105,6 +115,8 @@ @insertCueLine="insertCueLineAt(currentEditPage, index)" @insertSpacing="insertSpacingAt(currentEditPage, index)" @deleteLine="deleteLine(currentEditPage, index)" + @set-bulk-start="onSetBulkStart(index)" + @set-bulk-end="onSetBulkEnd(index)" /> @@ -155,6 +167,13 @@ /> + 1) { + await this.LOAD_SCRIPT_PAGE(startPage - 1); + } + const endPageLines = this.TMP_SCRIPT[endPage.toString()]; + if (endPageLines && endIndex === endPageLines.length - 1) { + await this.LOAD_SCRIPT_PAGE(endPage + 1); + } + + const startPageLines = this.TMP_SCRIPT[startPage.toString()]; + if (startIndex > 0 && startPageLines) { + this.previousLineOfStart = startPageLines[startIndex - 1] || null; + } else if (startPage > 1) { + const prevPage = this.TMP_SCRIPT[(startPage - 1).toString()]; + this.previousLineOfStart = prevPage ? prevPage[prevPage.length - 1] : null; + } else { + this.previousLineOfStart = null; + } + + const endLines = this.TMP_SCRIPT[endPage.toString()]; + if (endLines && endIndex < endLines.length - 1) { + this.nextLineOfEnd = endLines[endIndex + 1] || null; + } else { + const nextPage = this.TMP_SCRIPT[(endPage + 1).toString()]; + this.nextLineOfEnd = nextPage ? nextPage[0] : null; + } + }, + async onBulkApply({ actId, sceneId }) { + const { page: startPage, lineIndex: startIndex } = this.bulkEditStart; + const { page: endPage, lineIndex: endIndex } = this.bulkEditEnd; + + for (let p = startPage; p <= endPage; p++) { + await this.LOAD_SCRIPT_PAGE(p); + } + + for (let p = startPage; p <= endPage; p++) { + const pageLines = this.TMP_SCRIPT[p.toString()]; + if (!pageLines) continue; + const fromIndex = p === startPage ? startIndex : 0; + const toIndex = p === endPage ? endIndex : pageLines.length - 1; + for (let i = fromIndex; i <= toIndex; i++) { + if (this.DELETED_LINES(p).includes(i)) continue; + this.SET_LINE({ + pageNo: p, + lineIndex: i, + lineObj: { ...pageLines[i], act_id: actId, scene_id: sceneId }, + }); + } + } + + this.$bvModal.hide('bulk-act-scene-modal'); + this.exitBulkEditMode(); + }, ...mapMutations([ 'REMOVE_PAGE', 'ADD_BLANK_LINE', diff --git a/client/src/vue_components/show/config/script/ScriptLineViewer.vue b/client/src/vue_components/show/config/script/ScriptLineViewer.vue index 1b3bfd25..b0891e0f 100644 --- a/client/src/vue_components/show/config/script/ScriptLineViewer.vue +++ b/client/src/vue_components/show/config/script/ScriptLineViewer.vue @@ -119,8 +119,24 @@ + + + Start + + + End + + Date: Fri, 8 May 2026 18:22:00 +0100 Subject: [PATCH 2/2] Bump version to 0.27.3 --- client/package-lock.json | 4 ++-- client/package.json | 2 +- electron/package-lock.json | 4 ++-- electron/package.json | 2 +- server/pyproject.toml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 28d0135f..b19df44a 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "client", - "version": "0.27.2", + "version": "0.27.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "client", - "version": "0.27.2", + "version": "0.27.3", "dependencies": { "bootstrap": "4.6.2", "bootstrap-vue": "2.23.1", diff --git a/client/package.json b/client/package.json index 8df3c256..f7960e9e 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "client", - "version": "0.27.2", + "version": "0.27.3", "description": "DigiScript front end", "author": "DreamTeamProd", "private": true, diff --git a/electron/package-lock.json b/electron/package-lock.json index 8302779e..4e92a7ee 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "digiscript-electron", - "version": "0.27.2", + "version": "0.27.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digiscript-electron", - "version": "0.27.2", + "version": "0.27.3", "license": "GPL-3.0", "dependencies": { "bonjour-service": "^1.3.0", diff --git a/electron/package.json b/electron/package.json index bcee77a8..b7ad5fad 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,6 +1,6 @@ { "name": "digiscript-electron", - "version": "0.27.2", + "version": "0.27.3", "description": "DigiScript Electron Desktop Application", "author": "DreamTeamProd", "license": "GPL-3.0", diff --git a/server/pyproject.toml b/server/pyproject.toml index abf5722e..afcfffba 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -11,7 +11,7 @@ build-backend = "setuptools.build_meta" [project] name = "digiscript-server" -version = "0.27.2" +version = "0.27.3" description = "DigiScript server - Digital script management for theatrical shows" readme = "../README.md" requires-python = ">=3.13"