diff --git a/client/web/compose/src/components/Admin/EditorToolbar.vue b/client/web/compose/src/components/Admin/EditorToolbar.vue index 7244746d1..ab201f31c 100644 --- a/client/web/compose/src/components/Admin/EditorToolbar.vue +++ b/client/web/compose/src/components/Admin/EditorToolbar.vue @@ -47,6 +47,8 @@ > {{ $t('label.delete') }} + + {{ $t('label.saveAsCopy') }} + {{ $t('label.saveAndClose') }} + + {{ $t('build.addBlock') }} + + @@ -676,7 +701,7 @@ export default { appendBlock (block, msg) { this.calculateNewBlockPosition(block) - this.editor = { index: undefined, block: compose.PageBlockMaker(block) } + this.editor = { index: undefined, block } this.updateBlocks() if (!this.editor) { @@ -735,7 +760,7 @@ export default { return !req.size }, - async handleSaveLayout ({ closeOnSuccess = false, previewOnSuccess = false } = {}) { + async handleSaveLayout ({ closeOnSuccess = false, previewOnSuccess = false, alert = true } = {}) { const { namespaceID } = this.namespace // Record blocks @@ -788,26 +813,27 @@ export default { layout = await this.updatePageLayout({ ...layout, blocks }) return { page, layout } }) - }).then(({ page, layout }) => { - this.page = new compose.Page(page) - this.layout = new compose.PageLayout(layout) - this.unsavedBlocks.clear() - - this.toastSuccess(this.$t('notification:page.page-layout.save.success')) - + }).then(async ({ page, layout }) => { if (closeOnSuccess) { this.$router.push(this.previousPage || { name: 'admin.pages' }) return } - return this.fetchPageLayouts() + if (alert) { + this.toastSuccess(this.$t('notification:page.page-layout.save.success')) + } + + this.page = new compose.Page(page) + await this.fetchPageLayouts() + this.setLayout(layout.pageLayoutID) }).finally(() => { this.processing = false }).catch(this.toastErrorHandler(this.$t('notification:page.page-layout.save.failed'))) }, - handleCloneLayout () { + async handleCloneLayout ({ ref = false }) { this.processing = true + this.processingLayout = true const layout = { ...this.layout.clone(), @@ -817,13 +843,46 @@ export default { layout.meta.title = `${this.$t('copyOf')}${layout.meta.title}` - this.createPageLayout(layout).then(({ pageLayoutID }) => { - return this.fetchPageLayouts().then(() => { - this.setLayout(pageLayoutID) - this.toastSuccess(this.$t('notification:page.page-layout.clone.success')) + // If we are cloning a layout with references, we need to clone the blocks + if (!ref) { + const oldBlockIDs = {} + layout.blocks = [] + + // Sort based on if tab or not + this.blocks = this.blocks.toSorted((a, b) => { + if (a.kind === 'Tabs' && b.kind !== 'Tabs') { + return 1 // Move 'Tabs' to the end + } else if (a.kind !== 'Tabs' && b.kind === 'Tabs') { + return -1 // Keep 'Tabs' before other elements + } else { + return 0 // No change in order + } + }).map(block => { + const oldBlockID = block.blockID + + if (block.kind === 'Tabs') { + block.options.tabs = block.options.tabs.map(tab => { + tab.blockID = oldBlockIDs[tab.blockID] + return tab + }) + } + + block = block.clone() + oldBlockIDs[oldBlockID] = block.meta.tempID + + return block }) + } + + this.createPageLayout(layout).then(layout => { + this.layout = layout + this.layouts.push({ ...layout, label: layout.meta.title || layout.handle || layout.pageLayoutID }) + return this.handleSaveLayout({ alert: false }) + }).then(() => { + this.toastSuccess(this.$t('notification:page.page-layout.clone.success')) }).finally(() => { this.processing = false + this.processingLayout = false }).catch(this.toastErrorHandler(this.$t('notification:page.page-layout.clone.failed'))) }, @@ -884,7 +943,7 @@ export default { const paste = (event.clipboardData || window.clipboardData).getData('text') // Doing this to handle JSON parse error try { - const block = JSON.parse(paste) + const block = compose.pageBlockMaker(JSON.parse(paste)) const valid = this.isValid(block) if (valid) { diff --git a/lib/js/src/compose/types/page-block/base.ts b/lib/js/src/compose/types/page-block/base.ts index 5b2cf9ad8..0ac584f34 100644 --- a/lib/js/src/compose/types/page-block/base.ts +++ b/lib/js/src/compose/types/page-block/base.ts @@ -1,6 +1,7 @@ import { merge } from 'lodash' import { Apply, NoID } from '../../../cast' import { generateUID } from '../../helpers/idgen' +import { PageBlockMaker } from '.' interface PageBlockStyleVariants { [_: string]: string; @@ -105,7 +106,7 @@ export class PageBlock { } clone (): PageBlockInput { - return { ...JSON.parse(JSON.stringify(this)), blockID: NoID, meta: { tempID: '' } } + return PageBlockMaker({ ...JSON.parse(JSON.stringify(this)), blockID: NoID, meta: { tempID: generateUID() } }) } } diff --git a/locale/en/corteza-webapp-compose/page.yaml b/locale/en/corteza-webapp-compose/page.yaml index c00f0296a..97ce32b02 100644 --- a/locale/en/corteza-webapp-compose/page.yaml +++ b/locale/en/corteza-webapp-compose/page.yaml @@ -61,6 +61,9 @@ build: addBlock: Add block selectBlockTitle: Select type of the new block unsavedChanges: Unsaved changes will be lost. Do you wish to leave the page? + saveAsCopy: + ref: With references + noRef: Without references createLabel: Create page edit: create: Create page