From 843afdbcc613447a1b298f86aa9d897832ee6d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Popovics=20Andr=C3=A1s?= Date: Thu, 6 Jul 2017 09:45:03 +0100 Subject: [PATCH] [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! --- .../ng2-alfresco-documentlist/README.md | 61 +++++++++++++++++-- .../content-action.component.spec.ts | 4 +- .../content-action.component.ts | 13 ++-- .../document-list.component.spec.ts | 43 +++++++++---- .../src/components/document-list.component.ts | 14 ++++- .../src/models/content-action.model.ts | 2 + .../services/document-actions.service.spec.ts | 30 +++++++-- .../src/services/document-actions.service.ts | 16 +++-- .../services/folder-actions.service.spec.ts | 20 +++++- .../src/services/folder-actions.service.ts | 11 +++- .../components/alfresco-search.component.html | 9 ++- .../alfresco-search.component.spec.ts | 19 ++++-- .../components/alfresco-search.component.ts | 15 ++++- .../ng2-alfresco-search/src/i18n/en.json | 3 + 14 files changed, 214 insertions(+), 46 deletions(-) diff --git a/ng2-components/ng2-alfresco-documentlist/README.md b/ng2-components/ng2-alfresco-documentlist/README.md index 3bd3792129..59a543aead 100644 --- a/ng2-components/ng2-alfresco-documentlist/README.md +++ b/ng2-components/ng2-alfresco-documentlist/README.md @@ -25,6 +25,7 @@ * [Actions](#actions) + [Menu actions](#menu-actions) + [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 - Disable button checking the permission](#delete---disable-button-checking-the-permission) - [Download](#download) @@ -519,8 +520,24 @@ In the Example below will add the [ng2-alfresco-tag](https://www.npmjs.com/packa ### 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. -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. #### Menu actions @@ -529,18 +546,28 @@ You can define both folder and document actions at the same time. + + target="folder" + title="Delete" + handler="delete"> + + + + + ``` @@ -553,6 +580,11 @@ export class MyView { let entry = event.value.entry; 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"` 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 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 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 + + + + + + ``` @@ -680,6 +726,11 @@ export class MyView { let entry = event.value.entry; alert(`Custom folder action for ${entry.name}`); } + + myCustomActionAfterDelete(event) { + let entry = event.value.entry; + alert(`Custom callback after delete system action for ${entry.name}`); + } } ``` diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.spec.ts index 40f24becc2..858e0330b1 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.spec.ts @@ -160,7 +160,7 @@ describe('ContentAction', () => { expect(documentList.actions.length).toBe(1); let model = documentList.actions[0]; - model.handler(''); + model.execute(''); }); it('should sync localizable fields with model', () => { @@ -226,7 +226,7 @@ describe('ContentAction', () => { action.execute = handler; action.ngOnInit(); - action.model.handler(file); + action.model.execute(file); }); it('should allow registering model without handler', () => { diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.ts b/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.ts index 017e295c59..2574ebed99 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.ts @@ -77,11 +77,11 @@ export class ContentActionComponent implements OnInit, OnChanges { if (this.handler) { this.model.handler = this.getSystemHandler(this.target, this.handler); - } else if (this.execute) { - this.model.handler = (document: any): void => { - this.execute.emit({ - value: document - }); + } + + if (this.execute) { + this.model.execute = (value: any): void => { + this.execute.emit({ value }); }; } @@ -106,6 +106,9 @@ export class ContentActionComponent implements OnInit, OnChanges { if (ltarget === 'document') { if (this.documentActions) { + this.documentActions.permissionEvent.subscribe((permision) => { + this.permissionEvent.emit(permision); + }); return this.documentActions.getHandler(name); } return null; diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.spec.ts index 2cb38c59c8..377746f473 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.spec.ts @@ -27,7 +27,7 @@ import { NodeMinimalEntry, NodeMinimal, NodePaging } from '../models/document-li import { ShareDataRow, RowFilter, ImageResolver } from './../data/share-datatable-adapter'; import { DataTableModule } from 'ng2-alfresco-datatable'; import { DocumentMenuActionComponent } from './document-menu-action.component'; -import { Observable } from 'rxjs/Rx'; +import { Observable, Subject } from 'rxjs/Rx'; import { fakeNodeAnswerWithNOEntries, fakeNodeAnswerWithEntries, @@ -125,12 +125,10 @@ describe('DocumentList', () => { expect(columns[2]).toBe(column); }); - it('should execute action with node', () => { + it('should call action\'s handler with node', () => { let node = new FileNode(); let action = new ContentActionModel(); - action.handler = function () { - console.log('mock handler'); - }; + action.handler = () => {}; 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 action = new ContentActionModel(); - action.handler = function () { - console.log('mock handler'); - }; + action.handler = () => {}; action.permission = 'fake-permission'; - spyOn(action, 'handler').and.stub(); 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 = new Subject(); + 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) => { diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts index 540e6c1eeb..ce6eff19c1 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts @@ -19,7 +19,7 @@ import { Component, OnInit, Input, OnChanges, Output, SimpleChanges, EventEmitter, ElementRef, AfterContentInit, TemplateRef, NgZone, ViewChild, HostListener, ContentChild } from '@angular/core'; -import { Subject } from 'rxjs/Rx'; +import { Subject, Observable } from 'rxjs/Rx'; import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api'; import { AlfrescoTranslationService, DataColumnListComponent } from 'ng2-alfresco-core'; import { @@ -343,7 +343,17 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni */ executeContentAction(node: MinimalNodeEntity, action: ContentActionModel) { 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); }); + } } } diff --git a/ng2-components/ng2-alfresco-documentlist/src/models/content-action.model.ts b/ng2-components/ng2-alfresco-documentlist/src/models/content-action.model.ts index 46a293b021..b207170eed 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/models/content-action.model.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/models/content-action.model.ts @@ -19,6 +19,7 @@ export class ContentActionModel { icon: string; title: string; handler: ContentActionHandler; + execute: Function; target: string; permission: string; disableWithNoPermission: boolean = false; @@ -29,6 +30,7 @@ export class ContentActionModel { this.icon = obj.icon; this.title = obj.title; this.handler = obj.handler; + this.execute = obj.execute; this.target = obj.target; this.permission = obj.permission; this.disableWithNoPermission = obj.disableWithNoPermission; diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.spec.ts index c4607e2359..99c7f38d88 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.spec.ts @@ -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', () => { spyOn(documentListService, 'deleteNode').and.callThrough(); @@ -190,19 +204,26 @@ describe('DocumentActionsService', () => { let actionService = new DocumentActionsService(null, contentService); let file = new FileNode(); let result = actionService.getHandler('download')(file); - expect(result).toBeFalsy(); + result.subscribe((value) => { + expect(value).toBeFalsy(); + }); }); it('should require content service for download action', () => { let actionService = new DocumentActionsService(documentListService, null); let file = new FileNode(); let result = actionService.getHandler('download')(file); - expect(result).toBeFalsy(); + result.subscribe((value) => { + expect(value).toBeFalsy(); + }); }); it('should require file node for download action', () => { 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', () => { @@ -212,9 +233,10 @@ describe('DocumentActionsService', () => { let file = new FileNode(); let fileWithPermission: any = file; 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(deleteObservale.subscribe).toBeDefined; }); it('should support deletion only file node', () => { diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts index c248dc6a10..80ba1279d2 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts @@ -16,6 +16,7 @@ */ import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; import { ContentActionHandler } from '../models/content-action.model'; import { DocumentListService } from './document-list.service'; import { AlfrescoContentService } from 'ng2-alfresco-core'; @@ -74,7 +75,7 @@ export class DocumentActionsService { window.alert('standard document action 2'); } - private download(obj: any): boolean { + private download(obj: any): Observable { if (this.canExecuteAction(obj) && this.contentService) { let link = document.createElement('a'); document.body.appendChild(link); @@ -82,21 +83,26 @@ export class DocumentActionsService { link.href = this.contentService.getContentUrl(obj); link.click(); 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 { + let handlerObservale; + if (this.canExecuteAction(obj)) { 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') { target.reload(); } }); + return handlerObservale; } else { this.permissionEvent.next(new PermissionModel({type: 'content', action: 'delete', permission: permission})); + return Observable.throw(new Error('No permission to delete')); } } } diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts index 41eb245a6d..0ea7cc0e35 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts @@ -119,9 +119,10 @@ describe('FolderActionsService', () => { let folder = new FolderNode(); let folderWithPermission: any = folder; 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(deleteObservale.subscribe).toBeDefined; }); it('should not delete the folder node if there is no delete permission', (done) => { @@ -140,6 +141,23 @@ describe('FolderActionsService', () => { 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 ', () => { spyOn(documentListService, 'deleteNode').and.callThrough(); diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts index 58e561fe08..83bf92bbe4 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts @@ -19,7 +19,7 @@ import { Injectable } from '@angular/core'; import { ContentActionHandler } from '../models/content-action.model'; import { PermissionModel } from '../models/permissions.model'; import { DocumentListService } from './document-list.service'; -import { Subject } from 'rxjs/Rx'; +import { Subject, Observable } from 'rxjs/Rx'; @Injectable() export class FolderActionsService { @@ -71,16 +71,21 @@ export class FolderActionsService { window.alert('standard folder action 2'); } - private deleteNode(obj: any, target?: any, permission?: string) { + private deleteNode(obj: any, target?: any, permission?: string): Observable { + let handlerObservale: Observable; + if (this.canExecuteAction(obj)) { 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') { target.reload(); } }); + return handlerObservale; } else { this.permissionEvent.next(new PermissionModel({type: 'folder', action: 'delete', permission: permission})); + return Observable.throw(new Error('No permission to delete')); } } } diff --git a/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.html b/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.html index 7bbb0449e5..594449c024 100644 --- a/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.html +++ b/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.html @@ -50,7 +50,9 @@ + permission="delete" + handler="delete" + (permissionEvent)="handlePermission($event)"> + permission="delete" + handler="delete" + (execute)="onContentDelete($event)" + (permissionEvent)="handlePermission($event)"> diff --git a/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.spec.ts b/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.spec.ts index baaddce661..ec99d3ce97 100644 --- a/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.spec.ts +++ b/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.spec.ts @@ -22,8 +22,9 @@ import { Observable } from 'rxjs/Rx'; import { AlfrescoSearchComponent } from './alfresco-search.component'; import { TranslationMock } from './../assets/translation.service.mock'; 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 { PermissionModel } from 'ng2-alfresco-documentlist'; describe('AlfrescoSearchComponent', () => { @@ -104,7 +105,8 @@ describe('AlfrescoSearchComponent', () => { declarations: [AlfrescoSearchComponent], // declare the test component providers: [ AlfrescoSearchService, - { provide: AlfrescoTranslationService, useClass: TranslationMock } + { provide: AlfrescoTranslationService, useClass: TranslationMock }, + { provide: NotificationService, useClass: NotificationService } ] }).compileComponents().then(() => { fixture = TestBed.createComponent(AlfrescoSearchComponent); @@ -126,7 +128,7 @@ describe('AlfrescoSearchComponent', () => { {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(); @@ -142,11 +144,20 @@ describe('AlfrescoSearchComponent', () => { 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', () => { it('should call search service with the correct parameters', (done) => { let searchTerm = 'searchTerm63688', options = { - include: ['path'], + include: ['path', 'allowableOperations'], skipCount: 0, rootNodeId: '-my-', nodeType: 'my:type', diff --git a/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.ts b/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.ts index 1c7e457348..05852bb1a7 100644 --- a/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.ts +++ b/ng2-components/ng2-alfresco-search/src/components/alfresco-search.component.ts @@ -18,7 +18,8 @@ import { Component, EventEmitter, Input, Output, Optional, OnChanges, SimpleChanges, OnInit } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; 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'; @Component({ @@ -66,6 +67,7 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit { constructor(private searchService: AlfrescoSearchService, private translateService: AlfrescoTranslationService, + private notificationService: NotificationService, @Optional() private route: ActivatedRoute) { } @@ -107,7 +109,7 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit { private displaySearchResults(searchTerm) { if (searchTerm && this.searchService) { let searchOpts: SearchOptions = { - include: ['path'], + include: ['path', 'allowableOperations'], skipCount: this.skipCount, rootNodeId: this.rootNodeId, nodeType: this.resultType, @@ -147,4 +149,13 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit { this.skipCount = event.skipCount; 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); + } } diff --git a/ng2-components/ng2-alfresco-search/src/i18n/en.json b/ng2-components/ng2-alfresco-search/src/i18n/en.json index bfee68b4c5..a996bb02d4 100644 --- a/ng2-components/ng2-alfresco-search/src/i18n/en.json +++ b/ng2-components/ng2-alfresco-search/src/i18n/en.json @@ -42,5 +42,8 @@ } } } + }, + "PERMISSON": { + "LACKOF": "You don't have the {{permission}} permission to {{action}} the {{type}}" } }