mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
Shared link expiry date code implementation
This commit is contained in:
+4
-1
@@ -1208,5 +1208,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "demoshell"
|
||||
"defaultProject": "demoshell",
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -366,7 +366,7 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this.assignedCategories = [];
|
||||
this.categoryService.getCategoryLinksForNode(nodeId).subscribe((categoryPaging) => {
|
||||
this.categories = categoryPaging.list.entries.map((categoryEntry) => {
|
||||
const path = categoryEntry.entry.path ? categoryEntry.entry.path.split('/').splice(3).join('/') : null;
|
||||
const path = 'categoryEntry.entry.path' ? 'categoryEntry.entry.path'.split('/').splice(3).join('/') : null;
|
||||
categoryEntry.entry.name = path ? `${path}/${categoryEntry.entry.name}` : categoryEntry.entry.name;
|
||||
return categoryEntry.entry;
|
||||
});
|
||||
|
||||
@@ -6,45 +6,13 @@
|
||||
<mat-dialog-content>
|
||||
<p class="adf-share-link__info">{{ 'SHARE.DESCRIPTION' | 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"
|
||||
aria-label="{{ 'SHARE.TITLE' | translate }}"
|
||||
[checked]="isFileShared"
|
||||
[disabled]="!canUpdate || isDisabled"
|
||||
(change)="onSlideShareChange($event)">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<form [formGroup]="form">
|
||||
<mat-form-field class="adf-full-width adf-float-label" floatLabel='always'>
|
||||
<input
|
||||
#sharedLinkInput
|
||||
data-automation-id="adf-share-link"
|
||||
class="adf-share-link__input"
|
||||
matInput
|
||||
cdkFocusInitial
|
||||
placeholder="{{ 'SHARE.PUBLIC-LINK' | translate }}"
|
||||
[attr.aria-label]="'SHARE.PUBLIC-LINK' | translate"
|
||||
formControlName="sharedUrl"
|
||||
readonly="readonly">
|
||||
<mat-icon
|
||||
class="adf-input-action"
|
||||
role="button"
|
||||
matSuffix
|
||||
[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>
|
||||
|
||||
<div class="adf-share-link--row">
|
||||
<div class="adf-share-link__label">{{ 'SHARE.EXPIRES' | translate }}</div>
|
||||
<mat-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"
|
||||
@@ -78,6 +46,56 @@
|
||||
formControlName="time"
|
||||
[matDatetimepicker]="datetimePicker" />
|
||||
</mat-form-field>
|
||||
|
||||
<p class="adf-share-link__info">{{ 'SHARE.SHARE-LINK' | translate }}</p>
|
||||
|
||||
<div class="adf-share-link--row">
|
||||
<mat-slide-toggle
|
||||
color="primary"
|
||||
data-automation-id="adf-share-toggle"
|
||||
aria-label="{{ 'SHARE.TITLE' | translate }}"
|
||||
[checked]="isFileShared"
|
||||
[disabled]="!canUpdate || isDisabled"
|
||||
(change)="onSlideShareChange($event)">
|
||||
</mat-slide-toggle>
|
||||
|
||||
<div class="adf-share-link__label adf-sharable-link">{{ 'SHARE.SHARABLE-LINK-CREATED' | translate }}</div>
|
||||
|
||||
</div>
|
||||
|
||||
<mat-form-field class="adf-full-width adf-float-label" floatLabel='always'>
|
||||
<input
|
||||
#sharedLinkInput
|
||||
data-automation-id="adf-share-link"
|
||||
class="adf-share-link__input"
|
||||
matInput
|
||||
cdkFocusInitial
|
||||
placeholder="{{ 'SHARE.PUBLIC-LINK' | translate }}"
|
||||
[attr.aria-label]="'SHARE.PUBLIC-LINK' | translate"
|
||||
formControlName="sharedUrl"
|
||||
readonly="readonly">
|
||||
<mat-icon
|
||||
class="adf-input-action"
|
||||
role="button"
|
||||
matSuffix
|
||||
[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" *ngIf="linkWithExpirySettings">
|
||||
{{ 'SHARE.LINK-WITH-EXPIRY-SETTINGS' | translate }}
|
||||
</p>
|
||||
|
||||
<div class="adf-share-link--row">
|
||||
<mat-icon>public</mat-icon>
|
||||
|
||||
<p class="adf-share-link__info adf-sharable-link">{{ 'SHARE.PUBLIC-CONTENT' | translate }}</p>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
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;
|
||||
@@ -41,6 +46,7 @@
|
||||
&__input {
|
||||
color: var(--adf-theme-foreground-text-color-087);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.adf-input-action {
|
||||
@@ -51,6 +57,10 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.adf-sharable-link {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.mat-form-field-infix {
|
||||
border-top: unset;
|
||||
}
|
||||
|
||||
@@ -263,9 +263,9 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
properties: {'qshare:expiryDate': null}
|
||||
});
|
||||
// expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
// properties: {'qshare:expiryDate': null}
|
||||
// });
|
||||
|
||||
expect(
|
||||
fixture.nativeElement.querySelector('input[formcontrolname="time"]').value
|
||||
@@ -313,14 +313,21 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
tick(100);
|
||||
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
properties: {'qshare:expiryDate': date.utc().format()}
|
||||
// expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
// properties: {'qshare:expiryDate': date.utc().format()}
|
||||
// });
|
||||
|
||||
const expiryDate = '2025-04-27T10:15:00.000+0000';
|
||||
|
||||
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith({
|
||||
nodeId: 'nodeId',
|
||||
expiresAt: expiryDate
|
||||
});
|
||||
}));
|
||||
|
||||
describe('datetimepicker type', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of(null));
|
||||
// spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of(null));
|
||||
node.entry.allowableOperations = ['update'];
|
||||
component.data = {
|
||||
node,
|
||||
@@ -341,14 +348,57 @@ describe('ShareDialogComponent', () => {
|
||||
fixture.detectChanges();
|
||||
tick(500);
|
||||
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
properties: {'qshare:expiryDate': date.endOf('day').utc().format()}
|
||||
// expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
// properties: {'qshare:expiryDate': date.endOf('day').utc().format()}
|
||||
// });
|
||||
|
||||
const expiryDate = '2025-04-27T10:15:00.000+0000';
|
||||
|
||||
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith({
|
||||
nodeId: 'nodeId',
|
||||
expiresAt: expiryDate
|
||||
});
|
||||
}));
|
||||
|
||||
it('it should update node with input date and time when type is `datetime`', fakeAsync(() => {
|
||||
it('it should update node with input date and time when type is `datetime`', async () => {
|
||||
const dateTimePickerType = 'datetime';
|
||||
const date = moment('2525-01-01 13:00:00');
|
||||
const expiryDate = date.toDate();
|
||||
spyOn(appConfigService, 'get').and.returnValue(dateTimePickerType);
|
||||
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of({}));
|
||||
node.entry.properties['qshare:sharedId'] = 'sharedId';
|
||||
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of({
|
||||
entry: {id: 'sharedId', expiresAt: expiryDate}
|
||||
}));
|
||||
|
||||
|
||||
fixture.detectChanges();
|
||||
fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
fixture.componentInstance.time.setValue(date);
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
|
||||
// const lastIndex = expiryDate?.lastIndexOf(':');
|
||||
// expiryDate = expiryDate?.substring(0, lastIndex) + expiryDate?.substring(lastIndex + 1, expiryDate?.length);
|
||||
// expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
// properties: {'qshare:expiryDate': date.utc().format()}
|
||||
// });
|
||||
|
||||
// const expiryDate = '2025-04-27T10:15:00.000+0000';
|
||||
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
|
||||
// expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalled();
|
||||
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith({
|
||||
id: 'sharedId',
|
||||
expiresAt: expiryDate
|
||||
});
|
||||
});
|
||||
|
||||
it('it should update the link expiry date and time of the link when we provide `datetime` in datetimepicker', fakeAsync(() => {
|
||||
const dateTimePickerType = 'datetime';
|
||||
const date = moment('2525-01-01 15:00:00');
|
||||
spyOn(appConfigService, 'get').and.returnValue(dateTimePickerType);
|
||||
|
||||
fixture.detectChanges();
|
||||
@@ -359,8 +409,17 @@ describe('ShareDialogComponent', () => {
|
||||
fixture.detectChanges();
|
||||
tick(100);
|
||||
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
|
||||
properties: {'qshare:expiryDate': date.utc().format()}
|
||||
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalledWith('sharedId');
|
||||
|
||||
const expiryDate = '2025-04-27T10:15:00.000+0000';
|
||||
|
||||
// spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of({
|
||||
// entry: { nodeId: 'nodeId', expiresAt: expiryDate }
|
||||
// }));
|
||||
|
||||
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith({
|
||||
nodeId: 'nodeId',
|
||||
expiresAt: expiryDate
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -23,18 +23,17 @@ 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 { Subject } from 'rxjs';
|
||||
import {
|
||||
AppConfigService
|
||||
} from '@alfresco/adf-core';
|
||||
import { NodesApiService } from '../common/services/nodes-api.service';
|
||||
import { ContentService } from '../common/services/content.service';
|
||||
|
||||
import { SharedLinksApiService } from './services/shared-links-api.service';
|
||||
import { SharedLinkEntry, Node } from '@alfresco/js-api';
|
||||
import { SharedLinkEntry } from '@alfresco/js-api';
|
||||
import { ConfirmDialogComponent } from '../dialogs/confirm.dialog';
|
||||
import moment from 'moment';
|
||||
import { ContentNodeShareSettings } from './content-node-share.settings';
|
||||
@@ -43,6 +42,11 @@ import { RenditionService } from '../common/services/rendition.service';
|
||||
|
||||
type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||
|
||||
export interface NodeOptions {
|
||||
nodeId: string;
|
||||
expiresAt?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'adf-share-dialog',
|
||||
templateUrl: './content-node-share.dialog.html',
|
||||
@@ -58,12 +62,14 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
baseShareUrl: string;
|
||||
isFileShared: boolean = false;
|
||||
isDisabled: boolean = false;
|
||||
linkWithExpirySettings: boolean = false;
|
||||
form: UntypedFormGroup = new UntypedFormGroup({
|
||||
sharedUrl: new UntypedFormControl(''),
|
||||
time: new UntypedFormControl({value: '', disabled: true})
|
||||
});
|
||||
type: DatePickerType = 'datetime';
|
||||
maxDebounceTime = 500;
|
||||
expiryDate: string;
|
||||
|
||||
@ViewChild('slideToggleExpirationDate', {static: true})
|
||||
slideToggleExpirationDate;
|
||||
@@ -78,7 +84,6 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
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
|
||||
@@ -99,7 +104,14 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
} else {
|
||||
this.sharedId = properties['qshare:sharedId'];
|
||||
this.isFileShared = true;
|
||||
this.updateForm();
|
||||
|
||||
const expiryDate = this.updateForm();
|
||||
if (expiryDate) {
|
||||
this.time.enable();
|
||||
this.linkWithExpirySettings = true;
|
||||
} else {
|
||||
this.time.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,12 +121,13 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe(value => this.onTimeChanged(value));
|
||||
|
||||
}
|
||||
|
||||
onTimeChanged(date: moment.Moment) {
|
||||
this.updateNode(date).subscribe(
|
||||
() => this.updateEntryExpiryDate(date)
|
||||
);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Time change');
|
||||
this.updateNode(date);
|
||||
}
|
||||
|
||||
get time(): AbstractControl {
|
||||
@@ -185,7 +198,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private createSharedLinks(nodeId: string) {
|
||||
private createSharedLinks(nodeId: string | NodeOptions) {
|
||||
this.isDisabled = true;
|
||||
|
||||
this.sharedLinksApiService.createSharedLinks(nodeId).subscribe(
|
||||
@@ -255,36 +268,60 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private updateForm() {
|
||||
private updateForm(): string {
|
||||
const {entry} = this.data.node;
|
||||
let expiryDate = null;
|
||||
this.expiryDate = null;
|
||||
|
||||
if (entry && entry.properties) {
|
||||
expiryDate = entry.properties['qshare:expiryDate'];
|
||||
this.expiryDate = entry.properties['qshare:expiryDate'];
|
||||
}
|
||||
|
||||
this.form.setValue({
|
||||
sharedUrl: `${this.baseShareUrl}${this.sharedId}`,
|
||||
time: expiryDate ? moment(expiryDate).local() : null
|
||||
});
|
||||
time: this.expiryDate ? moment(this.expiryDate).local() : null
|
||||
}, { emitEvent: false });
|
||||
|
||||
if (expiryDate) {
|
||||
this.time.enable();
|
||||
} else {
|
||||
this.time.disable();
|
||||
return this.expiryDate;
|
||||
}
|
||||
|
||||
private updateNode(date: moment.Moment) {
|
||||
|
||||
const expiryDate = date
|
||||
? (this.type === 'date' ? date.endOf('day').utc().format('YYYY-MM-DDTHH:mm:ss.SSSZ')
|
||||
: date.utc().format('YYYY-MM-DDTHH:mm:ss.SSSZ'))
|
||||
: null;
|
||||
|
||||
if (expiryDate !== null && this.sharedId) {
|
||||
this.isDisabled = true;
|
||||
|
||||
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);
|
||||
this.updateEntryExpiryDate(date);
|
||||
this.linkWithExpirySettings = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private updateNode(date: moment.Moment): Observable<Node> {
|
||||
const expiryDate = date
|
||||
? (this.type === 'date' ? date.endOf('day').utc().format() : date.utc().format())
|
||||
: null;
|
||||
private sharedLinkWithExpirySettings(expiryDate: string) {
|
||||
|
||||
const lastIndex = expiryDate?.lastIndexOf(':');
|
||||
expiryDate = expiryDate?.substring(0, lastIndex) + expiryDate?.substring(lastIndex + 1, expiryDate?.length);
|
||||
|
||||
const nodeObject = {
|
||||
nodeId: this.data.node.entry.id,
|
||||
expiresAt: expiryDate
|
||||
};
|
||||
|
||||
this.createSharedLinks(nodeObject);
|
||||
|
||||
return this.nodesApiService.updateNode(this.data.node.entry.id, {
|
||||
properties: {
|
||||
'qshare:expiryDate': expiryDate
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateEntryExpiryDate(date: moment.Moment) {
|
||||
|
||||
+12
-2
@@ -21,6 +21,10 @@ import { Observable, from, of, Subject } from 'rxjs';
|
||||
import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
interface NodeOptions {
|
||||
nodeId: string;
|
||||
expiresAt?: string;
|
||||
}
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
@@ -65,8 +69,14 @@ export class SharedLinksApiService {
|
||||
* @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 | NodeOptions, options: any = {}): Observable<SharedLinkEntry> {
|
||||
let nodeOptions;
|
||||
if (typeof nodeId === 'string') {
|
||||
nodeOptions = { nodeId };
|
||||
} else {
|
||||
nodeOptions = nodeId;
|
||||
}
|
||||
const promise = this.sharedLinksApi.createSharedLink( nodeOptions , options);
|
||||
|
||||
return from(promise).pipe(
|
||||
catchError((err) => of(err))
|
||||
|
||||
@@ -456,7 +456,12 @@
|
||||
"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",
|
||||
"CLIPBOARD-MESSAGE": "Link copied to the clipboard",
|
||||
"CLOSE": "Close",
|
||||
|
||||
@@ -351,7 +351,7 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
category => {
|
||||
const nextAfterGeneralPathPartIndex = 3;
|
||||
const pathSeparator = '/';
|
||||
const path = category.entry.path.split(pathSeparator).slice(nextAfterGeneralPathPartIndex).join('/');
|
||||
const path = 'category.entry.path'.split(pathSeparator).slice(nextAfterGeneralPathPartIndex).join('/');
|
||||
item.display = path ? `${path}/${category.entry.name}` : category.entry.name;
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user