diff --git a/client/web/compose/src/mixins/record.js b/client/web/compose/src/mixins/record.js
index 72fe233b8..5a27081b3 100644
--- a/client/web/compose/src/mixins/record.js
+++ b/client/web/compose/src/mixins/record.js
@@ -13,6 +13,7 @@ export default {
processingUndelete: false,
processingSubmit: false,
record: undefined,
+ initialRecordState: undefined,
errors: new validator.Validated(),
}
},
@@ -163,6 +164,8 @@ export default {
} else {
this.inCreating = false
this.inEditing = false
+ // reset the record initial state in cases where the record edit page is redirected to the record view page
+ this.initialRecordState = this.record.clone()
if (this.showRecordModal) {
this.$emit('handle-record-redirect', { recordID: record.recordID, recordPageID: this.page.pageID })
@@ -172,6 +175,9 @@ export default {
if (!isNew) {
this.record = record
+ // reset the record initial state in cases where the record edit page is opened on a modal
+ this.initialRecordState = this.record.clone()
+
this.determineLayout().then(() => {
this.$root.$emit(`refetch-non-record-blocks:${this.page.pageID}`)
})
@@ -230,6 +236,7 @@ export default {
this.inCreating = false
this.inEditing = false
this.record = record
+ this.initialRecordState = this.record.clone()
this.$router.push({ name: route, params: { ...this.$route.params, recordID: record.recordID } })
}
@@ -326,6 +333,7 @@ export default {
this.onModalHide()
this.fields = []
this.record = new compose.Record(this.module, {})
+ this.initialRecordState = this.record.clone()
this.$emit('save')
})
.catch(this.toastErrorHandler(this.$t('notification:record.deleteBulkRecordUpdateFailed')))
diff --git a/client/web/compose/src/views/Admin/Modules/Edit.vue b/client/web/compose/src/views/Admin/Modules/Edit.vue
index 8c4cd66c1..1832deae7 100644
--- a/client/web/compose/src/views/Admin/Modules/Edit.vue
+++ b/client/web/compose/src/views/Admin/Modules/Edit.vue
@@ -3,7 +3,6 @@
{{ title }}
-
import axios from 'axios'
+import { isEqual } from 'lodash'
import { mapGetters } from 'vuex'
import RecordToolbar from 'corteza-webapp-compose/src/components/Common/RecordToolbar'
import record from 'corteza-webapp-compose/src/mixins/record'
@@ -156,6 +157,10 @@ export default {
getNextAndPrevRecord: 'ui/getNextAndPrevRecord',
}),
+ isNew () {
+ return this.record.recordID === NoID
+ },
+
title () {
const { name, handle } = this.module
const titlePrefix = this.inCreating ? 'create' : this.inEditing ? 'edit' : 'view'
@@ -232,6 +237,7 @@ export default {
created () {
this.createBlocks()
this.record = new compose.Record(this.module, { values: this.values })
+ this.initialRecordState = this.record.clone()
},
beforeDestroy () {
@@ -239,6 +245,14 @@ export default {
this.setDefaultValues()
},
+ beforeRouteLeave (to, from, next) {
+ this.checkUnsavedChanges(next, to)
+ },
+
+ beforeRouteUpdate (to, from, next) {
+ this.checkUnsavedChanges(next, to)
+ },
+
methods: {
createBlocks () {
this.fields.forEach(f => {
@@ -267,6 +281,7 @@ export default {
response()
.then(record => {
this.record = new compose.Record(module, record)
+ this.initialRecordState = this.record.clone()
})
.catch((e) => {
if (!axios.isCancel(e)) {
@@ -322,6 +337,17 @@ export default {
cancel()
})
},
+
+ checkUnsavedChanges (next, to) {
+ if (this.isNew) {
+ return true
+ } else {
+ const recordValues = JSON.parse(JSON.stringify(this.record.values))
+ const initialRecordState = JSON.parse(JSON.stringify(this.initialRecordState.values))
+
+ next(!isEqual(recordValues, initialRecordState) ? window.confirm(this.$t('general:editor.unsavedChanges')) : true)
+ }
+ },
},
}
diff --git a/client/web/compose/src/views/Namespace/Edit.vue b/client/web/compose/src/views/Namespace/Edit.vue
index 11ec69048..74c839568 100644
--- a/client/web/compose/src/views/Namespace/Edit.vue
+++ b/client/web/compose/src/views/Namespace/Edit.vue
@@ -782,15 +782,17 @@ export default {
},
checkUnsavedNamespace (next) {
- if (!this.namespace.deletedAt) {
+ if (this.isNew) {
+ next(true)
+ } else 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)
+ } else {
+ next(true)
}
-
- next()
},
setDefaultValues () {
diff --git a/client/web/compose/src/views/Public/Pages/Records/View.vue b/client/web/compose/src/views/Public/Pages/Records/View.vue
index c1bf21c0f..d0e9ef27e 100644
--- a/client/web/compose/src/views/Public/Pages/Records/View.vue
+++ b/client/web/compose/src/views/Public/Pages/Records/View.vue
@@ -110,6 +110,7 @@