From 14609ff49fc6ba1d5165a34448ebcdace048aab9 Mon Sep 17 00:00:00 2001 From: Rafael Velazco Date: Fri, 23 Aug 2024 11:27:30 -0400 Subject: [PATCH] fix(UVE): update page after changing template (#29695) ### Proposed Changes * Update page after changing template ### Checklist - [x] Tests ### Video #### Before https://github.com/user-attachments/assets/930d66f8-8971-4341-ac63-74ce46d6e53c #### After https://github.com/user-attachments/assets/59e42ca3-dec7-422b-88d1-9af2176b2e2d --- .../dot-ema-shell.component.spec.ts | 3 +- .../edit-ema-layout.component.spec.ts | 161 +++++++-------- .../edit-ema-layout.component.ts | 16 +- .../edit-ema/portlet/src/lib/shared/mocks.ts | 83 ++++---- .../src/lib/store/dot-uve.store.spec.ts | 41 +++- .../portlet/src/lib/store/dot-uve.store.ts | 153 ++++++++------- .../src/lib/store/features/layout/models.ts | 1 + .../lib/store/features/layout/withLayout.ts | 3 +- .../store/template-builder.store.spec.ts | 184 ++++++++++-------- .../store/template-builder.store.ts | 7 +- .../template-builder.component.ts | 5 +- 11 files changed, 364 insertions(+), 293 deletions(-) diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/dot-ema-shell/dot-ema-shell.component.spec.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/dot-ema-shell/dot-ema-shell.component.spec.ts index 4324eb94c300..c0652e706215 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/dot-ema-shell/dot-ema-shell.component.spec.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/dot-ema-shell/dot-ema-shell.component.spec.ts @@ -243,7 +243,8 @@ describe('DotEmaShellComponent', () => { { icon: 'pi-ellipsis-v', label: 'editema.editor.navbar.properties', - id: 'properties' + id: 'properties', + isDisabled: false } ]); }); diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-layout/edit-ema-layout.component.spec.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-layout/edit-ema-layout.component.spec.ts index f6e765bf286d..07b4fcd9648b 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-layout/edit-ema-layout.component.spec.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-layout/edit-ema-layout.component.spec.ts @@ -1,7 +1,7 @@ import { expect, describe } from '@jest/globals'; import { SpyObject } from '@ngneat/spectator'; import { Spectator, createComponentFactory, mockProvider } from '@ngneat/spectator/jest'; -import { MockModule } from 'ng-mocks'; +import { MockModule, MockProvider } from 'ng-mocks'; import { of } from 'rxjs'; import { HttpClientTestingModule } from '@angular/common/http/testing'; @@ -33,17 +33,44 @@ import { EditEmaLayoutComponent } from './edit-ema-layout.component'; import { DotActionUrlService } from '../services/dot-action-url/dot-action-url.service'; import { DotPageApiService } from '../services/dot-page-api.service'; +import { UVE_STATUS } from '../shared/enums'; import { UVEStore } from '../store/dot-uve.store'; +const PAGE_RESPONSE = { + containers: {}, + page: { + identifier: 'test' + }, + template: { + theme: 'testTheme' + }, + layout: { + body: { + rows: [ + { + columns: [ + { + containers: [ + { + identifier: 'test' + } + ] + } + ] + } + ] + } + } +}; + describe('EditEmaLayoutComponent', () => { let spectator: Spectator; let component: EditEmaLayoutComponent; let dotRouter: SpyObject; let store: SpyObject>; let templateBuilder: TemplateBuilderComponent; - let layoutService: DotPageLayoutService; + let dotPageLayoutService: DotPageLayoutService; let messageService: MessageService; - let addMock: jest.SpyInstance; globalThis.structuredClone = jest.fn().mockImplementation((obj) => obj); @@ -52,83 +79,43 @@ describe('EditEmaLayoutComponent', () => { imports: [HttpClientTestingModule, MockModule(TemplateBuilderModule)], providers: [ UVEStore, - MessageService, DotMessageService, DotActionUrlService, + mockProvider(MessageService), mockProvider(Router), mockProvider(ActivatedRoute), - { - provide: DotExperimentsService, - useValue: DotExperimentsServiceMock - }, - { provide: DotRouterService, useValue: new MockDotRouterJestService(jest) }, - { - provide: DotLicenseService, - useValue: { - isEnterprise: () => of(true) - } - }, - { - provide: DotPageApiService, - useValue: { - get: () => { - return of({ - containers: {}, - page: { - identifier: 'test' - }, - template: { - theme: 'testTheme' - }, - layout: { - body: { - rows: [ - { - columns: [ - { - containers: [ - { - identifier: 'test' - } - ] - } - ] - } - ] - } - } - }); - } - } - }, - { - provide: DotPageLayoutService, - useValue: { - save: () => { - return of({ - layout: {} - }); - } - } - }, mockProvider(DotContentTypeService), mockProvider(CoreWebService), - { - provide: DotLanguagesService, - useValue: new DotLanguagesServiceMock() - }, - { - provide: DotContentletLockerService, - useValue: { + mockProvider(DotPageLayoutService, { + save: jest.fn(() => of(PAGE_RESPONSE)) + }), + mockProvider(DotPageApiService, { + get: jest.fn(() => of(PAGE_RESPONSE)) + }), + MockProvider(DotExperimentsService, DotExperimentsServiceMock, 'useValue'), + MockProvider(DotRouterService, new MockDotRouterJestService(jest), 'useValue'), + MockProvider(DotLanguagesService, new DotLanguagesServiceMock(), 'useValue'), + MockProvider( + DotLicenseService, + { + isEnterprise: () => of(true) + }, + 'useValue' + ), + MockProvider( + DotContentletLockerService, + { unlock: (_inode: string) => of({}) - } - }, - { - provide: LoginService, - useValue: { + }, + 'useValue' + ), + MockProvider( + LoginService, + { getCurrentUser: () => of({}) - } - } + }, + 'useValue' + ) ] }); @@ -136,12 +123,10 @@ describe('EditEmaLayoutComponent', () => { spectator = createComponent(); component = spectator.component; dotRouter = spectator.inject(DotRouterService); - store = spectator.inject(UVEStore); - layoutService = spectator.inject(DotPageLayoutService); + store = spectator.inject(UVEStore, true); + dotPageLayoutService = spectator.inject(DotPageLayoutService); messageService = spectator.inject(MessageService); - addMock = jest.spyOn(messageService, 'add'); - store.load({ clientHost: 'http://localhost:3000', language_id: '1', @@ -158,29 +143,29 @@ describe('EditEmaLayoutComponent', () => { describe('Template Change', () => { it('should forbid navigation', () => { - const spy = jest.spyOn(dotRouter, 'forbidRouteDeactivation'); - templateBuilder.templateChange.emit(); - - expect(spy).toHaveBeenCalled(); + expect(dotRouter.forbidRouteDeactivation).toHaveBeenCalled(); }); it('should trigger a save after 5 secs', fakeAsync(() => { - const layoutServiceSave = jest.spyOn(layoutService, 'save'); + const updatePageResponseSpy = jest.spyOn(store, 'updatePageResponse'); + const setUveStatusSpy = jest.spyOn(store, 'setUveStatus'); templateBuilder.templateChange.emit(); tick(5000); - expect(layoutServiceSave).toHaveBeenCalled(); + expect(dotPageLayoutService.save).toHaveBeenCalled(); + expect(updatePageResponseSpy).toHaveBeenCalledWith(PAGE_RESPONSE); + expect(setUveStatusSpy).toHaveBeenCalledWith(UVE_STATUS.LOADING); - expect(addMock).toHaveBeenNthCalledWith(1, { + expect(messageService.add).toHaveBeenNthCalledWith(1, { severity: 'info', summary: 'Info', detail: 'dot.common.message.saving', life: 1000 }); - expect(addMock).toHaveBeenNthCalledWith(2, { + expect(messageService.add).toHaveBeenNthCalledWith(2, { severity: 'success', summary: 'Success', detail: 'dot.common.message.saved' @@ -188,12 +173,10 @@ describe('EditEmaLayoutComponent', () => { })); it('should unlock navigation after saving', fakeAsync(() => { - const allowRouting = jest.spyOn(dotRouter, 'allowRouteDeactivation'); - templateBuilder.templateChange.emit(); tick(6000); - expect(allowRouting).toHaveBeenCalled(); + expect(dotRouter.allowRouteDeactivation).toHaveBeenCalled(); })); it('should save right away if we request page leave before the 5 secs', () => { @@ -205,14 +188,14 @@ describe('EditEmaLayoutComponent', () => { expect(saveTemplate).toHaveBeenCalled(); - expect(addMock).toHaveBeenNthCalledWith(1, { + expect(messageService.add).toHaveBeenNthCalledWith(1, { severity: 'info', summary: 'Info', detail: 'dot.common.message.saving', life: 1000 }); - expect(addMock).toHaveBeenNthCalledWith(2, { + expect(messageService.add).toHaveBeenNthCalledWith(2, { severity: 'success', summary: 'Success', detail: 'dot.common.message.saved' diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-layout/edit-ema-layout.component.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-layout/edit-ema-layout.component.ts index fc536106e4fd..90cfa2ac5d37 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-layout/edit-ema-layout.component.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-layout/edit-ema-layout.component.ts @@ -12,13 +12,16 @@ import { finalize, switchMap, take, - takeUntil + takeUntil, + tap } from 'rxjs/operators'; import { DotMessageService, DotPageLayoutService, DotRouterService } from '@dotcms/data-access'; import { DotPageRender, DotTemplateDesigner } from '@dotcms/dotcms-models'; import { TemplateBuilderModule } from '@dotcms/template-builder'; +import { DotPageApiResponse } from '../services/dot-page-api.service'; +import { UVE_STATUS } from '../shared/enums'; import { UVEStore } from '../store/dot-uve.store'; export const DEBOUNCE_TIME = 5000; @@ -110,6 +113,7 @@ export class EditEmaLayoutComponent implements OnInit, OnDestroy { .pipe( // debounceTime should be before takeUntil to avoid calling the observable after unsubscribe. // More information: https://stackoverflow.com/questions/58974320/how-is-it-possible-to-stop-a-debounced-rxjs-observable + tap(() => this.uveStore.setUveStatus(UVE_STATUS.LOADING)), // Prevent the user to access page properties debounceTime(DEBOUNCE_TIME), takeUntil(this.destroy$), switchMap((layout: DotTemplateDesigner) => { @@ -138,17 +142,17 @@ export class EditEmaLayoutComponent implements OnInit, OnDestroy { * Handle the success save template * * @private - * @param {DotPageRender} _ + * @template T + * @param {T=unkonwm} page // To avoid getting type error with DotPageRender and DotPageApiResponse * @memberof EditEmaLayoutComponent */ - private handleSuccessSaveTemplate(page: DotPageRender): void { + private handleSuccessSaveTemplate(page: T): void { this.messageService.add({ severity: 'success', summary: 'Success', detail: this.dotMessageService.get('dot.common.message.saved') }); - - this.uveStore.updateLayout(page.layout); + this.uveStore.updatePageResponse(page as DotPageApiResponse); } /** @@ -164,6 +168,8 @@ export class EditEmaLayoutComponent implements OnInit, OnDestroy { summary: 'Error', detail: this.dotMessageService.get('dot.common.http.error.400.message') }); + + this.uveStore.setUveStatus(UVE_STATUS.ERROR); } /** diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/shared/mocks.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/shared/mocks.ts index 040b67f851a4..5150520af676 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/shared/mocks.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/shared/mocks.ts @@ -669,6 +669,48 @@ export const ACTION_PAYLOAD_MOCK: ActionPayload = { position: 'after' }; +export const BASE_SHELL_ITEMS = [ + { + icon: 'pi-file', + label: 'editema.editor.navbar.content', + href: 'content', + id: 'content' + }, + { + icon: 'pi-table', + label: 'editema.editor.navbar.layout', + href: 'layout', + id: 'layout', + isDisabled: false, + tooltip: null + }, + { + icon: 'pi-sliders-h', + label: 'editema.editor.navbar.rules', + id: 'rules', + href: `rules/${MOCK_RESPONSE_HEADLESS.page.identifier}`, + isDisabled: false + }, + { + iconURL: 'experiments', + label: 'editema.editor.navbar.experiments', + href: `experiments/${MOCK_RESPONSE_HEADLESS.page.identifier}`, + id: 'experiments', + isDisabled: false + }, + { + icon: 'pi-th-large', + label: 'editema.editor.navbar.page-tools', + id: 'page-tools' + }, + { + icon: 'pi-ellipsis-v', + label: 'editema.editor.navbar.properties', + id: 'properties', + isDisabled: false + } +]; + export const BASE_SHELL_PROPS_RESPONSE = { canRead: true, error: null, @@ -683,46 +725,7 @@ export const BASE_SHELL_PROPS_RESPONSE = { currentUrl: '/test-url', requestHostName: 'http://localhost:3000' }, - items: [ - { - icon: 'pi-file', - label: 'editema.editor.navbar.content', - href: 'content', - id: 'content' - }, - { - icon: 'pi-table', - label: 'editema.editor.navbar.layout', - href: 'layout', - id: 'layout', - isDisabled: false, - tooltip: null - }, - { - icon: 'pi-sliders-h', - label: 'editema.editor.navbar.rules', - id: 'rules', - href: `rules/${MOCK_RESPONSE_HEADLESS.page.identifier}`, - isDisabled: false - }, - { - iconURL: 'experiments', - label: 'editema.editor.navbar.experiments', - href: `experiments/${MOCK_RESPONSE_HEADLESS.page.identifier}`, - id: 'experiments', - isDisabled: false - }, - { - icon: 'pi-th-large', - label: 'editema.editor.navbar.page-tools', - id: 'page-tools' - }, - { - icon: 'pi-ellipsis-v', - label: 'editema.editor.navbar.properties', - id: 'properties' - } - ] + items: BASE_SHELL_ITEMS }; export const UVE_PAGE_RESPONSE_MAP = { diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/dot-uve.store.spec.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/dot-uve.store.spec.ts index 51740db95e2a..2b902d93dc3a 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/dot-uve.store.spec.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/dot-uve.store.spec.ts @@ -40,6 +40,7 @@ import { EDITOR_STATE, UVE_STATUS } from '../shared/enums'; import { ACTION_MOCK, ACTION_PAYLOAD_MOCK, + BASE_SHELL_ITEMS, BASE_SHELL_PROPS_RESPONSE, EMA_DRAG_ITEM_CONTENTLET_MOCK, getBoundsMock, @@ -166,6 +167,23 @@ describe('UVEStore', () => { it('should return the shell props for Headless Pages', () => { expect(store.$shellProps()).toEqual(BASE_SHELL_PROPS_RESPONSE); }); + it('should return the shell props with property item disable when loading', () => { + store.setUveStatus(UVE_STATUS.LOADING); + const baseItems = BASE_SHELL_ITEMS.slice(0, BASE_SHELL_ITEMS.length - 1); + + expect(store.$shellProps()).toEqual({ + ...BASE_SHELL_PROPS_RESPONSE, + items: [ + ...baseItems, + { + icon: 'pi-ellipsis-v', + label: 'editema.editor.navbar.properties', + id: 'properties', + isDisabled: true + } + ] + }); + }); it('should return the error for 404', () => { patchState(store, { errorCode: 404 }); @@ -258,7 +276,8 @@ describe('UVEStore', () => { { icon: 'pi-ellipsis-v', label: 'editema.editor.navbar.properties', - id: 'properties' + id: 'properties', + isDisabled: false } ] }); @@ -337,6 +356,23 @@ describe('UVEStore', () => { expect(store.status()).toBe(UVE_STATUS.LOADING); }); }); + + describe('updatePageResponse', () => { + it('should update the page response', () => { + const pageAPIResponse = { + ...MOCK_RESPONSE_HEADLESS, + page: { + ...MOCK_RESPONSE_HEADLESS.page, + title: 'New title' + } + }; + + store.updatePageResponse(pageAPIResponse); + + expect(store.pageAPIResponse()).toEqual(pageAPIResponse); + expect(store.status()).toBe(UVE_STATUS.LOADED); + }); + }); }); describe('withLoad', () => { @@ -556,7 +592,8 @@ describe('UVEStore', () => { layout: MOCK_RESPONSE_HEADLESS.layout, template: { identifier: MOCK_RESPONSE_HEADLESS.template.identifier, - themeId: MOCK_RESPONSE_HEADLESS.template.theme + themeId: MOCK_RESPONSE_HEADLESS.template.theme, + anonymous: false }, pageId: MOCK_RESPONSE_HEADLESS.page.identifier }); diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/dot-uve.store.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/dot-uve.store.ts index f5997118cb22..80506a47c69f 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/dot-uve.store.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/dot-uve.store.ts @@ -7,6 +7,7 @@ import { withLayout } from './features/layout/withLayout'; import { withLoad } from './features/load/withLoad'; import { ShellProps, UVEState } from './models'; +import { DotPageApiResponse } from '../services/dot-page-api.service'; import { UVE_STATUS } from '../shared/enums'; import { getErrorPayload, getRequestHostName, sanitizeURL } from '../utils'; @@ -26,92 +27,102 @@ const initialState: UVEState = { export const UVEStore = signalStore( withState(initialState), - withComputed(({ pageAPIResponse, isTraditionalPage, params, languages, errorCode: error }) => { - return { - $shellProps: computed(() => { - const response = pageAPIResponse(); + withComputed( + ({ pageAPIResponse, isTraditionalPage, params, languages, errorCode: error, status }) => { + return { + $shellProps: computed(() => { + const response = pageAPIResponse(); - const currentUrl = '/' + sanitizeURL(response?.page.pageURI); + const currentUrl = '/' + sanitizeURL(response?.page.pageURI); - const requestHostName = getRequestHostName(isTraditionalPage(), params()); + const requestHostName = getRequestHostName(isTraditionalPage(), params()); - const page = response?.page; - const templateDrawed = response?.template.drawed; + const page = response?.page; + const templateDrawed = response?.template.drawed; - const isLayoutDisabled = !page?.canEdit || !templateDrawed; + const isLayoutDisabled = !page?.canEdit || !templateDrawed; - const languageId = response?.viewAs.language?.id; - const translatedLanguages = languages(); - const errorCode = error(); + const languageId = response?.viewAs.language?.id; + const translatedLanguages = languages(); + const errorCode = error(); - const errorPayload = getErrorPayload(errorCode); + const errorPayload = getErrorPayload(errorCode); + const isLoading = status() === UVE_STATUS.LOADING; - return { - canRead: page?.canRead, - error: errorPayload, - translateProps: { - page, - languageId, - languages: translatedLanguages - }, - seoParams: { - siteId: response?.site?.identifier, - languageId: response?.viewAs.language.id, - currentUrl, - requestHostName - }, - items: [ - { - icon: 'pi-file', - label: 'editema.editor.navbar.content', - href: 'content', - id: 'content' - }, - { - icon: 'pi-table', - label: 'editema.editor.navbar.layout', - href: 'layout', - id: 'layout', - isDisabled: isLayoutDisabled, - tooltip: templateDrawed - ? null - : 'editema.editor.navbar.layout.tooltip.cannot.edit.advanced.template' - }, - { - icon: 'pi-sliders-h', - label: 'editema.editor.navbar.rules', - id: 'rules', - href: `rules/${page?.identifier}`, - isDisabled: !page?.canEdit - }, - { - iconURL: 'experiments', - label: 'editema.editor.navbar.experiments', - href: `experiments/${page?.identifier}`, - id: 'experiments', - isDisabled: !page?.canEdit + return { + canRead: page?.canRead, + error: errorPayload, + translateProps: { + page, + languageId, + languages: translatedLanguages }, - { - icon: 'pi-th-large', - label: 'editema.editor.navbar.page-tools', - id: 'page-tools' + seoParams: { + siteId: response?.site?.identifier, + languageId: response?.viewAs.language.id, + currentUrl, + requestHostName }, - { - icon: 'pi-ellipsis-v', - label: 'editema.editor.navbar.properties', - id: 'properties' - } - ] - }; - }) - }; - }), + items: [ + { + icon: 'pi-file', + label: 'editema.editor.navbar.content', + href: 'content', + id: 'content' + }, + { + icon: 'pi-table', + label: 'editema.editor.navbar.layout', + href: 'layout', + id: 'layout', + isDisabled: isLayoutDisabled, + tooltip: templateDrawed + ? null + : 'editema.editor.navbar.layout.tooltip.cannot.edit.advanced.template' + }, + { + icon: 'pi-sliders-h', + label: 'editema.editor.navbar.rules', + id: 'rules', + href: `rules/${page?.identifier}`, + isDisabled: !page?.canEdit + }, + { + iconURL: 'experiments', + label: 'editema.editor.navbar.experiments', + href: `experiments/${page?.identifier}`, + id: 'experiments', + isDisabled: !page?.canEdit + }, + { + icon: 'pi-th-large', + label: 'editema.editor.navbar.page-tools', + id: 'page-tools' + }, + { + icon: 'pi-ellipsis-v', + label: 'editema.editor.navbar.properties', + id: 'properties', + isDisabled: isLoading + } + ] + }; + }) + }; + } + ), withMethods((store) => { return { setUveStatus(status: UVE_STATUS) { patchState(store, { status }); + }, + updatePageResponse(pageAPIResponse: DotPageApiResponse) { + patchState(store, { + status: UVE_STATUS.LOADED, + pageAPIResponse + }); } }; }), diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/models.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/models.ts index 07138790e8a0..1184a5cf5dd9 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/models.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/models.ts @@ -6,6 +6,7 @@ export interface LayoutProps { template: { identifier: string; themeId: string; + anonymous?: boolean; }; pageId: string; } diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/withLayout.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/withLayout.ts index 730f90972478..8522a92ac46d 100644 --- a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/withLayout.ts +++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/withLayout.ts @@ -32,7 +32,8 @@ export function withLayout() { template: { identifier: response?.template.identifier, // The themeId should be here, in the old store we had a bad reference and we were saving all the templates with themeId undefined - themeId: response?.template.theme + themeId: response?.template.theme, + anonymous: response?.template?.anonymous || false }, pageId: response?.page.identifier }; diff --git a/core-web/libs/template-builder/src/lib/components/template-builder/store/template-builder.store.spec.ts b/core-web/libs/template-builder/src/lib/components/template-builder/store/template-builder.store.spec.ts index 1b2980bd2614..be65d5a110bf 100644 --- a/core-web/libs/template-builder/src/lib/components/template-builder/store/template-builder.store.spec.ts +++ b/core-web/libs/template-builder/src/lib/components/template-builder/store/template-builder.store.spec.ts @@ -30,6 +30,86 @@ global.structuredClone = jest.fn((val) => { return JSON.parse(JSON.stringify(val)); }); +// Here i just swapped the rows and changed the uuid as expected from the backend +const SWAPPED_ROWS_MOCK = [ + { + ...ROWS_MINIMAL_MOCK[1], + y: 0 // This sets the order of the rows + }, + { + ...ROWS_MINIMAL_MOCK[0], + y: 1 // This sets the order of the rows + } +]; + +// Update the containers uuid simulating the backend +const UPDATED_ROWS_MOCK: DotGridStackWidget[] = [ + { + ...ROWS_MINIMAL_MOCK[1], + id: 'random test 2', + y: 0, // This sets the order of the rows + subGridOpts: { + ...ROWS_MINIMAL_MOCK[1].subGridOpts, + children: ROWS_MINIMAL_MOCK[1].subGridOpts.children.map((col) => ({ + ...col, + id: 'hello there 2', + containers: col.containers.map((child, i) => ({ + ...child, + uuid: `${i + 1}` // 1 for the 0 index + })) + })) + } + }, + { + ...ROWS_MINIMAL_MOCK[0], + id: 'random test 1', + y: 1, // This sets the order of the rows + subGridOpts: { + ...ROWS_MINIMAL_MOCK[0].subGridOpts, + children: ROWS_MINIMAL_MOCK[0].subGridOpts.children.map((col) => ({ + ...col, + id: 'hello there 1', + containers: col.containers.map((child, i) => ({ + ...child, + uuid: `${i + 3}` // 1 for the 0 index and 2 for the first 2 containers + })) + })) + } + } +]; + +const RESULT_AFTER_MERGE_MOCK = [ + { + ...ROWS_MINIMAL_MOCK[1], + y: 0, // This sets the order of the rows + subGridOpts: { + ...ROWS_MINIMAL_MOCK[1].subGridOpts, + children: ROWS_MINIMAL_MOCK[1].subGridOpts.children.map((col) => ({ + ...col, + containers: col.containers.map((child, i) => ({ + ...child, + uuid: `${i + 1}` // 1 for the 0 index + })) + })) + } + }, + { + ...ROWS_MINIMAL_MOCK[0], + y: 1, // This sets the order of the rows + subGridOpts: { + ...ROWS_MINIMAL_MOCK[0].subGridOpts, + children: ROWS_MINIMAL_MOCK[0].subGridOpts.children.map((col) => ({ + ...col, + + containers: col.containers.map((child, i) => ({ + ...child, + uuid: `${i + 3}` // 1 for the 0 index and 2 for the first 2 containers + })) + })) + } + } +]; + describe('DotTemplateBuilderStore', () => { let service: DotTemplateBuilderStore; let rows$: Observable<{ rows: DotGridStackWidget[]; shouldEmit: boolean }>; @@ -519,89 +599,29 @@ describe('DotTemplateBuilderStore', () => { }); it('should update the rows with the new data', (done) => { - // Here i just swapped the rows and changed the uuid as expected from the backend - const swappedRows = [ - { - ...ROWS_MINIMAL_MOCK[1], - y: 0 // This sets the order of the rows - }, - { - ...ROWS_MINIMAL_MOCK[0], - y: 1 // This sets the order of the rows - } - ]; - - // Update the containers uuid simulating the backend - const updatedRows: DotGridStackWidget[] = [ - { - ...ROWS_MINIMAL_MOCK[1], - id: 'random test 2', - y: 0, // This sets the order of the rows - subGridOpts: { - ...ROWS_MINIMAL_MOCK[1].subGridOpts, - children: ROWS_MINIMAL_MOCK[1].subGridOpts.children.map((col) => ({ - ...col, - id: 'hello there 2', - containers: col.containers.map((child, i) => ({ - ...child, - uuid: `${i + 1}` // 1 for the 0 index - })) - })) - } - }, - { - ...ROWS_MINIMAL_MOCK[0], - id: 'random test 1', - y: 1, // This sets the order of the rows - subGridOpts: { - ...ROWS_MINIMAL_MOCK[0].subGridOpts, - children: ROWS_MINIMAL_MOCK[0].subGridOpts.children.map((col) => ({ - ...col, - id: 'hello there 1', - containers: col.containers.map((child, i) => ({ - ...child, - uuid: `${i + 3}` // 1 for the 0 index and 2 for the first 2 containers - })) - })) - } + service.setState({ + ...INITIAL_STATE_MOCK, + rows: SWAPPED_ROWS_MOCK, + layoutProperties: { + footer: false, + header: false, + sidebar: {} } - ]; + }); - const resultAfterMerge = [ - { - ...ROWS_MINIMAL_MOCK[1], - y: 0, // This sets the order of the rows - subGridOpts: { - ...ROWS_MINIMAL_MOCK[1].subGridOpts, - children: ROWS_MINIMAL_MOCK[1].subGridOpts.children.map((col) => ({ - ...col, - containers: col.containers.map((child, i) => ({ - ...child, - uuid: `${i + 1}` // 1 for the 0 index - })) - })) - } - }, - { - ...ROWS_MINIMAL_MOCK[0], - y: 1, // This sets the order of the rows - subGridOpts: { - ...ROWS_MINIMAL_MOCK[0].subGridOpts, - children: ROWS_MINIMAL_MOCK[0].subGridOpts.children.map((col) => ({ - ...col, + service.updateOldRows({ newRows: UPDATED_ROWS_MOCK, templateIdentifier: '111' }); - containers: col.containers.map((child, i) => ({ - ...child, - uuid: `${i + 3}` // 1 for the 0 index and 2 for the first 2 containers - })) - })) - } - } - ]; + rows$.subscribe(({ rows, shouldEmit }) => { + expect(rows).toEqual(RESULT_AFTER_MERGE_MOCK); + expect(shouldEmit).toEqual(false); + done(); + }); + }); + it('should update the rows with the new data - when is anonymous template (Custom)', (done) => { service.setState({ ...INITIAL_STATE_MOCK, - rows: swappedRows, + rows: SWAPPED_ROWS_MOCK, layoutProperties: { footer: false, header: false, @@ -609,16 +629,20 @@ describe('DotTemplateBuilderStore', () => { } }); - service.updateOldRows({ newRows: updatedRows, templateIdentifier: '111' }); + service.updateOldRows({ + newRows: UPDATED_ROWS_MOCK, + templateIdentifier: '11123', + isAnonymousTemplate: true + }); rows$.subscribe(({ rows, shouldEmit }) => { - expect(rows).toEqual(resultAfterMerge); + expect(rows).toEqual(RESULT_AFTER_MERGE_MOCK); expect(shouldEmit).toEqual(false); done(); }); }); - it('should replace the rows with the new data - when is diffrent template identifier', (done) => { + it('should replace the rows with the new data - when is diffent template identifier', (done) => { // Here i just swapped the rows and changed the uuid as expected from the backend const swappedRows = [ { diff --git a/core-web/libs/template-builder/src/lib/components/template-builder/store/template-builder.store.ts b/core-web/libs/template-builder/src/lib/components/template-builder/store/template-builder.store.ts index 9fe2f866d057..fd416417c283 100644 --- a/core-web/libs/template-builder/src/lib/components/template-builder/store/template-builder.store.ts +++ b/core-web/libs/template-builder/src/lib/components/template-builder/store/template-builder.store.ts @@ -396,15 +396,18 @@ export class DotTemplateBuilderStore extends ComponentStore { const { rows: oldRows } = state; - const shouldReplaceRows = state.templateIdentifier !== templateIdentifier; + const shouldReplaceRows = + state.templateIdentifier !== templateIdentifier && !isAnonymousTemplate; const newStateRows = shouldReplaceRows ? newRows diff --git a/core-web/libs/template-builder/src/lib/components/template-builder/template-builder.component.ts b/core-web/libs/template-builder/src/lib/components/template-builder/template-builder.component.ts index 4c7ded5bcc3e..5f9a56d7ca1e 100644 --- a/core-web/libs/template-builder/src/lib/components/template-builder/template-builder.component.ts +++ b/core-web/libs/template-builder/src/lib/components/template-builder/template-builder.component.ts @@ -236,10 +236,11 @@ export class TemplateBuilderComponent implements OnInit, AfterViewInit, OnDestro ngOnChanges(changes: SimpleChanges) { if (!changes.layout?.firstChange && changes.layout?.currentValue) { const parsedRows = parseFromDotObjectToGridStack(changes.layout.currentValue.body); + const currentTemplate = changes.template?.currentValue; this.store.updateOldRows({ newRows: parsedRows, - templateIdentifier: - changes.template?.currentValue.identifier || this.template.identifier + templateIdentifier: currentTemplate?.identifier || this.template.identifier, + isAnonymousTemplate: currentTemplate?.anonymous || this.template.anonymous // We createa a custom template for the page }); } }