diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.html b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.html
index 41decd7d723f..01dd0ecbc8a5 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.html
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.html
@@ -31,19 +31,24 @@
-
-
@if ($toolbar().runningExperiment; as runningExperiment) {
}
+
- Persona
+
Workflows
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.spec.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.spec.ts
index bd5f9d06150d..24b8b490d289 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.spec.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.spec.ts
@@ -1,4 +1,4 @@
-import { expect, describe } from '@jest/globals';
+import { expect, describe, it } from '@jest/globals';
import { byTestId, mockProvider, Spectator, createComponentFactory } from '@ngneat/spectator/jest';
import { MockComponent } from 'ng-mocks';
import { of } from 'rxjs';
@@ -9,7 +9,12 @@ import { By } from '@angular/platform-browser';
import { ConfirmationService, MessageService } from 'primeng/api';
-import { DotExperimentsService, DotLanguagesService, DotLicenseService } from '@dotcms/data-access';
+import {
+ DotExperimentsService,
+ DotLanguagesService,
+ DotLicenseService,
+ DotPersonalizeService
+} from '@dotcms/data-access';
import { LoginService } from '@dotcms/dotcms-js';
import {
DotExperimentsServiceMock,
@@ -37,19 +42,23 @@ import {
import { DotEmaBookmarksComponent } from '../dot-ema-bookmarks/dot-ema-bookmarks.component';
import { DotEmaRunningExperimentComponent } from '../dot-ema-running-experiment/dot-ema-running-experiment.component';
import { EditEmaLanguageSelectorComponent } from '../edit-ema-language-selector/edit-ema-language-selector.component';
+import { EditEmaPersonaSelectorComponent } from '../edit-ema-persona-selector/edit-ema-persona-selector.component';
const $apiURL = '/api/v1/page/json/123-xyz-567-xxl?host_id=123-xyz-567-xxl&language_id=1';
describe('DotUveToolbarComponent', () => {
let spectator: Spectator;
let messageService: MessageService;
+ let confirmationService: ConfirmationService;
+ let store: InstanceType;
const createComponent = createComponentFactory({
component: DotUveToolbarComponent,
imports: [
HttpClientTestingModule,
MockComponent(DotEmaBookmarksComponent),
- MockComponent(DotEmaRunningExperimentComponent)
+ MockComponent(DotEmaRunningExperimentComponent),
+ MockComponent(EditEmaPersonaSelectorComponent)
],
providers: [
UVEStore,
@@ -87,6 +96,14 @@ describe('DotUveToolbarComponent', () => {
add: jest.fn()
}
}
+ ],
+ componentProviders: [
+ {
+ provide: DotPersonalizeService,
+ useValue: {
+ getPersonalize: jest.fn()
+ }
+ }
]
});
@@ -118,11 +135,7 @@ describe('DotUveToolbarComponent', () => {
runningExperiment: null,
workflowActionsInode: pageAPIResponse?.page.inode,
unlockButton: null,
- showInfoDisplay: shouldShowInfoDisplay,
- personaSelector: {
- pageId: pageAPIResponse?.page.identifier,
- value: pageAPIResponse?.viewAs.persona ?? DEFAULT_PERSONA
- }
+ showInfoDisplay: shouldShowInfoDisplay
};
const baseUVEState = {
@@ -132,6 +145,10 @@ describe('DotUveToolbarComponent', () => {
pageParams: signal(params),
pageAPIResponse: signal(MOCK_RESPONSE_VTL),
$apiURL: signal($apiURL),
+ $personaSelector: signal({
+ pageId: pageAPIResponse?.page.identifier,
+ value: pageAPIResponse?.viewAs.persona ?? DEFAULT_PERSONA
+ }),
reloadCurrentPage: jest.fn(),
loadPageAsset: jest.fn(),
languages: signal([
@@ -148,6 +165,8 @@ describe('DotUveToolbarComponent', () => {
});
messageService = spectator.inject(MessageService);
+ confirmationService = spectator.inject(ConfirmationService);
+ store = spectator.inject(UVEStore);
});
describe('dot-ema-bookmarks', () => {
@@ -244,6 +263,96 @@ describe('DotUveToolbarComponent', () => {
expect(btn.getAttribute('href')).toBe($apiURL);
});
});
+
+ describe('dot-edit-ema-persona-selector', () => {
+ it('should have attr', () => {
+ const personaSelector = spectator.query(EditEmaPersonaSelectorComponent);
+
+ expect(personaSelector.pageId).toBe('123');
+ expect(personaSelector.value).toEqual({
+ archived: false,
+ baseType: 'PERSONA',
+ contentType: 'persona',
+ folder: 'SYSTEM_FOLDER',
+ hasLiveVersion: false,
+ hasTitleImage: false,
+ host: 'SYSTEM_HOST',
+ hostFolder: 'SYSTEM_HOST',
+ hostName: 'System Host',
+ identifier: 'modes.persona.no.persona',
+ inode: '',
+ keyTag: 'dot:persona',
+ languageId: 1,
+ live: false,
+ locked: false,
+ modDate: '0',
+ modUser: 'system',
+ modUserName: 'system user system user',
+ name: 'Default Visitor',
+ owner: 'SYSTEM_USER',
+ personalized: false,
+ sortOrder: 0,
+ stInode: 'c938b15f-bcb6-49ef-8651-14d455a97045',
+ title: 'Default Visitor',
+ titleImage: 'TITLE_IMAGE_NOT_FOUND',
+ url: 'demo.dotcms.com',
+ working: false
+ });
+ });
+
+ it('should personalize - no confirmation', () => {
+ const spyloadPageAsset = jest.spyOn(store, 'loadPageAsset');
+ spectator.triggerEventHandler(EditEmaPersonaSelectorComponent, 'selected', {
+ identifier: '123',
+ pageId: '123',
+ personalized: true
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } as any);
+ spectator.detectChanges();
+
+ expect(spyloadPageAsset).toHaveBeenCalledWith({
+ 'com.dotmarketing.persona.id': '123'
+ });
+ });
+
+ it('should personalize - confirmation', () => {
+ spectator.triggerEventHandler(EditEmaPersonaSelectorComponent, 'selected', {
+ identifier: '123',
+ pageId: '123',
+ personalized: false
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } as any);
+ spectator.detectChanges();
+
+ expect(confirmationService.confirm).toHaveBeenCalledWith({
+ accept: expect.any(Function),
+ acceptLabel: 'dot.common.dialog.accept',
+ header: 'editpage.personalization.confirm.header',
+ message: 'editpage.personalization.confirm.message',
+ reject: expect.any(Function),
+ rejectLabel: 'dot.common.dialog.reject'
+ });
+ });
+
+ it('should despersonalize', () => {
+ spectator.triggerEventHandler(EditEmaPersonaSelectorComponent, 'despersonalize', {
+ identifier: '123',
+ pageId: '123',
+ personalized: true
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } as any);
+
+ spectator.detectChanges();
+
+ expect(confirmationService.confirm).toHaveBeenCalledWith({
+ accept: expect.any(Function),
+ acceptLabel: 'dot.common.dialog.accept',
+ header: 'editpage.personalization.delete.confirm.header',
+ message: 'editpage.personalization.delete.confirm.message',
+ rejectLabel: 'dot.common.dialog.reject'
+ });
+ });
+ });
});
describe('State changes', () => {
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts
index 3ec216e00b77..c60adb1e5a09 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts
@@ -12,15 +12,17 @@ import { ConfirmationService, MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { ToolbarModule } from 'primeng/toolbar';
-import { DotMessageService } from '@dotcms/data-access';
-import { DotLanguage } from '@dotcms/dotcms-models';
+import { DotMessageService, DotPersonalizeService } from '@dotcms/data-access';
+import { DotPersona, DotLanguage } from '@dotcms/dotcms-models';
+import { DEFAULT_PERSONA } from '../../../shared/consts';
import { DotPage } from '../../../shared/models';
import { UVEStore } from '../../../store/dot-uve.store';
import { DotEmaBookmarksComponent } from '../dot-ema-bookmarks/dot-ema-bookmarks.component';
import { DotEmaInfoDisplayComponent } from '../dot-ema-info-display/dot-ema-info-display.component';
import { DotEmaRunningExperimentComponent } from '../dot-ema-running-experiment/dot-ema-running-experiment.component';
import { EditEmaLanguageSelectorComponent } from '../edit-ema-language-selector/edit-ema-language-selector.component';
+import { EditEmaPersonaSelectorComponent } from '../edit-ema-persona-selector/edit-ema-persona-selector.component';
@Component({
selector: 'dot-uve-toolbar',
@@ -31,22 +33,29 @@ import { EditEmaLanguageSelectorComponent } from '../edit-ema-language-selector/
DotEmaBookmarksComponent,
DotEmaInfoDisplayComponent,
DotEmaRunningExperimentComponent,
- ClipboardModule,
- EditEmaLanguageSelectorComponent
+ EditEmaPersonaSelectorComponent,
+ EditEmaLanguageSelectorComponent,
+ ClipboardModule
],
+ providers: [DotPersonalizeService],
templateUrl: './dot-uve-toolbar.component.html',
styleUrl: './dot-uve-toolbar.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DotUveToolbarComponent {
- languageSelector = viewChild('languageSelector');
+ $personaSelector = viewChild('personaSelector');
+
+ $languageSelector = viewChild('languageSelector');
#store = inject(UVEStore);
+
readonly #messageService = inject(MessageService);
readonly #dotMessageService = inject(DotMessageService);
readonly #confirmationService = inject(ConfirmationService);
+ readonly #personalizeService = inject(DotPersonalizeService);
readonly $toolbar = this.#store.$uveToolbar;
readonly $apiURL = this.#store.$apiURL;
+ readonly $personaSelectorProps = this.#store.$personaSelector;
@Output() translatePage = new EventEmitter<{ page: DotPage; newLanguage: number }>();
@@ -89,6 +98,75 @@ export class DotUveToolbarComponent {
}
/**
+ * Handle the persona selection
+ *
+ * @param {DotPersona} persona
+ * @memberof DotEmaComponent
+ */
+ onPersonaSelected(persona: DotPersona & { pageId: string }) {
+ if (persona.identifier === DEFAULT_PERSONA.identifier || persona.personalized) {
+ this.#store.loadPageAsset({
+ 'com.dotmarketing.persona.id': persona.identifier
+ });
+ } else {
+ this.#confirmationService.confirm({
+ header: this.#dotMessageService.get('editpage.personalization.confirm.header'),
+ message: this.#dotMessageService.get(
+ 'editpage.personalization.confirm.message',
+ persona.name
+ ),
+ acceptLabel: this.#dotMessageService.get('dot.common.dialog.accept'),
+ rejectLabel: this.#dotMessageService.get('dot.common.dialog.reject'),
+ accept: () => {
+ this.#personalizeService
+ .personalized(persona.pageId, persona.keyTag)
+ .subscribe(() => {
+ this.#store.loadPageAsset({
+ 'com.dotmarketing.persona.id': persona.identifier
+ });
+
+ this.$personaSelector().fetchPersonas();
+ }); // This does a take 1 under the hood
+ },
+ reject: () => {
+ this.$personaSelector().resetValue();
+ }
+ });
+ }
+ }
+
+ /**
+ * Handle the persona despersonalization
+ *
+ * @param {(DotPersona & { pageId: string })} persona
+ * @memberof EditEmaToolbarComponent
+ */
+ onDespersonalize(persona: DotPersona & { pageId: string; selected: boolean }) {
+ this.#confirmationService.confirm({
+ header: this.#dotMessageService.get('editpage.personalization.delete.confirm.header'),
+ message: this.#dotMessageService.get(
+ 'editpage.personalization.delete.confirm.message',
+ persona.name
+ ),
+ acceptLabel: this.#dotMessageService.get('dot.common.dialog.accept'),
+ rejectLabel: this.#dotMessageService.get('dot.common.dialog.reject'),
+ accept: () => {
+ this.#personalizeService
+ .despersonalized(persona.pageId, persona.keyTag)
+ .subscribe(() => {
+ this.$personaSelector().fetchPersonas();
+
+ if (persona.selected) {
+ this.#store.loadPageAsset({
+ 'com.dotmarketing.persona.id': DEFAULT_PERSONA.identifier
+ });
+ }
+ }); // This does a take 1 under the hood
+ }
+ });
+ }
+
+ /*
* Asks the user for confirmation to create a new translation for a given language.
*
* @param {DotLanguage} language - The language to create a new translation for.
@@ -116,7 +194,7 @@ export class DotUveToolbarComponent {
},
reject: () => {
// If is rejected, bring back the current language on selector
- this.languageSelector().listbox.writeValue(this.$toolbar().currentLanguage);
+ this.$languageSelector().listbox.writeValue(this.$toolbar().currentLanguage);
}
});
}
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/edit-ema-persona-selector/edit-ema-persona-selector.component.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/edit-ema-persona-selector/edit-ema-persona-selector.component.ts
index fbd23688f3da..a934c9cbed14 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/edit-ema-persona-selector/edit-ema-persona-selector.component.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/edit-ema-persona-selector/edit-ema-persona-selector.component.ts
@@ -111,8 +111,7 @@ export class EditEmaPersonaSelectorComponent implements AfterViewInit, OnChanges
* @memberof EditEmaPersonaSelectorComponent
*/
resetValue(): void {
- this.listbox.value = this.value;
- this.listbox.cd.detectChanges();
+ this.listbox.writeValue(this.value);
}
/**
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.spec.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.spec.ts
index 7dfaa010c8bb..450bc1f9e114 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.spec.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.spec.ts
@@ -34,6 +34,7 @@ import {
DotPropertiesService,
DotSeoMetaTagsService,
DotSeoMetaTagsUtilService,
+ DotSessionStorageService,
DotTempFileUploadService,
DotWorkflowActionsFireService,
PushPublishService
@@ -147,6 +148,7 @@ const createRouting = () =>
UVEStore,
DotFavoritePageService,
DotESContentService,
+ DotSessionStorageService,
{
provide: DotPropertiesService,
useValue: {
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/models.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/models.ts
index a51fb31413c4..fea55a82c03a 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/models.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/models.ts
@@ -128,10 +128,6 @@ export interface UVEToolbarProps {
hideSocialMedia: boolean;
};
};
- personaSelector: {
- pageId: string;
- value: DotPersona;
- };
runningExperiment?: DotExperiment;
currentLanguage: DotLanguage;
workflowActionsInode?: string;
@@ -141,3 +137,8 @@ export interface UVEToolbarProps {
};
showInfoDisplay?: boolean;
}
+
+export interface PersonaSelectorProps {
+ pageId: string;
+ value: DotPersona;
+}
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/toolbar/withUVEToolbar.spec.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/toolbar/withUVEToolbar.spec.ts
index 6a3b044ff152..445abbcf4d9c 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/toolbar/withUVEToolbar.spec.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/toolbar/withUVEToolbar.spec.ts
@@ -8,6 +8,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { withUVEToolbar } from './withUVEToolbar';
import { DotPageApiService } from '../../../../services/dot-page-api.service';
+import { DEFAULT_PERSONA } from '../../../../shared/consts';
import { UVE_STATUS } from '../../../../shared/enums';
import { MOCK_RESPONSE_HEADLESS } from '../../../../shared/mocks';
import { UVEState } from '../../../models';
@@ -47,7 +48,6 @@ describe('withEditor', () => {
mockProvider(Router),
mockProvider(ActivatedRoute),
mockProvider(Router),
- mockProvider(ActivatedRoute),
{
provide: DotPageApiService,
useValue: {
@@ -79,5 +79,12 @@ describe('withEditor', () => {
expect(store.$apiURL()).toBe(expectURL);
});
+
+ it('should return the personaSelector props', () => {
+ expect(store.$personaSelector()).toEqual({
+ pageId: '123',
+ value: DEFAULT_PERSONA
+ });
+ });
});
});
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/toolbar/withUVEToolbar.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/toolbar/withUVEToolbar.ts
index 047bb34bdbec..297b39476be4 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/toolbar/withUVEToolbar.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/toolbar/withUVEToolbar.ts
@@ -22,7 +22,7 @@ import {
sanitizeURL
} from '../../../../utils';
import { UVEState } from '../../../models';
-import { EditorToolbarState, UVEToolbarProps } from '../models';
+import { EditorToolbarState, PersonaSelectorProps, UVEToolbarProps } from '../models';
/**
* The initial state for the editor toolbar.
@@ -109,14 +109,18 @@ export function withUVEToolbar() {
: null,
runningExperiment: isExperimentRunning ? experiment : null,
workflowActionsInode: store.canEditPage() ? pageAPIResponse?.page.inode : null,
- personaSelector: {
- pageId: pageAPIResponse?.page.identifier,
- value: pageAPIResponse?.viewAs.persona ?? DEFAULT_PERSONA
- },
unlockButton: shouldShowUnlock ? unlockButton : null,
showInfoDisplay: shouldShowInfoDisplay
};
}),
+ $personaSelector: computed(() => {
+ const pageAPIResponse = store.pageAPIResponse();
+
+ return {
+ pageId: pageAPIResponse?.page.identifier,
+ value: pageAPIResponse?.viewAs.persona ?? DEFAULT_PERSONA
+ };
+ }),
$apiURL: computed(() => {
const pageParams = store.pageParams();
const url = sanitizeURL(pageParams?.url);
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.spec.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.spec.ts
index 60e16bc29bdb..82f5298bc27c 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.spec.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.spec.ts
@@ -541,10 +541,6 @@ describe('withEditor', () => {
urlContentMap: null,
runningExperiment: null,
workflowActionsInode: MOCK_RESPONSE_HEADLESS.page.inode,
- personaSelector: {
- pageId: MOCK_RESPONSE_HEADLESS.page.identifier,
- value: MOCK_RESPONSE_HEADLESS.viewAs.persona ?? DEFAULT_PERSONA
- },
unlockButton: null,
showInfoDisplay: false
});
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/utils/index.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/utils/index.ts
index 03a5affc8f18..5f643314740a 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/utils/index.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/utils/index.ts
@@ -110,7 +110,10 @@ export function deleteContentletFromContainer(action: ActionPayload): {
};
}
- return currentContainer;
+ return {
+ ...currentContainer,
+ personaTag
+ };
});
return {
diff --git a/core-web/libs/portlets/edit-ema/portlet/src/lib/utils/utils.spec.ts b/core-web/libs/portlets/edit-ema/portlet/src/lib/utils/utils.spec.ts
index e3d312039e26..9419124736a7 100644
--- a/core-web/libs/portlets/edit-ema/portlet/src/lib/utils/utils.spec.ts
+++ b/core-web/libs/portlets/edit-ema/portlet/src/lib/utils/utils.spec.ts
@@ -63,6 +63,11 @@ describe('utils functions', () => {
identifier: 'test',
uuid: 'test',
contentletsId: ['test']
+ },
+ {
+ identifier: 'test-2',
+ uuid: 'test',
+ contentletsId: ['test']
}
],
contentlet: {
@@ -82,6 +87,12 @@ describe('utils functions', () => {
uuid: 'test',
contentletsId: [],
personaTag: 'test'
+ },
+ {
+ identifier: 'test-2',
+ uuid: 'test',
+ contentletsId: ['test'],
+ personaTag: 'test' // In the last version this was not being added and it lead to saving content to the default persona and messing up with the pages
}
],
contentletsId: []