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..518c893c4f8d 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 @@ -22,6 +22,7 @@ import { DotRouterService } from '@dotcms/data-access'; import { CoreWebService, LoginService } from '@dotcms/dotcms-js'; +import { DotPageRender } from '@dotcms/dotcms-models'; import { TemplateBuilderComponent, TemplateBuilderModule } from '@dotcms/template-builder'; import { DotExperimentsServiceMock, @@ -33,8 +34,36 @@ 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<EditEmaLayoutComponent>; let component: EditEmaLayoutComponent; @@ -72,32 +101,7 @@ describe('EditEmaLayoutComponent', () => { provide: DotPageApiService, useValue: { get: () => { - return of({ - containers: {}, - page: { - identifier: 'test' - }, - template: { - theme: 'testTheme' - }, - layout: { - body: { - rows: [ - { - columns: [ - { - containers: [ - { - identifier: 'test' - } - ] - } - ] - } - ] - } - } - }); + return of(PAGE_RESPONSE); } } }, @@ -136,7 +140,7 @@ describe('EditEmaLayoutComponent', () => { spectator = createComponent(); component = spectator.component; dotRouter = spectator.inject(DotRouterService); - store = spectator.inject(UVEStore); + store = spectator.inject(UVEStore, true); layoutService = spectator.inject(DotPageLayoutService); messageService = spectator.inject(MessageService); @@ -166,12 +170,18 @@ describe('EditEmaLayoutComponent', () => { }); it('should trigger a save after 5 secs', fakeAsync(() => { - const layoutServiceSave = jest.spyOn(layoutService, 'save'); + const layoutServiceSave = jest + .spyOn(layoutService, 'save') + .mockReturnValue(of(PAGE_RESPONSE as unknown as DotPageRender)); + const updatePageResponseSpy = jest.spyOn(store, 'updatePageResponse'); + const setUveStatusSpy = jest.spyOn(store, 'setUveStatus'); templateBuilder.templateChange.emit(); tick(5000); expect(layoutServiceSave).toHaveBeenCalled(); + expect(updatePageResponseSpy).toHaveBeenCalledWith(PAGE_RESPONSE); + expect(setUveStatusSpy).toHaveBeenCalledWith(UVE_STATUS.LOADING); expect(addMock).toHaveBeenNthCalledWith(1, { severity: 'info', 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 875de3ea4c97..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 @@ -143,8 +143,7 @@ export class EditEmaLayoutComponent implements OnInit, OnDestroy { * * @private * @template T - * // To not get the error of the type with DotPageRender and DotPageApiResponse - * @param {T=unkonwm} page + * @param {T=unkonwm} page // To avoid getting type error with DotPageRender and DotPageApiResponse * @memberof EditEmaLayoutComponent */ private handleSuccessSaveTemplate<T = unknown>(page: T): void { 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/features/layout/models.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/layout/models.ts index 99125af5681e..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,7 +6,7 @@ export interface LayoutProps { template: { identifier: string; themeId: string; - anonymous: boolean; + anonymous?: boolean; }; pageId: string; } 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 222a327c5f4f..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 @@ -397,11 +397,11 @@ export class DotTemplateBuilderStore extends ComponentStore<DotTemplateBuilderSt { newRows, templateIdentifier, - isAnonymousTemplate + isAnonymousTemplate = false }: { newRows: DotGridStackWidget[]; templateIdentifier: string; - isAnonymousTemplate: boolean; + isAnonymousTemplate?: boolean; } ) => { const { rows: oldRows } = state;