mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[PRODSEC-6575] Shared link not accessible now after the expiry date which was earlier accessible even after that expiration date (#8540)
* Shared link expiry date code implementation * test case updated * removed unsed code * design changes as per the new design of Share dialog * test cases modification as per new design changes * placeholder modified for expiration date * look and feel changes for share dialog as per Shane comments * boolean name changed as per naming convention * review comments addressed * review comments addressed * type specified for node object * linting corrections * resolved nested ternary date operation into an independent statement * review comments addressed * used date-fns instead of moment.js in code as well as in test cases * review comments for date-fns addressed * removed extra line * removed extra empty lines in template * import changes and indentation correction * error in console resolved which was occuring after selecting date and time * used mat-datepicker instead of mat-datetimepicker * package-lock.json file updated for date-fns implementation * made type 'date' as default and removed the settings coming from the ACA * unit test case modifications as per calender changes * e2e modifications as per new calendar component
This commit is contained in:
parent
95927c6319
commit
479c96eabb
@ -132,23 +132,6 @@ describe('Share file', () => {
|
||||
await BrowserActions.closeMenuAndDialogs();
|
||||
});
|
||||
|
||||
it('[C286548] Should be possible to set expiry date for link', async () => {
|
||||
await contentServicesPage.clickShareButton();
|
||||
await shareDialog.checkDialogIsDisplayed();
|
||||
await shareDialog.clickExpireToggle();
|
||||
await shareDialog.setDefaultDay();
|
||||
await shareDialog.setDefaultHour();
|
||||
await shareDialog.setDefaultMinutes();
|
||||
await shareDialog.dateTimePickerDialogIsClosed();
|
||||
const value = await shareDialog.getExpirationDate();
|
||||
await shareDialog.clickCloseButton();
|
||||
await shareDialog.dialogIsClosed();
|
||||
await contentServicesPage.clickShareButton();
|
||||
await shareDialog.checkDialogIsDisplayed();
|
||||
await shareDialog.expirationDateInputHasValue(value);
|
||||
await BrowserActions.closeMenuAndDialogs();
|
||||
});
|
||||
|
||||
it('[C310329] Should be possible to set expiry date only for link', async () => {
|
||||
await LocalStorageUtil.setConfigField('sharedLinkDateTimePickerType', JSON.stringify('date'));
|
||||
await contentServicesPage.clickShareButton();
|
||||
|
@ -17,8 +17,7 @@
|
||||
|
||||
import { $$, $ } from 'protractor';
|
||||
import { BrowserVisibility, TogglePage, BrowserActions, DateTimePickerPage } from '@alfresco/adf-testing';
|
||||
import * as moment from 'moment';
|
||||
|
||||
import { format, add } from 'date-fns';
|
||||
export class ShareDialogPage {
|
||||
|
||||
togglePage = new TogglePage();
|
||||
@ -85,7 +84,7 @@ export class ShareDialogPage {
|
||||
}
|
||||
|
||||
async calendarTodayDayIsDisabled(): Promise<void> {
|
||||
const tomorrow = moment().add(1, 'days').format('D');
|
||||
const tomorrow = format(add(new Date(), {days: 1}), 'd');
|
||||
|
||||
if (tomorrow !== '1') {
|
||||
await this.dateTimePickerPage.checkCalendarTodayDayIsDisabled();
|
||||
@ -93,7 +92,7 @@ export class ShareDialogPage {
|
||||
}
|
||||
|
||||
async setDefaultDay(): Promise<void> {
|
||||
const tomorrow = moment().add(1, 'days').format('D');
|
||||
const tomorrow = format(add(new Date(), {days: 1}), 'd');
|
||||
await this.dateTimePickerPage.setDate(tomorrow);
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,61 @@
|
||||
<div class="adf-share-link__dialog-content">
|
||||
<div data-automation-id="adf-share-dialog-title" class="adf-share-link__title" role="heading" aria-level="1">
|
||||
<div class="adf-share-link__dialog-container">
|
||||
<div class="adf-share-link--row">
|
||||
<div
|
||||
data-automation-id="adf-share-dialog-title"
|
||||
class="adf-share-link__title adf-share-link__label adf-share-link__heading"
|
||||
role="heading"
|
||||
aria-level="1">
|
||||
{{ 'SHARE.DIALOG-TITLE' | translate }} {{ fileName }}
|
||||
</div>
|
||||
|
||||
<mat-icon mat-dialog-close class="adf-share-link__close adf-share-link__icon">close</mat-icon>
|
||||
</div>
|
||||
<mat-dialog-content>
|
||||
<p class="adf-share-link__info">{{ 'SHARE.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<hr class="adf-share-link__separation-line" />
|
||||
<form [formGroup]="form" class="adf-share-link__form">
|
||||
<div class="adf-share-link--row">
|
||||
<mat-icon class="adf-share-link__icon">timer</mat-icon>
|
||||
<div class="adf-share-link__label adf-sharable-link">{{ 'SHARE.LINK-EXPIRY-DATE' | translate }}
|
||||
</div>
|
||||
<mat-slide-toggle
|
||||
#slideToggleExpirationDate
|
||||
[disabled]="!canUpdate"
|
||||
color="primary"
|
||||
data-automation-id="adf-expire-toggle"
|
||||
aria-label="{{ 'SHARE.EXPIRES' | translate }}"
|
||||
[checked]="time.value"
|
||||
(change)="onToggleExpirationDate($event)">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div
|
||||
[style.display]="isExpiryDateToggleChecked ? 'block' : 'none'"
|
||||
data-automation-id="adf-slide-toggle-checked"
|
||||
class="adf-share-link__date-time-container">
|
||||
<mat-form-field class="adf-full-width adf-float-label" floatLabel='always'>
|
||||
<mat-label>{{ 'SHARE.EXPIRATION-PLACEHOLDER' | translate }}</mat-label>
|
||||
<mat-datepicker-toggle
|
||||
[disabled]="time.disabled"
|
||||
[for]="datePicker"
|
||||
matSuffix
|
||||
class="adf-share-link__icon adf-share-link__calender-icon">
|
||||
</mat-datepicker-toggle>
|
||||
<mat-datepicker
|
||||
#datePicker
|
||||
(closed)="onDatePickerClosed()">
|
||||
</mat-datepicker>
|
||||
<input
|
||||
class="adf-share-link__input"
|
||||
#datePickerInput
|
||||
matInput
|
||||
placeholder="{{ 'SHARE.EXPIRATION-PLACEHOLDER' | translate }}"
|
||||
[attr.aria-label]="'SHARE.EXPIRATION-LABEL' | translate"
|
||||
[min]="minDate"
|
||||
formControlName="time"
|
||||
[matDatepicker]="datePicker" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<p class="adf-share-link__info adf-share-link__para">{{ 'SHARE.SHARE-LINK' | translate }}</p>
|
||||
<div class="adf-share-link--row">
|
||||
<div class="adf-share-link__label">{{ 'SHARE.TITLE' | translate }}</div>
|
||||
|
||||
<mat-slide-toggle
|
||||
color="primary"
|
||||
data-automation-id="adf-share-toggle"
|
||||
@ -17,10 +64,13 @@
|
||||
[disabled]="!canUpdate || isDisabled"
|
||||
(change)="onSlideShareChange($event)">
|
||||
</mat-slide-toggle>
|
||||
<div class="adf-share-link__label adf-sharable-link">{{ 'SHARE.SHARABLE-LINK-CREATED' | translate }}
|
||||
</div>
|
||||
|
||||
<form [formGroup]="form">
|
||||
<mat-form-field class="adf-full-width adf-float-label" floatLabel='always'>
|
||||
</div>
|
||||
<mat-form-field
|
||||
class="adf-full-width adf-float-label"
|
||||
floatLabel='always'
|
||||
[ngClass]="isLinkWithExpiryDate? 'adf-share-link__border-color' : ''">
|
||||
<input
|
||||
#sharedLinkInput
|
||||
data-automation-id="adf-share-link"
|
||||
@ -32,58 +82,34 @@
|
||||
formControlName="sharedUrl"
|
||||
readonly="readonly">
|
||||
<mat-icon
|
||||
class="adf-input-action"
|
||||
class="adf-input-action adf-share-link__icon"
|
||||
role="button"
|
||||
matSuffix
|
||||
[clipboard-notification]="'SHARE.CLIPBOARD-MESSAGE' | translate" [adf-clipboard]
|
||||
[clipboard-notification]="'SHARE.CLIPBOARD-MESSAGE' | translate"
|
||||
[adf-clipboard]
|
||||
[attr.aria-label]="'SHARE.COPY_BUTTON_LABEL' | translate"
|
||||
[target]="sharedLinkInput"
|
||||
tabindex="0">
|
||||
content_copy
|
||||
</mat-icon>
|
||||
</mat-form-field>
|
||||
|
||||
<p class="adf-share-link__warn adf-share-link__para" *ngIf="isLinkWithExpiryDate">
|
||||
{{ 'SHARE.LINK-WITH-EXPIRY-SETTINGS' | translate }}
|
||||
</p>
|
||||
<div class="adf-share-link--row">
|
||||
<div class="adf-share-link__label">{{ 'SHARE.EXPIRES' | translate }}</div>
|
||||
<mat-slide-toggle
|
||||
#slideToggleExpirationDate
|
||||
[disabled]="!canUpdate"
|
||||
color="primary"
|
||||
data-automation-id="adf-expire-toggle"
|
||||
aria-label="{{ 'SHARE.EXPIRES' | translate }}"
|
||||
[checked]="time.value"
|
||||
(change)="onToggleExpirationDate($event)">
|
||||
</mat-slide-toggle>
|
||||
<mat-icon class="adf-share-link__icon">public</mat-icon>
|
||||
<p
|
||||
class="adf-share-link__info adf-sharable-link adf-share-link__public-content adf-share-link__para">
|
||||
{{ 'SHARE.PUBLIC-CONTENT' | translate }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<mat-form-field class="adf-full-width adf-float-label" floatLabel='always'>
|
||||
<mat-datetimepicker-toggle
|
||||
#matDatetimepickerToggle="matDatetimepickerToggle"
|
||||
[disabled]="time.disabled"
|
||||
[for]="datetimePicker"
|
||||
matSuffix>
|
||||
</mat-datetimepicker-toggle>
|
||||
<mat-datetimepicker
|
||||
#datetimePicker
|
||||
(closed)="onDatetimepickerClosed()"
|
||||
[type]="type"
|
||||
[timeInterval]="1">
|
||||
</mat-datetimepicker>
|
||||
<input class="adf-share-link__input"
|
||||
#dateTimePickerInput
|
||||
matInput
|
||||
placeholder="{{ 'SHARE.EXPIRATION-LABEL' | translate }}"
|
||||
[attr.aria-label]="'SHARE.EXPIRATION-LABEL' | translate"
|
||||
[min]="minDate"
|
||||
formControlName="time"
|
||||
[matDatetimepicker]="datetimePicker" />
|
||||
</mat-form-field>
|
||||
</form>
|
||||
<hr class="adf-share-link__separation-line" />
|
||||
</mat-dialog-content>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button data-automation-id="adf-share-dialog-close" mat-button color="primary" mat-dialog-close>
|
||||
{{ 'SHARE.CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,6 +7,14 @@
|
||||
&__dialog-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
background-color: var(--theme-grey-text-background-color);
|
||||
}
|
||||
|
||||
&__dialog-container {
|
||||
background-color: var(--theme-card-background-color);
|
||||
border-radius: 16px;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
&__label,
|
||||
@ -17,7 +25,7 @@
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
font-size: var(--theme-subheading-2-font-size);
|
||||
font-size: var(--theme-body-1-font-size);
|
||||
color: var(--adf-theme-foreground-text-color-087);
|
||||
}
|
||||
|
||||
@ -25,22 +33,68 @@
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&__info {
|
||||
&__form {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
&__public-content {
|
||||
color: var(--adf-theme-foreground-text-color-054);
|
||||
font-size: var(--theme-caption-font-size);
|
||||
}
|
||||
|
||||
&__warn {
|
||||
color: var(--theme-warn-color);
|
||||
font-size: var(--theme-caption-font-size);
|
||||
}
|
||||
|
||||
&--row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
/* stylelint-disable-next-line declaration-block-no-redundant-longhand-properties */
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
&__input {
|
||||
color: var(--adf-theme-foreground-text-color-087);
|
||||
}
|
||||
|
||||
&__separation-line {
|
||||
border: 1px solid var(--theme-grey-background-color);
|
||||
margin: 8px -24px;
|
||||
}
|
||||
|
||||
&__close {
|
||||
cursor: pointer;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
color: var(--adf-theme-foreground-icon-color-054);
|
||||
}
|
||||
|
||||
&__para {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__heading {
|
||||
font-weight: 700;
|
||||
font-size: var(--theme-subheading-2-font-size);
|
||||
}
|
||||
|
||||
&__calender-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
&__date-time-container {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
&__border-color {
|
||||
border: 1px solid var(--theme-warn-color);
|
||||
}
|
||||
}
|
||||
|
||||
.adf-input-action {
|
||||
@ -49,6 +103,13 @@
|
||||
|
||||
.adf-full-width {
|
||||
width: 100%;
|
||||
background-color: var(--theme-grey-text-background-color);
|
||||
border-radius: 6px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.adf-sharable-link {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.mat-form-field-infix {
|
||||
@ -57,9 +118,13 @@
|
||||
|
||||
.mat-dialog-actions {
|
||||
justify-content: flex-end;
|
||||
padding: 0;
|
||||
margin: 8px 0 0;
|
||||
|
||||
& > button {
|
||||
text-transform: uppercase;
|
||||
color: var(--adf-theme-foreground-base-color);
|
||||
background-color: var(--theme-grey-text-background-color);
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +132,20 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-dialog-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mat-form-field-appearance-legacy .mat-form-field-underline {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mat-form-field-appearance-legacy .mat-form-field-wrapper {
|
||||
padding-bottom: 8px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 380px) {
|
||||
.mat-dialog-container {
|
||||
padding: 0 15px;
|
||||
|
@ -28,9 +28,9 @@ import { RenditionService } from '../common/services/rendition.service';
|
||||
|
||||
import { SharedLinksApiService } from './services/shared-links-api.service';
|
||||
import { ShareDialogComponent } from './content-node-share.dialog';
|
||||
import moment from 'moment';
|
||||
import { ContentTestingModule } from '../testing/content.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { format, endOfDay } from 'date-fns';
|
||||
|
||||
describe('ShareDialogComponent', () => {
|
||||
let node;
|
||||
@ -45,6 +45,13 @@ describe('ShareDialogComponent', () => {
|
||||
let component: ShareDialogComponent;
|
||||
let appConfigService: AppConfigService;
|
||||
|
||||
const shareToggleId = '[data-automation-id="adf-share-toggle"]';
|
||||
|
||||
const getShareToggleLinkedClasses = (): DOMTokenList => fixture.nativeElement.querySelector(shareToggleId).classList;
|
||||
|
||||
const clickShareToggleButton = () => fixture.nativeElement.querySelector(`${shareToggleId} label`)
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
@ -137,7 +144,7 @@ describe('ShareDialogComponent', () => {
|
||||
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalled();
|
||||
expect(renditionService.getNodeRendition).toHaveBeenCalled();
|
||||
expect(fixture.nativeElement.querySelector('input[formcontrolname="sharedUrl"]').value).toBe('some-url/sharedId');
|
||||
expect(fixture.nativeElement.querySelector('.mat-slide-toggle').classList).toContain('mat-checked');
|
||||
expect(getShareToggleLinkedClasses()).toContain('mat-checked');
|
||||
});
|
||||
|
||||
it(`should not toggle share action when file has 'sharedId' property`, async () => {
|
||||
@ -160,7 +167,7 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
expect(sharedLinksApiService.createSharedLinks).not.toHaveBeenCalled();
|
||||
expect(fixture.nativeElement.querySelector('input[formcontrolname="sharedUrl"]').value).toBe('some-url/sharedId');
|
||||
expect(fixture.nativeElement.querySelector('.mat-slide-toggle').classList).toContain('mat-checked');
|
||||
expect(getShareToggleLinkedClasses()).toContain('mat-checked');
|
||||
});
|
||||
|
||||
it('should open a confirmation dialog when unshare button is triggered', () => {
|
||||
@ -176,8 +183,7 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.nativeElement.querySelector('.mat-slide-toggle label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
clickShareToggleButton();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
@ -196,8 +202,7 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.nativeElement.querySelector('.mat-slide-toggle label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
clickShareToggleButton();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
@ -216,8 +221,7 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.nativeElement.querySelector('.mat-slide-toggle label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
clickShareToggleButton();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
@ -235,12 +239,13 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.querySelector('.mat-slide-toggle').classList).toContain('mat-disabled');
|
||||
expect(fixture.nativeElement.querySelector('input[formcontrolname="time"]').disabled).toBe(true);
|
||||
expect(fixture.nativeElement.querySelector('mat-datetimepicker-toggle button').disabled).toBe(true);
|
||||
expect(getShareToggleLinkedClasses()).toContain('mat-disabled');
|
||||
});
|
||||
|
||||
it('should reset expiration date when toggle is unchecked', async () => {
|
||||
it('should delete the current link generated with expiry date and generate a new link without expiry date when toggle is unchecked', async () => {
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of());
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of({}));
|
||||
|
||||
node.entry.properties['qshare:sharedId'] = 'sharedId';
|
||||
node.entry.properties['qshare:sharedId'] = '2017-04-15T18:31:37+00:00';
|
||||
node.entry.allowableOperations = ['update'];
|
||||
@ -251,7 +256,7 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
component.form.controls['time'].setValue(moment());
|
||||
component.form.controls['time'].setValue(new Date());
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
@ -263,13 +268,8 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
properties: {'qshare:expiryDate': null}
|
||||
});
|
||||
|
||||
expect(
|
||||
fixture.nativeElement.querySelector('input[formcontrolname="time"]').value
|
||||
).toBe('');
|
||||
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
|
||||
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith('nodeId', undefined);
|
||||
});
|
||||
|
||||
it('should not allow expiration date action when node has no update permission', async () => {
|
||||
@ -284,43 +284,18 @@ describe('ShareDialogComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(fixture.nativeElement.querySelector('input[formcontrolname="time"]').disabled).toBe(true);
|
||||
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');
|
||||
});
|
||||
|
||||
it('should update node expiration date with selected date', fakeAsync(() => {
|
||||
const date = moment();
|
||||
node.entry.allowableOperations = ['update'];
|
||||
node.entry.properties['qshare:sharedId'] = 'sharedId';
|
||||
fixture.componentInstance.form.controls['time'].setValue(null);
|
||||
|
||||
component.data = {
|
||||
node,
|
||||
baseShareUrl: 'some-url/'
|
||||
};
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.nativeElement
|
||||
.querySelector(
|
||||
'mat-slide-toggle[data-automation-id="adf-expire-toggle"] label'
|
||||
)
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
fixture.componentInstance.form.controls['time'].setValue(date);
|
||||
fixture.detectChanges();
|
||||
|
||||
tick(100);
|
||||
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
properties: {'qshare:expiryDate': date.utc().format()}
|
||||
});
|
||||
}));
|
||||
|
||||
describe('datetimepicker type', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of(null));
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of());
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of({}));
|
||||
|
||||
node.entry.properties['qshare:sharedId'] = 'sharedId';
|
||||
node.entry.allowableOperations = ['update'];
|
||||
component.data = {
|
||||
node,
|
||||
@ -328,9 +303,9 @@ describe('ShareDialogComponent', () => {
|
||||
};
|
||||
});
|
||||
|
||||
it('it should update node with input date and end of day time when type is `date`', fakeAsync(() => {
|
||||
it('should update node with input date and end of day time when type is `date`', fakeAsync(() => {
|
||||
const dateTimePickerType = 'date';
|
||||
const date = moment('2525-01-01 13:00:00');
|
||||
const date = new Date('2525-01-01');
|
||||
spyOn(appConfigService, 'get').and.callFake(() => dateTimePickerType as any);
|
||||
|
||||
fixture.detectChanges();
|
||||
@ -341,26 +316,35 @@ describe('ShareDialogComponent', () => {
|
||||
fixture.detectChanges();
|
||||
tick(500);
|
||||
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
properties: {'qshare:expiryDate': date.endOf('day').utc().format()}
|
||||
const expiryDate = format(endOfDay(date as Date), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
|
||||
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
|
||||
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith('nodeId', {
|
||||
nodeId: 'nodeId',
|
||||
expiresAt: expiryDate
|
||||
});
|
||||
}));
|
||||
|
||||
it('it should update node with input date and time when type is `datetime`', fakeAsync(() => {
|
||||
it('should update node with input date and time when type is `datetime`', fakeAsync(() => {
|
||||
const dateTimePickerType = 'datetime';
|
||||
const date = moment('2525-01-01 13:00:00');
|
||||
const date = new Date('2525-01-01 13:00:00');
|
||||
spyOn(appConfigService, 'get').and.returnValue(dateTimePickerType);
|
||||
|
||||
fixture.detectChanges();
|
||||
fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
fixture.componentInstance.type = 'datetime';
|
||||
fixture.componentInstance.time.setValue(date);
|
||||
fixture.detectChanges();
|
||||
tick(100);
|
||||
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
properties: {'qshare:expiryDate': date.utc().format()}
|
||||
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
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -23,23 +23,19 @@ import {
|
||||
ViewChild,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material/dialog';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
||||
import { UntypedFormGroup, UntypedFormControl, AbstractControl } from '@angular/forms';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import {
|
||||
AppConfigService
|
||||
} from '@alfresco/adf-core';
|
||||
import { NodesApiService } from '../common/services/nodes-api.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { ContentService } from '../common/services/content.service';
|
||||
|
||||
import { SharedLinksApiService } from './services/shared-links-api.service';
|
||||
import { SharedLinkEntry, Node } from '@alfresco/js-api';
|
||||
import { SharedLinkBodyCreate, SharedLinkEntry } from '@alfresco/js-api';
|
||||
import { ConfirmDialogComponent } from '../dialogs/confirm.dialog';
|
||||
import moment from 'moment';
|
||||
import { ContentNodeShareSettings } from './content-node-share.settings';
|
||||
import { takeUntil, debounceTime } from 'rxjs/operators';
|
||||
import { RenditionService } from '../common/services/rendition.service';
|
||||
import { format, add, endOfDay } from 'date-fns';
|
||||
|
||||
type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||
|
||||
@ -52,33 +48,33 @@ type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||
})
|
||||
export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
|
||||
minDate = moment().add(1, 'd');
|
||||
minDate = add(new Date(), { days: 1 });
|
||||
sharedId: string;
|
||||
fileName: string;
|
||||
baseShareUrl: string;
|
||||
isFileShared: boolean = false;
|
||||
isDisabled: boolean = false;
|
||||
isFileShared = false;
|
||||
isDisabled = false;
|
||||
isLinkWithExpiryDate = false;
|
||||
form: UntypedFormGroup = new UntypedFormGroup({
|
||||
sharedUrl: new UntypedFormControl(''),
|
||||
time: new UntypedFormControl({value: '', disabled: true})
|
||||
});
|
||||
type: DatePickerType = 'datetime';
|
||||
type: DatePickerType = 'date';
|
||||
maxDebounceTime = 500;
|
||||
isExpiryDateToggleChecked: boolean;
|
||||
|
||||
@ViewChild('slideToggleExpirationDate', {static: true})
|
||||
slideToggleExpirationDate;
|
||||
|
||||
@ViewChild('dateTimePickerInput', {static: true})
|
||||
dateTimePickerInput;
|
||||
@ViewChild('datePickerInput', {static: true})
|
||||
datePickerInput;
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
private appConfigService: AppConfigService,
|
||||
private sharedLinksApiService: SharedLinksApiService,
|
||||
private dialogRef: MatDialogRef<ShareDialogComponent>,
|
||||
private dialog: MatDialog,
|
||||
private nodesApiService: NodesApiService,
|
||||
private contentService: ContentService,
|
||||
private renditionService: RenditionService,
|
||||
@Inject(MAT_DIALOG_DATA) public data: ContentNodeShareSettings
|
||||
@ -86,8 +82,6 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.type = this.appConfigService.get<DatePickerType>('sharedLinkDateTimePickerType', 'datetime');
|
||||
|
||||
if (this.data.node && this.data.node.entry) {
|
||||
this.fileName = this.data.node.entry.name;
|
||||
this.baseShareUrl = this.data.baseShareUrl;
|
||||
@ -99,7 +93,10 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
} else {
|
||||
this.sharedId = properties['qshare:sharedId'];
|
||||
this.isFileShared = true;
|
||||
this.updateForm();
|
||||
|
||||
const expiryDate = this.updateForm();
|
||||
this.isExpiryDateToggleChecked = this.isLinkWithExpiryDate = !!expiryDate;
|
||||
this.isLinkWithExpiryDate ? this.time.enable() : this.time.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,10 +108,8 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
.subscribe(value => this.onTimeChanged(value));
|
||||
}
|
||||
|
||||
onTimeChanged(date: moment.Moment) {
|
||||
this.updateNode(date).subscribe(
|
||||
() => this.updateEntryExpiryDate(date)
|
||||
);
|
||||
onTimeChanged(date: Date) {
|
||||
this.updateNode(date);
|
||||
}
|
||||
|
||||
get time(): AbstractControl {
|
||||
@ -147,15 +142,16 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
onToggleExpirationDate(slideToggle: MatSlideToggleChange) {
|
||||
if (slideToggle.checked) {
|
||||
this.time.enable();
|
||||
this.isExpiryDateToggleChecked = true;
|
||||
} else {
|
||||
this.time.disable();
|
||||
this.time.setValue(null);
|
||||
this.deleteSharedLink(this.sharedId, true);
|
||||
}
|
||||
}
|
||||
|
||||
onDatetimepickerClosed() {
|
||||
this.dateTimePickerInput.nativeElement.blur();
|
||||
|
||||
onDatePickerClosed() {
|
||||
this.datePickerInput.nativeElement.blur();
|
||||
if (!this.time.value) {
|
||||
this.slideToggleExpirationDate.checked = false;
|
||||
}
|
||||
@ -185,10 +181,10 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private createSharedLinks(nodeId: string) {
|
||||
private createSharedLinks(nodeId: string, sharedLinkWithExpirySettings?: SharedLinkBodyCreate) {
|
||||
this.isDisabled = true;
|
||||
|
||||
this.sharedLinksApiService.createSharedLinks(nodeId).subscribe(
|
||||
this.sharedLinksApiService.createSharedLinks(nodeId, sharedLinkWithExpirySettings).subscribe(
|
||||
(sharedLink: SharedLinkEntry) => {
|
||||
if (sharedLink.entry) {
|
||||
this.sharedId = sharedLink.entry.id;
|
||||
@ -215,7 +211,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
deleteSharedLink(sharedId: string) {
|
||||
deleteSharedLink(sharedId: string, dialogOpenFlag?: boolean) {
|
||||
this.isDisabled = true;
|
||||
|
||||
this.sharedLinksApiService
|
||||
@ -230,9 +226,15 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
this.data.node.entry.properties['qshare:sharedId'] = null;
|
||||
this.data.node.entry.properties['qshare:expiryDate'] = null;
|
||||
}
|
||||
if (dialogOpenFlag) {
|
||||
this.createSharedLinks(this.data.node.entry.id);
|
||||
this.isExpiryDateToggleChecked = false;
|
||||
this.isLinkWithExpiryDate = false;
|
||||
} else {
|
||||
this.dialogRef.close(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -255,7 +257,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private updateForm() {
|
||||
private updateForm(): Date {
|
||||
const {entry} = this.data.node;
|
||||
let expiryDate = null;
|
||||
|
||||
@ -265,34 +267,55 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.form.setValue({
|
||||
sharedUrl: `${this.baseShareUrl}${this.sharedId}`,
|
||||
time: expiryDate ? moment(expiryDate).local() : null
|
||||
});
|
||||
time: expiryDate ? new Date(expiryDate) : null
|
||||
}, { emitEvent: false });
|
||||
|
||||
if (expiryDate) {
|
||||
this.time.enable();
|
||||
return expiryDate;
|
||||
}
|
||||
|
||||
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 {
|
||||
this.time.disable();
|
||||
expiryDate = format((new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
}
|
||||
} else {
|
||||
expiryDate = null;
|
||||
}
|
||||
|
||||
private updateNode(date: moment.Moment): Observable<Node> {
|
||||
const expiryDate = date
|
||||
? (this.type === 'date' ? date.endOf('day').utc().format() : date.utc().format())
|
||||
: null;
|
||||
if (this.sharedId && expiryDate) {
|
||||
this.isDisabled = true;
|
||||
|
||||
return this.nodesApiService.updateNode(this.data.node.entry.id, {
|
||||
properties: {
|
||||
'qshare:expiryDate': expiryDate
|
||||
this.sharedLinksApiService.deleteSharedLink(this.sharedId).subscribe((response: any) => {
|
||||
if (response instanceof Error) {
|
||||
this.isDisabled = false;
|
||||
this.isFileShared = true;
|
||||
this.handleError(response);
|
||||
} else {
|
||||
this.sharedLinkWithExpirySettings(expiryDate as Date);
|
||||
this.isLinkWithExpiryDate = true;
|
||||
this.updateEntryExpiryDate(date);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private updateEntryExpiryDate(date: moment.Moment) {
|
||||
private sharedLinkWithExpirySettings(expiryDate: Date) {
|
||||
const nodeObject: SharedLinkBodyCreate = {
|
||||
nodeId: this.data.node.entry.id,
|
||||
expiresAt: expiryDate as Date
|
||||
};
|
||||
this.createSharedLinks(this.data.node.entry.id, nodeObject);
|
||||
}
|
||||
|
||||
private updateEntryExpiryDate(date: Date) {
|
||||
const {properties} = this.data.node.entry;
|
||||
|
||||
if (properties) {
|
||||
properties['qshare:expiryDate'] = date
|
||||
? date.local()
|
||||
? new Date(date)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { NodePaging, SharedLinkEntry, SharedlinksApi } from '@alfresco/js-api';
|
||||
import { NodePaging, SharedLinkBodyCreate, SharedLinkEntry, SharedlinksApi } from '@alfresco/js-api';
|
||||
import { Observable, from, of, Subject } from 'rxjs';
|
||||
import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
@ -62,11 +62,12 @@ export class SharedLinksApiService {
|
||||
* Creates a shared link available to the current user.
|
||||
*
|
||||
* @param nodeId ID of the node to link to
|
||||
* @param sharedLinkWithExpirySettings shared link with nodeId and expiryDate
|
||||
* @param options Options supported by JS-API
|
||||
* @returns The shared link just created
|
||||
*/
|
||||
createSharedLinks(nodeId: string, options: any = {}): Observable<SharedLinkEntry> {
|
||||
const promise = this.sharedLinksApi.createSharedLink({ nodeId }, options);
|
||||
createSharedLinks(nodeId: string, sharedLinkWithExpirySettings?: SharedLinkBodyCreate, options: any = {}): Observable<SharedLinkEntry> {
|
||||
const promise = this.sharedLinksApi.createSharedLink(sharedLinkWithExpirySettings? sharedLinkWithExpirySettings : { nodeId }, options);
|
||||
|
||||
return from(promise).pipe(
|
||||
catchError((err) => of(err))
|
||||
|
@ -456,8 +456,14 @@
|
||||
"DIALOG-TITLE": "Share",
|
||||
"DESCRIPTION": "Click the link below to copy it to the clipboard.",
|
||||
"TITLE": "Link to share",
|
||||
"SHARE-LINK": "Share Link",
|
||||
"SHARABLE-LINK-CREATED": "Sharable Link is Created",
|
||||
"PUBLIC-CONTENT": "This content is publicly available to anyone with this link",
|
||||
"LINK-WITH-EXPIRY-SETTINGS": "New link has been generated with expiry settings",
|
||||
"EXPIRES": "Expires on",
|
||||
"LINK-EXPIRY-DATE": "Link Expiry Date",
|
||||
"EXPIRATION-LABEL" : "Expiration Date",
|
||||
"EXPIRATION-PLACEHOLDER": "MM/DD/YYYY",
|
||||
"CLIPBOARD-MESSAGE": "Link copied to the clipboard",
|
||||
"CLOSE": "Close",
|
||||
"COPY_BUTTON_LABEL": "Copy link",
|
||||
|
@ -21,8 +21,8 @@ import { BrowserActions } from '../../utils/browser-actions';
|
||||
|
||||
export class DateTimePickerCalendarPage {
|
||||
|
||||
datePicker = $(`.mat-datetimepicker-calendar`);
|
||||
today = $(`.mat-datetimepicker-calendar-body-today`);
|
||||
datePicker = $(`.mat-datepicker-calendar`);
|
||||
today = $(`.mat-calendar-body-today`);
|
||||
timePicker = $('.mat-datetimepicker-clock');
|
||||
hourTime = $$('.mat-datetimepicker-clock-hours .mat-datetimepicker-clock-cell').first();
|
||||
minutesTime = $$('.mat-datetimepicker-clock-minutes .mat-datetimepicker-clock-cell').first();
|
||||
@ -47,7 +47,7 @@ export class DateTimePickerCalendarPage {
|
||||
async setDate(date?: string): Promise<boolean> {
|
||||
try {
|
||||
if (date) {
|
||||
await BrowserActions.clickScript(element.all(by.cssContainingText(`.mat-datetimepicker-calendar-body-cell-content`, date)).first());
|
||||
await BrowserActions.clickScript(element.all(by.cssContainingText(`.mat-datepicker-calendar-body-cell-content`, date)).first());
|
||||
} else {
|
||||
await this.setToday();
|
||||
}
|
||||
@ -59,7 +59,7 @@ export class DateTimePickerCalendarPage {
|
||||
}
|
||||
|
||||
async checkCalendarTodayDayIsDisabled(): Promise<void> {
|
||||
await BrowserVisibility.waitUntilElementIsPresent(element(by.cssContainingText('.mat-datetimepicker-calendar-body-disabled', await BrowserActions.getText(this.today))));
|
||||
await BrowserVisibility.waitUntilElementIsPresent(element(by.cssContainingText('.mat-calendar-body-cell-content', await BrowserActions.getText(this.today))));
|
||||
}
|
||||
|
||||
async setDefaultEnabledHour(): Promise<void> {
|
||||
|
@ -23,12 +23,14 @@ export class DateTimePickerPage {
|
||||
|
||||
rootElement: ElementFinder;
|
||||
dateTimePicker = $('.mat-datetimepicker-toggle');
|
||||
datePicker = $('.mat-datepicker-toggle');
|
||||
dateTime = new DateTimePickerCalendarPage();
|
||||
|
||||
constructor(rootElement?: ElementFinder) {
|
||||
if (rootElement) {
|
||||
this.rootElement = rootElement;
|
||||
this.dateTimePicker = this.rootElement.$('.mat-datetimepicker-toggle');
|
||||
this.datePicker = this.rootElement.$('.mat-datepicker-toggle');
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,12 +48,12 @@ export class DateTimePickerPage {
|
||||
}
|
||||
|
||||
async setDate(date?: string): Promise<boolean> {
|
||||
await BrowserActions.click(this.dateTimePicker);
|
||||
await BrowserActions.click(this.datePicker);
|
||||
return this.dateTime.setDate(date);
|
||||
}
|
||||
|
||||
async clickDateTimePicker(): Promise<void> {
|
||||
await BrowserActions.click(this.dateTimePicker);
|
||||
await BrowserActions.click(this.datePicker);
|
||||
}
|
||||
|
||||
async checkCalendarTodayDayIsDisabled(): Promise<void> {
|
||||
|
32
package-lock.json
generated
32
package-lock.json
generated
@ -36,6 +36,7 @@
|
||||
"apollo-angular": "^4.2.1",
|
||||
"chart.js": "2.9.4",
|
||||
"cropperjs": "1.5.13",
|
||||
"date-fns": "^2.30.0",
|
||||
"dotenv-expand": "^5.1.0",
|
||||
"editorjs-html": "3.4.2",
|
||||
"editorjs-paragraph-with-alignment": "3.0.0",
|
||||
@ -30973,6 +30974,37 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "2.30.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.11"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/date-fns"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns/node_modules/@babel/runtime": {
|
||||
"version": "7.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz",
|
||||
"integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns/node_modules/regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"node_modules/date-format": {
|
||||
"version": "4.0.14",
|
||||
"resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
|
||||
|
@ -80,6 +80,7 @@
|
||||
"apollo-angular": "^4.2.1",
|
||||
"chart.js": "2.9.4",
|
||||
"cropperjs": "1.5.13",
|
||||
"date-fns": "^2.30.0",
|
||||
"dotenv-expand": "^5.1.0",
|
||||
"editorjs-html": "3.4.2",
|
||||
"editorjs-paragraph-with-alignment": "3.0.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user