Skip to content

Commit

Permalink
chore(FTM): Add Unlock button to new Toolbar (#31096)
Browse files Browse the repository at this point in the history
This pull request introduces a new unlock button feature to the
`DotUveToolbarComponent` and includes various related changes across
multiple files. The most important changes include the addition of the
unlock button in the HTML template, corresponding styles, service
injections, and comprehensive unit tests to ensure the functionality
works as expected.

### Unlock Button Feature:

*
[`dot-uve-toolbar.component.html`](diffhunk://#diff-9937556e73b051b878ba22ad1ce971a70019a617d7979b3e0bcc814801ad350bR31-R43):
Added the unlock button with various properties and event binding for
unlocking a page.
*
[`dot-uve-toolbar.component.scss`](diffhunk://#diff-dd2bc3ab605f3a154f1a4b3b5de1f8e364e7bbc5a3fb4b078bba74aaedcad312R18-R22):
Added styles for the unlock button, including handling the disabled
state.
*
[`dot-uve-toolbar.component.ts`](diffhunk://#diff-217a9e619d6590c4f652e85353b9637ba5e464ddeb0424be35aef39bb8dceb30L29-R36):
Injected `DotContentletLockerService` and added the `unlockPage` method
to handle the unlocking logic.
[[1]](diffhunk://#diff-217a9e619d6590c4f652e85353b9637ba5e464ddeb0424be35aef39bb8dceb30L29-R36)
[[2]](diffhunk://#diff-217a9e619d6590c4f652e85353b9637ba5e464ddeb0424be35aef39bb8dceb30R93-R102)
[[3]](diffhunk://#diff-217a9e619d6590c4f652e85353b9637ba5e464ddeb0424be35aef39bb8dceb30R312-R347)
*
[`dot-uve-toolbar.component.spec.ts`](diffhunk://#diff-3eaa147616a5d1ff374a5fa27b0f38f0159a9039ef7e8d672dec43631f48a9e1R14):
Added unit tests for the unlock button, including tests for visibility,
state, and service call verification.
[[1]](diffhunk://#diff-3eaa147616a5d1ff374a5fa27b0f38f0159a9039ef7e8d672dec43631f48a9e1R14)
[[2]](diffhunk://#diff-3eaa147616a5d1ff374a5fa27b0f38f0159a9039ef7e8d672dec43631f48a9e1L112-R114)
[[3]](diffhunk://#diff-3eaa147616a5d1ff374a5fa27b0f38f0159a9039ef7e8d672dec43631f48a9e1R123)
[[4]](diffhunk://#diff-3eaa147616a5d1ff374a5fa27b0f38f0159a9039ef7e8d672dec43631f48a9e1R141-R143)
[[5]](diffhunk://#diff-3eaa147616a5d1ff374a5fa27b0f38f0159a9039ef7e8d672dec43631f48a9e1R206)
[[6]](diffhunk://#diff-3eaa147616a5d1ff374a5fa27b0f38f0159a9039ef7e8d672dec43631f48a9e1R227-R302)

### Additional Changes:

*
[`models.ts`](diffhunk://#diff-4b111bf572c55ee766710e9b4ac256c014112a06ad7e08baa8302b290458338bL9-R23):
Updated interfaces to include `UnlockOptions` for the new unlock button
feature.
*
[`withUVEToolbar.spec.ts`](diffhunk://#diff-7a5de702ac1dc81304f4c31816f5c0363aa56141f8afa583a87856e7a0d8482dL32-R32):
Adjusted the initial state to include `mockCurrentUser` for testing
purposes.
[[1]](diffhunk://#diff-7a5de702ac1dc81304f4c31816f5c0363aa56141f8afa583a87856e7a0d8482dL32-R32)
[[2]](diffhunk://#diff-7a5de702ac1dc81304f4c31816f5c0363aa56141f8afa583a87856e7a0d8482dL112-L128)
  • Loading branch information
zJaaal authored Jan 13, 2025
1 parent 52d9691 commit 80c3d62
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 127 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@
}

<div class="p-toolbar-group-end">
@if ($unlockButton(); as unlockButton) {
<p-button
[disabled]="unlockButton.disabled"
[pTooltip]="unlockButton.info.message | dm: unlockButton.info.args"
[escape]="false"
tooltipPosition="bottom"
icon="pi pi-lock"
styleClass="p-button-text p-button-sm p-button-rounded unlock-button"
[loading]="unlockButton.loading"
(click)="unlockPage(unlockButton.inode)"
data-testId="uve-toolbar-unlock-button"></p-button>
}

@if (runningExperiment) {
<dot-ema-running-experiment
[runningExperiment]="runningExperiment"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
color: var(--color-palette-primary-500);
cursor: pointer;
}

.p-button.unlock-button:disabled {
pointer-events: auto;
color: $color-palette-primary-500;
}
}

.p-toolbar-group-start,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ConfirmationService, MessageService } from 'primeng/api';

import { UVE_MODE } from '@dotcms/client';
import {
DotContentletLockerService,
DotDevicesService,
DotExperimentsService,
DotLanguagesService,
Expand Down Expand Up @@ -109,7 +110,8 @@ const baseUVEState = {
patchViewParams: jest.fn(),
orientation: signal(''),
clearDeviceAndSocialMedia: jest.fn(),
device: signal(DEFAULT_DEVICES.find((device) => device.inode === 'default'))
device: signal(DEFAULT_DEVICES.find((device) => device.inode === 'default')),
$unlockButton: signal(null)
};

describe('DotUveToolbarComponent', () => {
Expand All @@ -118,6 +120,7 @@ describe('DotUveToolbarComponent', () => {
let messageService: MessageService;
let confirmationService: ConfirmationService;
let devicesService: DotDevicesService;
let dotContentletLockerService: DotContentletLockerService;

const fixedDate = new Date('2024-01-01');
jest.spyOn(global, 'Date').mockImplementation(() => fixedDate);
Expand All @@ -135,6 +138,9 @@ describe('DotUveToolbarComponent', () => {
providers: [
UVEStore,
provideHttpClientTesting(),
mockProvider(DotContentletLockerService, {
unlock: jest.fn().mockReturnValue(of({}))
}),
mockProvider(ConfirmationService, {
confirm: jest.fn()
}),
Expand Down Expand Up @@ -197,6 +203,7 @@ describe('DotUveToolbarComponent', () => {
messageService = spectator.inject(MessageService, true);
devicesService = spectator.inject(DotDevicesService);
confirmationService = spectator.inject(ConfirmationService, true);
dotContentletLockerService = spectator.inject(DotContentletLockerService);
});

it('should have a dot-uve-workflow-actions component', () => {
Expand All @@ -217,6 +224,82 @@ describe('DotUveToolbarComponent', () => {
});
});

describe('unlock button', () => {
it('should be null', () => {
expect(spectator.query(byTestId('uve-toolbar-unlock-button'))).toBeNull();
});

it('should be true', () => {
baseUVEState.$unlockButton.set({
inode: '123',
disabled: false,
loading: false,
info: {
message: 'editpage.toolbar.page.release.lock.locked.by.user',
args: ['John Doe']
}
});
spectator.detectChanges();

expect(spectator.query(byTestId('uve-toolbar-unlock-button'))).toBeTruthy();
});

it('should be disabled', () => {
baseUVEState.$unlockButton.set({
disabled: true,
loading: false,
info: {
message: 'editpage.toolbar.page.release.lock.locked.by.user',
args: ['John Doe']
},
inode: '123'
});
spectator.detectChanges();
expect(
spectator
.query(byTestId('uve-toolbar-unlock-button'))
.getAttribute('ng-reflect-disabled')
).toEqual('true');
});

it('should be loading', () => {
baseUVEState.$unlockButton.set({
loading: true,
disabled: false,
inode: '123',
info: {
message: 'editpage.toolbar.page.release.lock.locked.by.user',
args: ['John Doe']
}
});
spectator.detectChanges();
expect(
spectator
.query(byTestId('uve-toolbar-unlock-button'))
.getAttribute('ng-reflect-loading')
).toEqual('true');
});

it('should call dotContentletLockerService.unlockPage', () => {
const spy = jest.spyOn(dotContentletLockerService, 'unlock');

baseUVEState.$unlockButton.set({
loading: true,
disabled: false,
inode: '123',
info: {
message: 'editpage.toolbar.page.release.lock.locked.by.user',
args: ['John Doe']
}
});
spectator.detectChanges();

spectator.click(byTestId('uve-toolbar-unlock-button'));

expect(spy).toHaveBeenCalledWith('123');
});
});

describe('dot-ema-bookmarks', () => {
it('should have attr', () => {
const bookmarks = spectator.query(DotEmaBookmarksComponent);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { tapResponse } from '@ngrx/operators';

import { ClipboardModule } from '@angular/cdk/clipboard';
import { NgClass, NgTemplateOutlet } from '@angular/common';
import {
Expand Down Expand Up @@ -26,7 +28,12 @@ import { ToolbarModule } from 'primeng/toolbar';
import { map } from 'rxjs/operators';

import { UVE_MODE } from '@dotcms/client';
import { DotDevicesService, DotMessageService, DotPersonalizeService } from '@dotcms/data-access';
import {
DotContentletLockerService,
DotDevicesService,
DotMessageService,
DotPersonalizeService
} from '@dotcms/data-access';
import { DotPersona, DotLanguage, DotDeviceListItem } from '@dotcms/dotcms-models';
import { DotMessagePipe } from '@dotcms/ui';

Expand Down Expand Up @@ -83,13 +90,16 @@ export class DotUveToolbarComponent {
readonly #confirmationService = inject(ConfirmationService);
readonly #personalizeService = inject(DotPersonalizeService);
readonly #deviceService = inject(DotDevicesService);
readonly #dotContentletLockerService = inject(DotContentletLockerService);

readonly $toolbar = this.#store.$uveToolbar;
readonly $showWorkflowActions = this.#store.$showWorkflowsActions;
readonly $isPreviewMode = this.#store.$isPreviewMode;
readonly $apiURL = this.#store.$apiURL;
readonly $personaSelectorProps = this.#store.$personaSelector;
readonly $infoDisplayProps = this.#store.$infoDisplayProps;
readonly $unlockButton = this.#store.$unlockButton;

readonly $devices: Signal<DotDeviceListItem[]> = toSignal(
this.#deviceService.get().pipe(map((devices = []) => [...DEFAULT_DEVICES, ...devices])),
{
Expand Down Expand Up @@ -299,4 +309,40 @@ export class DotUveToolbarComponent {
}
});
}

/**
* Unlocks a page with the specified inode.
*
* @param {string} inode
* @memberof EditEmaToolbarComponent
*/
unlockPage(inode: string) {
this.#messageService.add({
severity: 'info',
summary: this.#dotMessageService.get('edit.ema.page.unlock'),
detail: this.#dotMessageService.get('edit.ema.page.is.being.unlocked')
});

this.#dotContentletLockerService
.unlock(inode)
.pipe(
tapResponse({
next: () => {
this.#messageService.add({
severity: 'success',
summary: this.#dotMessageService.get('edit.ema.page.unlock'),
detail: this.#dotMessageService.get('edit.ema.page.unlock.success')
});
},
error: () => {
this.#messageService.add({
severity: 'error',
summary: this.#dotMessageService.get('edit.ema.page.unlock'),
detail: this.#dotMessageService.get('edit.ema.page.unlock.error')
});
}
})
)
.subscribe(() => this.#store.reloadCurrentPage());
}
}
17 changes: 13 additions & 4 deletions core-web/libs/portlets/edit-ema/portlet/src/lib/shared/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@ import { CommonErrors, DialogStatus, FormStatus } from './enums';

import { DotPageApiParams } from '../services/dot-page-api.service';

export interface MessagePipeOptions {
message: string;
args: string[];
}

export interface UnlockOptions {
inode: string;
loading: boolean;
info: MessagePipeOptions;
disabled: boolean;
}

export interface InfoOptions {
icon: string;
info: {
message: string;
args: string[];
};
info: MessagePipeOptions;
id: string;
actionIcon?: string;
}
Expand Down
Loading

0 comments on commit 80c3d62

Please sign in to comment.