diff --git a/packages/api-page-builder/__tests__/graphql/mocks/pageTemplates/simplePageBlockContent.ts b/packages/api-page-builder/__tests__/graphql/mocks/pageTemplates/simplePageBlockContent.ts deleted file mode 100644 index 0841930abea..00000000000 --- a/packages/api-page-builder/__tests__/graphql/mocks/pageTemplates/simplePageBlockContent.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { PageElementId } from "~/graphql"; - -const blockId = PageElementId.create().getValue(); - -/** - * Contains a grid > cell with a heading and a paragraph. - * The heading and paragraph are both editable (linked elements). - */ -export const simplePageBlockContent = { - id: blockId, - type: "block", - data: { - settings: { - width: { - desktop: { - value: "100%" - } - }, - margin: { - desktop: { - top: "0px", - right: "0px", - bottom: "0px", - left: "0px", - advanced: true - } - }, - padding: { - desktop: { - all: "10px" - } - }, - horizontalAlignFlex: { - desktop: "center" - }, - verticalAlign: { - desktop: "flex-start" - } - }, - variables: [ - { - id: "FDEezrJ8NH", - type: "heading", - label: "Heading text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Heading","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - }, - { - id: "SezNLOdXw3", - type: "paragraph", - label: "Paragraph text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - ] - }, - elements: [ - { - id: PageElementId.create().getValue(), - type: "grid", - data: { - settings: { - width: { - desktop: { - value: "1100px" - } - }, - margin: { - desktop: { - top: "0px", - right: "0px", - bottom: "0px", - left: "0px", - advanced: true - } - }, - padding: { - desktop: { - all: "10px" - } - }, - grid: { - cellsType: "12" - }, - gridSettings: { - desktop: { - flexDirection: "row" - }, - "mobile-landscape": { - flexDirection: "column" - } - }, - horizontalAlignFlex: { - desktop: "flex-start" - }, - verticalAlign: { - desktop: "flex-start" - } - } - }, - elements: [ - { - id: PageElementId.create().getValue(), - type: "cell", - data: { - settings: { - margin: { - desktop: { - top: "0px", - right: "0px", - bottom: "0px", - left: "0px", - advanced: true - } - }, - padding: { - desktop: { - all: "0px" - } - }, - grid: { - size: 12 - } - } - }, - elements: [ - { - id: PageElementId.create().getValue(), - type: "heading", - data: { - text: { - desktop: { - type: "heading", - alignment: "left", - tag: "h1" - }, - data: { - text: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Heading","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - }, - settings: { - margin: { - desktop: { - all: "0px" - } - }, - padding: { - desktop: { - all: "0px" - } - } - }, - variableId: "FDEezrJ8NH" - }, - elements: [], - path: ["UTaSFnVtkV", "uFzaV9SB6q", "k77Fdcod55", "BOMdKQBt23"] - }, - { - id: PageElementId.create().getValue(), - type: "paragraph", - data: { - text: { - desktop: { - type: "paragraph", - alignment: "left", - tag: "p" - }, - data: { - text: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - }, - settings: { - margin: { - desktop: { - all: "0px" - } - }, - padding: { - desktop: { - all: "0px" - } - } - }, - variableId: "SezNLOdXw3" - }, - elements: [], - path: ["UTaSFnVtkV", "uFzaV9SB6q", "k77Fdcod55", "BOMdKQBt23"] - } - ], - path: ["UTaSFnVtkV", "uFzaV9SB6q", "k77Fdcod55"] - } - ], - path: ["UTaSFnVtkV", "uFzaV9SB6q"] - } - ], - path: ["UTaSFnVtkV"] -}; diff --git a/packages/api-page-builder/__tests__/graphql/mocks/pageTemplates/simplePageTemplateContent.ts b/packages/api-page-builder/__tests__/graphql/mocks/pageTemplates/simplePageTemplateContent.ts deleted file mode 100644 index 100958dabf1..00000000000 --- a/packages/api-page-builder/__tests__/graphql/mocks/pageTemplates/simplePageTemplateContent.ts +++ /dev/null @@ -1,225 +0,0 @@ -/** - * Contains a grid > cell with a heading and a paragraph. - * The heading and paragraph are both editable (linked elements). - */ -export const simplePageTemplateContent = { - id: "lk860n5p", - type: "document", - data: { - template: { - variables: [ - { - blockId: "yAOxZQgZsv", - variables: [ - { - id: "aAUBVaa1fB", - type: "heading", - label: "Heading text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Heading","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - }, - { - id: "iwpP2qZAHy", - type: "paragraph", - label: "Paragraph text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - ] - } - ] - } - }, - elements: [ - { - id: "yAOxZQgZsv", - type: "block", - data: { - templateBlockId: "yAOxZQgZsv", - settings: { - width: { - desktop: { - value: "100%" - } - }, - margin: { - desktop: { - top: "0px", - right: "0px", - bottom: "0px", - left: "0px", - advanced: true - } - }, - padding: { - desktop: { - all: "10px" - } - }, - horizontalAlignFlex: { - desktop: "center" - }, - verticalAlign: { - desktop: "flex-start" - } - }, - variables: [ - { - id: "aAUBVaa1fB", - type: "heading", - label: "Heading text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Heading","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - }, - { - id: "iwpP2qZAHy", - type: "paragraph", - label: "Paragraph text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - ] - }, - elements: [ - { - id: "luzsb731h5", - type: "grid", - data: { - settings: { - width: { - desktop: { - value: "1100px" - } - }, - margin: { - desktop: { - top: "0px", - right: "0px", - bottom: "0px", - left: "0px", - advanced: true - } - }, - padding: { - desktop: { - all: "10px" - } - }, - grid: { - cellsType: "12" - }, - gridSettings: { - desktop: { - flexDirection: "row" - }, - "mobile-landscape": { - flexDirection: "column" - } - }, - horizontalAlignFlex: { - desktop: "flex-start" - }, - verticalAlign: { - desktop: "flex-start" - } - } - }, - elements: [ - { - id: "c1KzABC9LJ", - type: "cell", - data: { - settings: { - margin: { - desktop: { - top: "0px", - right: "0px", - bottom: "0px", - left: "0px", - advanced: true - } - }, - padding: { - desktop: { - all: "0px" - } - }, - grid: { - size: 12 - }, - horizontalAlignFlex: { - desktop: "flex-start" - } - } - }, - elements: [ - { - id: "aAUBVaa1fB", - type: "heading", - data: { - text: { - desktop: { - type: "heading", - alignment: "left", - tag: "h1" - }, - data: { - text: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Heading","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - }, - settings: { - margin: { - desktop: { - all: "0px" - } - }, - padding: { - desktop: { - all: "0px" - } - } - }, - variableId: "aAUBVaa1fB" - }, - elements: [], - path: ["lk860n5p", "yAOxZQgZsv", "luzsb731h5", "c1KzABC9LJ"] - }, - { - id: "iwpP2qZAHy", - type: "paragraph", - data: { - text: { - desktop: { - type: "paragraph", - alignment: "left", - tag: "p" - }, - data: { - text: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - }, - settings: { - margin: { - desktop: { - all: "0px" - } - }, - padding: { - desktop: { - all: "0px" - } - } - }, - variableId: "iwpP2qZAHy" - }, - elements: [], - path: ["lk860n5p", "yAOxZQgZsv", "luzsb731h5", "c1KzABC9LJ"] - } - ], - path: ["lk860n5p", "yAOxZQgZsv", "luzsb731h5"] - } - ], - path: ["lk860n5p", "yAOxZQgZsv"] - } - ], - path: ["lk860n5p"] - } - ], - path: [] -}; diff --git a/packages/api-page-builder/__tests__/graphql/pageTemplates.test.ts b/packages/api-page-builder/__tests__/graphql/pageTemplates.test.ts deleted file mode 100644 index 1140aa5180d..00000000000 --- a/packages/api-page-builder/__tests__/graphql/pageTemplates.test.ts +++ /dev/null @@ -1,370 +0,0 @@ -import useGqlHandler from "./useGqlHandler"; -import { simplePageTemplateContent } from "~tests/graphql/mocks/pageTemplates/simplePageTemplateContent"; -import { simplePageBlockContent } from "~tests/graphql/mocks/pageTemplates/simplePageBlockContent"; - -jest.setTimeout(100000); - -describe("Page Templates Test", () => { - const { - createPageTemplate, - updatePageTemplate, - updatePage, - unlinkPageFromTemplate, - createPageFromTemplate, - createCategory, - createBlockCategory, - createPageBlock - } = useGqlHandler(); - - test("unlinking a page from a page template should remove all template-related data", async () => { - await createCategory({ - data: { - slug: `slug`, - name: `name`, - url: `/some-url/`, - layout: `layout` - } - }); - - const pageTemplate = await createPageTemplate({ - data: { - title: "test-template", - slug: "test-template", - description: "test", - tags: [], - layout: "static", - pageCategory: "slug" - } - }).then(([response]) => response.data.pageBuilder.createPageTemplate.data); - - await updatePageTemplate({ - id: pageTemplate.id, - data: { - content: simplePageTemplateContent - } - }); - - const pageCreatedFromTemplate = await createPageFromTemplate({ - category: "slug", - templateId: pageTemplate.id, - meta: { - location: { - folderId: "root" - } - } - }).then(([response]) => response.data.pageBuilder.createPageFromTemplate.data); - - // Update values of "Heading text" and "Paragraph text" variables. This how it's done in the page editor. - await updatePage({ - id: pageCreatedFromTemplate.id, - data: { - content: { - id: "lk81y1na", - type: "document", - data: { - template: { - variables: [ - { - blockId: "yAOxZQgZsv", - variables: [ - { - id: "aAUBVaa1fB", - type: "heading", - label: "Heading text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-HEADING","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - }, - { - id: "iwpP2qZAHy", - type: "paragraph", - label: "Paragraph text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-PARAGRAPH","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - ] - } - ] - } - }, - elements: [], - path: [] - } - } - }); - - // Unlinked page should no longer contain template variable-related data. - const unlinkedPage = await unlinkPageFromTemplate({ id: pageCreatedFromTemplate.id }).then( - ([response]) => response.data.pageBuilder.unlinkPageFromTemplate.data - ); - - expect(unlinkedPage.content).toMatchObject({ - id: "lk81y1na", - type: "document", - data: {}, - elements: [ - { - id: "yAOxZQgZsv", - type: "block", - data: { - variables: [] - }, - elements: [ - { - elements: [ - { - elements: [ - { - type: "heading", - data: { - text: { - data: { - text: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-HEADING","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - }, - variableId: "aAUBVaa1fB" - } - }, - { - type: "paragraph", - data: { - text: { - data: { - text: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-PARAGRAPH","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}' - } - } - } - } - ] - } - ] - } - ] - } - ] - }); - }); - - test("unlinking a page from a page template that contains a block should remove all template-related data", async () => { - await createCategory({ - data: { - slug: `slug`, - name: `name`, - url: `/some-url/`, - layout: `layout` - } - }); - - await createBlockCategory({ - data: { - slug: `block-category`, - name: `block-category-name`, - icon: `block-category-icon`, - description: `block-category-description` - } - }); - - const pageBlock = await createPageBlock({ - data: { - name: "New block", - blockCategory: "block-category", - content: simplePageBlockContent - } - }).then(([response]) => response.data.pageBuilder.createPageBlock.data); - - const pageTemplate = await createPageTemplate({ - data: { - title: "test-template", - slug: "test-template", - description: "test", - tags: [], - layout: "static", - pageCategory: "slug" - } - }).then(([response]) => response.data.pageBuilder.createPageTemplate.data); - - // Add block to the page template. - await updatePageTemplate({ - id: pageTemplate.id, - data: { - content: { - id: "lkb798zg", - type: "document", - data: { - template: { - variables: [ - { - blockId: "DABBrS43HC", - variables: [] - } - ] - } - }, - elements: [ - { - id: "DABBrS43HC", - type: "block", - data: { - templateBlockId: "DABBrS43HC", - settings: { - width: { - desktop: { - value: "100%" - } - }, - margin: { - desktop: { - top: "0px", - right: "0px", - bottom: "0px", - left: "0px", - advanced: true - } - }, - padding: { - desktop: { - all: "10px" - } - }, - horizontalAlignFlex: { - desktop: "center" - }, - verticalAlign: { - desktop: "flex-start" - } - }, - variables: [], - blockId: pageBlock.id - }, - elements: [], - path: ["lkb798zg"] - } - ], - path: [] - } - } - }); - - const pageCreatedFromTemplate = await createPageFromTemplate({ - category: "slug", - templateId: pageTemplate.id, - meta: { - location: { - folderId: "root" - } - } - }).then(([response]) => response.data.pageBuilder.createPageFromTemplate.data); - - // Update values of "Heading text" and "Paragraph text" variables. This how it's done in the page editor. - await updatePage({ - id: pageCreatedFromTemplate.id, - data: { - content: { - id: "lkb798zg", - type: "document", - data: { - template: { - variables: [ - { - blockId: "DABBrS43HC", - variables: [ - { - id: "DABBrS43HC#FDEezrJ8NH", - label: "Heading text", - type: "heading", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-HEADING","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":null,"format":"","indent":0,"type":"root","version":1}}' - }, - { - id: "DABBrS43HC#SezNLOdXw3", - label: "Paragraph text", - type: "paragraph", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-PARAGRAPH","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":null,"format":"","indent":0,"type":"root","version":1}}' - } - ] - } - ], - slug: "test-template" - } - }, - elements: [], - path: [] - } - } - }); - - // Unlinked page should no longer contain template variable-related data. - const unlinkedPage = await unlinkPageFromTemplate({ id: pageCreatedFromTemplate.id }).then( - ([response]) => response.data.pageBuilder.unlinkPageFromTemplate.data - ); - - expect(unlinkedPage.content).toMatchObject({ - id: "lkb798zg", - type: "document", - data: {}, - elements: [ - { - id: "DABBrS43HC", - type: "block", - data: { - variables: [ - { - id: "DABBrS43HC#FDEezrJ8NH", - type: "heading", - label: "Heading text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-HEADING","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":null,"format":"","indent":0,"type":"root","version":1}}' - }, - { - id: "DABBrS43HC#SezNLOdXw3", - type: "paragraph", - label: "Paragraph text", - value: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-PARAGRAPH","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":null,"format":"","indent":0,"type":"root","version":1}}' - } - ], - blockId: pageBlock.id - }, - elements: [ - { - type: "grid", - elements: [ - { - type: "cell", - elements: [ - { - type: "heading", - data: { - text: { - desktop: { - type: "heading", - alignment: "left", - tag: "h1" - }, - data: { - text: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-HEADING","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading-element","version":1,"tag":"h1","styles":[{"styleId":"heading1","type":"typography"}]}],"direction":null,"format":"","indent":0,"type":"root","version":1}}' - } - }, - variableId: "DABBrS43HC#FDEezrJ8NH" - } - }, - { - type: "paragraph", - data: { - text: { - desktop: { - type: "paragraph", - alignment: "left", - tag: "p" - }, - data: { - text: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"UPDATED-PARAGRAPH","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"paragraph-element","version":1,"styles":[{"styleId":"paragraph1","type":"typography"}]}],"direction":null,"format":"","indent":0,"type":"root","version":1}}' - } - }, - variableId: "DABBrS43HC#SezNLOdXw3" - } - } - ] - } - ] - } - ] - } - ] - }); - }); -}); diff --git a/packages/api-page-builder/src/graphql/crud/pages.crud.ts b/packages/api-page-builder/src/graphql/crud/pages.crud.ts index 455895bf06f..7f8fb4a8e84 100644 --- a/packages/api-page-builder/src/graphql/crud/pages.crud.ts +++ b/packages/api-page-builder/src/graphql/crud/pages.crud.ts @@ -8,7 +8,6 @@ import { Page, PageBuilderContextObject, PageBuilderStorageOperations, - PageContentWithTemplate, PageElementProcessor, PagesCrud, PageStorageOperationsGetWhereParams, @@ -506,63 +505,6 @@ export const createPageCrud = (params: CreatePageCrudParams): PagesCrud => { } }, - async unlinkPageFromTemplate(this: PageBuilderContextObject, id): Promise { - const page = await this.getPage(id); - if (!page) { - throw new NotFoundError(`Page not found.`); - } - - if (!page.content?.data.template) { - throw new WebinyError( - "Cannot continue because the page is not linked to a template." - ); - } - - const resolvedPageElements = await context.pageBuilder.resolvePageTemplate( - page.content as PageContentWithTemplate - ); - - // Run element processors on the full page content for potential transformations. - const processedPage = await context.pageBuilder.processPageContent({ - ...page, - content: { ...page.content, elements: resolvedPageElements } - }); - - // Delete template-related data. - const allTemplateVariableIds = processedPage - .content!.data.template.variables.map((variablesForBlock: Record) => { - return variablesForBlock.variables.map((v: Record) => v.id); - }) - .flat(); - - for (let i = 0; i < processedPage.content!.elements.length; i++) { - const blockElement = processedPage.content!.elements[i]; - - if ("templateBlockId" in blockElement.data) { - delete blockElement.data.templateBlockId; - - // In the presence of a block ID, we know that this block is not a template block. - // Variable values need to stay intact. - if (blockElement.data.blockId) { - continue; - } - - // Let's delete all template-related variables on block. - if (Array.isArray(blockElement.data.variables)) { - blockElement.data.variables = blockElement.data.variables.filter( - (variable: Record) => - !allTemplateVariableIds.includes(variable.id) - ); - } - } - } - - // Delete base template-related data. - delete processedPage.content!.data.template; - - return this.updatePage(id, processedPage); - }, - async updatePage(id, input): Promise { await pagesPermissions.ensure({ rwd: "w" }); diff --git a/packages/api-page-builder/src/graphql/graphql/pages.gql.ts b/packages/api-page-builder/src/graphql/graphql/pages.gql.ts index 54bef647fbf..89a4fb86a14 100644 --- a/packages/api-page-builder/src/graphql/graphql/pages.gql.ts +++ b/packages/api-page-builder/src/graphql/graphql/pages.gql.ts @@ -244,8 +244,6 @@ const createBasePageGraphQL = (): GraphQLSchemaPlugin => { # Duplicate page by given ID. duplicatePage(id: ID!, meta: JSON): PbPageResponse - unlinkPageFromTemplate(id: ID!): PbPageResponse - # Publish page publishPage(id: ID!): PbPageResponse @@ -499,12 +497,6 @@ const createBasePageGraphQL = (): GraphQLSchemaPlugin => { } }, - unlinkPageFromTemplate: async (_, args: any, context) => { - return resolve(() => { - return context.pageBuilder.unlinkPageFromTemplate(args.id); - }); - }, - publishPage: async (_, args: any, context) => { return resolve(() => context.pageBuilder.publishPage(args.id)); }, diff --git a/packages/api-page-builder/src/graphql/types.ts b/packages/api-page-builder/src/graphql/types.ts index fe1d0cf352d..99d11b1a79e 100644 --- a/packages/api-page-builder/src/graphql/types.ts +++ b/packages/api-page-builder/src/graphql/types.ts @@ -215,7 +215,6 @@ export interface PagesCrud { page: string, meta?: Record ): Promise; - unlinkPageFromTemplate(id: string): Promise; updatePage(id: string, data: PbUpdatePageInput): Promise; deletePage(id: string): Promise<[TPage, TPage]>; publishPage(id: string): Promise; diff --git a/packages/app-page-builder/src/pageEditor/config/Toolbar/InjectVariableValuesIntoElement.ts b/packages/app-page-builder/src/pageEditor/config/Toolbar/InjectVariableValuesIntoElement.ts new file mode 100644 index 00000000000..06e75b37d3a --- /dev/null +++ b/packages/app-page-builder/src/pageEditor/config/Toolbar/InjectVariableValuesIntoElement.ts @@ -0,0 +1,39 @@ +import { plugins } from "@webiny/plugins"; +import { PbBlockVariable, PbEditorPageElementVariableRendererPlugin, PbElement } from "~/types"; + +export class InjectVariableValuesIntoElement { + private elementVariablePlugins: PbEditorPageElementVariableRendererPlugin[]; + + constructor() { + this.elementVariablePlugins = plugins.byType( + "pb-editor-page-element-variable-renderer" + ); + } + execute(element: PbElement, variables: PbBlockVariable[]): PbElement { + element.elements = element.elements.map(element => { + const { variableId } = element.data; + + if (variableId) { + const elementVariables = + variables.filter(variable => variable.id.split(".")[0] === variableId) || []; + + const elementVariablePlugin = this.elementVariablePlugins.find( + plugin => plugin.elementType === element.type + ); + + if (elementVariablePlugin) { + // we need to replace element value with the one from variables before removing variableId + element = elementVariablePlugin.setElementValue(element, elementVariables); + } + } + + if (element.elements && element.elements.length) { + return this.execute(element, variables); + } + + return element; + }); + + return element; + } +} diff --git a/packages/app-page-builder/src/pageEditor/config/Toolbar/UnlinkPageFromTemplate.ts b/packages/app-page-builder/src/pageEditor/config/Toolbar/UnlinkPageFromTemplate.ts new file mode 100644 index 00000000000..52215b93a1a --- /dev/null +++ b/packages/app-page-builder/src/pageEditor/config/Toolbar/UnlinkPageFromTemplate.ts @@ -0,0 +1,29 @@ +import { PbEditorElement, PbElement } from "~/types"; +import { InjectVariableValuesIntoElement } from "~/pageEditor/config/Toolbar/InjectVariableValuesIntoElement"; + +export class UnlinkPageFromTemplate { + execute(content: PbEditorElement) { + const newContent = structuredClone(content); + const injectVariableValues = new InjectVariableValuesIntoElement(); + + const unlinkedBlocks = (newContent.elements as PbElement[]).map(block => { + delete block.data["templateBlockId"]; + + if (block.data.blockId) { + return block; + } + + const blockVariables = block.data.variables || []; + + const blockWithValues = injectVariableValues.execute(block, blockVariables); + + delete blockWithValues.data["variables"]; + + return blockWithValues; + }); + + delete newContent.data["template"]; + + return { ...newContent, elements: unlinkedBlocks }; + } +} diff --git a/packages/app-page-builder/src/pageEditor/config/Toolbar/UnlinkTemplate.tsx b/packages/app-page-builder/src/pageEditor/config/Toolbar/UnlinkTemplate.tsx index 1a560b38a77..672177bda00 100644 --- a/packages/app-page-builder/src/pageEditor/config/Toolbar/UnlinkTemplate.tsx +++ b/packages/app-page-builder/src/pageEditor/config/Toolbar/UnlinkTemplate.tsx @@ -1,13 +1,13 @@ import React, { useCallback, useState } from "react"; import { css } from "emotion"; -import { useMutation } from "@apollo/react-hooks"; import { IconButton, ButtonPrimary } from "@webiny/ui/Button"; import { Dialog, DialogCancel, DialogTitle, DialogActions, DialogContent } from "@webiny/ui/Dialog"; import { ReactComponent as LockIcon } from "@material-design-icons/svg/outlined/lock.svg"; import { useTemplateMode } from "~/pageEditor/hooks/useTemplateMode"; import { usePage } from "~/pageEditor/hooks/usePage"; -import { UNLINK_PAGE_FROM_TEMPLATE } from "~/pageEditor/graphql"; import { PageEditorConfig } from "~/pageEditor/editorConfig/PageEditorConfig"; +import { useEventActionHandler, useUpdateElement } from "~/editor"; +import { UnlinkPageFromTemplate } from "~/pageEditor/config/Toolbar/UnlinkPageFromTemplate"; const unlinkTemplateDialog = css` & .mdc-dialog__surface { @@ -36,10 +36,11 @@ const unlinkTemplateDialog = css` const UnlinkTemplateAction = () => { const [isModalShown, setIsModalShown] = useState(false); - const [unlinkPage, unlinkPageMutation] = useMutation(UNLINK_PAGE_FROM_TEMPLATE); + const [updatingPage, setUpdatingPage] = useState(false); + const { getRawElementTree } = useEventActionHandler(); + const updateElement = useUpdateElement(); const [page] = usePage(); - const onOpen = useCallback(() => { setIsModalShown(true); }, []); @@ -48,13 +49,17 @@ const UnlinkTemplateAction = () => { setIsModalShown(false); }, []); - const onUnlink = useCallback(() => { - unlinkPage({ - variables: { id: page.id } - }).then(() => { - // TODO: We do a screen refresh just because of some weird state inconsistency-related - // TODO: issue. Should fix this when there's more time at hand. - window.location.reload(); + const onUnlink = useCallback(async () => { + const content = await getRawElementTree(); + const unlinkPageFromTemplate = new UnlinkPageFromTemplate(); + const unlinkedContent = unlinkPageFromTemplate.execute(content); + + setUpdatingPage(true); + updateElement(unlinkedContent, { + history: true, + onFinish: () => { + window.location.reload(); + } }); }, [page.id]); @@ -75,7 +80,7 @@ const UnlinkTemplateAction = () => { Cancel - + Unlink template diff --git a/packages/app-page-builder/src/pageEditor/graphql.ts b/packages/app-page-builder/src/pageEditor/graphql.ts index 848189c6b36..e353bc711e3 100644 --- a/packages/app-page-builder/src/pageEditor/graphql.ts +++ b/packages/app-page-builder/src/pageEditor/graphql.ts @@ -88,15 +88,3 @@ export const GET_PAGE = gql` } } `; - -export const UNLINK_PAGE_FROM_TEMPLATE = gql` - mutation UnlinkPageFromTemplate($id: ID!) { - pageBuilder { - unlinkPageFromTemplate(id: $id) { - data { - content - } - } - } - } -`;