From 39e65bc54defc4ef7823992365d17ea986a17f84 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Mon, 20 Jan 2025 16:15:21 +0100 Subject: [PATCH 1/3] Prevent multiple submits in various Vue components [SCI-9221] --- .../vue/components/action_toolbar.vue | 8 +++-- .../vue/experiments/modals/duplicate.vue | 6 +++- .../vue/experiments/modals/edit.vue | 7 +++- .../vue/experiments/modals/move.vue | 9 +++--- app/javascript/vue/experiments/modals/new.vue | 8 +++-- app/javascript/vue/label_template/table.vue | 32 ++++++++++++++++++- app/javascript/vue/my_modules/modals/edit.vue | 9 ++++-- app/javascript/vue/my_modules/modals/move.vue | 9 ++++-- app/javascript/vue/my_modules/modals/new.vue | 9 ++++-- app/javascript/vue/projects/modals/edit.vue | 8 +++-- .../vue/projects/modals/edit_folder.vue | 6 +++- app/javascript/vue/projects/modals/move.vue | 6 +++- app/javascript/vue/projects/modals/new.vue | 9 +++--- .../vue/projects/modals/new_folder.vue | 6 +++- .../vue/protocol/modals/publish_protocol.vue | 8 ++++- .../vue/protocol_import/file_import_modal.vue | 9 ++++-- app/javascript/vue/protocols/modals/new.vue | 9 ++++-- .../vue/repositories/modals/duplicate.vue | 9 ++++-- .../vue/repositories/modals/edit.vue | 9 ++++-- .../vue/repositories/modals/export.vue | 9 ++++-- .../vue/repositories/modals/new.vue | 9 ++++-- .../vue/repository_print_modal/container.vue | 9 ++++-- .../vue/shared/datatable/action_toolbar.vue | 5 +-- .../vue/shared/datatable/toolbar.vue | 20 ++++++------ .../vue/storage_locations/modals/assign.vue | 12 +++---- .../vue/storage_locations/modals/move.vue | 9 ++++-- .../vue/storage_locations/modals/new_edit.vue | 16 +++++----- 27 files changed, 196 insertions(+), 69 deletions(-) diff --git a/app/javascript/vue/components/action_toolbar.vue b/app/javascript/vue/components/action_toolbar.vue index 0190e2909..ea4678416 100644 --- a/app/javascript/vue/components/action_toolbar.vue +++ b/app/javascript/vue/components/action_toolbar.vue @@ -4,7 +4,7 @@ :class="{ 'sn-action-toolbar--button-overflow': buttonOverflow }" :style="`width: ${width}px; bottom: ${bottomOffset}px; transform: translateX(${leftOffset}px)`" :data-e2e="`e2e-CO-actionToolbar`"> -
+
@@ -94,7 +94,8 @@ export default { width: 0, bottomOffset: 0, leftOffset: 0, - buttonOverflow: false + buttonOverflow: false, + submitting: false }; }, created() { @@ -185,6 +186,8 @@ export default { break; case 'request': event.stopPropagation(); + this.submitting = true; + $.ajax({ type: action.request_method, url: action.path, @@ -194,6 +197,7 @@ export default { }).fail((data) => { HelperModule.flashAlertMsg(data.responseJSON && data.responseJSON.message || data.message, 'danger'); }).always(() => { + this.submitting = false; if (this.reloadCallback) this.reloadCallback(); }); break; diff --git a/app/javascript/vue/experiments/modals/duplicate.vue b/app/javascript/vue/experiments/modals/duplicate.vue index a29c8386d..3cbf4cb58 100644 --- a/app/javascript/vue/experiments/modals/duplicate.vue +++ b/app/javascript/vue/experiments/modals/duplicate.vue @@ -21,7 +21,7 @@
@@ -53,10 +53,13 @@ export default { data() { return { targetProject: null, + submitting: false }; }, methods: { submit() { + this.submitting = true; + axios.post(this.experiment.urls.clone, { experiment: { project_id: this.targetProject, @@ -65,6 +68,7 @@ export default { this.$emit('update'); window.location.replace(response.data.url); }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.message, 'danger'); }); }, diff --git a/app/javascript/vue/experiments/modals/edit.vue b/app/javascript/vue/experiments/modals/edit.vue index 4ec0028ad..06cdab164 100644 --- a/app/javascript/vue/experiments/modals/edit.vue +++ b/app/javascript/vue/experiments/modals/edit.vue @@ -30,7 +30,7 @@
@@ -55,6 +55,7 @@ export default { return { name: this.experiment.name, description: this.experiment.description, + submitting: false }; }, computed: { @@ -69,6 +70,8 @@ export default { mixins: [modalMixin], methods: { submit() { + this.submitting = true; + axios.patch(this.experiment.urls.update, { experiment: { name: this.name, @@ -76,8 +79,10 @@ export default { }, }).then((response) => { this.$emit('update'); + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.message, 'danger'); }); }, diff --git a/app/javascript/vue/experiments/modals/move.vue b/app/javascript/vue/experiments/modals/move.vue index e125daf1f..f76d9df67 100644 --- a/app/javascript/vue/experiments/modals/move.vue +++ b/app/javascript/vue/experiments/modals/move.vue @@ -20,7 +20,7 @@ @@ -49,12 +49,13 @@ export default { data() { return { targetProject: null, - disableSubmit: false + submitting: false }; }, methods: { async submit() { - this.disableSubmit = true; + this.submitting = true; + await axios.post(this.experiment.movePath, { project_id: this.targetProject }).then((response) => { @@ -63,7 +64,7 @@ export default { }).catch((error) => { HelperModule.flashAlertMsg(error.response.data.message, 'danger'); }); - this.disableSubmit = false; + this.submitting = false; }, changeProject(project) { this.targetProject = project; diff --git a/app/javascript/vue/experiments/modals/new.vue b/app/javascript/vue/experiments/modals/new.vue index b98621cff..62d246371 100644 --- a/app/javascript/vue/experiments/modals/new.vue +++ b/app/javascript/vue/experiments/modals/new.vue @@ -29,7 +29,7 @@ @@ -54,7 +54,8 @@ export default { return { name: '', description: '', - error: null + error: null, + submitting: false }; }, computed: { @@ -68,6 +69,8 @@ export default { mixins: [modalMixin], methods: { submit() { + this.submitting = true; + axios.post(this.createUrl, { experiment: { name: this.name, @@ -77,6 +80,7 @@ export default { this.$emit('create'); window.location.replace(response.data.path); }).catch((error) => { + this.submitting = false; this.error = error.response.data.name[0]; }); }, diff --git a/app/javascript/vue/label_template/table.vue b/app/javascript/vue/label_template/table.vue index 778b77c46..650b9b550 100644 --- a/app/javascript/vue/label_template/table.vue +++ b/app/javascript/vue/label_template/table.vue @@ -99,7 +99,8 @@ export default { headerName: this.i18n.t('label_templates.index.created_at'), sortable: true } - ] + ], + submitting: false }; }, computed: { @@ -133,41 +134,70 @@ export default { }, methods: { setDefault(action) { + if (this.submitting) return; + + this.submitting = true; + axios.post(action.path).then((response) => { this.reloadingTable = true; + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.error, 'danger'); }); }, duplicate(action, rows) { + if (this.submitting) return; + + this.submitting = true; + axios.post(action.path, { selected_ids: rows.map((row) => row.id) }).then((response) => { this.reloadingTable = true; + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.error, 'danger'); }); }, createTemplate(action) { + if (this.submitting) return; + + this.submitting = true; + axios.post(action.path).then((response) => { window.location.href = response.data.redirect_url; }); }, syncFluicsLabels(action) { + if (this.submitting) return; + + this.submitting = true; + axios.post(action.path).then((response) => { this.reloadingTable = true; + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.error, 'danger'); }); }, async deleteTemplates(action, rows) { + if (this.submitting) return; + const ok = await this.$refs.deleteModal.show(); + if (ok) { + this.submitting = true; + axios.delete(action.path, { data: { selected_ids: rows.map((row) => row.id) } }).then((response) => { this.reloadingTable = true; + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.error, 'danger'); }); } diff --git a/app/javascript/vue/my_modules/modals/edit.vue b/app/javascript/vue/my_modules/modals/edit.vue index 394b8e6cd..64c5e8715 100644 --- a/app/javascript/vue/my_modules/modals/edit.vue +++ b/app/javascript/vue/my_modules/modals/edit.vue @@ -21,7 +21,7 @@ @@ -44,7 +44,8 @@ export default { }, data() { return { - name: this.my_module.name + name: this.my_module.name, + submitting: false }; }, computed: { @@ -55,13 +56,17 @@ export default { mixins: [modalMixin], methods: { submit() { + this.submitting = true; + axios.patch(this.my_module.urls.update, { my_module: { name: this.name } }).then(() => { this.$emit('update'); + this.submitting = false; }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.message, 'danger'); }); } diff --git a/app/javascript/vue/my_modules/modals/move.vue b/app/javascript/vue/my_modules/modals/move.vue index 452960f13..af96f8ea0 100644 --- a/app/javascript/vue/my_modules/modals/move.vue +++ b/app/javascript/vue/my_modules/modals/move.vue @@ -19,7 +19,7 @@ @@ -47,17 +47,22 @@ export default { }, data() { return { - targetExperiment: null + targetExperiment: null, + submitting: false }; }, methods: { submit() { + this.submitting = true; + axios.post(this.my_module.movePath, { to_experiment_id: this.targetExperiment }).then((response) => { this.$emit('move'); + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.message, 'danger'); }); }, diff --git a/app/javascript/vue/my_modules/modals/new.vue b/app/javascript/vue/my_modules/modals/new.vue index b362698b0..cf3b9240e 100644 --- a/app/javascript/vue/my_modules/modals/new.vue +++ b/app/javascript/vue/my_modules/modals/new.vue @@ -63,7 +63,7 @@ @@ -100,7 +100,8 @@ export default { tags: [], users: [], allTags: [], - allUsers: [] + allUsers: [], + submitting: false }; }, computed: { @@ -135,6 +136,8 @@ export default { methods: { submit() { + this.submitting = true; + axios.post(this.createUrl, { my_module: { name: this.name, @@ -144,7 +147,9 @@ export default { } }).then(() => { this.$emit('create'); + this.submitting = false; }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.message, 'danger'); }); }, diff --git a/app/javascript/vue/projects/modals/edit.vue b/app/javascript/vue/projects/modals/edit.vue index 04f3ac812..2f8dd4450 100644 --- a/app/javascript/vue/projects/modals/edit.vue +++ b/app/javascript/vue/projects/modals/edit.vue @@ -34,7 +34,7 @@ @@ -78,11 +78,13 @@ export default { visible: !this.project.hidden, defaultRole: this.project.default_public_user_role_id, error: null, - userRoles: [] + userRoles: [], + submitting: false }; }, methods: { submit() { + this.submitting = true; axios.put(this.project.urls.update, { project: { name: this.name, @@ -92,7 +94,9 @@ export default { }).then(() => { this.error = null; this.$emit('update'); + this.submitting = false; }).catch((error) => { + this.submitting = false; this.error = error.response.data.errors.name; }); }, diff --git a/app/javascript/vue/projects/modals/edit_folder.vue b/app/javascript/vue/projects/modals/edit_folder.vue index 4c0afa8fa..ad1963424 100644 --- a/app/javascript/vue/projects/modals/edit_folder.vue +++ b/app/javascript/vue/projects/modals/edit_folder.vue @@ -23,7 +23,7 @@ @@ -52,10 +52,12 @@ export default { return { name: this.folder.name, error: null, + submitting: false }; }, methods: { submit() { + this.submitting = true; axios.put(this.folder.urls.update, { project_folder: { name: this.name, @@ -63,7 +65,9 @@ export default { }).then(() => { this.error = null; this.$emit('update'); + this.submitting = false; }).catch((error) => { + this.submitting = false; this.error = error.response.data.errors.name; }); }, diff --git a/app/javascript/vue/projects/modals/move.vue b/app/javascript/vue/projects/modals/move.vue index 0b92d73a9..39c39e911 100644 --- a/app/javascript/vue/projects/modals/move.vue +++ b/app/javascript/vue/projects/modals/move.vue @@ -36,7 +36,7 @@ @@ -66,6 +66,7 @@ export default { selectedFolderId: null, foldersTree: [], query: '', + submitting: false }; }, components: { @@ -115,6 +116,7 @@ export default { this.selectedFolderId = folderId; }, submit() { + this.submitting = true; axios.post(this.moveToUrl, { destination_folder_id: this.selectedFolderId || 'root_folder', movables: this.selectedObjects.map((obj) => ( @@ -125,8 +127,10 @@ export default { )), }).then((response) => { this.$emit('move'); + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; HelperModule.flashAlertMsg(error.response.data.message, 'danger'); }); }, diff --git a/app/javascript/vue/projects/modals/new.vue b/app/javascript/vue/projects/modals/new.vue index 9d48fa18d..0a87fbcdd 100644 --- a/app/javascript/vue/projects/modals/new.vue +++ b/app/javascript/vue/projects/modals/new.vue @@ -36,7 +36,7 @@ @@ -81,13 +81,14 @@ export default { visible: false, defaultRole: null, error: null, - disableSubmit: false, + submitting: false, userRoles: [] }; }, methods: { async submit() { - this.disableSubmit = true; + this.submitting = true; + await axios.post(this.createUrl, { project: { name: this.name, @@ -101,7 +102,7 @@ export default { }).catch((error) => { this.error = error.response.data.name; }); - this.disableSubmit = false; + this.submitting = false; }, changeRole(role) { this.defaultRole = role; diff --git a/app/javascript/vue/projects/modals/new_folder.vue b/app/javascript/vue/projects/modals/new_folder.vue index e87cc9d51..49e3b7a70 100644 --- a/app/javascript/vue/projects/modals/new_folder.vue +++ b/app/javascript/vue/projects/modals/new_folder.vue @@ -23,7 +23,7 @@ @@ -55,10 +55,12 @@ export default { return { name: '', error: null, + submitting: false }; }, methods: { submit() { + this.submitting = true; axios.post(this.createFolderUrl, { project_folder: { name: this.name, @@ -68,8 +70,10 @@ export default { }).then(() => { this.error = null; this.$emit('create'); + this.submitting = false; }).catch((error) => { this.error = error.response.data.name; + this.submitting = false; }); }, changeRole(role) { diff --git a/app/javascript/vue/protocol/modals/publish_protocol.vue b/app/javascript/vue/protocol/modals/publish_protocol.vue index ce336e758..3de84b956 100644 --- a/app/javascript/vue/protocol/modals/publish_protocol.vue +++ b/app/javascript/vue/protocol/modals/publish_protocol.vue @@ -25,7 +25,7 @@ @@ -40,6 +40,11 @@ export default { required: true } }, + data() { + return { + submitting: false + } + }, mounted() { $(this.$refs.modal).modal('show'); $(this.$refs.modal).on('hidden.bs.modal', () => { @@ -51,6 +56,7 @@ export default { confirm() { $(this.$refs.modal).modal('hide'); this.$emit('publish', this.protocol.attributes.version_comment); + this.submitting = true; }, cancel() { $(this.$refs.modal).modal('hide'); diff --git a/app/javascript/vue/protocol_import/file_import_modal.vue b/app/javascript/vue/protocol_import/file_import_modal.vue index 96f55b84a..6729ab8da 100644 --- a/app/javascript/vue/protocol_import/file_import_modal.vue +++ b/app/javascript/vue/protocol_import/file_import_modal.vue @@ -13,7 +13,8 @@ @@ -85,11 +85,14 @@ export default { visible: false, defaultRole: null, userRoles: [], - error: null + error: null, + submitting: false }; }, methods: { submit() { + this.submitting = true; + axios.post(this.createUrl, { protocol: { name: this.name, @@ -99,7 +102,9 @@ export default { }).then(() => { this.error = null; this.$emit('create'); + this.submitting = false; }).catch((error) => { + this.submitting = false; this.error = error.response.data.error; }); }, diff --git a/app/javascript/vue/repositories/modals/duplicate.vue b/app/javascript/vue/repositories/modals/duplicate.vue index f5c211def..d4100fcc2 100644 --- a/app/javascript/vue/repositories/modals/duplicate.vue +++ b/app/javascript/vue/repositories/modals/duplicate.vue @@ -24,7 +24,7 @@ @@ -49,11 +49,14 @@ export default { data() { return { name: this.repository.name, - error: null + error: null, + submitting: false }; }, methods: { submit() { + this.submitting = true; + axios.post(this.repository.urls.duplicate, { repository: { name: this.name @@ -61,8 +64,10 @@ export default { }).then((response) => { this.error = null; this.$emit('duplicate'); + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; this.error = error.response.data.name; }); } diff --git a/app/javascript/vue/repositories/modals/edit.vue b/app/javascript/vue/repositories/modals/edit.vue index 882fff3da..db220afb8 100644 --- a/app/javascript/vue/repositories/modals/edit.vue +++ b/app/javascript/vue/repositories/modals/edit.vue @@ -25,7 +25,7 @@ @@ -49,11 +49,14 @@ export default { data() { return { name: this.repository.name, - error: null + error: null, + submitting: false }; }, methods: { submit() { + this.submitting = true; + axios.put(this.repository.urls.update, { repository: { name: this.name @@ -61,7 +64,9 @@ export default { }).then(() => { this.error = null; this.$emit('update'); + this.submitting = false; }).catch((error) => { + this.submitting = false; this.error = error.response.data.name; }); } diff --git a/app/javascript/vue/repositories/modals/export.vue b/app/javascript/vue/repositories/modals/export.vue index 61504798a..0ee51a864 100644 --- a/app/javascript/vue/repositories/modals/export.vue +++ b/app/javascript/vue/repositories/modals/export.vue @@ -27,7 +27,7 @@ @@ -48,7 +48,8 @@ export default { mixins: [modalMixin], data() { return { - selectedOption: this.exportAction.export_file_type + selectedOption: this.exportAction.export_file_type, + submitting: false }; }, methods: { @@ -58,10 +59,14 @@ export default { file_type: this.selectedOption }; + this.submitting = true; + axios.post(this.exportAction.path, payload).then((response) => { this.$emit('export'); + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = flase; HelperModule.flashAlertMsg(error.response.data.error, 'danger'); }); } diff --git a/app/javascript/vue/repositories/modals/new.vue b/app/javascript/vue/repositories/modals/new.vue index ae28b32df..89456a718 100644 --- a/app/javascript/vue/repositories/modals/new.vue +++ b/app/javascript/vue/repositories/modals/new.vue @@ -25,7 +25,7 @@ @@ -50,11 +50,14 @@ export default { data() { return { name: '', - error: null + error: null, + submitting: false }; }, methods: { submit() { + this.submitting = true; + axios.post(this.createUrl, { repository: { name: this.name @@ -62,8 +65,10 @@ export default { }).then((response) => { this.error = null; this.$emit('create'); + this.submitting = false; HelperModule.flashAlertMsg(response.data.message, 'success'); }).catch((error) => { + this.submitting = false; this.error = error.response.data.name; }); } diff --git a/app/javascript/vue/repository_print_modal/container.vue b/app/javascript/vue/repository_print_modal/container.vue index aaea08718..11bdbe501 100644 --- a/app/javascript/vue/repository_print_modal/container.vue +++ b/app/javascript/vue/repository_print_modal/container.vue @@ -63,7 +63,7 @@ @@ -114,7 +114,8 @@ export default { zebraPrinters: null, labelTemplateError: null, labelTemplateCode: null, - fetchedPrintersAndTemplates: false + fetchedPrintersAndTemplates: false, + submitting: false }; }, components: { @@ -223,6 +224,8 @@ export default { }); }, submitPrint() { + this.submitting = true; + this.$nextTick(() => { if (this.selectedPrinter.attributes.type_of === 'zebra') { this.zebraPrinters.print( @@ -247,8 +250,10 @@ export default { }, (data) => { $(this.$refs.modal).modal('hide'); this.$emit('close'); + this.submitting = false; PrintProgressModal.init(data); }).fail(() => { + this.submitting = false; HelperModule.flashAlertMsg(this.i18n.t('repository_row.modal_print_label.general_error'), 'danger'); }); } diff --git a/app/javascript/vue/shared/datatable/action_toolbar.vue b/app/javascript/vue/shared/datatable/action_toolbar.vue index d7cd7a80c..bb581080b 100644 --- a/app/javascript/vue/shared/datatable/action_toolbar.vue +++ b/app/javascript/vue/shared/datatable/action_toolbar.vue @@ -1,5 +1,5 @@