From af6ac42aa3ec6805a2a18b920128beafcb9a3cdc Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Mon, 5 Dec 2022 14:34:14 +0200 Subject: [PATCH 1/5] feat: Add prompt to overwrite changes when concurrent editing occurs (#4817) * feat: Add prompt to overwrite changes when concurrent editing occurs * chore: undo config schema update --- packages/editor-ui/src/Interface.ts | 2 +- packages/editor-ui/src/mixins/restApi.ts | 4 ++-- .../editor-ui/src/mixins/workflowHelpers.ts | 20 +++++++++++++++++-- .../src/plugins/i18n/locales/en.json | 4 ++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index ca734f6ef6b44..4376bd9c5dffa 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -205,7 +205,7 @@ export interface IRestApi { removeTestWebhook(workflowId: string): Promise; runWorkflow(runData: IStartRunData): Promise; createNewWorkflow(sendData: IWorkflowDataUpdate): Promise; - updateWorkflow(id: string, data: IWorkflowDataUpdate): Promise; + updateWorkflow(id: string, data: IWorkflowDataUpdate, forceSave?: boolean): Promise; deleteWorkflow(name: string): Promise; getWorkflow(id: string): Promise; getWorkflows(filter?: object): Promise; diff --git a/packages/editor-ui/src/mixins/restApi.ts b/packages/editor-ui/src/mixins/restApi.ts index fecfd5f3a40f4..111cd81c487cd 100644 --- a/packages/editor-ui/src/mixins/restApi.ts +++ b/packages/editor-ui/src/mixins/restApi.ts @@ -105,8 +105,8 @@ export const restApi = Vue.extend({ }, // Updates an existing workflow - updateWorkflow: (id: string, data: IWorkflowDataUpdate): Promise => { - return self.restApi().makeRestApiRequest('PATCH', `/workflows/${id}`, data); + updateWorkflow: (id: string, data: IWorkflowDataUpdate, forceSave = false): Promise => { + return self.restApi().makeRestApiRequest('PATCH', `/workflows/${id}${forceSave ? '?forceSave=true' : ''}`, data); }, // Deletes a workflow diff --git a/packages/editor-ui/src/mixins/workflowHelpers.ts b/packages/editor-ui/src/mixins/workflowHelpers.ts index eb424bf84eee2..41eb90c6e989f 100644 --- a/packages/editor-ui/src/mixins/workflowHelpers.ts +++ b/packages/editor-ui/src/mixins/workflowHelpers.ts @@ -703,7 +703,7 @@ export const workflowHelpers = mixins( } }, - async saveCurrentWorkflow({id, name, tags}: {id?: string, name?: string, tags?: string[]} = {}, redirect = true): Promise { + async saveCurrentWorkflow({id, name, tags}: {id?: string, name?: string, tags?: string[]} = {}, redirect = true, forceSave = false): Promise { const currentWorkflow = id || this.$route.params.name; if (!currentWorkflow || ['new', PLACEHOLDER_EMPTY_WORKFLOW_ID].includes(currentWorkflow)) { @@ -726,7 +726,7 @@ export const workflowHelpers = mixins( workflowDataRequest.hash = this.workflowsStore.workflowHash; - const workflowData = await this.restApi().updateWorkflow(currentWorkflow, workflowDataRequest); + const workflowData = await this.restApi().updateWorkflow(currentWorkflow, workflowDataRequest, forceSave); this.workflowsStore.setWorkflowHash(workflowData.hash); if (name) { @@ -747,6 +747,22 @@ export const workflowHelpers = mixins( } catch (error) { this.uiStore.removeActiveAction('workflowSaving'); + if (error.errorCode === 400 && error.message.startsWith('Your most recent changes may be lost')) { + const overwrite = await this.confirmMessage( + this.$locale.baseText('workflows.concurrentChanges.confirmMessage.message'), + this.$locale.baseText('workflows.concurrentChanges.confirmMessage.title'), + null, + this.$locale.baseText('workflows.concurrentChanges.confirmMessage.confirmButtonText'), + this.$locale.baseText('workflows.concurrentChanges.confirmMessage.cancelButtonText'), + ); + + if (overwrite) { + return this.saveCurrentWorkflow({id, name, tags}, redirect, true); + } + + return false; + } + this.$showMessage({ title: this.$locale.baseText('workflowHelpers.showMessage.title'), message: error.message, diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json index 29fc447e38e13..6b997a625322e 100644 --- a/packages/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/editor-ui/src/plugins/i18n/locales/en.json @@ -1399,6 +1399,10 @@ "workflows.shareModal.notAvailable": "Sharing workflows with others is currently available only on n8n cloud, our hosted offering.", "workflows.shareModal.notAvailable.button": "Explore n8n cloud", "workflows.roles.editor": "Editor", + "workflows.concurrentChanges.confirmMessage.title": "Workflow was edited by someone else", + "workflows.concurrentChanges.confirmMessage.message": "Another user made an edit to this workflow since you last saved it. Do you want to overwrite their changes?", + "workflows.concurrentChanges.confirmMessage.cancelButtonText": "Cancel", + "workflows.concurrentChanges.confirmMessage.confirmButtonText": "Overwrite then save", "importCurlModal.title": "Import cURL command", "importCurlModal.input.label": "cURL Command", "importCurlModal.input.placeholder": "Paste the cURL command here", From 1b7952a516a5c5dfe1f79e25f811fc044a5e4962 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Mon, 5 Dec 2022 14:48:56 +0200 Subject: [PATCH 2/5] feat: Fix checkbox line height and make checkbox label clickable (#4818) * fix: Update checkbox design and make checkbox label clickable * fix: Remove checkbox ids * chore: remove unused imports --- .../src/components/N8nCheckbox/Checkbox.vue | 16 +++++++++++++++- .../src/components/N8nInputLabel/InputLabel.vue | 8 ++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/design-system/src/components/N8nCheckbox/Checkbox.vue b/packages/design-system/src/components/N8nCheckbox/Checkbox.vue index cb655ab8d7d48..06105faf4ce5b 100644 --- a/packages/design-system/src/components/N8nCheckbox/Checkbox.vue +++ b/packages/design-system/src/components/N8nCheckbox/Checkbox.vue @@ -1,6 +1,7 @@ @@ -58,6 +60,14 @@ export default Vue.extend({ onChange(event: Event) { this.$emit('input', event); }, + onLabelClick() { + const checkboxComponent = this.$refs.checkbox as ElCheckbox; + if (!checkboxComponent) { + return; + } + + (checkboxComponent.$el as HTMLElement).click(); + }, }, }); @@ -70,5 +80,9 @@ export default Vue.extend({ span { white-space: normal; } + + label { + cursor: pointer; + } } diff --git a/packages/design-system/src/components/N8nInputLabel/InputLabel.vue b/packages/design-system/src/components/N8nInputLabel/InputLabel.vue index 4ba6974d5dd2d..e600a80cb5c7c 100644 --- a/packages/design-system/src/components/N8nInputLabel/InputLabel.vue +++ b/packages/design-system/src/components/N8nInputLabel/InputLabel.vue @@ -1,5 +1,5 @@