From 5df6f25a31f873c7d9ed7303e36f41186d3b1e28 Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Mon, 25 May 2026 06:53:02 -0700 Subject: [PATCH] 5465: restore submit buttons when duplicate modal is dismissed The duplicate-detection modal in audit_duplicates_controller intercepts the submit event with preventDefault and shows a Bootstrap modal. Dismissing the modal with 'Make Changes' or the close button never triggers a real form submission, so any submit button left in a UJS "Saving" / "disabled" state by handlers that fire before our submit listener has nothing to restore it. Snapshot every submit button in the form when the modal opens, and on hidden.bs.modal (when the user dismissed without merging) restore each button's disabled flag plus its visible text. The merge path is exempt from the restore because mergeAndSubmit actually submits the form and the page transitions away. --- .../audit_duplicates_controller.js | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/app/javascript/controllers/audit_duplicates_controller.js b/app/javascript/controllers/audit_duplicates_controller.js index 24c8c0b4e1..3ec5dff391 100644 --- a/app/javascript/controllers/audit_duplicates_controller.js +++ b/app/javascript/controllers/audit_duplicates_controller.js @@ -102,13 +102,47 @@ export default class extends Controller { document.getElementById('duplicateItemsModal')?.remove() document.body.insertAdjacentHTML('beforeend', modalHtml) - - const modal = new bootstrap.Modal(document.getElementById('duplicateItemsModal')) + + // Snapshot the form's submit buttons so we can restore their interactive + // state when the user dismisses the modal without merging. Rails UJS + // (or any other delegated handler that fires before our submit listener) + // may have disabled the button and swapped its text to a "Saving" label + // by the time we reach this point; if the user clicks "Make Changes" or + // the close button, no actual submission happens and nothing else would + // re-enable the button. + const submitButtons = this.element.querySelectorAll('input[type="submit"], button[type="submit"]') + const buttonSnapshots = Array.from(submitButtons).map(button => ({ + button, + disabled: button.disabled, + value: button.tagName === 'INPUT' ? button.value : null, + html: button.tagName === 'BUTTON' ? button.innerHTML : null, + })) + + const modalElement = document.getElementById('duplicateItemsModal') + const modal = new bootstrap.Modal(modalElement) modal.show() - + + let merging = false + document.getElementById('confirmMerge').addEventListener('click', () => { + merging = true this.mergeAndSubmit(duplicates, buttonName) }) + + modalElement.addEventListener('hidden.bs.modal', () => { + // Only restore when the user dismissed without merging — the merge + // path submits the form, which navigates away anyway. + if (merging) return + buttonSnapshots.forEach(snapshot => { + snapshot.button.disabled = snapshot.disabled + if (snapshot.value !== null) { + snapshot.button.value = snapshot.value + } + if (snapshot.html !== null) { + snapshot.button.innerHTML = snapshot.html + } + }) + }, { once: true }) } mergeAndSubmit(duplicates, buttonName) {