From b9591ea37fe931dcedc718e7e11b633b23dec64e Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Sun, 14 Oct 2018 22:18:56 +0300 Subject: [PATCH] [ACA] Shared link - update functionality (#713) * toggle expiration input field * expiration input field animation * update node on value changed * cleanup code * test * fix test * remove event parameter * remove event parameter --- .../shared/content-node-share/animation.ts | 53 +++++++++++++++++++ .../content-node-share.dialog.html | 9 ++-- .../content-node-share.dialog.spec.ts | 32 ++++++++++- .../content-node-share.dialog.ts | 41 +++++++------- 4 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 src/app/components/shared/content-node-share/animation.ts diff --git a/src/app/components/shared/content-node-share/animation.ts b/src/app/components/shared/content-node-share/animation.ts new file mode 100644 index 000000000..f9083ddec --- /dev/null +++ b/src/app/components/shared/content-node-share/animation.ts @@ -0,0 +1,53 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + state, + style, + transition, + animate, + sequence, + AnimationStateMetadata, + AnimationTransitionMetadata +} from '@angular/animations'; + +export const formFieldAnimation: ( + | AnimationStateMetadata + | AnimationTransitionMetadata)[] = [ + state( + 'false', + style({ + opacity: 0, + height: 0, + visibility: 'hidden' + }) + ), + transition( + 'true => false', + sequence([ + animate('200ms linear', style({ opacity: 0, height: 0 })), + animate('2ms', style({ visibility: 'hidden' })) + ]) + ), + transition( + 'false => true', + sequence([ + animate('200ms linear', style({ opacity: 1, height: '*' })), + animate('200ms', style({ visibility: 'visible' })) + ]) + ) +]; diff --git a/src/app/components/shared/content-node-share/content-node-share.dialog.html b/src/app/components/shared/content-node-share/content-node-share.dialog.html index 5fcc3cea5..2155d8f8d 100644 --- a/src/app/components/shared/content-node-share/content-node-share.dialog.html +++ b/src/app/components/shared/content-node-share/content-node-share.dialog.html @@ -15,7 +15,7 @@ data-automation-id="adf-share-toggle" [checked]="isFileShared" [disabled]="!canUpdate || isDisabled" - (change)="onSlideShareChange($event)"> + (change)="onSlideShareChange()"> @@ -39,15 +39,16 @@ - + { let node; @@ -36,6 +37,7 @@ describe('ShareDialogComponent', () => { openSnackMessage: jasmine.createSpy('openSnackMessage') }; let sharedLinksApiService: SharedLinksApiService; + let nodesApiService: NodesApiService; let fixture; let component; @@ -58,6 +60,7 @@ describe('ShareDialogComponent', () => { fixture = TestBed.createComponent(ShareDialogComponent); matDialog = TestBed.get(MatDialog); sharedLinksApiService = TestBed.get(SharedLinksApiService); + nodesApiService = TestBed.get(NodesApiService); component = fixture.componentInstance; }); @@ -176,7 +179,7 @@ describe('ShareDialogComponent', () => { it('should unshare file when confirmation dialog returns true', fakeAsync(() => { spyOn(matDialog, 'open').and.returnValue({ beforeClose: () => of(true) }); - spyOn(sharedLinksApiService, 'deleteSharedLink'); + spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of(null)); node.entry.properties['qshare:sharedId'] = 'sharedId'; component.data = { @@ -242,4 +245,31 @@ describe('ShareDialogComponent', () => { .disabled ).toBe(true); }); + + it('should update node expiration date with selected date and time', () => { + const date = moment(); + node.entry.properties['qshare:sharedId'] = 'sharedId'; + node.entry.allowableOperations = []; + spyOn(nodesApiService, 'updateNode').and.returnValue(of({})); + fixture.componentInstance.form.controls['time'].setValue(null); + + component.data = { + node, + permission: true, + baseShareUrl: 'some-url/' + }; + + fixture.detectChanges(); + + fixture.nativeElement + .querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"]') + .dispatchEvent(new MouseEvent('click')); + + fixture.componentInstance.form.controls['time'].setValue(date); + fixture.detectChanges(); + + expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', { + properties: { 'qshare:expiryDate': date.utc().format() } + }); + }); }); diff --git a/src/app/components/shared/content-node-share/content-node-share.dialog.ts b/src/app/components/shared/content-node-share/content-node-share.dialog.ts index 98bcf4412..c288f12c5 100644 --- a/src/app/components/shared/content-node-share/content-node-share.dialog.ts +++ b/src/app/components/shared/content-node-share/content-node-share.dialog.ts @@ -27,7 +27,14 @@ import { import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material'; import { FormGroup, FormControl } from '@angular/forms'; import { Subscription, Observable, throwError } from 'rxjs'; -import { skip, skipWhile, mergeMap, catchError } from 'rxjs/operators'; +import { + skip, + mergeMap, + catchError, + distinctUntilChanged +} from 'rxjs/operators'; +import { trigger } from '@angular/animations'; +import { formFieldAnimation } from './animation'; import { SharedLinksApiService, NodesApiService } from '@alfresco/adf-core'; import { SharedLinkEntry, MinimalNodeEntryEntity } from 'alfresco-js-api'; import { ConfirmDialogComponent } from '@alfresco/adf-content-services'; @@ -38,7 +45,8 @@ import moment from 'moment-es6'; templateUrl: './content-node-share.dialog.html', styleUrls: ['./content-node-share.dialog.scss'], host: { class: 'adf-share-dialog' }, - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, + animations: [trigger('visibilityChanged', formFieldAnimation)] }) export class ShareDialogComponent implements OnInit, OnDestroy { private subscriptions: Subscription[] = []; @@ -71,16 +79,15 @@ export class ShareDialogComponent implements OnInit, OnDestroy { } this.subscriptions.push( - this.form.valueChanges + this.form.controls.time.valueChanges .pipe( skip(1), - skipWhile(() => !this.isTimeFieldValid), + distinctUntilChanged(), mergeMap( updates => this.updateNode(updates), formUpdates => formUpdates ), catchError(error => { - this.form.controls.time.setValue(null); return throwError(error); }) ) @@ -113,23 +120,15 @@ export class ShareDialogComponent implements OnInit, OnDestroy { this.deleteSharedLink(this.sharedId); } - onSlideShareChange(event: any) { - if (event.checked) { - this.createSharedLinks(this.data.node.entry.id); - } else { - this.openConfirmationDialog(); - } - } - - get isTimeFieldValid() { - return this.form.controls.time.valid; + onSlideShareChange() { + this.openConfirmationDialog(); } get canUpdate() { return this.data.permission; } - removeExpires() { + removeExpirationDate() { this.form.controls.time.setValue(null); } @@ -208,19 +207,17 @@ export class ShareDialogComponent implements OnInit, OnDestroy { }); } - private updateNode(updates): Observable { + private updateNode(date: moment.Moment): Observable { return this.nodesApiService.updateNode(this.data.node.entry.id, { properties: { - 'qshare:expiryDate': updates.time ? updates.time.utc().format() : null + 'qshare:expiryDate': date ? date.utc().format() : null } }); } - private updateEntryExpiryDate(updates) { + private updateEntryExpiryDate(date: moment.Moment) { const { properties } = this.data.node.entry; - properties['qshare:expiryDate'] = updates.time - ? updates.time.local() - : null; + properties['qshare:expiryDate'] = date ? date.local() : null; } }