Skip to content

Commit

Permalink
chore(uve): Add FF for Preview Mode (#30623)
Browse files Browse the repository at this point in the history
This pull request introduces a new feature flag for UVE preview mode and
integrates it into the existing system. The changes include updates to
feature flag definitions, component additions, and modifications to the
store to handle the new flag.

### Feature Flag Updates:
* Added `FEATURE_FLAG_UVE_PREVIEW_MODE` to `FeaturedFlags` in
`shared-models.ts`.
* Updated `ConfigurationResource.java` to include
`FEATURE_FLAG_UVE_PREVIEW_MODE` in the list of feature flags.

### Component Additions:
* Created `DotUveToolbarComponent` with its HTML, SCSS, and TypeScript
files.
[[1]](diffhunk://#diff-217a9e619d6590c4f652e85353b9637ba5e464ddeb0424be35aef39bb8dceb30R1-R11)
[[2]](diffhunk://#diff-9937556e73b051b878ba22ad1ce971a70019a617d7979b3e0bcc814801ad350bR1)
[[3]](diffhunk://#diff-3eaa147616a5d1ff374a5fa27b0f38f0159a9039ef7e8d672dec43631f48a9e1R1-R22)

### Store Modifications:
* Added `withFlags` feature to handle the fetching and state management
of feature flags in `dot-uve.store.ts`.
[[1]](diffhunk://#diff-42fdc01a4da73b6ecede38045c03fd631badeb73e299fbb4ed6442eb1f3ad963R5-R8)
[[2]](diffhunk://#diff-42fdc01a4da73b6ecede38045c03fd631badeb73e299fbb4ed6442eb1f3ad963L148-R152)
* Created a new model and utility function for managing feature flags in
`flags/models.ts` and `flags/withFlags.ts`.
[[1]](diffhunk://#diff-56a4c0b92a1c5300b155f1aaa7b4f6fec8507d90243521edba9d8c7568148aceR1-R7)
[[2]](diffhunk://#diff-c000e8963865d1e077268b3e4de0a84c5d2709623e8e172bf395431078528d65R1-R55)

### Component Integration:
* Integrated `DotUveToolbarComponent` into
`edit-ema-editor.component.html` and updated SCSS accordingly.
[[1]](diffhunk://#diff-7f93b3d5700edd531f6ee9f65ed695175ee686d7b1cfa63b46de3669e65fb1efR1-R6)
[[2]](diffhunk://#diff-9f57717118542461b370728d90435befd6cecc18f94bf130ab48acd3ef795ca1L23-R24)
* Updated imports and component declarations in
`edit-ema-editor.component.ts` to include the new toolbar component.
[[1]](diffhunk://#diff-24dc496db1eb6feb3e10a031baa4b4b63c20f1cd02ade574065f6b967f11c365L47-R50)
[[2]](diffhunk://#diff-24dc496db1eb6feb3e10a031baa4b4b63c20f1cd02ade574065f6b967f11c365L111-R111)
[[3]](diffhunk://#diff-24dc496db1eb6feb3e10a031baa4b4b63c20f1cd02ade574065f6b967f11c365R150)
  • Loading branch information
zJaaal authored Nov 12, 2024
1 parent b71b004 commit 474fab0
Show file tree
Hide file tree
Showing 18 changed files with 264 additions and 19 deletions.
3 changes: 2 additions & 1 deletion core-web/libs/dotcms-models/src/lib/shared-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export const enum FeaturedFlags {
FEATURE_FLAG_CONTENT_EDITOR2_ENABLED = 'CONTENT_EDITOR2_ENABLED',
FEATURE_FLAG_CONTENT_EDITOR2_CONTENT_TYPE = 'CONTENT_EDITOR2_CONTENT_TYPE',
FEATURE_FLAG_ANNOUNCEMENTS = 'FEATURE_FLAG_ANNOUNCEMENTS',
FEATURE_FLAG_NEW_EDIT_PAGE = 'FEATURE_FLAG_NEW_EDIT_PAGE'
FEATURE_FLAG_NEW_EDIT_PAGE = 'FEATURE_FLAG_NEW_EDIT_PAGE',
FEATURE_FLAG_UVE_PREVIEW_MODE = 'FEATURE_FLAG_UVE_PREVIEW_MODE'
}

export const FEATURE_FLAG_NOT_FOUND = 'NOT_FOUND';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
DotLanguagesService,
DotLicenseService,
DotMessageService,
DotPropertiesService,
DotWorkflowActionsFireService,
PushPublishService
} from '@dotcms/data-access';
Expand Down Expand Up @@ -56,6 +57,7 @@ import { DotPageApiService } from '../services/dot-page-api.service';
import { DEFAULT_PERSONA, WINDOW } from '../shared/consts';
import { FormStatus, NG_CUSTOM_EVENTS } from '../shared/enums';
import {
dotPropertiesServiceMock,
PAGE_RESPONSE_BY_LANGUAGE_ID,
PAGE_RESPONSE_URL_CONTENT_MAP,
PAYLOAD_MOCK
Expand Down Expand Up @@ -103,6 +105,10 @@ describe('DotEmaShellComponent', () => {
DotMessageService,
DialogService,
DotWorkflowActionsFireService,
{
provide: DotPropertiesService,
useValue: dotPropertiesServiceMock
},
{
provide: DotcmsConfigService,
useValue: new DotcmsConfigServiceMock()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>dot-uve-toolbar works!</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { DotUveToolbarComponent } from './dot-uve-toolbar.component';

describe('DotUveToolbarComponent', () => {
let component: DotUveToolbarComponent;
let fixture: ComponentFixture<DotUveToolbarComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DotUveToolbarComponent]
}).compileComponents();

fixture = TestBed.createComponent(DotUveToolbarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'dot-uve-toolbar',
standalone: true,
imports: [],
templateUrl: './dot-uve-toolbar.component.html',
styleUrl: './dot-uve-toolbar.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DotUveToolbarComponent {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<dot-edit-ema-toolbar (editUrlContentMap)="editContentMap($event)" />
@if ($previewMode()) {
<dot-uve-toolbar />
} @else {
<dot-edit-ema-toolbar (editUrlContentMap)="editContentMap($event)" />
}

@if ($editorProps().seoResults && ogTagsResults$) {
<dot-results-seo-tool
[seoMedia]="$editorProps().seoResults.socialMedia"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ dot-ema-page-dropzone {
inset: 0;
}

dot-edit-ema-toolbar {
dot-edit-ema-toolbar,
dot-uve-toolbar {
grid-column: 1 / -1;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
DotLicenseService,
DotMessageService,
DotPersonalizeService,
DotPropertiesService,
DotSeoMetaTagsService,
DotSeoMetaTagsUtilService,
DotTempFileUploadService,
Expand Down Expand Up @@ -67,6 +68,7 @@ import {

import { DotEditEmaWorkflowActionsComponent } from './components/dot-edit-ema-workflow-actions/dot-edit-ema-workflow-actions.component';
import { DotEmaRunningExperimentComponent } from './components/dot-ema-running-experiment/dot-ema-running-experiment.component';
import { DotUveToolbarComponent } from './components/dot-uve-toolbar/dot-uve-toolbar.component';
import { CONTENT_TYPE_MOCK } from './components/edit-ema-palette/components/edit-ema-palette-content-type/edit-ema-palette-content-type.component.spec';
import { CONTENTLETS_MOCK } from './components/edit-ema-palette/edit-ema-palette.component.spec';
import { EditEmaToolbarComponent } from './components/edit-ema-toolbar/edit-ema-toolbar.component';
Expand All @@ -87,7 +89,8 @@ import {
newContentlet,
PAYLOAD_MOCK,
UVE_PAGE_RESPONSE_MAP,
EMA_DRAG_ITEM_CONTENTLET_MOCK
EMA_DRAG_ITEM_CONTENTLET_MOCK,
dotPropertiesServiceMock
} from '../shared/mocks';
import { ActionPayload, ContentTypeDragPayload } from '../shared/models';
import { UVEStore } from '../store/dot-uve.store';
Expand Down Expand Up @@ -144,6 +147,13 @@ const createRouting = () =>
UVEStore,
DotFavoritePageService,
DotESContentService,
{
provide: DotPropertiesService,
useValue: {
...dotPropertiesServiceMock,
getKeyAsList: () => of([])
}
},
{
provide: DotAlertConfirmService,
useValue: {
Expand Down Expand Up @@ -378,7 +388,6 @@ describe('EditEmaEditorComponent', () => {
dotWorkflowActionsFireService = spectator.inject(DotWorkflowActionsFireService, true);
router = spectator.inject(Router, true);
dotPageApiService = spectator.inject(DotPageApiService, true);

addMessageSpy = jest.spyOn(messageService, 'add');
jest.spyOn(dotLicenseService, 'isEnterprise').mockReturnValue(of(true));

Expand Down Expand Up @@ -421,6 +430,23 @@ describe('EditEmaEditorComponent', () => {
});
});

it('should show the old toolbar when FEATURE_FLAG_UVE_PREVIEW_MODE is false', () => {
const toolbar = spectator.query(EditEmaToolbarComponent);

expect(toolbar).not.toBeNull();
});

it('should show the new toolbar when FEATURE_FLAG_UVE_PREVIEW_MODE is true', () => {
store.setFlags({
FEATURE_FLAG_UVE_PREVIEW_MODE: true
});
spectator.detectChanges();

const toolbar = spectator.query(DotUveToolbarComponent);

expect(toolbar).not.toBeNull();
});

it('should hide components when the store changes for a variant', () => {
const componentsToHide = [
'palette',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,10 @@ import {
SeoMetaTagsResult
} from '@dotcms/dotcms-models';
import { DotResultsSeoToolComponent } from '@dotcms/portlets/dot-ema/ui';
import {
SafeUrlPipe,
DotSpinnerModule,
DotMessagePipe,
DotCopyContentModalService
} from '@dotcms/ui';
import { SafeUrlPipe, DotSpinnerModule, DotCopyContentModalService } from '@dotcms/ui';
import { isEqual } from '@dotcms/utils';

import { DotEmaBookmarksComponent } from './components/dot-ema-bookmarks/dot-ema-bookmarks.component';
import { DotUveToolbarComponent } from './components/dot-uve-toolbar/dot-uve-toolbar.component';
import { EditEmaPaletteComponent } from './components/edit-ema-palette/edit-ema-palette.component';
import { EditEmaToolbarComponent } from './components/edit-ema-toolbar/edit-ema-toolbar.component';
import { EmaContentletToolsComponent } from './components/ema-contentlet-tools/ema-contentlet-tools.component';
Expand Down Expand Up @@ -110,13 +105,12 @@ import {
DotEmaDialogComponent,
ConfirmDialogModule,
EditEmaToolbarComponent,
DotMessagePipe,
EmaPageDropzoneComponent,
EditEmaPaletteComponent,
EmaContentletToolsComponent,
DotEmaBookmarksComponent,
ProgressBarModule,
DotResultsSeoToolComponent,
DotUveToolbarComponent,
DotBlockEditorSidebarComponent
],
providers: [
Expand Down Expand Up @@ -158,6 +152,7 @@ export class EditEmaEditorComponent implements OnInit, OnDestroy {
readonly host = '*';
readonly $ogTags: WritableSignal<SeoMetaTags> = signal(undefined);
readonly $editorProps = this.uveStore.$editorProps;
readonly $previewMode = this.uveStore.$previewMode;

get contentWindow(): Window {
return this.iframe.nativeElement.contentWindow;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InjectionToken } from '@angular/core';

import { DotPersona } from '@dotcms/dotcms-models';
import { DotPersona, FeaturedFlags } from '@dotcms/dotcms-models';

import { CommonErrors } from './enums';
import { CommonErrorsInfo } from './models';
Expand Down Expand Up @@ -67,3 +67,5 @@ export const DEFAULT_PERSONA: DotPersona = {
hasLiveVersion: false,
modUser: 'system'
};

export const UVE_FEATURE_FLAGS = [FeaturedFlags.FEATURE_FLAG_UVE_PREVIEW_MODE];
10 changes: 9 additions & 1 deletion core-web/libs/portlets/edit-ema/portlet/src/lib/shared/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { of } from 'rxjs';
import {
DEFAULT_VARIANT_ID,
DotPageContainerStructure,
CONTAINER_SOURCE
CONTAINER_SOURCE,
FeaturedFlags
} from '@dotcms/dotcms-models';
import {
mockSites,
Expand Down Expand Up @@ -956,3 +957,10 @@ export const UVE_PAGE_RESPONSE_MAP = {
containers: dotPageContainerStructureMock
})
};

export const dotPropertiesServiceMock = {
getFeatureFlags: () =>
of({
[FeaturedFlags.FEATURE_FLAG_UVE_PREVIEW_MODE]: false
})
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
DotExperimentsService,
DotLanguagesService,
DotLicenseService,
DotMessageService
DotMessageService,
DotPropertiesService
} from '@dotcms/data-access';
import { LoginService } from '@dotcms/dotcms-js';
import {
Expand All @@ -37,6 +38,7 @@ import { UVE_STATUS } from '../shared/enums';
import {
BASE_SHELL_ITEMS,
BASE_SHELL_PROPS_RESPONSE,
dotPropertiesServiceMock,
HEADLESS_BASE_QUERY_PARAMS,
MOCK_RESPONSE_HEADLESS,
MOCK_RESPONSE_VTL,
Expand Down Expand Up @@ -65,6 +67,10 @@ describe('UVEStore', () => {
MessageService,
mockProvider(Router),
mockProvider(ActivatedRoute),
{
provide: DotPropertiesService,
useValue: dotPropertiesServiceMock
},
{
provide: DotPageApiService,
useValue: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { patchState, signalStore, withComputed, withMethods, withState } from '@
import { computed } from '@angular/core';

import { withEditor } from './features/editor/withEditor';
import { withFlags } from './features/flags/withFlags';
import { withLayout } from './features/layout/withLayout';
import { withLoad } from './features/load/withLoad';
import { ShellProps, TranslateProps, UVEState } from './models';

import { DotPageApiResponse } from '../services/dot-page-api.service';
import { UVE_FEATURE_FLAGS } from '../shared/consts';
import { UVE_STATUS } from '../shared/enums';
import { getErrorPayload, getRequestHostName, sanitizeURL } from '../utils';

Expand Down Expand Up @@ -145,5 +147,6 @@ export const UVEStore = signalStore(
}),
withLoad(),
withLayout(),
withEditor()
withEditor(),
withFlags(UVE_FEATURE_FLAGS)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { FeaturedFlags } from '@dotcms/dotcms-models';

export type UVEFlags = { [key in FeaturedFlags]?: boolean };

export interface WithFlagsState {
flags: UVEFlags;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { describe } from '@jest/globals';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { signalStore, withState } from '@ngrx/signals';
import { of } from 'rxjs';

import { DotPropertiesService } from '@dotcms/data-access';
import { FeaturedFlags } from '@dotcms/dotcms-models';

import { withFlags } from './withFlags';

import { DotPageApiParams } from '../../../services/dot-page-api.service';
import { UVE_FEATURE_FLAGS } from '../../../shared/consts';
import { UVE_STATUS } from '../../../shared/enums';
import { UVEState } from '../../models';

const initialState: UVEState = {
isEnterprise: false,
languages: [],
pageAPIResponse: null,
currentUser: null,
experiment: null,
errorCode: null,
params: {} as DotPageApiParams,
status: UVE_STATUS.LOADING,
isTraditionalPage: true,
canEditPage: false,
pageIsLocked: true
};

export const uveStoreMock = signalStore(
withState<UVEState>(initialState),
withFlags(UVE_FEATURE_FLAGS)
);

const MOCK_RESPONSE = UVE_FEATURE_FLAGS.reduce((acc, flag) => {
acc[flag] = true;

return acc;
}, {});

describe('withFlags', () => {
let spectator: SpectatorService<InstanceType<typeof uveStoreMock>>;
let store: InstanceType<typeof uveStoreMock>;

const createService = createServiceFactory({
service: uveStoreMock,
providers: [
{
provide: DotPropertiesService,
useValue: {
getFeatureFlags: jest.fn().mockReturnValue(of(MOCK_RESPONSE))
}
}
]
});

beforeEach(() => {
spectator = createService();
store = spectator.service;
});

describe('onInit', () => {
it('should call propertiesService.getFeatureFlags with flags', () => {
const propertiesService = spectator.inject(DotPropertiesService);

expect(propertiesService.getFeatureFlags).toHaveBeenCalledWith(UVE_FEATURE_FLAGS);
});

it('should patch state with flags', () => {
expect(store.flags()).toEqual(MOCK_RESPONSE);
});
});
describe('methods', () => {
describe('setFlags', () => {
it('should patch state with flags', () => {
store.setFlags(MOCK_RESPONSE);

expect(store.flags()).toEqual(MOCK_RESPONSE);
});
});
});
describe('computed', () => {
it('should return $previewMode', () => {
expect(store.$previewMode()).toEqual(
MOCK_RESPONSE[FeaturedFlags.FEATURE_FLAG_UVE_PREVIEW_MODE]
);
});
});
});
Loading

0 comments on commit 474fab0

Please sign in to comment.