mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[APPS-2108] break direct dependency on moment.js (#9032)
* break direct dependency on moment.js * [ci:force] preserve moment for cli tools * remove MatMomentDatetimeModule from content * share dialog fixes * revert testing module changes * remove incorrect date modules * fix html
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
color="primary"
|
||||
data-automation-id="adf-expire-toggle"
|
||||
aria-label="{{ 'SHARE.EXPIRES' | translate }}"
|
||||
[checked]="time.value"
|
||||
[checked]="!!time.value"
|
||||
(change)="onToggleExpirationDate($event)">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
@@ -27,9 +27,10 @@ import { ContentTestingModule } from '../testing/content.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { format, endOfDay } from 'date-fns';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
|
||||
describe('ShareDialogComponent', () => {
|
||||
let node;
|
||||
let node: NodeEntry;
|
||||
let matDialog: MatDialog;
|
||||
const notificationServiceMock = {
|
||||
openSnackMessage: jasmine.createSpy('openSnackMessage')
|
||||
@@ -42,6 +43,7 @@ describe('ShareDialogComponent', () => {
|
||||
let appConfigService: AppConfigService;
|
||||
|
||||
const shareToggleId = '[data-automation-id="adf-share-toggle"]';
|
||||
const expireToggle = '[data-automation-id="adf-expire-toggle"]';
|
||||
|
||||
const getShareToggleLinkedClasses = (): DOMTokenList => fixture.nativeElement.querySelector(shareToggleId).classList;
|
||||
|
||||
@@ -53,32 +55,26 @@ describe('ShareDialogComponent', () => {
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
const clickExpireToggleButton = () => fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
const clickExpireToggleButton = () => fixture.nativeElement.querySelector(`${expireToggle} label`).dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
const clickShareToggleButton = () => fixture.nativeElement.querySelector(`${shareToggleId} label`)
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
const clickShareToggleButton = () => fixture.nativeElement.querySelector(`${shareToggleId} label`).dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ContentTestingModule
|
||||
],
|
||||
imports: [TranslateModule.forRoot(), ContentTestingModule],
|
||||
providers: [
|
||||
{provide: NotificationService, useValue: notificationServiceMock},
|
||||
{ provide: NotificationService, useValue: notificationServiceMock },
|
||||
{
|
||||
provide: MatDialogRef, useValue: {
|
||||
close: () => {
|
||||
}
|
||||
provide: MatDialogRef,
|
||||
useValue: {
|
||||
close: () => {}
|
||||
}
|
||||
},
|
||||
{provide: MAT_DIALOG_DATA, useValue: {}}
|
||||
{ provide: MAT_DIALOG_DATA, useValue: {} }
|
||||
]
|
||||
});
|
||||
fixture = TestBed.createComponent(ShareDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.maxDebounceTime = 0;
|
||||
|
||||
matDialog = TestBed.inject(MatDialog);
|
||||
sharedLinksApiService = TestBed.inject(SharedLinksApiService);
|
||||
@@ -89,8 +85,15 @@ describe('ShareDialogComponent', () => {
|
||||
node = {
|
||||
entry: {
|
||||
id: 'nodeId',
|
||||
name: 'node1',
|
||||
nodeType: 'cm:content',
|
||||
allowableOperations: ['update'],
|
||||
isFile: true,
|
||||
isFolder: false,
|
||||
modifiedAt: null,
|
||||
modifiedByUser: null,
|
||||
createdAt: null,
|
||||
createdByUser: null,
|
||||
properties: {}
|
||||
}
|
||||
};
|
||||
@@ -104,9 +107,7 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
describe('Error Handling', () => {
|
||||
it('should emit a generic error when unshare fails', (done) => {
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(
|
||||
of(new Error(`{ "error": { "statusCode": 999 } }`))
|
||||
);
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of(new Error(`{ "error": { "statusCode": 999 } }`)));
|
||||
|
||||
const sub = sharedLinksApiService.error.subscribe((err) => {
|
||||
expect(err.statusCode).toBe(999);
|
||||
@@ -119,9 +120,7 @@ describe('ShareDialogComponent', () => {
|
||||
});
|
||||
|
||||
it('should emit permission error when unshare fails', (done) => {
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(
|
||||
of(new Error(`{ "error": { "statusCode": 403 } }`))
|
||||
);
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of(new Error(`{ "error": { "statusCode": 403 } }`)));
|
||||
|
||||
const sub = sharedLinksApiService.error.subscribe((err) => {
|
||||
expect(err.statusCode).toBe(403);
|
||||
@@ -135,10 +134,12 @@ describe('ShareDialogComponent', () => {
|
||||
});
|
||||
|
||||
it(`should toggle share action when property 'sharedId' does not exists`, () => {
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of({
|
||||
entry: {id: 'sharedId', sharedId: 'sharedId'}
|
||||
}));
|
||||
spyOn(renditionService, 'getNodeRendition').and.returnValue(Promise.resolve({url: '', mimeType: ''}));
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(
|
||||
of({
|
||||
entry: { id: 'sharedId', sharedId: 'sharedId' }
|
||||
})
|
||||
);
|
||||
spyOn(renditionService, 'getNodeRendition').and.returnValue(Promise.resolve({ url: '', mimeType: '' }));
|
||||
|
||||
component.data = {
|
||||
node,
|
||||
@@ -154,10 +155,12 @@ describe('ShareDialogComponent', () => {
|
||||
});
|
||||
|
||||
it(`should not toggle share action when file has 'sharedId' property`, async () => {
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of({
|
||||
entry: {id: 'sharedId', sharedId: 'sharedId'}
|
||||
}));
|
||||
spyOn(renditionService, 'getNodeRendition').and.returnValue(Promise.resolve({url: '', mimeType: ''}));
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(
|
||||
of({
|
||||
entry: { id: 'sharedId', sharedId: 'sharedId' }
|
||||
})
|
||||
);
|
||||
spyOn(renditionService, 'getNodeRendition').and.returnValue(Promise.resolve({ url: '', mimeType: '' }));
|
||||
|
||||
node.entry.properties['qshare:sharedId'] = 'sharedId';
|
||||
|
||||
@@ -177,7 +180,7 @@ describe('ShareDialogComponent', () => {
|
||||
});
|
||||
|
||||
it('should open a confirmation dialog when unshare button is triggered', () => {
|
||||
spyOn(matDialog, 'open').and.returnValue({beforeClosed: () => of(false)} as any);
|
||||
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any);
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough();
|
||||
|
||||
node.entry.properties['qshare:sharedId'] = 'sharedId';
|
||||
@@ -197,7 +200,7 @@ describe('ShareDialogComponent', () => {
|
||||
});
|
||||
|
||||
it('should unshare file when confirmation dialog returns true', fakeAsync(() => {
|
||||
spyOn(matDialog, 'open').and.returnValue({beforeClosed: () => of(true)} as any);
|
||||
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(true) } as any);
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of({}));
|
||||
node.entry.properties['qshare:sharedId'] = 'sharedId';
|
||||
|
||||
@@ -216,7 +219,7 @@ describe('ShareDialogComponent', () => {
|
||||
}));
|
||||
|
||||
it('should not unshare file when confirmation dialog returns false', fakeAsync(() => {
|
||||
spyOn(matDialog, 'open').and.returnValue({beforeClosed: () => of(false)} as any);
|
||||
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any);
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough();
|
||||
node.entry.properties['qshare:sharedId'] = 'sharedId';
|
||||
|
||||
@@ -283,12 +286,10 @@ describe('ShareDialogComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(fixture.nativeElement.querySelector('.mat-slide-toggle[data-automation-id="adf-expire-toggle"]')
|
||||
.classList).toContain('mat-disabled');
|
||||
expect(fixture.nativeElement.querySelector('.mat-slide-toggle[data-automation-id="adf-expire-toggle"]').classList).toContain('mat-disabled');
|
||||
expect(fixture.nativeElement.querySelector('[data-automation-id="adf-slide-toggle-checked"]').style.display).toEqual('none');
|
||||
});
|
||||
|
||||
|
||||
describe('datetimepicker type', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of());
|
||||
@@ -324,29 +325,6 @@ describe('ShareDialogComponent', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should update node with input date and time when type is `datetime`', fakeAsync(() => {
|
||||
const dateTimePickerType = 'datetime';
|
||||
const date = new Date('2525-01-01 13:00:00');
|
||||
spyOn(appConfigService, 'get').and.returnValue(dateTimePickerType);
|
||||
|
||||
fixture.detectChanges();
|
||||
clickExpireToggleButton();
|
||||
|
||||
fixture.componentInstance.type = 'datetime';
|
||||
fixture.componentInstance.time.setValue(date);
|
||||
component.onTimeChanged();
|
||||
fixture.detectChanges();
|
||||
tick(100);
|
||||
|
||||
const expiryDate = format((new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
|
||||
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
|
||||
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith('nodeId', {
|
||||
nodeId: 'nodeId',
|
||||
expiresAt: expiryDate
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not update node when provided date is less than minDate', () => {
|
||||
fixture.detectChanges();
|
||||
clickExpireToggleButton();
|
||||
@@ -366,10 +344,14 @@ describe('ShareDialogComponent', () => {
|
||||
expect(component.form.controls['time'].value).toBeNull();
|
||||
});
|
||||
|
||||
it('should show an error if provided date is invalid', () => {
|
||||
it('should show an error if provided date is invalid', async () => {
|
||||
fixture.detectChanges();
|
||||
clickExpireToggleButton();
|
||||
fillInDatepickerInput('32');
|
||||
fillInDatepickerInput('incorrect');
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const error = fixture.debugElement.query(By.css('[data-automation-id="adf-share-link-input-warning"]'));
|
||||
|
||||
expect(error).toBeTruthy();
|
||||
|
@@ -18,17 +18,20 @@
|
||||
import { Component, Inject, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
||||
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Subject } from 'rxjs';
|
||||
import { ContentService } from '../common/services/content.service';
|
||||
import { SharedLinksApiService } from './services/shared-links-api.service';
|
||||
import { SharedLinkBodyCreate, SharedLinkEntry } from '@alfresco/js-api';
|
||||
import { SharedLinkBodyCreate } from '@alfresco/js-api';
|
||||
import { ConfirmDialogComponent } from '../dialogs/confirm.dialog';
|
||||
import { ContentNodeShareSettings } from './content-node-share.settings';
|
||||
import { RenditionService } from '../common/services/rendition.service';
|
||||
import { format, add, endOfDay, isBefore } from 'date-fns';
|
||||
|
||||
type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||
interface SharedDialogFormProps {
|
||||
sharedUrl: FormControl<string>;
|
||||
time: FormControl<Date>;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'adf-share-dialog',
|
||||
@@ -38,7 +41,7 @@ type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
private minDateValidator = (control: AbstractControl): any =>
|
||||
private minDateValidator = (control: FormControl<Date>): any =>
|
||||
isBefore(endOfDay(new Date(control.value)), this.minDate) ? { invalidDate: true } : null;
|
||||
|
||||
minDate = add(new Date(), { days: 1 });
|
||||
@@ -48,20 +51,15 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
isFileShared = false;
|
||||
isDisabled = false;
|
||||
isLinkWithExpiryDate = false;
|
||||
form: FormGroup = new FormGroup({
|
||||
form = new FormGroup<SharedDialogFormProps>({
|
||||
sharedUrl: new FormControl(''),
|
||||
time: new FormControl({ value: '', disabled: true }, [Validators.required, this.minDateValidator])
|
||||
time: new FormControl({ value: null, disabled: true }, [Validators.required, this.minDateValidator])
|
||||
});
|
||||
type: DatePickerType = 'date';
|
||||
maxDebounceTime = 500;
|
||||
isExpiryDateToggleChecked: boolean;
|
||||
|
||||
@ViewChild('slideToggleExpirationDate', { static: true })
|
||||
slideToggleExpirationDate;
|
||||
|
||||
@ViewChild('datePickerInput', { static: true })
|
||||
datePickerInput;
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
@@ -99,7 +97,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
get time(): AbstractControl {
|
||||
get time(): FormControl<Date> {
|
||||
return this.form.controls['time'];
|
||||
}
|
||||
|
||||
@@ -177,7 +175,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
this.isDisabled = true;
|
||||
|
||||
this.sharedLinksApiService.createSharedLinks(nodeId, sharedLinkWithExpirySettings).subscribe(
|
||||
(sharedLink: SharedLinkEntry) => {
|
||||
(sharedLink) => {
|
||||
if (sharedLink.entry) {
|
||||
this.sharedId = sharedLink.entry.id;
|
||||
if (this.data.node.entry.properties) {
|
||||
@@ -267,11 +265,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
private updateNode(date: Date) {
|
||||
let expiryDate: Date | string;
|
||||
if (date) {
|
||||
if (this.type === 'date') {
|
||||
expiryDate = format(endOfDay(new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
} else {
|
||||
expiryDate = format(new Date(date), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
}
|
||||
expiryDate = format(endOfDay(new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
} else {
|
||||
expiryDate = null;
|
||||
}
|
||||
|
@@ -25,7 +25,6 @@ import { FolderDialogComponent } from './folder.dialog';
|
||||
import { NodeLockDialogComponent } from './node-lock.dialog';
|
||||
import { ConfirmDialogComponent } from './confirm.dialog';
|
||||
import { MatDatetimepickerModule } from '@mat-datetimepicker/core';
|
||||
import { MatMomentDatetimeModule } from '@mat-datetimepicker/moment';
|
||||
import { LibraryDialogComponent } from './library/library.dialog';
|
||||
import { ContentDirectiveModule } from '../directives';
|
||||
import { DownloadZipDialogModule } from './download-zip/download-zip.dialog.module';
|
||||
@@ -37,7 +36,6 @@ import { DownloadZipDialogModule } from './download-zip/download-zip.dialog.modu
|
||||
CoreModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatMomentDatetimeModule,
|
||||
MatDatetimepickerModule,
|
||||
ContentDirectiveModule,
|
||||
DownloadZipDialogModule
|
||||
|
Reference in New Issue
Block a user