Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(edit-ema): Show notification for duplicate contentlet in container #27335 #27351

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { describe, expect } from '@jest/globals';
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest';
import { of } from 'rxjs';

import { DotLicenseService } from '@dotcms/data-access';
import { MessageService } from 'primeng/api';

import { DotLicenseService, DotMessageService } from '@dotcms/data-access';
import {
MockDotMessageService,
mockDotContainers,
mockDotLayout,
mockDotTemplate,
Expand Down Expand Up @@ -54,11 +57,16 @@ describe('EditEmaStore', () => {
service: EditEmaStore,
mocks: [DotPageApiService, DotActionUrlService],
providers: [
MessageService,
{
provide: DotLicenseService,
useValue: {
isEnterprise: () => of(true)
}
},
{
provide: DotMessageService,
useValue: new MockDotMessageService({})
}
]
});
Expand All @@ -85,120 +93,6 @@ describe('EditEmaStore', () => {
});
});

describe('url sanitize', () => {
it('should remove the slash from the start', (done) => {
spectator.service.load({
clientHost: 'http://localhost:3000',
language_id: '1',
url: '/cool',
'com.dotmarketing.persona.id': '123'
});

spectator.service.editorState$.subscribe((state) => {
expect(state.apiURL).toEqual(
'http://localhost/api/v1/page/json/cool?language_id=1&com.dotmarketing.persona.id=modes.persona.no.persona'
);
done();
});
});

it("should remove the slash from the end if it's not the only character", (done) => {
spectator.service.load({
clientHost: 'http://localhost:3000',
language_id: '1',
url: 'super-cool/',
'com.dotmarketing.persona.id': '123'
});

spectator.service.editorState$.subscribe((state) => {
expect(state.apiURL).toEqual(
'http://localhost/api/v1/page/json/super-cool?language_id=1&com.dotmarketing.persona.id=modes.persona.no.persona'
);
done();
});
});

it('should remove the slash from the end and the beggining', (done) => {
spectator.service.load({
clientHost: 'http://localhost:3000',
language_id: '1',
url: '/hello-there/',
'com.dotmarketing.persona.id': '123'
});

spectator.service.editorState$.subscribe((state) => {
expect(state.apiURL).toEqual(
'http://localhost/api/v1/page/json/hello-there?language_id=1&com.dotmarketing.persona.id=modes.persona.no.persona'
);
done();
});
});

it('should remove the index if a nested path', (done) => {
spectator.service.load({
clientHost: 'http://localhost:3000',
language_id: '1',
url: 'i-have-the-high-ground/index',
'com.dotmarketing.persona.id': '123'
});

spectator.service.editorState$.subscribe((state) => {
expect(state.apiURL).toEqual(
'http://localhost/api/v1/page/json/i-have-the-high-ground?language_id=1&com.dotmarketing.persona.id=modes.persona.no.persona'
);
done();
});
});

it('should remove the index if a nested path with slash', (done) => {
spectator.service.load({
clientHost: 'http://localhost:3000',
language_id: '1',
url: 'no-index-please/index/',
'com.dotmarketing.persona.id': '123'
});

spectator.service.editorState$.subscribe((state) => {
expect(state.apiURL).toEqual(
'http://localhost/api/v1/page/json/no-index-please?language_id=1&com.dotmarketing.persona.id=modes.persona.no.persona'
);
done();
});
});

it('should leave as it is for valid url', (done) => {
spectator.service.load({
clientHost: 'http://localhost:3000',
language_id: '1',
url: 'this-is-where-the-fun-begins',
'com.dotmarketing.persona.id': '123'
});

spectator.service.editorState$.subscribe((state) => {
expect(state.apiURL).toEqual(
'http://localhost/api/v1/page/json/this-is-where-the-fun-begins?language_id=1&com.dotmarketing.persona.id=modes.persona.no.persona'
);
done();
});
});

it('should leave as it is for a nested valid url', (done) => {
spectator.service.load({
clientHost: 'http://localhost:3000',
language_id: '1',
url: 'hello-there/general-kenobi',
'com.dotmarketing.persona.id': '123'
});

spectator.service.editorState$.subscribe((state) => {
expect(state.apiURL).toEqual(
'http://localhost/api/v1/page/json/hello-there/general-kenobi?language_id=1&com.dotmarketing.persona.id=modes.persona.no.persona'
);
done();
});
});
});

describe('selectors', () => {
it('should return editorState', (done) => {
spectator.service.editorState$.subscribe((state) => {
Expand Down Expand Up @@ -513,5 +407,58 @@ describe('EditEmaStore', () => {
pageId: 'page-identifier-123'
});
});

it('should not add form to page when the form is dupe and triggers a message', () => {
const messageService = spectator.inject(MessageService);

const addMessageSpy = jest.spyOn(messageService, 'add');

const payload: ActionPayload = {
pageId: 'page-identifier-123',
language_id: '1',
container: {
identifier: 'container-identifier-123',
uuid: '123',
acceptTypes: 'test',
maxContentlets: 1,
contentletsId: ['existing-contentlet-123', 'form-identifier-123']
},
pageContainers: [
{
identifier: 'container-identifier-123',
uuid: '123',
contentletsId: ['existing-contentlet-123', 'form-identifier-123']
}
],
contentlet: {
identifier: 'existing-contentlet-123',
inode: 'existing-contentlet-inode-456',
title: 'Hello World'
}
};
const dotPageApiService = spectator.inject(DotPageApiService);
dotPageApiService.save.andReturn(of({}));
dotPageApiService.getFormIndetifier.andReturn(of('form-identifier-123'));

spectator.service.load({
clientHost: 'http://localhost:3000',
language_id: 'en',
url: 'test-url',
'com.dotmarketing.persona.id': '123'
});
spectator.service.saveFormToPage({
payload,
formId: 'form-identifier-789',
// eslint-disable-next-line @typescript-eslint/no-empty-function
whenSaved: () => {}
});

expect(addMessageSpy).toHaveBeenCalledWith({
severity: 'info',
summary: 'editpage.content.add.already.title',
detail: 'editpage.content.add.already.message',
life: 2000
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { EMPTY, Observable, forkJoin } from 'rxjs';
import { HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { MessageService } from 'primeng/api';

import { catchError, map, shareReplay, switchMap, take, tap } from 'rxjs/operators';

import { DotLicenseService } from '@dotcms/data-access';
import { DotLicenseService, DotMessageService } from '@dotcms/data-access';
import { DotContainerMap, DotLayout, DotPageContainerStructure } from '@dotcms/dotcms-models';

import { DotActionUrlService } from '../../services/dot-action-url/dot-action-url.service';
Expand All @@ -18,7 +20,7 @@ import {
import { DEFAULT_PERSONA, EDIT_CONTENTLET_URL, ADD_CONTENTLET_URL } from '../../shared/consts';
import { EDITOR_STATE } from '../../shared/enums';
import { ActionPayload, SavePagePayload } from '../../shared/models';
import { insertContentletInContainer } from '../../utils';
import { insertContentletInContainer, sanitizeURL } from '../../utils';

type DialogType = 'content' | 'form' | 'widget' | 'shell' | null;

Expand All @@ -34,7 +36,7 @@ export interface EditEmaState {
editorState: EDITOR_STATE;
}

function getFormId(dotPageApiService) {
function getFormId(dotPageApiService: DotPageApiService) {
return (source: Observable<unknown>) =>
source.pipe(
switchMap(({ payload, formId, whenSaved }) => {
Expand All @@ -60,7 +62,9 @@ export class EditEmaStore extends ComponentStore<EditEmaState> {
constructor(
private dotPageApiService: DotPageApiService,
private dotActionUrl: DotActionUrlService,
private dotLicenseService: DotLicenseService
private dotLicenseService: DotLicenseService,
private messageService: MessageService,
private dotMessageService: DotMessageService
) {
super();
}
Expand Down Expand Up @@ -212,7 +216,26 @@ export class EditEmaStore extends ComponentStore<EditEmaState> {
}),
getFormId(this.dotPageApiService),
switchMap(({ whenSaved, payload }) => {
const pageContainers = insertContentletInContainer(payload);
const { pageContainers, didInsert } = insertContentletInContainer(payload);

// This should not be called here but since here is where we get the form contentlet
// we need to do it here, we need to refactor editor and will fix there.
if (!didInsert) {
this.messageService.add({
severity: 'info',
summary: this.dotMessageService.get(
'editpage.content.add.already.title'
),
detail: this.dotMessageService.get(
'editpage.content.add.already.message'
),
life: 2000
});

this.updateEditorState(EDITOR_STATE.LOADED);

return EMPTY;
}

return this.dotPageApiService
.save({
Expand Down Expand Up @@ -409,13 +432,7 @@ export class EditEmaStore extends ComponentStore<EditEmaState> {
}

private createPageURL(params: DotPageApiParams): string {
const url = params.url
.replace(/^\/|\/$/g, '') // Remove slashes from the beginning and end of the url
.split('/')
.filter((part, i) => {
return !i || part !== 'index'; // Filter the index from the url if it is at the last position
})
.join('/');
const url = sanitizeURL(params.url);

return `${url}?language_id=${params.language_id}&com.dotmarketing.persona.id=${params['com.dotmarketing.persona.id']}`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@
[style]="{
width: '400px'
}"
[rejectIcon]="null"
[acceptIcon]="null"
rejectIcon="hidden"
acceptIcon="hidden"
rejectButtonStyleClass="p-button-outlined"
data-testId="confirm-dialog"></p-confirmDialog>
Loading