diff --git a/client/web/admin/src/components/Application/CApplicationEditorUnify.vue b/client/web/admin/src/components/Application/CApplicationEditorUnify.vue index a186b45ee..354147122 100644 --- a/client/web/admin/src/components/Application/CApplicationEditorUnify.vue +++ b/client/web/admin/src/components/Application/CApplicationEditorUnify.vue @@ -58,6 +58,7 @@ data-test-id="file-logo-upload" accept="image/*" :placeholder="$t('logo.placeholder')" + @change="$emit('change-detected')" /> diff --git a/client/web/admin/src/components/Role/CRoleEditorMembers.vue b/client/web/admin/src/components/Role/CRoleEditorMembers.vue index ff56cdc30..202cc5db5 100644 --- a/client/web/admin/src/components/Role/CRoleEditorMembers.vue +++ b/client/web/admin/src/components/Role/CRoleEditorMembers.vue @@ -154,7 +154,7 @@ export default { this.$set(this.members, i, { ...this.members[i], label: label, dirty: true }) } - this.memberUsers.push({ value: member.userID, label }) + this.memberUsers.push(member) } }, diff --git a/client/web/admin/src/views/Automation/Workflow/Editor.vue b/client/web/admin/src/views/Automation/Workflow/Editor.vue index e5a88646e..c0a6f89a9 100644 --- a/client/web/admin/src/views/Automation/Workflow/Editor.vue +++ b/client/web/admin/src/views/Automation/Workflow/Editor.vue @@ -48,6 +48,7 @@ diff --git a/client/web/admin/src/views/Federation/Nodes/Editor.vue b/client/web/admin/src/views/Federation/Nodes/Editor.vue index db4906b39..edd73d85b 100644 --- a/client/web/admin/src/views/Federation/Nodes/Editor.vue +++ b/client/web/admin/src/views/Federation/Nodes/Editor.vue @@ -131,6 +131,7 @@ import { mapGetters } from 'vuex' import editorHelpers from 'corteza-webapp-admin/src/mixins/editorHelpers' import CFederationEditorInfo from 'corteza-webapp-admin/src/components/Federation/CFederationEditorInfo' import CSubmitButton from 'corteza-webapp-admin/src/components/CSubmitButton' +import { cloneDeep, isEqual } from 'lodash' export default { i18nOptions: { @@ -158,6 +159,7 @@ export default { data () { return { node: {}, + initialNodeState: {}, // Processing and success flags for each form info: { @@ -175,6 +177,14 @@ export default { } }, + beforeRouteUpdate (to, from, next) { + this.checkUnsavedChanges(next, to) + }, + + beforeRouteLeave (to, from, next) { + this.checkUnsavedChanges(next, to) + }, + computed: { ...mapGetters({ can: 'rbac/can', @@ -201,7 +211,17 @@ export default { this.fetchNode() this.fetchGeneratedUrl() } else { - this.node = {} + this.node = { + name: '', + baseURL: '', + contact: '', + } + + this.initialNodeState = { + name: '', + baseURL: '', + contact: '', + } } }, }, @@ -214,6 +234,7 @@ export default { this.$FederationAPI.nodeRead({ nodeID: this.nodeID }) .then(node => { this.node = node // new federation.Node(node) + this.initialNodeState = cloneDeep(node) }) .catch(this.toastErrorHandler(this.$t('notification:federation.fetch.error'))) .finally(() => { @@ -250,6 +271,7 @@ export default { this.$FederationAPI.nodeUpdate(payload) .then(node => { this.node = node + this.initialNodeState = cloneDeep(node) this.animateSuccess('info') this.toastSuccess(this.$t('notification:federation.update.success')) @@ -343,6 +365,16 @@ export default { copyUrl () { navigator.clipboard.writeText(this.generate.url) }, + + checkUnsavedChanges (next, to) { + const isNewPage = this.$route.path.includes('/new') && to.name.includes('edit') + + if (isNewPage) { + 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 58022127e..aed0dd3ef 100644 --- a/client/web/admin/src/views/System/Apigw/Editor.vue +++ b/client/web/admin/src/views/System/Apigw/Editor.vue @@ -53,6 +53,7 @@ diff --git a/client/web/admin/src/views/System/Application/Editor.vue b/client/web/admin/src/views/System/Application/Editor.vue index 03e95a259..b70f8040c 100644 --- a/client/web/admin/src/views/System/Application/Editor.vue +++ b/client/web/admin/src/views/System/Application/Editor.vue @@ -7,10 +7,11 @@ :title="title" > diff --git a/client/web/admin/src/views/System/Connection/Editor.vue b/client/web/admin/src/views/System/Connection/Editor.vue index ec6fd7568..474de8327 100644 --- a/client/web/admin/src/views/System/Connection/Editor.vue +++ b/client/web/admin/src/views/System/Connection/Editor.vue @@ -63,6 +63,7 @@ diff --git a/client/web/admin/src/views/System/Queue/Editor.vue b/client/web/admin/src/views/System/Queue/Editor.vue index 94845de6d..54bae0d74 100644 --- a/client/web/admin/src/views/System/Queue/Editor.vue +++ b/client/web/admin/src/views/System/Queue/Editor.vue @@ -34,6 +34,7 @@ diff --git a/client/web/admin/src/views/System/Role/Editor.vue b/client/web/admin/src/views/System/Role/Editor.vue index f11e14c64..12b12b944 100644 --- a/client/web/admin/src/views/System/Role/Editor.vue +++ b/client/web/admin/src/views/System/Role/Editor.vue @@ -70,6 +70,7 @@ diff --git a/client/web/admin/src/views/System/SensitivityLevel/Editor.vue b/client/web/admin/src/views/System/SensitivityLevel/Editor.vue index 09b93b1bd..56069f59c 100644 --- a/client/web/admin/src/views/System/SensitivityLevel/Editor.vue +++ b/client/web/admin/src/views/System/SensitivityLevel/Editor.vue @@ -32,6 +32,7 @@ diff --git a/client/web/admin/src/views/System/Template/Editor.vue b/client/web/admin/src/views/System/Template/Editor.vue index 4a9d3bd45..04f95f03e 100644 --- a/client/web/admin/src/views/System/Template/Editor.vue +++ b/client/web/admin/src/views/System/Template/Editor.vue @@ -62,6 +62,7 @@ diff --git a/client/web/admin/src/views/System/User/Editor.vue b/client/web/admin/src/views/System/User/Editor.vue index ae51b3012..040e3b261 100644 --- a/client/web/admin/src/views/System/User/Editor.vue +++ b/client/web/admin/src/views/System/User/Editor.vue @@ -100,6 +100,7 @@ diff --git a/client/web/compose/src/components/Admin/Module/UniqueValues.vue b/client/web/compose/src/components/Admin/Module/UniqueValues.vue index e138a78f1..a35252437 100644 --- a/client/web/compose/src/components/Admin/Module/UniqueValues.vue +++ b/client/web/compose/src/components/Admin/Module/UniqueValues.vue @@ -25,7 +25,7 @@
@@ -145,12 +145,6 @@ export default { computed: { rules: { get () { - this.module.config.recordDeDup.rules.forEach(rule => { - if (rule.constraints === null) { - rule.constraints = [] - } - }) - return this.module.config.recordDeDup.rules }, set (value) { @@ -185,6 +179,10 @@ export default { }, updateRuleConstraint (rule) { + if (!rule.constraints) { + rule.constraints = [] + } + rule.constraints.push({ attribute: rule.currentField.name, modifier: 'case-sensitive', @@ -197,7 +195,7 @@ export default { }, filterFieldOptions (rule) { - const selectedFields = rule.constraints.map(({ attribute }) => attribute) + const selectedFields = rule.constraints ? rule.constraints.map(({ attribute }) => attribute) : [] return this.module.fields.filter(({ name }) => !selectedFields.includes(name)) }, diff --git a/client/web/compose/src/views/Admin/Charts/Edit.vue b/client/web/compose/src/views/Admin/Charts/Edit.vue index d789c2624..d9c5b321d 100644 --- a/client/web/compose/src/views/Admin/Charts/Edit.vue +++ b/client/web/compose/src/views/Admin/Charts/Edit.vue @@ -311,6 +311,7 @@
diff --git a/client/web/compose/src/views/Admin/Modules/Edit.vue b/client/web/compose/src/views/Admin/Modules/Edit.vue index da5baf712..ebdcb3c1a 100644 --- a/client/web/compose/src/views/Admin/Modules/Edit.vue +++ b/client/web/compose/src/views/Admin/Modules/Edit.vue @@ -452,6 +452,7 @@ diff --git a/client/web/compose/src/views/Namespace/Edit.vue b/client/web/compose/src/views/Namespace/Edit.vue index 99e73fd48..04995b7e6 100644 --- a/client/web/compose/src/views/Namespace/Edit.vue +++ b/client/web/compose/src/views/Namespace/Edit.vue @@ -318,6 +318,7 @@ diff --git a/client/web/reporter/src/components/Report/Blocks/index.vue b/client/web/reporter/src/components/Report/Blocks/index.vue index 81fac5bda..79501662b 100644 --- a/client/web/reporter/src/components/Report/Blocks/index.vue +++ b/client/web/reporter/src/components/Report/Blocks/index.vue @@ -165,6 +165,8 @@ export default { sizes.forEach((size, index) => { this.block.elements[index].meta.size = size }) + + this.$emit('item-updated', this.index) }, getScenarioDefinition (element) { diff --git a/client/web/reporter/src/components/Report/Grid.vue b/client/web/reporter/src/components/Report/Grid.vue index f92b7abcd..ec118d96d 100644 --- a/client/web/reporter/src/components/Report/Grid.vue +++ b/client/web/reporter/src/components/Report/Grid.vue @@ -28,6 +28,8 @@ :y="item.y" :class="{ 'editable-grid-item': editable }" drag-ignore-from=".gutter" + @moved="onBlockUpdated(index)" + @resized="onBlockUpdated(index)" > diff --git a/client/web/reporter/src/mixins/report.js b/client/web/reporter/src/mixins/report.js index 0c0a9524a..ed1349e32 100644 --- a/client/web/reporter/src/mixins/report.js +++ b/client/web/reporter/src/mixins/report.js @@ -15,6 +15,7 @@ export default { return this.$SystemAPI.reportRead({ reportID }) .then(report => { this.report = new system.Report(report) + this.initialReportState = this.report.clone() }) .catch(this.toastErrorHandler(this.$t('notification:report.fetchFailed'))) .finally(() => { @@ -44,6 +45,8 @@ export default { return this.$SystemAPI.reportCreate(report) .then(report => { this.report = new system.Report(report) + this.initialReportState = this.report.clone() + this.detectStateChange = false this.toastSuccess(this.$t('notification:report.created')) this.$router.push({ name: 'report.edit', params: { reportID: report.reportID } }) }) @@ -55,6 +58,8 @@ export default { return this.$SystemAPI.reportUpdate(report) .then(report => { this.report = new system.Report(report) + this.initialReportState = this.report.clone() + this.detectStateChange = false this.toastSuccess(this.$t('notification:report.updated')) }) .catch(this.toastErrorHandler(this.$t('notification:report.updateFailed'))) diff --git a/client/web/reporter/src/views/Report/Builder.vue b/client/web/reporter/src/views/Report/Builder.vue index efd30684d..4d4804434 100644 --- a/client/web/reporter/src/views/Report/Builder.vue +++ b/client/web/reporter/src/views/Report/Builder.vue @@ -85,6 +85,7 @@ v-if="report && canRead && showReport" :blocks.sync="reportBlocks" editable + @item-updated="onBlockUpdated" > @@ -411,6 +424,8 @@ export default { report: undefined, + unsavedBlocks: new Set(), + dataframes: [], blocks: { @@ -630,10 +645,19 @@ export default { }, }, + beforeRouteUpdate (to, from, next) { + this.checkUnsavedBlocks(next) + }, + + beforeRouteLeave (to, from, next) { + this.checkUnsavedBlocks(next) + }, + watch: { reportID: { immediate: true, handler (reportID) { + this.unsavedBlocks.clear() this.scenarios.selected = undefined if (reportID) { @@ -814,6 +838,7 @@ export default { .then(() => { this.mapBlocks() this.refreshReport() + this.unsavedBlocks.clear() }) }, @@ -842,6 +867,8 @@ export default { }, updateBlock () { + this.unsavedBlocks.add(this.blocks.currentIndex) + if (this.currentBlock) { const elements = this.currentBlock.elements @@ -860,6 +887,7 @@ export default { deleteBlock (index = undefined) { this.reindexBlocks(this.reportBlocks.filter((p, i) => index !== i)) + this.unsavedBlocks.add(index) }, // Display elements @@ -887,6 +915,8 @@ export default { this.editBlock(this.blocks.currentIndex) this.setCurrentDisplayElement(this.currentBlock.elements.length - 1) + + this.updateBlock() }, // Scenarios @@ -924,6 +954,15 @@ export default { getOptionKey (scenario) { return scenario }, + + // Trigger browser dialog on page leave to prevent unsaved changes + checkUnsavedBlocks (next) { + next(!this.unsavedBlocks.size || window.confirm(this.$t('builder:unsaved-changes'))) + }, + + onBlockUpdated (index) { + this.unsavedBlocks.add(index) + }, }, } diff --git a/client/web/reporter/src/views/Report/Edit.vue b/client/web/reporter/src/views/Report/Edit.vue index e0a672a18..f7a3303c8 100644 --- a/client/web/reporter/src/views/Report/Edit.vue +++ b/client/web/reporter/src/views/Report/Edit.vue @@ -103,6 +103,7 @@ :placeholder="$t('name')" required :state="nameState" + @input="handleDetectStateChange" /> @@ -121,6 +122,7 @@ :placeholder="$t('placeholder-handle')" required :state="handleState" + @input="handleDetectStateChange" /> @@ -178,6 +181,7 @@ import { handle } from '@cortezaproject/corteza-vue' import report from 'corteza-webapp-reporter/src/mixins/report' import EditorToolbar from 'corteza-webapp-reporter/src/components/EditorToolbar' import { mapGetters } from 'vuex' +import { isEqual } from 'lodash' export default { name: 'EditReport', @@ -197,6 +201,9 @@ export default { processing: false, report: undefined, + initialReportState: undefined, + + detectStateChange: false, } }, @@ -268,9 +275,44 @@ export default { this.fetchReport(reportID) } else { this.report = new system.Report() + this.initialReportState = new system.Report() } }, }, }, + + beforeRouteUpdate (to, from, next) { + this.checkUnsavedChart(next) + }, + + beforeRouteLeave (to, from, next) { + this.checkUnsavedChart(next) + }, + + methods: { + handleDetectStateChange () { + this.detectStateChange = true + }, + + checkUnsavedChart (next) { + const reportState = { + handle: this.report.handle, + meta: { + name: this.report.meta.name, + description: this.report.meta.description, + }, + } + + const initialReportState = { + handle: this.initialReportState.handle, + meta: { + name: this.initialReportState.meta.name, + description: this.initialReportState.meta.description, + }, + } + + next(!isEqual(reportState, initialReportState) ? window.confirm(this.$t('unsavedChanges')) : true) + }, + }, } diff --git a/lib/js/src/compose/types/module-field/base.ts b/lib/js/src/compose/types/module-field/base.ts index 98decb6ae..376f7c0cb 100644 --- a/lib/js/src/compose/types/module-field/base.ts +++ b/lib/js/src/compose/types/module-field/base.ts @@ -121,7 +121,23 @@ export class ModuleField { applyOptions (o?: Partial): void { if (!o) return - Apply(this.options, o, Object, 'description', 'hint') + if (o.description) { + this.options.description = { + ...this.options.description, + ...o.description, + } + + this.options.description.edit = this.options.description.edit || undefined + } + + if (o.hint) { + this.options.hint = { + ...this.options.hint, + ...o.hint, + } + + this.options.hint.edit = this.options.hint.edit || undefined + } } clone (): ModuleField { diff --git a/lib/js/src/system/index.ts b/lib/js/src/system/index.ts index ca63ee84f..c403b5e76 100644 --- a/lib/js/src/system/index.ts +++ b/lib/js/src/system/index.ts @@ -6,6 +6,7 @@ export { Reminder } from './types/reminder' export { Template } from './types/template' export { Report } from './types/report' export { DalConnection } from './types/dalConnection' +export { AuthClient } from './types/authClient' export { SystemEvent, RoleEvent, diff --git a/lib/js/src/system/types/application.ts b/lib/js/src/system/types/application.ts index 14003137f..518aaf136 100644 --- a/lib/js/src/system/types/application.ts +++ b/lib/js/src/system/types/application.ts @@ -1,4 +1,71 @@ +import { Apply, CortezaID, ISO8601Date, NoID } from '../../cast' +import { IsOf } from '../../guards' + +interface PartialApplication extends Partial> { + createdAt?: string|number|Date; + updatedAt?: string|number|Date; +} + +interface Unify { + name: string; + listed: boolean, + url: string, + config: string, + iconID: string, + logoID: string +} + export class Application { - // @todo port application class here - [_: string]: unknown + public applicationID = undefined + public name = '' + public ownerID?: number = 0; + public enabled = false + public weight?: number = 0; + + public unify?: Unify = { + name: '', + listed: false, + url: '', + config: '', + iconID: NoID, + logoID: NoID, + }; + + public canGrant: boolean = true; + public canUpdateApplication: boolean = true; + public canDeleteApplication: boolean = true; + + constructor (r?: PartialApplication) { + this.apply(r) + } + + apply (r?: PartialApplication): void { + Apply(this, r, CortezaID, 'applicationID') + Apply(this, r, String, 'name') + Apply(this, r, Number, 'weight', 'ownerID') + Apply(this, r, Boolean, 'enabled', 'canGrant', 'canUpdateApplication', 'canDeleteApplication') + + + if (r && IsOf(r, 'unify')) { + this.unify = r.unify + } + } + + /** + * Returns resource ID + */ + get resourceID (): string { + return `${this.resourceType}:${this.applicationID}` + } + + /** + * Resource type + */ + get resourceType (): string { + return 'system:application' + } + + clone (): Application { + return new Application(JSON.parse(JSON.stringify(this))) + } } diff --git a/lib/js/src/system/types/authClient.ts b/lib/js/src/system/types/authClient.ts new file mode 100644 index 000000000..14f7dc857 --- /dev/null +++ b/lib/js/src/system/types/authClient.ts @@ -0,0 +1,88 @@ +import { Apply, CortezaID, ISO8601Date, NoID } from "../../cast"; +import { IsOf } from "../../guards"; + +interface PartialAuthClient + extends Partial< + Omit + > { + createdAt?: string | number | Date; + updatedAt?: string | number | Date; + deletedAt?: string | number | Date; + lastUsedAt?: string | number | Date; +} + +interface AuthClientMeta { + name: string; + description: string; +} + +interface DefSecurity { + impersonateUser: string; + permittedRoles: Array; + prohibitedRoles: Array; + forcedRoles: Array; +} + +export class AuthClient { + public authClientID = NoID; + public handle = ""; + public scope = "profile api"; + public redirectURI = ""; + public validGrant = 'authorization_code'; + + public meta: AuthClientMeta = { + name: "", + description: "", + }; + + public security: DefSecurity = { + impersonateUser: "0", + permittedRoles: [], + prohibitedRoles: [], + forcedRoles: [], + }; + + public enabled = true; + public trusted = false; + + public createdAt?: Date = undefined; + public updatedAt?: Date = undefined; + public deletedAt?: Date = undefined; + + public createdBy = NoID; + public updatedBy = NoID; + public deletedBy = NoID; + + public canDeleteAuthClient = false; + public canGrant = false; + public canUpdateAuthClient = false; + + constructor (o?: PartialAuthClient) { + this.apply(o) + } + + apply (o?: PartialAuthClient): void { + Apply(this, o, CortezaID, 'authClientID') + Apply(this, o, ISO8601Date, 'createdAt', 'updatedAt', 'deletedAt'); + Apply(this, o, String, 'handle', 'scope', 'redirectURI', 'validGrant'); + Apply(this, o, Boolean, 'enabled', 'trusted', 'canDeleteAuthClient', 'canGrant', 'canUpdateAuthClient'); + + + if (IsOf(o, 'meta')) { + this.meta = { ...o.meta } + } + + if (IsOf(o, 'security')) { + this.security = { + ...this.security, + ...o.security + } + } + + Apply(this, o, CortezaID, 'createdBy', 'updatedBy', 'deletedBy'); + } + + clone(): AuthClient { + return new AuthClient(JSON.parse(JSON.stringify(this))); + } +} diff --git a/lib/js/src/system/types/dalConnection.ts b/lib/js/src/system/types/dalConnection.ts index 5ca834c6f..52669122e 100644 --- a/lib/js/src/system/types/dalConnection.ts +++ b/lib/js/src/system/types/dalConnection.ts @@ -89,9 +89,9 @@ export class DalConnection { public updatedAt?: Date = undefined public deletedAt?: Date = undefined - public createdBy = '' - public updatedBy = '' - public deletedBy = '' + public createdBy = NoID + public updatedBy = NoID + public deletedBy = NoID public canDeleteConnection = false public canManageDalConfig = false @@ -112,7 +112,7 @@ export class DalConnection { } if (IsOf(dc, 'config')) { - this.config = { ...dc.config.privacy } + this.config = { ...dc.config } if (this.connectionID !== NoID && this.canManageDalConfig) { this.config = { @@ -124,6 +124,12 @@ export class DalConnection { }, ...dc.config, } + + if (!this.config.privacy.sensitivityLevelID) { + this.config.privacy = { + sensitivityLevelID: NoID, + } + } } } @@ -141,4 +147,8 @@ export class DalConnection { } } } + + clone (): DalConnection { + return new DalConnection(JSON.parse(JSON.stringify(this))) + } } diff --git a/lib/js/src/system/types/report.ts b/lib/js/src/system/types/report.ts index 6e440f52f..bf6334fe3 100644 --- a/lib/js/src/system/types/report.ts +++ b/lib/js/src/system/types/report.ts @@ -35,7 +35,10 @@ interface ReportScenario { export class Report { public reportID = NoID public handle = '' - public meta: Meta = {} + public meta: Meta = { + name: '', + description: '', + } public sources: Array = [] public blocks: Array = [] public scenarios: Array = [] @@ -102,4 +105,8 @@ export class Report { 'canRunReport', ) } + + clone (): Report { + return new Report(JSON.parse(JSON.stringify(this))) + } } diff --git a/lib/js/src/system/types/role.ts b/lib/js/src/system/types/role.ts index 4c6f0f335..1f3d12a3d 100644 --- a/lib/js/src/system/types/role.ts +++ b/lib/js/src/system/types/role.ts @@ -100,4 +100,8 @@ export class Role { get isContext (): boolean { return this.meta?.context?.expr?.length > 0 } + + clone (): Role { + return new Role(JSON.parse(JSON.stringify(this))) + } } diff --git a/lib/js/src/system/types/template.ts b/lib/js/src/system/types/template.ts index 2194aeda1..09e3cab43 100644 --- a/lib/js/src/system/types/template.ts +++ b/lib/js/src/system/types/template.ts @@ -19,7 +19,10 @@ export class Template { public language = '' public type = 'text/html' public partial = false - public meta: Meta = {} + public meta: Meta = { + short: '', + description: '', + } public template = '' public labels: object = {} public ownerID = NoID @@ -63,4 +66,8 @@ export class Template { get resourceType (): string { return 'system:template' } + + clone (): Template { + return new Template(JSON.parse(JSON.stringify(this))) + } } diff --git a/lib/js/src/system/types/user.ts b/lib/js/src/system/types/user.ts index 0de36438b..9c5759409 100644 --- a/lib/js/src/system/types/user.ts +++ b/lib/js/src/system/types/user.ts @@ -106,4 +106,8 @@ export class User { this.userID, ].join(' ').toLocaleLowerCase() } + + clone (): User { + return new User(JSON.parse(JSON.stringify(this))) + } } diff --git a/locale/en/corteza-webapp-admin/general.yaml b/locale/en/corteza-webapp-admin/general.yaml index 0f7cb9638..d78e90b18 100644 --- a/locale/en/corteza-webapp-admin/general.yaml +++ b/locale/en/corteza-webapp-admin/general.yaml @@ -47,4 +47,5 @@ label: delete: Delete undelete: Undelete fileTypeNotAllowed: File type not allowed - +editor: + unsavedChanges: Unsaved changes will be lost. Do you wish to leave the page? diff --git a/locale/en/corteza-webapp-compose/chart.yaml b/locale/en/corteza-webapp-compose/chart.yaml index aeb8c8101..f9449982f 100644 --- a/locale/en/corteza-webapp-compose/chart.yaml +++ b/locale/en/corteza-webapp-compose/chart.yaml @@ -220,6 +220,7 @@ name: Chart name * handle: Handle generalSettings: General settings notification: + unsavedChanges: Unsaved changes will be lost. Do you wish to leave the page? loadFailed: Could not load chart saveFailed: Could not save this chart saved: Chart saved diff --git a/locale/en/corteza-webapp-compose/module.yaml b/locale/en/corteza-webapp-compose/module.yaml index dce38d400..cf6a923da 100644 --- a/locale/en/corteza-webapp-compose/module.yaml +++ b/locale/en/corteza-webapp-compose/module.yaml @@ -193,6 +193,7 @@ forModule: recordPage: Record page for module general: fields: Module fields + unsavedChanges: Unsaved changes will be lost. Do you wish to leave the page? label: attributes: Attributes handle: Handle diff --git a/locale/en/corteza-webapp-compose/namespace.yaml b/locale/en/corteza-webapp-compose/namespace.yaml index 7390c92cc..8572320c3 100644 --- a/locale/en/corteza-webapp-compose/namespace.yaml +++ b/locale/en/corteza-webapp-compose/namespace.yaml @@ -58,6 +58,7 @@ manage: title: Manage namespaces list-view: Back to namespace list delete: Delete + unsavedChanges: Unsaved changes will be lost. Do you wish to leave the page? disabled: Disabled diff --git a/locale/en/corteza-webapp-compose/page.yaml b/locale/en/corteza-webapp-compose/page.yaml index 5c548e57a..e9f183096 100644 --- a/locale/en/corteza-webapp-compose/page.yaml +++ b/locale/en/corteza-webapp-compose/page.yaml @@ -88,6 +88,7 @@ moduleEdit: Edit module navigation: page: Pages viewPage: View Page +unsavedChanges: Unsaved changes will be lost. Do you wish to leave the page? newPlaceholder: Page title noBlock: No block added yet noPages: No pages diff --git a/locale/en/corteza-webapp-reporter/builder.yaml b/locale/en/corteza-webapp-reporter/builder.yaml index 58f01522c..82bbf75e4 100644 --- a/locale/en/corteza-webapp-reporter/builder.yaml +++ b/locale/en/corteza-webapp-reporter/builder.yaml @@ -73,6 +73,7 @@ select-all: Select all unselect-all: Unselect all value: Value name: Name +unsaved-changes: Unsaved changes will be lost. Do you wish to leave the page? filter: operators: like: Like diff --git a/locale/en/corteza-webapp-reporter/edit.yaml b/locale/en/corteza-webapp-reporter/edit.yaml index 4ad8b4388..7aa8d0142 100644 --- a/locale/en/corteza-webapp-reporter/edit.yaml +++ b/locale/en/corteza-webapp-reporter/edit.yaml @@ -5,6 +5,7 @@ name: Name name-with-star: 'Name*' new-report: New Report permissions: Permissions +unsavedChanges: Unsaved changes will be lost. Do you wish to leave the page? report: create: Create Report builder: Report Builder