From e663fb5a20de63c837f08a31f41b680cf754a041 Mon Sep 17 00:00:00 2001 From: Jay George Date: Fri, 29 May 2026 10:44:49 +0100 Subject: [PATCH 1/3] Apply the regenerate handle pattern for replicator sections / tabs so that you don't accidentally change the handle when editing the name --- .../js/components/blueprints/Section.vue | 40 +++++++++--------- resources/js/components/blueprints/Tab.vue | 41 +++++++++---------- 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/resources/js/components/blueprints/Section.vue b/resources/js/components/blueprints/Section.vue index b8385486ab1..16ca646c318 100644 --- a/resources/js/components/blueprints/Section.vue +++ b/resources/js/components/blueprints/Section.vue @@ -53,8 +53,17 @@ type="text" class="font-mono text-sm" v-model="editingSection.handle" - @input="handleSyncedWithDisplay = false" - /> + > + + @@ -156,7 +165,6 @@ export default { return { editingSection: false, editingField: null, - handleSyncedWithDisplay: false, saveKeyBinding: null, }; }, @@ -192,12 +200,6 @@ export default { }, }, - 'editingSection.display': function (display) { - if (this.editingSection && this.handleSyncedWithDisplay) { - this.editingSection.handle = snake_case(display); - } - }, - editingSection: { handler(isEditing) { if (isEditing) { @@ -219,15 +221,15 @@ export default { }, }, - created() { - // This logic isn't ideal, but it was better than passing along a 'isNew' boolean and having - // to deal with stripping it out and making it not new, etc. Good enough for a quick win. - if (!this.section.handle || this.section.handle == 'new_section' || this.section.handle == 'new_set') { - this.handleSyncedWithDisplay = true; - } - }, - methods: { + regenerateHandle() { + if (!this.editingSection) { + return; + } + + this.editingSection.handle = snake_case(this.editingSection.display); + }, + fieldLinked(field) { this.section.fields.push(field); this.$toast.success(__('Field added')); @@ -263,10 +265,6 @@ export default { }, editConfirmed() { - if (!this.editingSection.handle) { - this.editingSection.handle = snake_case(this.editingSection.display); - } - this.$emit('updated', { ...this.section, ...this.editingSection }); this.editingSection = false; }, diff --git a/resources/js/components/blueprints/Tab.vue b/resources/js/components/blueprints/Tab.vue index 0224caf3842..3d35c6cbf3b 100644 --- a/resources/js/components/blueprints/Tab.vue +++ b/resources/js/components/blueprints/Tab.vue @@ -32,7 +32,17 @@ - + + + @@ -98,19 +108,10 @@ export default { instructions: this.tab.instructions, icon: this.tab.icon, editing: false, - handleSyncedWithDisplay: false, saveKeyBinding: null, }; }, - created() { - // This logic isn't ideal, but it was better than passing along a 'isNew' boolean and having - // to deal with stripping it out and making it not new, etc. Good enough for a quick win. - if (!this.handle || this.handle == 'new_tab' || this.handle == 'new_set_group') { - this.handleSyncedWithDisplay = true; - } - }, - computed: { isActive() { return this.currentTab === this.tab._id; @@ -149,15 +150,19 @@ export default { }, methods: { + regenerateHandle() { + this.handle = snake_case(this.display); + }, + edit() { + this.display = this.tab.display; + this.handle = this.tab.handle; + this.instructions = this.tab.instructions; + this.icon = this.tab.icon; this.editing = true; }, editConfirmed() { - if (!this.handle) { - this.handle = snake_case(this.display); - } - this.$emit('updated', { ...this.tab, handle: this.handle, @@ -194,14 +199,6 @@ export default { }, fieldUpdated(handle, value) { - if (handle === 'display' && this.handleSyncedWithDisplay) { - this.handle = snake_case(value); - } - - if (handle === 'handle') { - this.handleSyncedWithDisplay = false; - } - this[handle] = value; }, From 9f0645c0fdb85044c726c207e138cedec0780734 Mon Sep 17 00:00:00 2001 From: Jay George Date: Fri, 29 May 2026 11:00:20 +0100 Subject: [PATCH 2/3] Add some ARIA labels for the regenerate buttons --- resources/js/components/blueprints/Section.vue | 1 + resources/js/components/blueprints/Tab.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/resources/js/components/blueprints/Section.vue b/resources/js/components/blueprints/Section.vue index 16ca646c318..ac9f4ca4610 100644 --- a/resources/js/components/blueprints/Section.vue +++ b/resources/js/components/blueprints/Section.vue @@ -59,6 +59,7 @@ icon="sync" size="sm" variant="ghost" + :aria-label="__('Regenerate from: :field', { field: __('Display') })" @click="regenerateHandle" v-tooltip="__('Regenerate from: :field', { field: __('Display') })" /> diff --git a/resources/js/components/blueprints/Tab.vue b/resources/js/components/blueprints/Tab.vue index 3d35c6cbf3b..815965487a8 100644 --- a/resources/js/components/blueprints/Tab.vue +++ b/resources/js/components/blueprints/Tab.vue @@ -38,6 +38,7 @@ icon="sync" size="sm" variant="ghost" + :aria-label="__('Regenerate from: :field', { field: __('Title') })" @click="regenerateHandle" v-tooltip="__('Regenerate from: :field', { field: __('Title') })" /> From 65008a513c4d829cfbc0cab85fd3df36c2e3727c Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 3 Jun 2026 15:57:58 -0400 Subject: [PATCH 3/3] Restore auto-sync for new sets/tabs while keeping it off for re-opens Re-introduces handleSyncedWithDisplay, but sets it in edit() rather than created() so existing items always open with sync disabled. New items with placeholder handles still get the live sync UX. Also restores the empty- handle safety net in editConfirmed() for both files. Co-Authored-By: Claude Sonnet 4.6 --- resources/js/components/blueprints/Section.vue | 13 +++++++++++++ resources/js/components/blueprints/Tab.vue | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/resources/js/components/blueprints/Section.vue b/resources/js/components/blueprints/Section.vue index ac9f4ca4610..59f95fe09a4 100644 --- a/resources/js/components/blueprints/Section.vue +++ b/resources/js/components/blueprints/Section.vue @@ -53,6 +53,7 @@ type="text" class="font-mono text-sm" v-model="editingSection.handle" + @input="handleSyncedWithDisplay = false" >