From 84bfc13e2a90596a31142c01d09baacc63bbbedc Mon Sep 17 00:00:00 2001 From: Kelani Tolulope Date: Wed, 4 Oct 2023 08:22:30 +0100 Subject: [PATCH] Fix unsaved changes logic when a resources is deleted --- .../admin/src/views/Automation/Workflow/Editor.vue | 4 ++-- .../admin/src/views/Federation/Nodes/Editor.vue | 4 +++- client/web/admin/src/views/System/Apigw/Editor.vue | 4 +++- .../admin/src/views/System/Application/Editor.vue | 4 +++- .../admin/src/views/System/AuthClient/Editor.vue | 4 +++- .../admin/src/views/System/Connection/Editor.vue | 3 ++- client/web/admin/src/views/System/Queue/Editor.vue | 7 +++++-- client/web/admin/src/views/System/Role/Editor.vue | 3 ++- .../src/views/System/SensitivityLevel/Editor.vue | 3 ++- .../web/admin/src/views/System/Template/Editor.vue | 3 ++- client/web/admin/src/views/System/User/Editor.vue | 3 ++- client/web/compose/src/views/Admin/Charts/Edit.vue | 7 ++++++- .../web/compose/src/views/Admin/Modules/Edit.vue | 8 +++++++- client/web/compose/src/views/Admin/Pages/Edit.vue | 12 +++++++++--- client/web/compose/src/views/Namespace/Edit.vue | 14 ++++++++++---- client/web/reporter/src/mixins/report.js | 1 + client/web/reporter/src/views/Report/Builder.vue | 4 ++++ client/web/reporter/src/views/Report/Edit.vue | 4 ++++ client/web/workflow/src/views/Workflow/Editor.vue | 3 ++- 19 files changed, 72 insertions(+), 23 deletions(-) diff --git a/client/web/admin/src/views/Automation/Workflow/Editor.vue b/client/web/admin/src/views/Automation/Workflow/Editor.vue index c0a6f89a99..ba8b77cd17 100644 --- a/client/web/admin/src/views/Automation/Workflow/Editor.vue +++ b/client/web/admin/src/views/Automation/Workflow/Editor.vue @@ -206,7 +206,6 @@ export default { this.$AutomationAPI.workflowUndelete({ workflowID: this.workflowID }) .then(() => { this.fetchWorkflow() - this.toastSuccess(this.$t('notification:workflow.undelete.success')) }) .catch(this.toastErrorHandler(this.$t('notification:workflow.undelete.error'))) @@ -217,6 +216,7 @@ export default { this.$AutomationAPI.workflowDelete({ workflowID: this.workflowID }) .then(() => { this.fetchWorkflow() + this.workflow.deletedAt = new Date() this.toastSuccess(this.$t('notification:workflow.delete.success')) this.$router.push({ name: 'automation.workflow' }) @@ -236,7 +236,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.workflow.deletedAt) { next(true) } else if (!to.name.includes('edit')) { next(!isEqual(this.workflow, this.initialWorkflowState) ? window.confirm(this.$t('general:editor.unsavedChanges')) : true) diff --git a/client/web/admin/src/views/Federation/Nodes/Editor.vue b/client/web/admin/src/views/Federation/Nodes/Editor.vue index 21aa89a696..495722f2ee 100644 --- a/client/web/admin/src/views/Federation/Nodes/Editor.vue +++ b/client/web/admin/src/views/Federation/Nodes/Editor.vue @@ -313,6 +313,8 @@ export default { .then(() => { this.fetchNode() + this.node.deletedAt = new Date() + this.toastSuccess(this.$t('notification:federation.delete.success')) this.$router.push({ name: 'federation.nodes' }) }) @@ -363,7 +365,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.node.deletedAt) { next(true) } else if (!to.name.includes('edit')) { next(!isEqual(this.node, this.initialNodeState) ? window.confirm(this.$t('general:editor.unsavedChanges')) : true) diff --git a/client/web/admin/src/views/System/Apigw/Editor.vue b/client/web/admin/src/views/System/Apigw/Editor.vue index a4863f8ade..e4ce776129 100644 --- a/client/web/admin/src/views/System/Apigw/Editor.vue +++ b/client/web/admin/src/views/System/Apigw/Editor.vue @@ -226,6 +226,8 @@ export default { .then(() => { this.fetchRoute() + this.route.deletedAt = new Date() + this.toastSuccess(this.$t('notification:gateway.delete.success')) this.$router.push({ name: 'system.apigw' }) }) @@ -347,7 +349,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.route.deletedAt) { next(true) } else if (!to.name.includes('edit')) { const routeState = !isEqual(this.route, this.initialRouteState) diff --git a/client/web/admin/src/views/System/Application/Editor.vue b/client/web/admin/src/views/System/Application/Editor.vue index a2c34c78c9..db9066f159 100644 --- a/client/web/admin/src/views/System/Application/Editor.vue +++ b/client/web/admin/src/views/System/Application/Editor.vue @@ -330,6 +330,8 @@ export default { .then(() => { this.fetchApplication() + this.application.deletedAt = new Date() + this.toastSuccess(this.$t('notification:application.delete.success')) this.$router.push({ name: 'system.application' }) }) @@ -343,7 +345,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.application.deletedAt) { next(true) } else if (!to.name.includes('edit')) { next(!isEqual(this.application, this.initialApplicationState) || this.unifyAssetStateChange ? window.confirm(this.$t('general:editor.unsavedChanges')) : true) diff --git a/client/web/admin/src/views/System/AuthClient/Editor.vue b/client/web/admin/src/views/System/AuthClient/Editor.vue index 547c2bd623..7aeaae4b5e 100644 --- a/client/web/admin/src/views/System/AuthClient/Editor.vue +++ b/client/web/admin/src/views/System/AuthClient/Editor.vue @@ -188,6 +188,8 @@ export default { .then(() => { this.fetchAuthclient() + this.authclient.deletedAt = new Date() + this.toastSuccess(this.$t('notification:authclient.delete.success')) this.$router.push({ name: 'system.authClient' }) }) @@ -223,7 +225,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.authclient.deletedAt) { next(true) } else if (!to.name.includes('edit')) { next(!isEqual(this.authclient, this.initialAuthclientState) ? window.confirm(this.$t('general:editor.unsavedChanges')) : true) diff --git a/client/web/admin/src/views/System/Connection/Editor.vue b/client/web/admin/src/views/System/Connection/Editor.vue index 3c652458a2..85504a5830 100644 --- a/client/web/admin/src/views/System/Connection/Editor.vue +++ b/client/web/admin/src/views/System/Connection/Editor.vue @@ -247,6 +247,7 @@ export default { /** * Resource deleted, move back to the list */ + this.connection.deletedAt = new Date() this.$router.push({ name: `system.connection` }) } else { this.connection.deletedAt = null @@ -261,7 +262,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.connection.deletedAt) { next(true) } else if (!to.name.includes('edit')) { next(!isEqual(this.connection, this.initialConnectionState) ? window.confirm(this.$t('general:editor.unsavedChanges')) : true) diff --git a/client/web/admin/src/views/System/Queue/Editor.vue b/client/web/admin/src/views/System/Queue/Editor.vue index 82ada35d24..885c541c2a 100644 --- a/client/web/admin/src/views/System/Queue/Editor.vue +++ b/client/web/admin/src/views/System/Queue/Editor.vue @@ -197,7 +197,10 @@ export default { .then(() => { this.fetchQueue() this.toastSuccess(this.$t(`notification:queue.${event}.success`)) - if (!deletedAt) this.$router.push({ name: 'system.queue' }) + if (!deletedAt) { + this.queue.deletedAt = new Date() + this.$router.push({ name: 'system.queue' }) + } }) .catch(this.toastErrorHandler(this.$t(`notification:queue.${event}.error`))) .finally(() => { @@ -208,7 +211,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.queue.deletedAt) { next(true) } else if (!to.name.includes('edit')) { next(!isEqual(this.queue, this.initialQueueState) ? window.confirm(this.$t('general:editor.unsavedChanges')) : true) diff --git a/client/web/admin/src/views/System/Role/Editor.vue b/client/web/admin/src/views/System/Role/Editor.vue index 455c4c66d2..61f5424956 100644 --- a/client/web/admin/src/views/System/Role/Editor.vue +++ b/client/web/admin/src/views/System/Role/Editor.vue @@ -229,6 +229,7 @@ export default { .then(() => { this.fetchRole() + this.role.deletedAt = new Date() this.toastSuccess(this.$t('notification:role.delete.success')) this.$router.push({ name: 'system.role' }) }) @@ -334,7 +335,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.role.deletedAt) { next(true) } else if (!to.name.includes('edit')) { const isDirty = (this.roleMembers || []).some(m => m.dirty !== m.current) || !isEqual(this.role, this.initialRoleState) diff --git a/client/web/admin/src/views/System/SensitivityLevel/Editor.vue b/client/web/admin/src/views/System/SensitivityLevel/Editor.vue index d63a9f0c1e..bec273be45 100644 --- a/client/web/admin/src/views/System/SensitivityLevel/Editor.vue +++ b/client/web/admin/src/views/System/SensitivityLevel/Editor.vue @@ -188,6 +188,7 @@ export default { .then(() => { this.fetchSensitivityLevel() + this.sensitivityLevel.deletedAt = new Date() this.toastSuccess(this.$t('notification:sensitivityLevel.delete.success')) this.$router.push({ name: 'system.sensitivityLevel' }) }) @@ -199,7 +200,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.sensitivityLevel.deletedAt) { next(true) } else if (!to.name.includes('edit')) { next(!isEqual(this.sensitivityLevel, this.initialSensitivityLevelState) ? window.confirm(this.$t('general:editor.unsavedChanges')) : true) diff --git a/client/web/admin/src/views/System/Template/Editor.vue b/client/web/admin/src/views/System/Template/Editor.vue index d19be9607a..c6614503e4 100644 --- a/client/web/admin/src/views/System/Template/Editor.vue +++ b/client/web/admin/src/views/System/Template/Editor.vue @@ -193,6 +193,7 @@ export default { .then(() => { this.fetchTemplate() + this.template.deletedAt = new Date() this.toastSuccess(this.$t('notification:template.delete.success')) this.$router.push({ name: 'system.template' }) }) @@ -240,7 +241,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.template.deletedAt) { next(true) } else if (!to.name.includes('edit')) { next(!isEqual(this.template, this.initialTemplateState) ? window.confirm(this.$t('general:editor.unsavedChanges')) : true) diff --git a/client/web/admin/src/views/System/User/Editor.vue b/client/web/admin/src/views/System/User/Editor.vue index 86e0cf302e..06a47039e5 100644 --- a/client/web/admin/src/views/System/User/Editor.vue +++ b/client/web/admin/src/views/System/User/Editor.vue @@ -349,6 +349,7 @@ export default { .then(() => { this.fetchUser() + this.user.deletedAt = new Date() this.toastSuccess(this.$t('notification:user.delete.success')) this.$router.push({ name: 'system.user' }) }) @@ -525,7 +526,7 @@ export default { checkUnsavedChanges (next, to) { const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') - if (isNewPage) { + if (isNewPage || this.user.deletedAt) { next(true) } else if (!to.name.includes('edit')) { let userChangesStatus = !isEqual(this.user, this.initialUserState) diff --git a/client/web/compose/src/views/Admin/Charts/Edit.vue b/client/web/compose/src/views/Admin/Charts/Edit.vue index 97fdf194ea..880231a52f 100644 --- a/client/web/compose/src/views/Admin/Charts/Edit.vue +++ b/client/web/compose/src/views/Admin/Charts/Edit.vue @@ -825,6 +825,8 @@ export default { this.processingDelete = true this.deleteChart(this.chart).then(() => { + this.chart.deletedAt = new Date() + this.toastSuccess(this.$t('notification:chart.deleted')) this.$router.push({ name: 'admin.charts' }) }) @@ -953,7 +955,10 @@ export default { }, checkUnsavedChart (next) { - next(!isEqual(this.chart, this.initialChartState) ? window.confirm(this.$t('notification.unsavedChanges')) : true) + if (!this.chart.deletedAt) { + return next(!isEqual(this.chart, this.initialChartState) ? window.confirm(this.$t('notification.unsavedChanges')) : true) + } + next() }, }, } diff --git a/client/web/compose/src/views/Admin/Modules/Edit.vue b/client/web/compose/src/views/Admin/Modules/Edit.vue index 9dbec26853..35ec720a34 100644 --- a/client/web/compose/src/views/Admin/Modules/Edit.vue +++ b/client/web/compose/src/views/Admin/Modules/Edit.vue @@ -735,7 +735,11 @@ export default { }), checkUnsavedModule (next) { - next(!isEqual(this.module.clone(), this.initialModuleState.clone()) ? window.confirm(this.$t('general.unsavedChanges')) : true) + if (!this.module.deletedAt) { + return next(!isEqual(this.module.clone(), this.initialModuleState.clone()) ? window.confirm(this.$t('general.unsavedChanges')) : true) + } + + next() }, handleNewField () { @@ -853,6 +857,8 @@ export default { this.processingDelete = true this.deleteModule(this.module).then(() => { + this.module.deletedAt = new Date() + const moduleRecordPage = this.pages.find(p => p.moduleID === this.module.moduleID) if (moduleRecordPage) { return this.deletePage({ ...moduleRecordPage, strategy: 'rebase' }) diff --git a/client/web/compose/src/views/Admin/Pages/Edit.vue b/client/web/compose/src/views/Admin/Pages/Edit.vue index 24cdc4b930..4c717841c1 100644 --- a/client/web/compose/src/views/Admin/Pages/Edit.vue +++ b/client/web/compose/src/views/Admin/Pages/Edit.vue @@ -1283,6 +1283,8 @@ export default { this.processingDelete = true this.deletePage({ ...this.page, strategy }).then(() => { + this.page.deletedAt = new Date() + this.$router.push({ name: 'admin.pages' }) }) .catch(this.toastErrorHandler(this.$t('notification:page.deleteFailed'))) @@ -1403,10 +1405,14 @@ export default { }, checkUnsavedComposePage (next) { - const layoutsStateChange = this.layouts.some((layout) => layout.meta.updated) - const pageStateChange = !isEqual(this.page, this.initialPageState) + if (!this.page.deletedAt) { + const layoutsStateChange = this.layouts.some((layout) => layout.meta.updated) + const pageStateChange = !isEqual(this.page, this.initialPageState) + + return next((layoutsStateChange || pageStateChange) ? window.confirm(this.$t('unsavedChanges')) : true) + } - next((layoutsStateChange || pageStateChange) ? window.confirm(this.$t('unsavedChanges')) : true) + next() }, setDefaultValues () { diff --git a/client/web/compose/src/views/Namespace/Edit.vue b/client/web/compose/src/views/Namespace/Edit.vue index 448fdbb562..11ec69048b 100644 --- a/client/web/compose/src/views/Namespace/Edit.vue +++ b/client/web/compose/src/views/Namespace/Edit.vue @@ -673,6 +673,8 @@ export default { this.deleteNamespace({ namespaceID }) .catch(this.toastErrorHandler(this.$t('notification:namespace.deleteFailed'))) .then(() => { + this.namespace.deletedAt = new Date() + if (applicationID) { return this.$SystemAPI.applicationDelete({ applicationID }) } @@ -780,11 +782,15 @@ export default { }, checkUnsavedNamespace (next) { - const namespaceState = !isEqual(this.namespace.clone(), this.initialNamespaceState.clone()) - const isApplicationState = !(this.isApplication === this.isApplicationInitialState) - const namespaceAssetsState = !isEqual(this.namespaceAssets, this.namespaceAssetsInitialState) + if (!this.namespace.deletedAt) { + const namespaceState = !isEqual(this.namespace.clone(), this.initialNamespaceState.clone()) + const isApplicationState = !(this.isApplication === this.isApplicationInitialState) + const namespaceAssetsState = !isEqual(this.namespaceAssets, this.namespaceAssetsInitialState) + + return next((namespaceState || isApplicationState || namespaceAssetsState) ? window.confirm(this.$t('manage.unsavedChanges')) : true) + } - next((namespaceState || isApplicationState || namespaceAssetsState) ? window.confirm(this.$t('manage.unsavedChanges')) : true) + next() }, setDefaultValues () { diff --git a/client/web/reporter/src/mixins/report.js b/client/web/reporter/src/mixins/report.js index dbda893dda..fa8fd24370 100644 --- a/client/web/reporter/src/mixins/report.js +++ b/client/web/reporter/src/mixins/report.js @@ -80,6 +80,7 @@ export default { return this.$SystemAPI.reportDelete(this.report) .then(() => { + this.report.deletedAt = new Date() this.toastSuccess(this.$t('notification:report.delete')) this.$router.push({ name: 'report.list' }) }) diff --git a/client/web/reporter/src/views/Report/Builder.vue b/client/web/reporter/src/views/Report/Builder.vue index 43099aa546..d0122f4c34 100644 --- a/client/web/reporter/src/views/Report/Builder.vue +++ b/client/web/reporter/src/views/Report/Builder.vue @@ -975,6 +975,10 @@ export default { // Trigger browser dialog on page leave to prevent unsaved changes checkUnsavedBlocks (next) { + if (this.report.deletedAt) { + return next(true) + } + next(!this.unsavedBlocks.size || window.confirm(this.$t('builder:unsaved-changes'))) }, diff --git a/client/web/reporter/src/views/Report/Edit.vue b/client/web/reporter/src/views/Report/Edit.vue index 9694807034..1f520957d1 100644 --- a/client/web/reporter/src/views/Report/Edit.vue +++ b/client/web/reporter/src/views/Report/Edit.vue @@ -299,6 +299,10 @@ export default { }, checkUnsavedChart (next) { + if (this.report.deletedAt) { + return next(true) + } + const reportState = { handle: this.report.handle, meta: { diff --git a/client/web/workflow/src/views/Workflow/Editor.vue b/client/web/workflow/src/views/Workflow/Editor.vue index e683fe6127..6894bd310a 100644 --- a/client/web/workflow/src/views/Workflow/Editor.vue +++ b/client/web/workflow/src/views/Workflow/Editor.vue @@ -94,7 +94,7 @@ export default { }, beforeRouteLeave (to, from, next) { - if (this.changeDetected) { + if (this.changeDetected && !this.workflow.deletedAt) { next(window.confirm(this.$t('notification:confirm-unsaved-changes'))) } else { window.onbeforeunload = null @@ -197,6 +197,7 @@ export default { .then(() => { // Disable unsaved changes prompt this.workflow = {} + this.workflow.deletedAt = new Date() this.$router.push({ name: 'workflow.list' }) this.toastSuccess(this.$t('notification:delete.success')) })