mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
[ADF-523] Fix delete operation in the search component (#2020)
* Search delete permission notification fix * Support content deletion inside search results * Forgotten broken test fix. * Update alfresco-document-list READDME.md * Update alfresco-document-list READDME.md II * Adding TOC to README.md * Build fix * Fix the build for now and ever!
This commit is contained in:
parent
ee871ba578
commit
843afdbcc6
@ -25,6 +25,7 @@
|
|||||||
* [Actions](#actions)
|
* [Actions](#actions)
|
||||||
+ [Menu actions](#menu-actions)
|
+ [Menu actions](#menu-actions)
|
||||||
+ [Default action handlers](#default-action-handlers)
|
+ [Default action handlers](#default-action-handlers)
|
||||||
|
- [Delete - System handler combined with custom handler](#delete---system-handler-combined-with-custom-handler)
|
||||||
- [Delete - Show notification message with no permission](#delete---show-notification-message-with-no-permission)
|
- [Delete - Show notification message with no permission](#delete---show-notification-message-with-no-permission)
|
||||||
- [Delete - Disable button checking the permission](#delete---disable-button-checking-the-permission)
|
- [Delete - Disable button checking the permission](#delete---disable-button-checking-the-permission)
|
||||||
- [Download](#download)
|
- [Download](#download)
|
||||||
@ -519,8 +520,24 @@ In the Example below will add the [ng2-alfresco-tag](https://www.npmjs.com/packa
|
|||||||
|
|
||||||
### Actions
|
### Actions
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `target` | string | | "document" or "folder" |
|
||||||
|
| `title` | string | | The title of the action as shown in the menu |
|
||||||
|
| `handler` | string | | System type actions. Can be "delete" or "download" |
|
||||||
|
| `permission` | string | | Then name of the permission |
|
||||||
|
|
||||||
|
Events:
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `execute` | Emitted when user clicks on the action. For combined handlers see below |
|
||||||
|
| `permissionEvent` | Emitted when a permission error happens |
|
||||||
|
|
||||||
DocumentList supports declarative actions for Documents and Folders.
|
DocumentList supports declarative actions for Documents and Folders.
|
||||||
Each action can be bound to either default out-of-box handler or a custom behavior.
|
Each action can be bound to either default out-of-box handler, to a custom behavior or to both of them.
|
||||||
You can define both folder and document actions at the same time.
|
You can define both folder and document actions at the same time.
|
||||||
|
|
||||||
#### Menu actions
|
#### Menu actions
|
||||||
@ -529,18 +546,28 @@ You can define both folder and document actions at the same time.
|
|||||||
<adf-document-list ...>
|
<adf-document-list ...>
|
||||||
<content-actions>
|
<content-actions>
|
||||||
|
|
||||||
|
<!-- system handler -->
|
||||||
<content-action
|
<content-action
|
||||||
target="document"
|
target="folder"
|
||||||
title="System action"
|
title="Delete"
|
||||||
handler="system2">
|
handler="delete">
|
||||||
</content-action>
|
</content-action>
|
||||||
|
|
||||||
|
<!-- custom handler -->
|
||||||
<content-action
|
<content-action
|
||||||
target="document"
|
target="document"
|
||||||
title="Custom action"
|
title="Custom action"
|
||||||
(execute)="myCustomAction1($event)">
|
(execute)="myCustomAction1($event)">
|
||||||
</content-action>
|
</content-action>
|
||||||
|
|
||||||
|
<!-- combined handler -->
|
||||||
|
<content-action
|
||||||
|
target="document"
|
||||||
|
title="Delete with additional custom callback"
|
||||||
|
handler="delete"
|
||||||
|
(execute)="myCustomActionAfterDelete($event)">
|
||||||
|
</content-action>
|
||||||
|
|
||||||
</content-actions>
|
</content-actions>
|
||||||
</adf-document-list>
|
</adf-document-list>
|
||||||
```
|
```
|
||||||
@ -553,6 +580,11 @@ export class MyView {
|
|||||||
let entry = event.value.entry;
|
let entry = event.value.entry;
|
||||||
alert(`Custom document action for ${entry.name}`);
|
alert(`Custom document action for ${entry.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myCustomActionAfterDelete(event) {
|
||||||
|
let entry = event.value.entry;
|
||||||
|
alert(`Custom callback after delete system action for ${entry.name}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -570,6 +602,10 @@ The following action handlers are provided out-of-box:
|
|||||||
All system handler names are case-insensitive, `handler="download"` and `handler="DOWNLOAD"`
|
All system handler names are case-insensitive, `handler="download"` and `handler="DOWNLOAD"`
|
||||||
will trigger the same `download` action.
|
will trigger the same `download` action.
|
||||||
|
|
||||||
|
##### Delete - System handler combined with custom handler
|
||||||
|
|
||||||
|
If you specify both of the **handler="delete"** and your custom **(execute)="myCustomActionAfterDelete($event)"**, your callback will be invoked after a successful delete happened. A successful delete operation happens if there is neither permission error, neither other network related error for the delete operation request. For handling permission errors see the section below.
|
||||||
|
|
||||||
##### Delete - Show notification message with no permission
|
##### Delete - Show notification message with no permission
|
||||||
|
|
||||||
You can show a notification error when the user don't have the right permission to perform the action.
|
You can show a notification error when the user don't have the right permission to perform the action.
|
||||||
@ -650,24 +686,34 @@ Initiates download of the corresponding document file.
|
|||||||
|
|
||||||
#### Folder actions
|
#### Folder actions
|
||||||
|
|
||||||
Folder actions have the same declaration as document actions except ```taget="folder"``` attribute value.
|
Folder actions have the same declaration as document actions except ```taget="folder"``` attribute value. You can define system, custom or combined handlers as well just as with the document actions.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<adf-document-list ...>
|
<adf-document-list ...>
|
||||||
<content-actions>
|
<content-actions>
|
||||||
|
|
||||||
|
<!-- system handler -->
|
||||||
<content-action
|
<content-action
|
||||||
target="folder"
|
target="folder"
|
||||||
title="Default folder action 1"
|
title="Default folder action 1"
|
||||||
handler="system1">
|
handler="system1">
|
||||||
</content-action>
|
</content-action>
|
||||||
|
|
||||||
|
<!-- custom handler -->
|
||||||
<content-action
|
<content-action
|
||||||
target="folder"
|
target="folder"
|
||||||
title="Custom folder action"
|
title="Custom folder action"
|
||||||
(execute)="myFolderAction1($event)">
|
(execute)="myFolderAction1($event)">
|
||||||
</content-action>
|
</content-action>
|
||||||
|
|
||||||
|
<!-- combined handler -->
|
||||||
|
<content-action
|
||||||
|
target="folder"
|
||||||
|
title="Delete with additional custom callback"
|
||||||
|
handler="delete"
|
||||||
|
(execute)="myCustomActionAfterDelete($event)">
|
||||||
|
</content-action>
|
||||||
|
|
||||||
</content-actions>
|
</content-actions>
|
||||||
</adf-document-list>
|
</adf-document-list>
|
||||||
```
|
```
|
||||||
@ -680,6 +726,11 @@ export class MyView {
|
|||||||
let entry = event.value.entry;
|
let entry = event.value.entry;
|
||||||
alert(`Custom folder action for ${entry.name}`);
|
alert(`Custom folder action for ${entry.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myCustomActionAfterDelete(event) {
|
||||||
|
let entry = event.value.entry;
|
||||||
|
alert(`Custom callback after delete system action for ${entry.name}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ describe('ContentAction', () => {
|
|||||||
expect(documentList.actions.length).toBe(1);
|
expect(documentList.actions.length).toBe(1);
|
||||||
|
|
||||||
let model = documentList.actions[0];
|
let model = documentList.actions[0];
|
||||||
model.handler('<obj>');
|
model.execute('<obj>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should sync localizable fields with model', () => {
|
it('should sync localizable fields with model', () => {
|
||||||
@ -226,7 +226,7 @@ describe('ContentAction', () => {
|
|||||||
action.execute = handler;
|
action.execute = handler;
|
||||||
|
|
||||||
action.ngOnInit();
|
action.ngOnInit();
|
||||||
action.model.handler(file);
|
action.model.execute(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow registering model without handler', () => {
|
it('should allow registering model without handler', () => {
|
||||||
|
@ -77,11 +77,11 @@ export class ContentActionComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
if (this.handler) {
|
if (this.handler) {
|
||||||
this.model.handler = this.getSystemHandler(this.target, this.handler);
|
this.model.handler = this.getSystemHandler(this.target, this.handler);
|
||||||
} else if (this.execute) {
|
}
|
||||||
this.model.handler = (document: any): void => {
|
|
||||||
this.execute.emit({
|
if (this.execute) {
|
||||||
value: document
|
this.model.execute = (value: any): void => {
|
||||||
});
|
this.execute.emit({ value });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +106,9 @@ export class ContentActionComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
if (ltarget === 'document') {
|
if (ltarget === 'document') {
|
||||||
if (this.documentActions) {
|
if (this.documentActions) {
|
||||||
|
this.documentActions.permissionEvent.subscribe((permision) => {
|
||||||
|
this.permissionEvent.emit(permision);
|
||||||
|
});
|
||||||
return this.documentActions.getHandler(name);
|
return this.documentActions.getHandler(name);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -27,7 +27,7 @@ import { NodeMinimalEntry, NodeMinimal, NodePaging } from '../models/document-li
|
|||||||
import { ShareDataRow, RowFilter, ImageResolver } from './../data/share-datatable-adapter';
|
import { ShareDataRow, RowFilter, ImageResolver } from './../data/share-datatable-adapter';
|
||||||
import { DataTableModule } from 'ng2-alfresco-datatable';
|
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||||
import { DocumentMenuActionComponent } from './document-menu-action.component';
|
import { DocumentMenuActionComponent } from './document-menu-action.component';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable, Subject } from 'rxjs/Rx';
|
||||||
import {
|
import {
|
||||||
fakeNodeAnswerWithNOEntries,
|
fakeNodeAnswerWithNOEntries,
|
||||||
fakeNodeAnswerWithEntries,
|
fakeNodeAnswerWithEntries,
|
||||||
@ -125,12 +125,10 @@ describe('DocumentList', () => {
|
|||||||
expect(columns[2]).toBe(column);
|
expect(columns[2]).toBe(column);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should execute action with node', () => {
|
it('should call action\'s handler with node', () => {
|
||||||
let node = new FileNode();
|
let node = new FileNode();
|
||||||
let action = new ContentActionModel();
|
let action = new ContentActionModel();
|
||||||
action.handler = function () {
|
action.handler = () => {};
|
||||||
console.log('mock handler');
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(action, 'handler').and.stub();
|
spyOn(action, 'handler').and.stub();
|
||||||
|
|
||||||
@ -139,19 +137,42 @@ describe('DocumentList', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should execute action with node and permission', () => {
|
it('should call action\'s handler with node and permission', () => {
|
||||||
let node = new FileNode();
|
let node = new FileNode();
|
||||||
let action = new ContentActionModel();
|
let action = new ContentActionModel();
|
||||||
action.handler = function () {
|
action.handler = () => {};
|
||||||
console.log('mock handler');
|
|
||||||
};
|
|
||||||
action.permission = 'fake-permission';
|
action.permission = 'fake-permission';
|
||||||
|
|
||||||
spyOn(action, 'handler').and.stub();
|
spyOn(action, 'handler').and.stub();
|
||||||
|
|
||||||
documentList.executeContentAction(node, action);
|
documentList.executeContentAction(node, action);
|
||||||
expect(action.handler).toHaveBeenCalledWith(node, documentList, 'fake-permission');
|
|
||||||
|
|
||||||
|
expect(action.handler).toHaveBeenCalledWith(node, documentList, 'fake-permission');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call action\'s execute with node if it is defined', () => {
|
||||||
|
let node = new FileNode();
|
||||||
|
let action = new ContentActionModel();
|
||||||
|
action.execute = () => {};
|
||||||
|
spyOn(action, 'execute').and.stub();
|
||||||
|
|
||||||
|
documentList.executeContentAction(node, action);
|
||||||
|
|
||||||
|
expect(action.execute).toHaveBeenCalledWith(node);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call action\'s execute only after the handler has been executed', () => {
|
||||||
|
const deleteObservable: Subject<any> = new Subject<any>();
|
||||||
|
let node = new FileNode();
|
||||||
|
let action = new ContentActionModel();
|
||||||
|
action.handler = () => deleteObservable;
|
||||||
|
action.execute = () => {};
|
||||||
|
spyOn(action, 'execute').and.stub();
|
||||||
|
|
||||||
|
documentList.executeContentAction(node, action);
|
||||||
|
|
||||||
|
expect(action.execute).not.toHaveBeenCalled();
|
||||||
|
deleteObservable.next();
|
||||||
|
expect(action.execute).toHaveBeenCalledWith(node);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show the loading state during the loading of new elements', (done) => {
|
it('should show the loading state during the loading of new elements', (done) => {
|
||||||
|
@ -19,7 +19,7 @@ import {
|
|||||||
Component, OnInit, Input, OnChanges, Output, SimpleChanges, EventEmitter, ElementRef,
|
Component, OnInit, Input, OnChanges, Output, SimpleChanges, EventEmitter, ElementRef,
|
||||||
AfterContentInit, TemplateRef, NgZone, ViewChild, HostListener, ContentChild
|
AfterContentInit, TemplateRef, NgZone, ViewChild, HostListener, ContentChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Subject } from 'rxjs/Rx';
|
import { Subject, Observable } from 'rxjs/Rx';
|
||||||
import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api';
|
import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api';
|
||||||
import { AlfrescoTranslationService, DataColumnListComponent } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, DataColumnListComponent } from 'ng2-alfresco-core';
|
||||||
import {
|
import {
|
||||||
@ -343,7 +343,17 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
|||||||
*/
|
*/
|
||||||
executeContentAction(node: MinimalNodeEntity, action: ContentActionModel) {
|
executeContentAction(node: MinimalNodeEntity, action: ContentActionModel) {
|
||||||
if (node && node.entry && action) {
|
if (node && node.entry && action) {
|
||||||
action.handler(node, this, action.permission);
|
let handlerSub;
|
||||||
|
|
||||||
|
if (typeof action.handler === 'function') {
|
||||||
|
handlerSub = action.handler(node, this, action.permission);
|
||||||
|
} else {
|
||||||
|
handlerSub = Observable.of(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof action.execute === 'function') {
|
||||||
|
handlerSub.subscribe(() => { action.execute(node); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ export class ContentActionModel {
|
|||||||
icon: string;
|
icon: string;
|
||||||
title: string;
|
title: string;
|
||||||
handler: ContentActionHandler;
|
handler: ContentActionHandler;
|
||||||
|
execute: Function;
|
||||||
target: string;
|
target: string;
|
||||||
permission: string;
|
permission: string;
|
||||||
disableWithNoPermission: boolean = false;
|
disableWithNoPermission: boolean = false;
|
||||||
@ -29,6 +30,7 @@ export class ContentActionModel {
|
|||||||
this.icon = obj.icon;
|
this.icon = obj.icon;
|
||||||
this.title = obj.title;
|
this.title = obj.title;
|
||||||
this.handler = obj.handler;
|
this.handler = obj.handler;
|
||||||
|
this.execute = obj.execute;
|
||||||
this.target = obj.target;
|
this.target = obj.target;
|
||||||
this.permission = obj.permission;
|
this.permission = obj.permission;
|
||||||
this.disableWithNoPermission = obj.disableWithNoPermission;
|
this.disableWithNoPermission = obj.disableWithNoPermission;
|
||||||
|
@ -116,6 +116,20 @@ describe('DocumentActionsService', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call the error on the returned Observable if there are no permissions', (done) => {
|
||||||
|
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||||
|
|
||||||
|
let file = new FileNode();
|
||||||
|
const deleteObservable = service.getHandler('delete')(file);
|
||||||
|
|
||||||
|
deleteObservable.subscribe({
|
||||||
|
error: (error) => {
|
||||||
|
expect(error.message).toEqual('No permission to delete');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should delete the file node if there is the delete permission', () => {
|
it('should delete the file node if there is the delete permission', () => {
|
||||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||||
|
|
||||||
@ -190,19 +204,26 @@ describe('DocumentActionsService', () => {
|
|||||||
let actionService = new DocumentActionsService(null, contentService);
|
let actionService = new DocumentActionsService(null, contentService);
|
||||||
let file = new FileNode();
|
let file = new FileNode();
|
||||||
let result = actionService.getHandler('download')(file);
|
let result = actionService.getHandler('download')(file);
|
||||||
expect(result).toBeFalsy();
|
result.subscribe((value) => {
|
||||||
|
expect(value).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should require content service for download action', () => {
|
it('should require content service for download action', () => {
|
||||||
let actionService = new DocumentActionsService(documentListService, null);
|
let actionService = new DocumentActionsService(documentListService, null);
|
||||||
let file = new FileNode();
|
let file = new FileNode();
|
||||||
let result = actionService.getHandler('download')(file);
|
let result = actionService.getHandler('download')(file);
|
||||||
expect(result).toBeFalsy();
|
result.subscribe((value) => {
|
||||||
|
expect(value).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should require file node for download action', () => {
|
it('should require file node for download action', () => {
|
||||||
let folder = new FolderNode();
|
let folder = new FolderNode();
|
||||||
expect(service.getHandler('download')(folder)).toBeFalsy();
|
let result = service.getHandler('download')(folder);
|
||||||
|
result.subscribe((value) => {
|
||||||
|
expect(value).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete file node', () => {
|
it('should delete file node', () => {
|
||||||
@ -212,9 +233,10 @@ describe('DocumentActionsService', () => {
|
|||||||
let file = new FileNode();
|
let file = new FileNode();
|
||||||
let fileWithPermission: any = file;
|
let fileWithPermission: any = file;
|
||||||
fileWithPermission.entry.allowableOperations = [permission];
|
fileWithPermission.entry.allowableOperations = [permission];
|
||||||
service.getHandler('delete')(fileWithPermission, null, permission);
|
const deleteObservale = service.getHandler('delete')(fileWithPermission, null, permission);
|
||||||
|
|
||||||
expect(documentListService.deleteNode).toHaveBeenCalledWith(file.entry.id);
|
expect(documentListService.deleteNode).toHaveBeenCalledWith(file.entry.id);
|
||||||
|
expect(deleteObservale.subscribe).toBeDefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support deletion only file node', () => {
|
it('should support deletion only file node', () => {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
import { ContentActionHandler } from '../models/content-action.model';
|
import { ContentActionHandler } from '../models/content-action.model';
|
||||||
import { DocumentListService } from './document-list.service';
|
import { DocumentListService } from './document-list.service';
|
||||||
import { AlfrescoContentService } from 'ng2-alfresco-core';
|
import { AlfrescoContentService } from 'ng2-alfresco-core';
|
||||||
@ -74,7 +75,7 @@ export class DocumentActionsService {
|
|||||||
window.alert('standard document action 2');
|
window.alert('standard document action 2');
|
||||||
}
|
}
|
||||||
|
|
||||||
private download(obj: any): boolean {
|
private download(obj: any): Observable<boolean> {
|
||||||
if (this.canExecuteAction(obj) && this.contentService) {
|
if (this.canExecuteAction(obj) && this.contentService) {
|
||||||
let link = document.createElement('a');
|
let link = document.createElement('a');
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
@ -82,21 +83,26 @@ export class DocumentActionsService {
|
|||||||
link.href = this.contentService.getContentUrl(obj);
|
link.href = this.contentService.getContentUrl(obj);
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
return true;
|
return Observable.of(true);
|
||||||
}
|
}
|
||||||
return false;
|
return Observable.of(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private deleteNode(obj: any, target?: any, permission?: string) {
|
private deleteNode(obj: any, target?: any, permission?: string): Observable<any> {
|
||||||
|
let handlerObservale;
|
||||||
|
|
||||||
if (this.canExecuteAction(obj)) {
|
if (this.canExecuteAction(obj)) {
|
||||||
if (this.hasPermission(obj.entry, permission)) {
|
if (this.hasPermission(obj.entry, permission)) {
|
||||||
this.documentListService.deleteNode(obj.entry.id).subscribe(() => {
|
handlerObservale = this.documentListService.deleteNode(obj.entry.id);
|
||||||
|
handlerObservale.subscribe(() => {
|
||||||
if (target && typeof target.reload === 'function') {
|
if (target && typeof target.reload === 'function') {
|
||||||
target.reload();
|
target.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return handlerObservale;
|
||||||
} else {
|
} else {
|
||||||
this.permissionEvent.next(new PermissionModel({type: 'content', action: 'delete', permission: permission}));
|
this.permissionEvent.next(new PermissionModel({type: 'content', action: 'delete', permission: permission}));
|
||||||
|
return Observable.throw(new Error('No permission to delete'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,9 +119,10 @@ describe('FolderActionsService', () => {
|
|||||||
let folder = new FolderNode();
|
let folder = new FolderNode();
|
||||||
let folderWithPermission: any = folder;
|
let folderWithPermission: any = folder;
|
||||||
folderWithPermission.entry.allowableOperations = [ permission ];
|
folderWithPermission.entry.allowableOperations = [ permission ];
|
||||||
service.getHandler('delete')(folderWithPermission, null, permission);
|
const deleteObservale = service.getHandler('delete')(folderWithPermission, null, permission);
|
||||||
|
|
||||||
expect(documentListService.deleteNode).toHaveBeenCalledWith(folder.entry.id);
|
expect(documentListService.deleteNode).toHaveBeenCalledWith(folder.entry.id);
|
||||||
|
expect(deleteObservale.subscribe).toBeDefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not delete the folder node if there is no delete permission', (done) => {
|
it('should not delete the folder node if there is no delete permission', (done) => {
|
||||||
@ -140,6 +141,23 @@ describe('FolderActionsService', () => {
|
|||||||
service.getHandler('delete')(folderWithPermission);
|
service.getHandler('delete')(folderWithPermission);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call the error on the returned Observable if there is no delete permission', (done) => {
|
||||||
|
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||||
|
|
||||||
|
let folder = new FolderNode();
|
||||||
|
let folderWithPermission: any = folder;
|
||||||
|
folderWithPermission.entry.allowableOperations = ['create', 'update'];
|
||||||
|
const deleteObservable = service.getHandler('delete')(folderWithPermission);
|
||||||
|
|
||||||
|
deleteObservable.subscribe({
|
||||||
|
error: (error) => {
|
||||||
|
expect(error.message).toEqual('No permission to delete');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
it('should delete the folder node if there is the delete and others permission ', () => {
|
it('should delete the folder node if there is the delete and others permission ', () => {
|
||||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { ContentActionHandler } from '../models/content-action.model';
|
import { ContentActionHandler } from '../models/content-action.model';
|
||||||
import { PermissionModel } from '../models/permissions.model';
|
import { PermissionModel } from '../models/permissions.model';
|
||||||
import { DocumentListService } from './document-list.service';
|
import { DocumentListService } from './document-list.service';
|
||||||
import { Subject } from 'rxjs/Rx';
|
import { Subject, Observable } from 'rxjs/Rx';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FolderActionsService {
|
export class FolderActionsService {
|
||||||
@ -71,16 +71,21 @@ export class FolderActionsService {
|
|||||||
window.alert('standard folder action 2');
|
window.alert('standard folder action 2');
|
||||||
}
|
}
|
||||||
|
|
||||||
private deleteNode(obj: any, target?: any, permission?: string) {
|
private deleteNode(obj: any, target?: any, permission?: string): Observable<any> {
|
||||||
|
let handlerObservale: Observable<any>;
|
||||||
|
|
||||||
if (this.canExecuteAction(obj)) {
|
if (this.canExecuteAction(obj)) {
|
||||||
if (this.hasPermission(obj.entry, permission)) {
|
if (this.hasPermission(obj.entry, permission)) {
|
||||||
this.documentListService.deleteNode(obj.entry.id).subscribe(() => {
|
handlerObservale = this.documentListService.deleteNode(obj.entry.id);
|
||||||
|
handlerObservale.subscribe(() => {
|
||||||
if (target && typeof target.reload === 'function') {
|
if (target && typeof target.reload === 'function') {
|
||||||
target.reload();
|
target.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return handlerObservale;
|
||||||
} else {
|
} else {
|
||||||
this.permissionEvent.next(new PermissionModel({type: 'folder', action: 'delete', permission: permission}));
|
this.permissionEvent.next(new PermissionModel({type: 'folder', action: 'delete', permission: permission}));
|
||||||
|
return Observable.throw(new Error('No permission to delete'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,9 @@
|
|||||||
<content-action
|
<content-action
|
||||||
target="folder"
|
target="folder"
|
||||||
title="{{'SEARCH.DOCUMENT_LIST.ACTIONS.FOLDER.DELETE' | translate}}"
|
title="{{'SEARCH.DOCUMENT_LIST.ACTIONS.FOLDER.DELETE' | translate}}"
|
||||||
handler="delete">
|
permission="delete"
|
||||||
|
handler="delete"
|
||||||
|
(permissionEvent)="handlePermission($event)">
|
||||||
</content-action>
|
</content-action>
|
||||||
<!-- document actions -->
|
<!-- document actions -->
|
||||||
<content-action
|
<content-action
|
||||||
@ -61,7 +63,10 @@
|
|||||||
<content-action
|
<content-action
|
||||||
target="document"
|
target="document"
|
||||||
title="{{'SEARCH.DOCUMENT_LIST.ACTIONS.DOCUMENT.DELETE' | translate}}"
|
title="{{'SEARCH.DOCUMENT_LIST.ACTIONS.DOCUMENT.DELETE' | translate}}"
|
||||||
handler="delete">
|
permission="delete"
|
||||||
|
handler="delete"
|
||||||
|
(execute)="onContentDelete($event)"
|
||||||
|
(permissionEvent)="handlePermission($event)">
|
||||||
</content-action>
|
</content-action>
|
||||||
</content-actions>
|
</content-actions>
|
||||||
</adf-document-list>
|
</adf-document-list>
|
||||||
|
@ -22,8 +22,9 @@ import { Observable } from 'rxjs/Rx';
|
|||||||
import { AlfrescoSearchComponent } from './alfresco-search.component';
|
import { AlfrescoSearchComponent } from './alfresco-search.component';
|
||||||
import { TranslationMock } from './../assets/translation.service.mock';
|
import { TranslationMock } from './../assets/translation.service.mock';
|
||||||
import { AlfrescoSearchService } from '../services/alfresco-search.service';
|
import { AlfrescoSearchService } from '../services/alfresco-search.service';
|
||||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, CoreModule, NotificationService } from 'ng2-alfresco-core';
|
||||||
import { DocumentListModule } from 'ng2-alfresco-documentlist';
|
import { DocumentListModule } from 'ng2-alfresco-documentlist';
|
||||||
|
import { PermissionModel } from 'ng2-alfresco-documentlist';
|
||||||
|
|
||||||
describe('AlfrescoSearchComponent', () => {
|
describe('AlfrescoSearchComponent', () => {
|
||||||
|
|
||||||
@ -104,7 +105,8 @@ describe('AlfrescoSearchComponent', () => {
|
|||||||
declarations: [AlfrescoSearchComponent], // declare the test component
|
declarations: [AlfrescoSearchComponent], // declare the test component
|
||||||
providers: [
|
providers: [
|
||||||
AlfrescoSearchService,
|
AlfrescoSearchService,
|
||||||
{ provide: AlfrescoTranslationService, useClass: TranslationMock }
|
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
|
||||||
|
{ provide: NotificationService, useClass: NotificationService }
|
||||||
]
|
]
|
||||||
}).compileComponents().then(() => {
|
}).compileComponents().then(() => {
|
||||||
fixture = TestBed.createComponent(AlfrescoSearchComponent);
|
fixture = TestBed.createComponent(AlfrescoSearchComponent);
|
||||||
@ -126,7 +128,7 @@ describe('AlfrescoSearchComponent', () => {
|
|||||||
{provide: ActivatedRoute, useValue: {params: Observable.from([{q: 'exampleTerm692'}])}}
|
{provide: ActivatedRoute, useValue: {params: Observable.from([{q: 'exampleTerm692'}])}}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let search = new AlfrescoSearchComponent(null, null, injector.get(ActivatedRoute));
|
let search = new AlfrescoSearchComponent(null, null, null, injector.get(ActivatedRoute));
|
||||||
|
|
||||||
search.ngOnInit();
|
search.ngOnInit();
|
||||||
|
|
||||||
@ -142,11 +144,20 @@ describe('AlfrescoSearchComponent', () => {
|
|||||||
expect(translationService.addTranslationFolder).toHaveBeenCalledWith('ng2-alfresco-search', 'assets/ng2-alfresco-search');
|
expect(translationService.addTranslationFolder).toHaveBeenCalledWith('ng2-alfresco-search', 'assets/ng2-alfresco-search');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should show the Notification snackbar on permission error', () => {
|
||||||
|
const notoficationService = TestBed.get(NotificationService);
|
||||||
|
spyOn(notoficationService, 'openSnackMessage');
|
||||||
|
|
||||||
|
component.handlePermission(new PermissionModel());
|
||||||
|
|
||||||
|
expect(notoficationService.openSnackMessage).toHaveBeenCalledWith('PERMISSON.LACKOF', 3000);
|
||||||
|
});
|
||||||
|
|
||||||
describe('Search results', () => {
|
describe('Search results', () => {
|
||||||
|
|
||||||
it('should call search service with the correct parameters', (done) => {
|
it('should call search service with the correct parameters', (done) => {
|
||||||
let searchTerm = 'searchTerm63688', options = {
|
let searchTerm = 'searchTerm63688', options = {
|
||||||
include: ['path'],
|
include: ['path', 'allowableOperations'],
|
||||||
skipCount: 0,
|
skipCount: 0,
|
||||||
rootNodeId: '-my-',
|
rootNodeId: '-my-',
|
||||||
nodeType: 'my:type',
|
nodeType: 'my:type',
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
import { Component, EventEmitter, Input, Output, Optional, OnChanges, SimpleChanges, OnInit } from '@angular/core';
|
import { Component, EventEmitter, Input, Output, Optional, OnChanges, SimpleChanges, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
import { AlfrescoSearchService, SearchOptions } from './../services/alfresco-search.service';
|
import { AlfrescoSearchService, SearchOptions } from './../services/alfresco-search.service';
|
||||||
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, NotificationService } from 'ng2-alfresco-core';
|
||||||
|
import { PermissionModel } from 'ng2-alfresco-documentlist';
|
||||||
import { NodePaging, Pagination } from 'alfresco-js-api';
|
import { NodePaging, Pagination } from 'alfresco-js-api';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -66,6 +67,7 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit {
|
|||||||
|
|
||||||
constructor(private searchService: AlfrescoSearchService,
|
constructor(private searchService: AlfrescoSearchService,
|
||||||
private translateService: AlfrescoTranslationService,
|
private translateService: AlfrescoTranslationService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
@Optional() private route: ActivatedRoute) {
|
@Optional() private route: ActivatedRoute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +109,7 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit {
|
|||||||
private displaySearchResults(searchTerm) {
|
private displaySearchResults(searchTerm) {
|
||||||
if (searchTerm && this.searchService) {
|
if (searchTerm && this.searchService) {
|
||||||
let searchOpts: SearchOptions = {
|
let searchOpts: SearchOptions = {
|
||||||
include: ['path'],
|
include: ['path', 'allowableOperations'],
|
||||||
skipCount: this.skipCount,
|
skipCount: this.skipCount,
|
||||||
rootNodeId: this.rootNodeId,
|
rootNodeId: this.rootNodeId,
|
||||||
nodeType: this.resultType,
|
nodeType: this.resultType,
|
||||||
@ -147,4 +149,13 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit {
|
|||||||
this.skipCount = event.skipCount;
|
this.skipCount = event.skipCount;
|
||||||
this.displaySearchResults(this.searchTerm);
|
this.displaySearchResults(this.searchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onContentDelete(entry: any) {
|
||||||
|
this.displaySearchResults(this.searchTerm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public handlePermission(permission: PermissionModel): void {
|
||||||
|
let permissionErrorMessage: any = this.translateService.get('PERMISSON.LACKOF', permission);
|
||||||
|
this.notificationService.openSnackMessage(permissionErrorMessage.value, 3000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,5 +42,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"PERMISSON": {
|
||||||
|
"LACKOF": "You don't have the {{permission}} permission to {{action}} the {{type}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user