mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ACS-5748] The file gets unshared when setting the past expiration date (#8876)
* [ACS-5748] set validation for share link input * [ACS-5748] code smells * [ACS-5748] lint * [ACS-5748] rebase * [ACS-5748] CR fixes * [ACS-5748] rebase
This commit is contained in:
committed by
GitHub
parent
06bfded238
commit
44694c0ee1
@@ -51,7 +51,12 @@
|
|||||||
[attr.aria-label]="'SHARE.EXPIRATION-LABEL' | translate"
|
[attr.aria-label]="'SHARE.EXPIRATION-LABEL' | translate"
|
||||||
[min]="minDate"
|
[min]="minDate"
|
||||||
formControlName="time"
|
formControlName="time"
|
||||||
[matDatepicker]="datePicker" />
|
(keydown)="preventIncorrectCharacters($event)"
|
||||||
|
(blur)="onTimeChanged()"
|
||||||
|
(keydown.enter)="datePickerInput.blur()"
|
||||||
|
[matDatepicker]="datePicker"/>
|
||||||
|
<mat-error *ngIf="time.errors?.['invalidDate'] && (time.dirty || time.touched)"
|
||||||
|
data-automation-id="adf-share-link-input-warning">{{ 'SHARE.INVALID_DATE_ERROR' | translate }}</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<p class="adf-share-link__info adf-share-link__para">{{ 'SHARE.SHARE-LINK' | translate }}</p>
|
<p class="adf-share-link__info adf-share-link__para">{{ 'SHARE.SHARE-LINK' | translate }}</p>
|
||||||
|
@@ -21,12 +21,12 @@ import { of } from 'rxjs';
|
|||||||
import { NotificationService, AppConfigService } from '@alfresco/adf-core';
|
import { NotificationService, AppConfigService } from '@alfresco/adf-core';
|
||||||
import { NodesApiService } from '../common/services/nodes-api.service';
|
import { NodesApiService } from '../common/services/nodes-api.service';
|
||||||
import { RenditionService } from '../common/services/rendition.service';
|
import { RenditionService } from '../common/services/rendition.service';
|
||||||
|
|
||||||
import { SharedLinksApiService } from './services/shared-links-api.service';
|
import { SharedLinksApiService } from './services/shared-links-api.service';
|
||||||
import { ShareDialogComponent } from './content-node-share.dialog';
|
import { ShareDialogComponent } from './content-node-share.dialog';
|
||||||
import { ContentTestingModule } from '../testing/content.testing.module';
|
import { ContentTestingModule } from '../testing/content.testing.module';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { format, endOfDay } from 'date-fns';
|
import { format, endOfDay } from 'date-fns';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
describe('ShareDialogComponent', () => {
|
describe('ShareDialogComponent', () => {
|
||||||
let node;
|
let node;
|
||||||
@@ -45,6 +45,17 @@ describe('ShareDialogComponent', () => {
|
|||||||
|
|
||||||
const getShareToggleLinkedClasses = (): DOMTokenList => fixture.nativeElement.querySelector(shareToggleId).classList;
|
const getShareToggleLinkedClasses = (): DOMTokenList => fixture.nativeElement.querySelector(shareToggleId).classList;
|
||||||
|
|
||||||
|
const fillInDatepickerInput = (value: string) => {
|
||||||
|
const input = fixture.debugElement.query(By.css('.adf-share-link__input')).nativeElement;
|
||||||
|
input.value = value;
|
||||||
|
input.dispatchEvent(new Event('input'));
|
||||||
|
input.dispatchEvent(new Event('blur'));
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
const clickExpireToggleButton = () => fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
||||||
|
.dispatchEvent(new MouseEvent('click'));
|
||||||
|
|
||||||
const clickShareToggleButton = () => fixture.nativeElement.querySelector(`${shareToggleId} label`)
|
const clickShareToggleButton = () => fixture.nativeElement.querySelector(`${shareToggleId} label`)
|
||||||
.dispatchEvent(new MouseEvent('click'));
|
.dispatchEvent(new MouseEvent('click'));
|
||||||
|
|
||||||
@@ -250,17 +261,10 @@ describe('ShareDialogComponent', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
component.form.controls['time'].setValue(new Date());
|
component.form.controls['time'].setValue(new Date());
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
clickExpireToggleButton();
|
||||||
fixture.nativeElement
|
|
||||||
.querySelector('.mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
|
||||||
.dispatchEvent(new MouseEvent('click'));
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
|
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
|
||||||
@@ -304,10 +308,10 @@ describe('ShareDialogComponent', () => {
|
|||||||
spyOn(appConfigService, 'get').and.callFake(() => dateTimePickerType as any);
|
spyOn(appConfigService, 'get').and.callFake(() => dateTimePickerType as any);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
clickExpireToggleButton();
|
||||||
.dispatchEvent(new MouseEvent('click'));
|
|
||||||
|
|
||||||
fixture.componentInstance.time.setValue(date);
|
fixture.componentInstance.time.setValue(date);
|
||||||
|
component.onTimeChanged();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
tick(500);
|
tick(500);
|
||||||
|
|
||||||
@@ -326,11 +330,11 @@ describe('ShareDialogComponent', () => {
|
|||||||
spyOn(appConfigService, 'get').and.returnValue(dateTimePickerType);
|
spyOn(appConfigService, 'get').and.returnValue(dateTimePickerType);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
clickExpireToggleButton();
|
||||||
.dispatchEvent(new MouseEvent('click'));
|
|
||||||
|
|
||||||
fixture.componentInstance.type = 'datetime';
|
fixture.componentInstance.type = 'datetime';
|
||||||
fixture.componentInstance.time.setValue(date);
|
fixture.componentInstance.time.setValue(date);
|
||||||
|
component.onTimeChanged();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
tick(100);
|
tick(100);
|
||||||
|
|
||||||
@@ -342,5 +346,44 @@ describe('ShareDialogComponent', () => {
|
|||||||
expiresAt: expiryDate
|
expiresAt: expiryDate
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should not update node when provided date is less than minDate', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
clickExpireToggleButton();
|
||||||
|
fillInDatepickerInput('01.01.2010');
|
||||||
|
|
||||||
|
expect(component.form.invalid).toBeTrue();
|
||||||
|
expect(sharedLinksApiService.deleteSharedLink).not.toHaveBeenCalled();
|
||||||
|
expect(sharedLinksApiService.createSharedLinks).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not accept alphabets in the datepicker input', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
clickExpireToggleButton();
|
||||||
|
fillInDatepickerInput('test');
|
||||||
|
|
||||||
|
expect(component.form.invalid).toBeTrue();
|
||||||
|
expect(component.form.controls['time'].value).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show an error if provided date is invalid', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
clickExpireToggleButton();
|
||||||
|
fillInDatepickerInput('32');
|
||||||
|
const error = fixture.debugElement.query(By.css('[data-automation-id="adf-share-link-input-warning"]'));
|
||||||
|
|
||||||
|
expect(error).toBeTruthy();
|
||||||
|
expect(component.time.hasError('invalidDate')).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show an error when provided date is valid', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
clickExpireToggleButton();
|
||||||
|
fillInDatepickerInput('12.12.2525');
|
||||||
|
const error = fixture.debugElement.query(By.css('[data-automation-id="adf-share-link-input-warning"]'));
|
||||||
|
|
||||||
|
expect(error).toBeNull();
|
||||||
|
expect(component.time.hasError('invalidDate')).toBeFalse();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -18,17 +18,21 @@
|
|||||||
import { Component, Inject, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core';
|
import { Component, Inject, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
||||||
import { UntypedFormGroup, UntypedFormControl, AbstractControl } from '@angular/forms';
|
import {
|
||||||
|
UntypedFormGroup,
|
||||||
|
UntypedFormControl,
|
||||||
|
AbstractControl,
|
||||||
|
Validators,
|
||||||
|
ValidationErrors
|
||||||
|
} from '@angular/forms';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { ContentService } from '../common/services/content.service';
|
import { ContentService } from '../common/services/content.service';
|
||||||
|
|
||||||
import { SharedLinksApiService } from './services/shared-links-api.service';
|
import { SharedLinksApiService } from './services/shared-links-api.service';
|
||||||
import { SharedLinkBodyCreate, SharedLinkEntry } from '@alfresco/js-api';
|
import { SharedLinkBodyCreate, SharedLinkEntry } from '@alfresco/js-api';
|
||||||
import { ConfirmDialogComponent } from '../dialogs/confirm.dialog';
|
import { ConfirmDialogComponent } from '../dialogs/confirm.dialog';
|
||||||
import { ContentNodeShareSettings } from './content-node-share.settings';
|
import { ContentNodeShareSettings } from './content-node-share.settings';
|
||||||
import { takeUntil, debounceTime } from 'rxjs/operators';
|
|
||||||
import { RenditionService } from '../common/services/rendition.service';
|
import { RenditionService } from '../common/services/rendition.service';
|
||||||
import { format, add, endOfDay } from 'date-fns';
|
import { format, add, endOfDay, isBefore } from 'date-fns';
|
||||||
|
|
||||||
type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||||
|
|
||||||
@@ -40,6 +44,10 @@ type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class ShareDialogComponent implements OnInit, OnDestroy {
|
export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||||
|
private minDateValidator = (control: AbstractControl): ValidationErrors | null => {
|
||||||
|
return isBefore(endOfDay(new Date(control.value)), this.minDate) ? {invalidDate: true} : null;
|
||||||
|
};
|
||||||
|
|
||||||
minDate = add(new Date(), { days: 1 });
|
minDate = add(new Date(), { days: 1 });
|
||||||
sharedId: string;
|
sharedId: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
@@ -49,7 +57,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
isLinkWithExpiryDate = false;
|
isLinkWithExpiryDate = false;
|
||||||
form: UntypedFormGroup = new UntypedFormGroup({
|
form: UntypedFormGroup = new UntypedFormGroup({
|
||||||
sharedUrl: new UntypedFormControl(''),
|
sharedUrl: new UntypedFormControl(''),
|
||||||
time: new UntypedFormControl({ value: '', disabled: true })
|
time: new UntypedFormControl({value: '', disabled: true}, [Validators.required, this.minDateValidator])
|
||||||
});
|
});
|
||||||
type: DatePickerType = 'date';
|
type: DatePickerType = 'date';
|
||||||
maxDebounceTime = 500;
|
maxDebounceTime = 500;
|
||||||
@@ -90,12 +98,12 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
this.isLinkWithExpiryDate ? this.time.enable() : this.time.disable();
|
this.isLinkWithExpiryDate ? this.time.enable() : this.time.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.time.valueChanges.pipe(debounceTime(this.maxDebounceTime), takeUntil(this.onDestroy$)).subscribe((value) => this.onTimeChanged(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onTimeChanged(date: Date) {
|
onTimeChanged() {
|
||||||
this.updateNode(date);
|
if (this.time.valid) {
|
||||||
|
this.updateNode(this.time.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get time(): AbstractControl {
|
get time(): AbstractControl {
|
||||||
@@ -137,12 +145,17 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onDatePickerClosed() {
|
onDatePickerClosed() {
|
||||||
this.datePickerInput.nativeElement.blur();
|
this.onTimeChanged();
|
||||||
if (!this.time.value) {
|
if (!this.time.value) {
|
||||||
this.slideToggleExpirationDate.checked = false;
|
this.slideToggleExpirationDate.checked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preventIncorrectCharacters(e: KeyboardEvent): boolean {
|
||||||
|
const regex = /[^\d/.-]/;
|
||||||
|
return e.key.length === 1 ? !regex.test(e.key) : true;
|
||||||
|
}
|
||||||
|
|
||||||
private openConfirmationDialog() {
|
private openConfirmationDialog() {
|
||||||
this.isFileShared = false;
|
this.isFileShared = false;
|
||||||
|
|
||||||
|
@@ -533,7 +533,8 @@
|
|||||||
"REMOVE": "Remove"
|
"REMOVE": "Remove"
|
||||||
},
|
},
|
||||||
"UNSHARE_ERROR": "Error unsharing this file",
|
"UNSHARE_ERROR": "Error unsharing this file",
|
||||||
"UNSHARE_PERMISSION_ERROR": "You don't have permission to unshare this file"
|
"UNSHARE_PERMISSION_ERROR": "You don't have permission to unshare this file",
|
||||||
|
"INVALID_DATE_ERROR": "Invalid date"
|
||||||
},
|
},
|
||||||
"PERMISSION_MANAGER": {
|
"PERMISSION_MANAGER": {
|
||||||
"PERMISSION_DISPLAY": {
|
"PERMISSION_DISPLAY": {
|
||||||
|
Reference in New Issue
Block a user