mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-2540] Lock node feature (#3138)
* add adf-node-lock directive * add lock-node service + button in context menu * unit tests * docs * unit tests fix * Remove unnecessary imports * PR changes * Remove fit from tests * Update specific node from list on lock/ulock
This commit is contained in:
committed by
Denys Vuika
parent
7b7e39d989
commit
7d1b4bf14a
@@ -21,32 +21,43 @@ import { MaterialModule } from '../material.module';
|
||||
|
||||
import { DownloadZipDialogComponent } from './download-zip.dialog';
|
||||
import { FolderDialogComponent } from './folder.dialog';
|
||||
import { NodeLockDialogComponent } from './node-lock.dialog';
|
||||
import { ShareDialogComponent } from './share.dialog';
|
||||
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { FormModule } from '@alfresco/adf-core';
|
||||
import { MatDatetimepickerModule } from '@mat-datetimepicker/core';
|
||||
import { MatMomentDatetimeModule } from '@mat-datetimepicker/moment';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
MaterialModule,
|
||||
TranslateModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
FormModule,
|
||||
ReactiveFormsModule,
|
||||
MatMomentDatetimeModule,
|
||||
MatDatetimepickerModule
|
||||
],
|
||||
declarations: [
|
||||
DownloadZipDialogComponent,
|
||||
FolderDialogComponent,
|
||||
NodeLockDialogComponent,
|
||||
ShareDialogComponent
|
||||
],
|
||||
exports: [
|
||||
DownloadZipDialogComponent,
|
||||
FolderDialogComponent,
|
||||
NodeLockDialogComponent,
|
||||
ShareDialogComponent
|
||||
],
|
||||
entryComponents: [
|
||||
DownloadZipDialogComponent,
|
||||
FolderDialogComponent,
|
||||
NodeLockDialogComponent,
|
||||
ShareDialogComponent
|
||||
]
|
||||
})
|
||||
|
47
lib/content-services/dialogs/node-lock.dialog.html
Normal file
47
lib/content-services/dialogs/node-lock.dialog.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<h2 mat-dialog-title>
|
||||
{{ 'CORE.FILE_DIALOG.FILE_LOCK' | translate }}
|
||||
</h2>
|
||||
|
||||
<mat-dialog-content>
|
||||
<br />
|
||||
<form [formGroup]="form" (submit)="submit()">
|
||||
<mat-checkbox [formControl]="form.controls['isLocked']" ngDefaultControl>
|
||||
{{ 'CORE.FILE_DIALOG.FILE_LOCK_CHECKBOX' | translate }} <strong>"{{ nodeName }}"</strong>
|
||||
</mat-checkbox>
|
||||
|
||||
<br />
|
||||
|
||||
<div *ngIf="form.value.isLocked">
|
||||
<mat-checkbox [formControl]="form.controls['allowOwner']" ngDefaultControl>
|
||||
{{ 'CORE.FILE_DIALOG.ALLOW_OTHERS_CHECKBOX' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<br />
|
||||
|
||||
<mat-checkbox [formControl]="form.controls['isTimeLock']" ngDefaultControl>
|
||||
{{ 'CORE.FILE_DIALOG.TIME_LOCK_CHECKBOX' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<br />
|
||||
|
||||
<mat-form-field *ngIf="form.value.isTimeLock">
|
||||
<mat-datetimepicker-toggle [for]="datetimePicker" matSuffix></mat-datetimepicker-toggle>
|
||||
<mat-datetimepicker #datetimePicker type="datetime" openOnFocus="true" timeInterval="1"></mat-datetimepicker>
|
||||
<input matInput [formControl]="form.controls['time']" [matDatetimepicker]="datetimePicker" required autocomplete="false">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
<br />
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions class="adf-dialog-buttons">
|
||||
<span class="adf-fill-remaining-space"></span>
|
||||
|
||||
<button mat-button mat-dialog-close>
|
||||
{{ 'CORE.FILE_DIALOG.CANCEL_BUTTON.LABEL' | translate }}
|
||||
</button>
|
||||
|
||||
<button class="adf-dialog-action-button" mat-button (click)="submit()">
|
||||
{{ 'CORE.FILE_DIALOG.SAVE_BUTTON.LABEL' | translate }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
161
lib/content-services/dialogs/node-lock.dialog.spec.ts
Normal file
161
lib/content-services/dialogs/node-lock.dialog.spec.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
/*!
|
||||
* @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 moment from 'moment-es6';
|
||||
|
||||
import { async, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
||||
import { ComponentFixture } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatDialogRef } from '@angular/material';
|
||||
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import { AlfrescoApiService, TranslationService } from '@alfresco/adf-core';
|
||||
import { NodeLockDialogComponent } from './node-lock.dialog';
|
||||
|
||||
describe('NodeLockDialogComponent', () => {
|
||||
|
||||
let fixture: ComponentFixture<NodeLockDialogComponent>;
|
||||
let component: NodeLockDialogComponent;
|
||||
let translationService: TranslationService;
|
||||
let alfrescoApi: AlfrescoApiService;
|
||||
let expiryDate;
|
||||
const dialogRef = {
|
||||
close: jasmine.createSpy('close')
|
||||
};
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
BrowserDynamicTestingModule
|
||||
],
|
||||
declarations: [
|
||||
NodeLockDialogComponent
|
||||
],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: dialogRef }
|
||||
]
|
||||
});
|
||||
|
||||
TestBed.overrideModule(BrowserDynamicTestingModule, {
|
||||
set: { entryComponents: [NodeLockDialogComponent] }
|
||||
});
|
||||
|
||||
TestBed.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NodeLockDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||
|
||||
translationService = TestBed.get(TranslationService);
|
||||
spyOn(translationService, 'get').and.returnValue(Observable.of('message'));
|
||||
});
|
||||
|
||||
describe('Node lock dialog component', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.clock().mockDate(new Date());
|
||||
expiryDate = moment().add(1, 'minutes');
|
||||
|
||||
component.data = {
|
||||
node: {
|
||||
id: 'node-id',
|
||||
name: 'node-name',
|
||||
isLocked: true,
|
||||
properties: {
|
||||
['cm:lockType']: 'WRITE_LOCK',
|
||||
['cm:expiryDate']: expiryDate
|
||||
}
|
||||
},
|
||||
onError: () => {}
|
||||
};
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should init dialog with form inputs', () => {
|
||||
expect(component.nodeName).toBe('node-name');
|
||||
expect(component.form.value.isLocked).toBe(true);
|
||||
expect(component.form.value.allowOwner).toBe(true);
|
||||
expect(component.form.value.isTimeLock).toBe(true);
|
||||
expect(component.form.value.time.format()).toBe(expiryDate.format());
|
||||
});
|
||||
|
||||
it('should update form inputs', () => {
|
||||
let newTime = moment();
|
||||
component.form.controls['isLocked'].setValue(false);
|
||||
component.form.controls['allowOwner'].setValue(false);
|
||||
component.form.controls['isTimeLock'].setValue(false);
|
||||
component.form.controls['time'].setValue(newTime);
|
||||
|
||||
expect(component.form.value.isLocked).toBe(false);
|
||||
expect(component.form.value.allowOwner).toBe(false);
|
||||
expect(component.form.value.isTimeLock).toBe(false);
|
||||
expect(component.form.value.time.format()).toBe(newTime.format());
|
||||
});
|
||||
|
||||
it('should submit the form and lock the node', () => {
|
||||
spyOn(alfrescoApi.nodesApi, 'lockNode').and.returnValue(Promise.resolve({}));
|
||||
|
||||
component.submit();
|
||||
|
||||
expect(alfrescoApi.nodesApi.lockNode).toHaveBeenCalledWith(
|
||||
'node-id',
|
||||
{
|
||||
'timeToExpire': 60,
|
||||
'type': 'ALLOW_OWNER_CHANGES',
|
||||
'lifetime': 'PERSISTENT'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should submit the form and unlock the node', () => {
|
||||
spyOn(alfrescoApi.nodesApi, 'unlockNode').and.returnValue(Promise.resolve({}));
|
||||
|
||||
component.form.controls['isLocked'].setValue(false);
|
||||
component.submit();
|
||||
|
||||
expect(alfrescoApi.nodesApi.unlockNode).toHaveBeenCalledWith('node-id');
|
||||
});
|
||||
|
||||
it('should call dialog to close with form data when submit is succesfluly', fakeAsync(() => {
|
||||
const node = { entry: {} };
|
||||
spyOn(alfrescoApi.nodesApi, 'lockNode').and.returnValue(Promise.resolve(node));
|
||||
|
||||
component.submit();
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(dialogRef.close).toHaveBeenCalledWith(node.entry);
|
||||
}));
|
||||
|
||||
it('should call onError if submit fails', fakeAsync(() => {
|
||||
spyOn(alfrescoApi.nodesApi, 'lockNode').and.returnValue(Promise.reject('error'));
|
||||
spyOn(component.data, 'onError');
|
||||
|
||||
component.submit();
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.data.onError).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
});
|
94
lib/content-services/dialogs/node-lock.dialog.ts
Normal file
94
lib/content-services/dialogs/node-lock.dialog.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/*!
|
||||
* @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 moment from 'moment-es6';
|
||||
|
||||
import { Component, Inject, OnInit, Optional } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
|
||||
import { MinimalNodeEntryEntity, NodeEntry } from 'alfresco-js-api';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-node-lock',
|
||||
styleUrls: ['./folder.dialog.scss'],
|
||||
templateUrl: './node-lock.dialog.html'
|
||||
})
|
||||
export class NodeLockDialogComponent implements OnInit {
|
||||
|
||||
form: FormGroup;
|
||||
node: MinimalNodeEntryEntity = null;
|
||||
nodeName: string;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
public dialog: MatDialogRef<NodeLockDialogComponent>,
|
||||
private alfrescoApi: AlfrescoApiService,
|
||||
@Optional()
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: any
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
const { node } = this.data;
|
||||
this.nodeName = node.name;
|
||||
|
||||
this.form = this.formBuilder.group({
|
||||
isLocked: node.isLocked || false,
|
||||
allowOwner: node.properties['cm:lockType'] === 'WRITE_LOCK',
|
||||
isTimeLock: !!node.properties['cm:expiryDate'],
|
||||
time: !!node.properties['cm:expiryDate'] ? moment(node.properties['cm:expiryDate']) : moment()
|
||||
});
|
||||
}
|
||||
|
||||
private get lockTimeInSeconds(): number {
|
||||
if (this.form.value.isTimeLock) {
|
||||
let duration = moment.duration(moment(this.form.value.time).diff(moment()));
|
||||
return duration.asSeconds();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private get nodeBodyLock(): object {
|
||||
return {
|
||||
'timeToExpire': this.lockTimeInSeconds,
|
||||
'type': this.form.value.allowOwner ? 'ALLOW_OWNER_CHANGES' : 'FULL',
|
||||
'lifetime': 'PERSISTENT'
|
||||
};
|
||||
}
|
||||
|
||||
private toggleLock(): Promise<NodeEntry> {
|
||||
const { alfrescoApi: { nodesApi }, data: { node } } = this;
|
||||
|
||||
if (this.form.value.isLocked) {
|
||||
return nodesApi.lockNode(node.id, this.nodeBodyLock);
|
||||
}
|
||||
|
||||
return nodesApi.unlockNode(node.id);
|
||||
}
|
||||
|
||||
submit(): void {
|
||||
this.toggleLock()
|
||||
.then(node => {
|
||||
this.data.node.isLocked = this.form.value.isLocked;
|
||||
this.dialog.close(node.entry);
|
||||
})
|
||||
.catch(error => this.data.onError(error));
|
||||
}
|
||||
}
|
@@ -17,4 +17,5 @@
|
||||
|
||||
export * from './download-zip.dialog';
|
||||
export * from './folder.dialog';
|
||||
export * from './node-lock.dialog';
|
||||
export * from './share.dialog';
|
||||
|
Reference in New Issue
Block a user