Skip to content

Commit

Permalink
Fix #25375: Template Builder Fix Autosave Feature (#25389)
Browse files Browse the repository at this point in the history
* remove auto publish and save from template portlet

* fix save triggering on init

* fix autosave on leave for new template builder

* add test case

* fix broken tests

* enhance emit of changes

* solve feedback

* add destroy subject

* add test for emit changes

* fix console error

* solve feedback
  • Loading branch information
zJaaal committed Jul 7, 2023
1 parent e702b68 commit 09ca574
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 97 deletions.
Expand Up @@ -266,6 +266,34 @@ describe('DotEditLayoutComponent', () => {
expect(component.pageState).toEqual(new DotPageRender(mockDotRenderedPage()));
}));

it('should save the layout instantly when closeEditLayout is true', () => {
const res: DotPageRender = new DotPageRender(mockDotRenderedPage());
spyOn(dotPageLayoutService, 'save').and.returnValue(of(res));

layoutDesignerDe.triggerEventHandler('updateTemplate', {
themeId: '123',
layout: fakeLayout,
title: null
});

dotEditLayoutService.changeCloseEditLayoutState(true);

expect(dotGlobalMessageService.loading).toHaveBeenCalledWith('Saving');
expect(dotGlobalMessageService.success).toHaveBeenCalledWith('Saved');
expect(dotGlobalMessageService.error).not.toHaveBeenCalled();

expect(dotPageLayoutService.save).toHaveBeenCalledWith('123', {
themeId: '123',
layout: fakeLayout,
title: null
});
expect(dotTemplateContainersCacheService.set).toHaveBeenCalledWith({
'/default/': processedContainers[0].container,
'/banner/': processedContainers[1].container
});
expect(component.pageState).toEqual(new DotPageRender(mockDotRenderedPage()));
});

it('should not save the layout when observable is destroy', fakeAsync(() => {
const res: DotPageRender = new DotPageRender(mockDotRenderedPage());
spyOn(dotPageLayoutService, 'save').and.returnValue(of(res));
Expand Down
Expand Up @@ -41,6 +41,8 @@ export class DotEditLayoutComponent implements OnInit, OnDestroy {

@HostBinding('style.minWidth') width = '100%';

private lastLayout: DotTemplateDesigner;

constructor(
private route: ActivatedRoute,
private dotRouterService: DotRouterService,
Expand Down Expand Up @@ -69,6 +71,7 @@ export class DotEditLayoutComponent implements OnInit, OnDestroy {

this.saveTemplateDebounce();
this.apiLink = `api/v1/page/render${this.pageState.page.pageURI}?language_id=${this.pageState.page.languageId}`;
this.subscribeOnChangeBeforeLeaveHandler();
}

ngOnDestroy() {
Expand Down Expand Up @@ -122,6 +125,7 @@ export class DotEditLayoutComponent implements OnInit, OnDestroy {
nextUpdateTemplate(value: DotTemplateDesigner) {
this.canRouteBeDesativated(false);
this.updateTemplate.next(value);
this.lastLayout = value;
}

/**
Expand Down Expand Up @@ -215,4 +219,20 @@ export class DotEditLayoutComponent implements OnInit, OnDestroy {
{}
);
}

/**
* Handle save changes before leave
*
* @private
* @memberof DotEditLayoutComponent
*/
private subscribeOnChangeBeforeLeaveHandler(): void {
this.dotEditLayoutService.closeEditLayout$
.pipe(takeUntil(this.destroy$))
.subscribe((res) => {
if (res) {
this.onSave(this.lastLayout);
}
});
}
}
@@ -1,14 +1,14 @@
<ng-container *ngIf="vm$ | async as vm">
<dot-portlet-base [boxed]="false" *ngIf="vm.working.identifier">
<dot-portlet-base *ngIf="vm.working.identifier" [boxed]="false">
<dot-portlet-toolbar [title]="vm.working.title">
<ng-container left *ngIf="vm.working.title">
<ng-container *ngIf="vm.working.title" left>
<button
data-testId="editTemplateButton"
pButton
class="p-button-text"
icon="pi pi-pencil"
[label]="'templates.edit' | dm"
(click)="editTemplateProps()"
data-testId="editTemplateButton"
pButton
icon="pi pi-pencil"
></button>
<dot-api-link [href]="vm.apiLink"></dot-api-link>
</ng-container>
Expand All @@ -20,7 +20,6 @@
[item]="vm.working"
(updateTemplate)="updateWorkingTemplate($event)"
(saveAndPublish)="saveAndPublishTemplate($event)"
(save)="saveTemplate($event)"
(cancel)="cancelTemplate()"
(custom)="onCustomEvent($event)"
></dot-template-builder>
Expand Down
Expand Up @@ -253,7 +253,10 @@ describe('DotTemplateCreateEditComponent', () => {
goToEditTemplate: jasmine.createSpy(),
goToTemplateList: jasmine.createSpy(),
saveTemplate: jasmine.createSpy(),
saveWorkingTemplate: jasmine.createSpy()
saveWorkingTemplate: jasmine.createSpy(),
saveAndPublishTemplate: jasmine.createSpy(),
updateTemplate: jasmine.createSpy(),
updateWorkingTemplate: jasmine.createSpy()
};
});

Expand Down Expand Up @@ -493,43 +496,7 @@ describe('DotTemplateCreateEditComponent', () => {
});

describe('edit layout', () => {
it('should save', () => {
const builder = de.query(By.css('dot-template-builder'));
builder.triggerEventHandler('save', {
layout: {
title: '',
width: '',
footer: true,
header: false,
sidebar: {},
body: {
rows: []
}
},
themeId: '123'
});

expect(store.saveTemplate).toHaveBeenCalledWith({
type: 'design',
title: 'Some template',
layout: {
title: '',
width: '',
footer: true,
header: false,
sidebar: {},
body: {
rows: []
}
},
identifier: '123',
friendlyName: '',
theme: '123',
image: ''
});
});

it('should call saveWorkingTemplate when updateTemplate', () => {
it('should call updateWorkingTemplate from store when updateTemplate', () => {
const builder = de.query(By.css('dot-template-builder'));
builder.triggerEventHandler('updateTemplate', {
layout: {
Expand Down Expand Up @@ -564,7 +531,7 @@ describe('DotTemplateCreateEditComponent', () => {
image: ''
};

expect(store.saveWorkingTemplate).toHaveBeenCalledWith(template);
expect(store.updateWorkingTemplate).toHaveBeenCalledWith(template);
});

it('should saveAndPublishTemplate', () => {
Expand Down Expand Up @@ -695,13 +662,13 @@ describe('DotTemplateCreateEditComponent', () => {
});

describe('edit layout', () => {
it('should save', () => {
it('should save and publish', () => {
const builder = de.query(By.css('dot-template-builder'));
builder.triggerEventHandler('save', {
builder.triggerEventHandler('saveAndPublish', {
body: `<h1>##Container and stuff</h1>`
});

expect(store.saveTemplate).toHaveBeenCalledWith({
expect(store.saveAndPublishTemplate).toHaveBeenCalledWith({
type: 'advanced',
title: 'Some template',
body: '<h1>##Container and stuff</h1>',
Expand All @@ -711,13 +678,13 @@ describe('DotTemplateCreateEditComponent', () => {
});
});

it('should call saveWorkingTemplate when updateTemplate', () => {
it('should call updateWorkingTemplate from store when updateTemplate', () => {
const builder = de.query(By.css('dot-template-builder'));
builder.triggerEventHandler('updateTemplate', {
body: `<h1>##Container and stuff</h1>`
});

expect(store.saveWorkingTemplate).toHaveBeenCalledWith({
expect(store.updateWorkingTemplate).toHaveBeenCalledWith({
type: 'advanced',
title: 'Some template',
body: '<h1>##Container and stuff</h1>',
Expand Down
Expand Up @@ -98,26 +98,13 @@ export class DotTemplateCreateEditComponent implements OnInit, OnDestroy {
}

/**
* Update Working Template
* Format template item to be updated on store
*
* @param DotTemplate template
* @param {DotTemplate} template
* @memberof DotTemplateCreateEditComponent
*/
updateWorkingTemplate(template: DotTemplate): void {
this.store.saveWorkingTemplate({
...this.form.value,
...this.formatTemplateItem(template)
});
}

/**
* Save template to store
*
* @param DotTemplate template
* @memberof DotTemplateCreateEditComponent
*/
saveTemplate(template: DotTemplate): void {
this.store.saveTemplate({
this.store.updateWorkingTemplate({
...this.form.value,
...this.formatTemplateItem(template)
});
Expand Down
Expand Up @@ -88,7 +88,6 @@ const messageServiceMock = new MockDotMessageService({
let component: DotEditLayoutDesignerComponent;
let fixture: ComponentFixture<DotEditLayoutDesignerComponent>;
let dotThemesService: DotThemesService;
let dotEditLayoutService: DotEditLayoutService;

describe('DotEditLayoutDesignerComponent', () => {
beforeEach(() => {
Expand Down Expand Up @@ -158,7 +157,6 @@ describe('DotEditLayoutDesignerComponent', () => {
fixture = TestBed.createComponent(DotEditLayoutDesignerComponent);
component = fixture.componentInstance;
dotThemesService = TestBed.inject(DotThemesService);
dotEditLayoutService = TestBed.inject(DotEditLayoutService);
});

describe('edit layout', () => {
Expand Down Expand Up @@ -222,13 +220,6 @@ describe('DotEditLayoutDesignerComponent', () => {
);
});

it('should save changes when closeEditLayout is true', () => {
spyOn(component.save, 'emit');
dotEditLayoutService.changeCloseEditLayoutState(true);
fixture.detectChanges();
expect(component.save.emit).toHaveBeenCalledTimes(1);
});

it('should save changes when editing the form.', () => {
spyOn(component.updateTemplate, 'emit');
component.form.get('title').setValue('Hello');
Expand Down
Expand Up @@ -104,7 +104,6 @@ export class DotEditLayoutDesignerComponent implements OnInit, OnDestroy, OnChan

ngOnInit(): void {
this.setupLayout();
this.saveChangesBeforeLeave();
}

ngOnChanges(changes: SimpleChanges): void {
Expand Down Expand Up @@ -297,14 +296,4 @@ export class DotEditLayoutDesignerComponent implements OnInit, OnDestroy, OnChan
})
);
}

private saveChangesBeforeLeave(): void {
this.dotEditLayoutService.closeEditLayout$
.pipe(takeUntil(this.destroy$))
.subscribe((res) => {
if (res) {
this.onSave();
}
});
}
}
Expand Up @@ -12,7 +12,7 @@ import { DotContainersServiceMock } from '@dotcms/utils-testing';
import { TemplateBuilderSidebarComponent } from './template-builder-sidebar.component';

import { DotTemplateBuilderStore } from '../../store/template-builder.store';
import { DOT_MESSAGE_SERVICE_TB_MOCK } from '../../utils/mocks';
import { DOT_MESSAGE_SERVICE_TB_MOCK, GRIDSTACK_DATA_MOCK } from '../../utils/mocks';
import { TemplateBuilderBoxComponent } from '../template-builder-box/template-builder-box.component';

describe('TemplateBuilderSidebarComponent', () => {
Expand Down Expand Up @@ -48,7 +48,7 @@ describe('TemplateBuilderSidebarComponent', () => {
{
hostProps: {
sidebarProperties: {
postion: 'left',
location: 'left',
width: 'medium',
containers: []
}
Expand All @@ -60,6 +60,21 @@ describe('TemplateBuilderSidebarComponent', () => {

boxComponent = spectator.query(TemplateBuilderBoxComponent);

store.init({
items: GRIDSTACK_DATA_MOCK,
layoutProperties: {
header: true,
footer: true,
sidebar: {
location: 'left',
width: 'medium',
containers: []
}
},
resizingRowID: '',
containerMap: {}
});

spectator.detectChanges();
});

Expand Down
Expand Up @@ -39,7 +39,7 @@ export class DotTemplateBuilderStore extends ComponentStore<DotTemplateBuilderSt
constructor() {
super({
items: [],
layoutProperties: { header: true, footer: true, sidebar: {} },
layoutProperties: undefined,
resizingRowID: '',
containerMap: {}
});
Expand Down
Expand Up @@ -90,6 +90,12 @@ describe('TemplateBuilderComponent', () => {
store = spectator.inject(DotTemplateBuilderStore);
dialog = spectator.inject(DialogService);
openDialogMock = jest.spyOn(dialog, 'open');
spectator.detectChanges();
});
it('should not trigger a template change when store is initialized', () => {
// Store init is called on init
const changeMock = jest.spyOn(spectator.component.templateChange, 'emit');
expect(changeMock).not.toHaveBeenCalled();
});

it('should have a Add Row Button', () => {
Expand Down

0 comments on commit 09ca574

Please sign in to comment.