mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-1041] Node picker, first iteration (#2122)
* First try * Dialog basic functionality * Search input * Hammering it together * Fist working proto for copy * Fix the tests and tslint errors for a happier world * Add more tests (and test shells for the future) * copyNode and moveNode methods * Copy and move actions for content type * Extract common parts in favor of using them in folder content type also * Small fixes * Copy and Move actions for folders as well * Style fixes, ui behaviours and tests needed to be written * Move duplicated search service from documentlist to core * Use search service from core within the search component * Fix dialog width * Update docs * Tests for node selector * Change seletionMade event's name to select
This commit is contained in:
committed by
Eugenio Romano
parent
952da3ab99
commit
4fd8bfb875
@@ -117,6 +117,22 @@
|
|||||||
|
|
||||||
<content-actions>
|
<content-actions>
|
||||||
<!-- folder actions -->
|
<!-- folder actions -->
|
||||||
|
<content-action
|
||||||
|
icon="content_copy"
|
||||||
|
target="folder"
|
||||||
|
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.COPY' | translate}}"
|
||||||
|
permission="update"
|
||||||
|
[disableWithNoPermission]="true"
|
||||||
|
handler="copy">
|
||||||
|
</content-action>
|
||||||
|
<content-action
|
||||||
|
icon="redo"
|
||||||
|
target="folder"
|
||||||
|
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.MOVE' | translate}}"
|
||||||
|
permission="update"
|
||||||
|
[disableWithNoPermission]="true"
|
||||||
|
handler="move">
|
||||||
|
</content-action>
|
||||||
<content-action
|
<content-action
|
||||||
icon="delete"
|
icon="delete"
|
||||||
target="folder"
|
target="folder"
|
||||||
@@ -133,6 +149,22 @@
|
|||||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DOWNLOAD' | translate}}"
|
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DOWNLOAD' | translate}}"
|
||||||
handler="download">
|
handler="download">
|
||||||
</content-action>
|
</content-action>
|
||||||
|
<content-action
|
||||||
|
icon="content_copy"
|
||||||
|
target="document"
|
||||||
|
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.COPY' | translate}}"
|
||||||
|
permission="update"
|
||||||
|
[disableWithNoPermission]="true"
|
||||||
|
handler="copy">
|
||||||
|
</content-action>
|
||||||
|
<content-action
|
||||||
|
icon="redo"
|
||||||
|
target="document"
|
||||||
|
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.MOVE' | translate}}"
|
||||||
|
permission="update"
|
||||||
|
[disableWithNoPermission]="true"
|
||||||
|
handler="move">
|
||||||
|
</content-action>
|
||||||
<content-action
|
<content-action
|
||||||
icon="delete"
|
icon="delete"
|
||||||
target="document"
|
target="document"
|
||||||
|
@@ -28,7 +28,7 @@ const alfrescoLibs = [
|
|||||||
|
|
||||||
module.exports = webpackMerge(commonConfig, {
|
module.exports = webpackMerge(commonConfig, {
|
||||||
|
|
||||||
devtool: 'cheap-module-eval-source-map',
|
devtool: 'cheap-module-source-map',
|
||||||
|
|
||||||
output: {
|
output: {
|
||||||
path: helpers.root('dist'),
|
path: helpers.root('dist'),
|
||||||
|
@@ -10,15 +10,15 @@
|
|||||||
},
|
},
|
||||||
"ACTIONS": {
|
"ACTIONS": {
|
||||||
"FOLDER": {
|
"FOLDER": {
|
||||||
"SYSTEM_1": "System folder action 1",
|
"COPY": "Copy",
|
||||||
"CUSTOM": "Custom folder action",
|
"MOVE": "Move",
|
||||||
"DELETE": "Delete"
|
"DELETE": "Delete"
|
||||||
},
|
},
|
||||||
"DOCUMENT": {
|
"DOCUMENT": {
|
||||||
"DOWNLOAD": "Download",
|
"DOWNLOAD": "Download",
|
||||||
"DELETE": "Delete",
|
"COPY": "Copy",
|
||||||
"SYSTEM_2": "System document action 2",
|
"MOVE": "Move",
|
||||||
"CUSTOM": "Custom action"
|
"DELETE": "Delete"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -85,6 +85,7 @@ export { UpdateNotification } from './src/services/card-view-update.service';
|
|||||||
export { ClickNotification } from './src/services/card-view-update.service';
|
export { ClickNotification } from './src/services/card-view-update.service';
|
||||||
export { AppConfigModule } from './src/services/app-config.service';
|
export { AppConfigModule } from './src/services/app-config.service';
|
||||||
export { UserPreferencesService } from './src/services/user-preferences.service';
|
export { UserPreferencesService } from './src/services/user-preferences.service';
|
||||||
|
import { SearchService } from './src/services/search.service';
|
||||||
|
|
||||||
export { DeletedNodesApiService } from './src/services/deleted-nodes-api.service';
|
export { DeletedNodesApiService } from './src/services/deleted-nodes-api.service';
|
||||||
export { FavoritesApiService } from './src/services/favorites-api.service';
|
export { FavoritesApiService } from './src/services/favorites-api.service';
|
||||||
|
@@ -0,0 +1,63 @@
|
|||||||
|
/*!
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export let fakeSearch = {
|
||||||
|
list: {
|
||||||
|
pagination: {
|
||||||
|
count: 1,
|
||||||
|
hasMoreItems: false,
|
||||||
|
totalItems: 1,
|
||||||
|
skipCount: 0,
|
||||||
|
maxItems: 100
|
||||||
|
},
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
entry: {
|
||||||
|
id: '123',
|
||||||
|
name: 'MyDoc',
|
||||||
|
content: {
|
||||||
|
mimetype: 'text/plain'
|
||||||
|
},
|
||||||
|
createdByUser: {
|
||||||
|
displayName: 'John Doe'
|
||||||
|
},
|
||||||
|
modifiedByUser: {
|
||||||
|
displayName: 'John Doe'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export let fakeError = {
|
||||||
|
error: {
|
||||||
|
errorKey: 'Search failed',
|
||||||
|
statusCode: 400,
|
||||||
|
briefSummary: '08220082 search failed',
|
||||||
|
stackTrace: 'For security reasons the stack trace is no longer displayed, but the property is kept for previous versions.',
|
||||||
|
descriptionURL: 'https://api-explorer.alfresco.com'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export let fakeApi = {
|
||||||
|
core: {
|
||||||
|
queriesApi: {
|
||||||
|
findNodes: (term, opts) => Promise.resolve(fakeSearch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@@ -16,9 +16,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
import { AlfrescoApiService, CoreModule } from 'ng2-alfresco-core';
|
|
||||||
import { fakeApi, fakeError, fakeSearch } from '../assets/search.service.mock';
|
import { fakeApi, fakeError, fakeSearch } from '../assets/search.service.mock';
|
||||||
|
import { CookieServiceMock } from './../assets/cookie.service.mock';
|
||||||
|
import { AlfrescoApiService } from './alfresco-api.service';
|
||||||
|
import { AlfrescoSettingsService } from './alfresco-settings.service';
|
||||||
|
import { AppConfigModule } from './app-config.service';
|
||||||
|
import { AuthenticationService } from './authentication.service';
|
||||||
|
import { CookieService } from './cookie.service';
|
||||||
|
import { LogService } from './log.service';
|
||||||
import { SearchService } from './search.service';
|
import { SearchService } from './search.service';
|
||||||
|
import { StorageService } from './storage.service';
|
||||||
|
import { UserPreferencesService } from './user-preferences.service';
|
||||||
|
|
||||||
declare let jasmine: any;
|
declare let jasmine: any;
|
||||||
|
|
||||||
@@ -30,10 +38,18 @@ describe('SearchService', () => {
|
|||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
CoreModule
|
AppConfigModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
SearchService
|
SearchService,
|
||||||
|
AuthenticationService,
|
||||||
|
AlfrescoApiService,
|
||||||
|
AlfrescoSettingsService,
|
||||||
|
AuthenticationService,
|
||||||
|
StorageService,
|
||||||
|
UserPreferencesService,
|
||||||
|
{ provide: CookieService, useClass: CookieServiceMock },
|
||||||
|
LogService
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
@@ -17,8 +17,9 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NodePaging } from 'alfresco-js-api';
|
import { NodePaging } from 'alfresco-js-api';
|
||||||
import { AlfrescoApiService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
|
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
import { AlfrescoApiService } from './alfresco-api.service';
|
||||||
|
import { AuthenticationService } from './authentication.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal service used by Document List component.
|
* Internal service used by Document List component.
|
||||||
@@ -26,7 +27,7 @@ import { Observable } from 'rxjs/Rx';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class SearchService {
|
export class SearchService {
|
||||||
|
|
||||||
constructor(public authService: AlfrescoAuthenticationService,
|
constructor(public authService: AuthenticationService,
|
||||||
private apiService: AlfrescoApiService) {
|
private apiService: AlfrescoApiService) {
|
||||||
}
|
}
|
||||||
|
|
@@ -32,6 +32,7 @@
|
|||||||
- [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)
|
||||||
|
- [Copy and move](#copy-and-move)
|
||||||
+ [Folder actions](#folder-actions)
|
+ [Folder actions](#folder-actions)
|
||||||
* [Context Menu](#context-menu)
|
* [Context Menu](#context-menu)
|
||||||
* [Navigation mode](#navigation-mode)
|
* [Navigation mode](#navigation-mode)
|
||||||
@@ -630,9 +631,12 @@ You can define both folder and document actions at the same time.
|
|||||||
|
|
||||||
<!-- system handler -->
|
<!-- system handler -->
|
||||||
<content-action
|
<content-action
|
||||||
target="folder"
|
icon="content_copy"
|
||||||
title="Delete"
|
target="document"
|
||||||
handler="delete">
|
title="copy"
|
||||||
|
permission="update"
|
||||||
|
[disableWithNoPermission]="true"
|
||||||
|
handler="copy">
|
||||||
</content-action>
|
</content-action>
|
||||||
|
|
||||||
<!-- custom handler -->
|
<!-- custom handler -->
|
||||||
@@ -647,6 +651,7 @@ You can define both folder and document actions at the same time.
|
|||||||
target="document"
|
target="document"
|
||||||
title="Delete with additional custom callback"
|
title="Delete with additional custom callback"
|
||||||
handler="delete"
|
handler="delete"
|
||||||
|
permission="delete"
|
||||||
(execute)="myCustomActionAfterDelete($event)">
|
(execute)="myCustomActionAfterDelete($event)">
|
||||||
</content-action>
|
</content-action>
|
||||||
|
|
||||||
@@ -679,6 +684,8 @@ All document actions are rendered as a dropdown menu as on the picture below:
|
|||||||
The following action handlers are provided out-of-box:
|
The following action handlers are provided out-of-box:
|
||||||
|
|
||||||
- **Download** (document)
|
- **Download** (document)
|
||||||
|
- **Copy** (document, folder)
|
||||||
|
- **Move** (document, folder)
|
||||||
- **Delete** (document, folder)
|
- **Delete** (document, folder)
|
||||||
|
|
||||||
All system handler names are case-insensitive, `handler="download"` and `handler="DOWNLOAD"`
|
All system handler names are case-insensitive, `handler="download"` and `handler="DOWNLOAD"`
|
||||||
@@ -766,6 +773,40 @@ Initiates download of the corresponding document file.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
##### Copy and move
|
||||||
|
|
||||||
|
Shows the destination chooser dialog for copy and move actions
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-document-list ...>
|
||||||
|
<content-actions>
|
||||||
|
|
||||||
|
<content-action
|
||||||
|
icon="content_copy"
|
||||||
|
target="document"
|
||||||
|
title="copy"
|
||||||
|
permission="update"
|
||||||
|
[disableWithNoPermission]="true"
|
||||||
|
handler="copy">
|
||||||
|
</content-action>
|
||||||
|
|
||||||
|
<content-action
|
||||||
|
icon="redo"
|
||||||
|
target="document"
|
||||||
|
title="move"
|
||||||
|
permission="update"
|
||||||
|
[disableWithNoPermission]="true"
|
||||||
|
handler="move">
|
||||||
|
</content-action>
|
||||||
|
|
||||||
|
</content-actions>
|
||||||
|
</adf-document-list>
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
#### Folder actions
|
#### Folder actions
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
@@ -25,6 +25,7 @@ import { ContentActionListComponent } from './src/components/content-action/cont
|
|||||||
import { ContentActionComponent } from './src/components/content-action/content-action.component';
|
import { ContentActionComponent } from './src/components/content-action/content-action.component';
|
||||||
import { ContentColumnListComponent } from './src/components/content-column/content-column-list.component';
|
import { ContentColumnListComponent } from './src/components/content-column/content-column-list.component';
|
||||||
import { ContentColumnComponent } from './src/components/content-column/content-column.component';
|
import { ContentColumnComponent } from './src/components/content-column/content-column.component';
|
||||||
|
import { ContentNodeSelectorComponent } from './src/components/content-node-selector/content-node-selector.component';
|
||||||
import { DocumentListComponent } from './src/components/document-list.component';
|
import { DocumentListComponent } from './src/components/document-list.component';
|
||||||
import { DocumentMenuActionComponent } from './src/components/document-menu-action.component';
|
import { DocumentMenuActionComponent } from './src/components/document-menu-action.component';
|
||||||
import { EmptyFolderContentDirective } from './src/components/empty-folder/empty-folder-content.directive';
|
import { EmptyFolderContentDirective } from './src/components/empty-folder/empty-folder-content.directive';
|
||||||
@@ -34,6 +35,7 @@ import { MaterialModule } from './src/material.module';
|
|||||||
import { DocumentActionsService } from './src/services/document-actions.service';
|
import { DocumentActionsService } from './src/services/document-actions.service';
|
||||||
import { DocumentListService } from './src/services/document-list.service';
|
import { DocumentListService } from './src/services/document-list.service';
|
||||||
import { FolderActionsService } from './src/services/folder-actions.service';
|
import { FolderActionsService } from './src/services/folder-actions.service';
|
||||||
|
import { NodeActionsService } from './src/services/node-actions.service';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
export * from './src/components/document-list.component';
|
export * from './src/components/document-list.component';
|
||||||
@@ -71,13 +73,15 @@ export const DOCUMENT_LIST_DIRECTIVES: any[] = [
|
|||||||
EmptyFolderContentDirective,
|
EmptyFolderContentDirective,
|
||||||
BreadcrumbComponent,
|
BreadcrumbComponent,
|
||||||
DropdownSitesComponent,
|
DropdownSitesComponent,
|
||||||
DropdownBreadcrumbComponent
|
DropdownBreadcrumbComponent,
|
||||||
|
ContentNodeSelectorComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
export const DOCUMENT_LIST_PROVIDERS: any[] = [
|
export const DOCUMENT_LIST_PROVIDERS: any[] = [
|
||||||
DocumentListService,
|
DocumentListService,
|
||||||
FolderActionsService,
|
FolderActionsService,
|
||||||
DocumentActionsService
|
DocumentActionsService,
|
||||||
|
NodeActionsService
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -92,6 +96,9 @@ export const DOCUMENT_LIST_PROVIDERS: any[] = [
|
|||||||
providers: [
|
providers: [
|
||||||
...DOCUMENT_LIST_PROVIDERS
|
...DOCUMENT_LIST_PROVIDERS
|
||||||
],
|
],
|
||||||
|
entryComponents: [
|
||||||
|
ContentNodeSelectorComponent
|
||||||
|
],
|
||||||
exports: [
|
exports: [
|
||||||
DataTableModule,
|
DataTableModule,
|
||||||
...DOCUMENT_LIST_DIRECTIVES,
|
...DOCUMENT_LIST_DIRECTIVES,
|
||||||
|
@@ -17,12 +17,13 @@
|
|||||||
|
|
||||||
import { EventEmitter } from '@angular/core';
|
import { EventEmitter } from '@angular/core';
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
import { AlfrescoContentService, CoreModule } from 'ng2-alfresco-core';
|
import { AlfrescoContentService, AlfrescoTranslationService, CoreModule, NotificationService } from 'ng2-alfresco-core';
|
||||||
import { FileNode } from './../../assets/document-library.model.mock';
|
import { FileNode } from './../../assets/document-library.model.mock';
|
||||||
import { DocumentListServiceMock } from './../../assets/document-list.service.mock';
|
import { DocumentListServiceMock } from './../../assets/document-list.service.mock';
|
||||||
import { ContentActionHandler } from './../../models/content-action.model';
|
import { ContentActionHandler } from './../../models/content-action.model';
|
||||||
import { DocumentActionsService } from './../../services/document-actions.service';
|
import { DocumentActionsService } from './../../services/document-actions.service';
|
||||||
import { FolderActionsService } from './../../services/folder-actions.service';
|
import { FolderActionsService } from './../../services/folder-actions.service';
|
||||||
|
import { NodeActionsService } from './../../services/node-actions.service';
|
||||||
import { DocumentListComponent } from './../document-list.component';
|
import { DocumentListComponent } from './../document-list.component';
|
||||||
import { ContentActionListComponent } from './content-action-list.component';
|
import { ContentActionListComponent } from './content-action-list.component';
|
||||||
import { ContentActionComponent } from './content-action.component';
|
import { ContentActionComponent } from './content-action.component';
|
||||||
@@ -35,6 +36,9 @@ describe('ContentAction', () => {
|
|||||||
let folderActions: FolderActionsService;
|
let folderActions: FolderActionsService;
|
||||||
|
|
||||||
let contentService: AlfrescoContentService;
|
let contentService: AlfrescoContentService;
|
||||||
|
let translateService: AlfrescoTranslationService;
|
||||||
|
let notificationService: NotificationService;
|
||||||
|
let nodeActionsService: NodeActionsService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
@@ -49,9 +53,12 @@ describe('ContentAction', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
contentService = TestBed.get(AlfrescoContentService);
|
contentService = TestBed.get(AlfrescoContentService);
|
||||||
|
translateService = <AlfrescoTranslationService> { addTranslationFolder: () => {}};
|
||||||
|
nodeActionsService = new NodeActionsService(null, translateService, null, null);
|
||||||
|
notificationService = new NotificationService(null);
|
||||||
let documentServiceMock = new DocumentListServiceMock();
|
let documentServiceMock = new DocumentListServiceMock();
|
||||||
documentActions = new DocumentActionsService(null, null);
|
documentActions = new DocumentActionsService(translateService, notificationService, nodeActionsService);
|
||||||
folderActions = new FolderActionsService(null, contentService);
|
folderActions = new FolderActionsService(translateService, notificationService, nodeActionsService, null, contentService);
|
||||||
|
|
||||||
documentList = new DocumentListComponent(documentServiceMock, null, null, null);
|
documentList = new DocumentListComponent(documentServiceMock, null, null, null);
|
||||||
actionList = new ContentActionListComponent(documentList);
|
actionList = new ContentActionListComponent(documentList);
|
||||||
|
@@ -0,0 +1,73 @@
|
|||||||
|
<header mdDialogTitle
|
||||||
|
class="adf-content-node-selector-title"
|
||||||
|
data-automation-id="content-node-selector-title">{{title}}</header>
|
||||||
|
|
||||||
|
<section mdDialogContent
|
||||||
|
class="adf-content-node-selector-content"
|
||||||
|
(node-select)="onNodeSelect($event)"
|
||||||
|
(node-unselect)="onNodeUnselect($event)">
|
||||||
|
|
||||||
|
<md-input-container floatPlaceholder="never" class="adf-content-node-selector-content-input">
|
||||||
|
<input #searchInput
|
||||||
|
mdInput
|
||||||
|
placeholder="Search"
|
||||||
|
(keyup)="search(searchInput.value)"
|
||||||
|
[value]="searchTerm"
|
||||||
|
data-automation-id="content-node-selector-search-input">
|
||||||
|
|
||||||
|
<md-icon *ngIf="searchTerm.length > 0"
|
||||||
|
mdSuffix (click)="clear()"
|
||||||
|
class="adf-content-node-selector-content-input-icon"
|
||||||
|
data-automation-id="content-node-selector-search-clear">clear</md-icon>
|
||||||
|
|
||||||
|
<md-icon *ngIf="searchTerm.length === 0"
|
||||||
|
mdSuffix
|
||||||
|
class="adf-content-node-selector-content-input-icon"
|
||||||
|
data-automation-id="content-node-selector-search-icon">search</md-icon>
|
||||||
|
|
||||||
|
</md-input-container>
|
||||||
|
|
||||||
|
<adf-sites-dropdown
|
||||||
|
(change)="siteChanged($event)"
|
||||||
|
data-automation-id="content-node-selector-sites-combo"></adf-sites-dropdown>
|
||||||
|
|
||||||
|
<div class="adf-content-node-selector-content-list" data-automation-id="content-node-selector-content-list">
|
||||||
|
<adf-document-list *ngIf="searched"
|
||||||
|
#documentList
|
||||||
|
[node]="nodes"
|
||||||
|
[permissionsStyle]="permissionsStyle"
|
||||||
|
[creationMenuActions]="false"
|
||||||
|
[currentFolderId]="currentFolderId"
|
||||||
|
[selectionMode]="'single'"
|
||||||
|
[contextMenuActions]="false"
|
||||||
|
[contentActions]="false"
|
||||||
|
[allowDropFiles]="false"
|
||||||
|
[enablePagination]="false"
|
||||||
|
data-automation-id="content-node-selector-document-list">
|
||||||
|
<empty-folder-content>
|
||||||
|
<template>
|
||||||
|
<div>{{ 'NODE_SELECTOR.NO_RESULTS' | translate }}</div>
|
||||||
|
</template>
|
||||||
|
</empty-folder-content>
|
||||||
|
</adf-document-list>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer mdDialogActions class="adf-content-node-selector-actions">
|
||||||
|
|
||||||
|
<button *ngIf="inDialog"
|
||||||
|
md-button
|
||||||
|
class="adf-content-node-selector-actions-cancel"
|
||||||
|
(click)="close()"
|
||||||
|
data-automation-id="content-node-selector-actions-cancel">{{ 'NODE_SELECTOR.CANCEL' | translate }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button md-button
|
||||||
|
[disabled]="!chosenNode"
|
||||||
|
class="adf-content-node-selector-actions-choose"
|
||||||
|
(click)="choose()"
|
||||||
|
data-automation-id="content-node-selector-actions-choose">{{ 'NODE_SELECTOR.CHOOSE' | translate }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</footer>
|
@@ -0,0 +1,116 @@
|
|||||||
|
@import 'theming';
|
||||||
|
|
||||||
|
.#{$ADF}-content-node-selector-dialog {
|
||||||
|
|
||||||
|
.mat-dialog-container {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$ADF}-content-node-selector {
|
||||||
|
&-title,
|
||||||
|
&-content,
|
||||||
|
&-actions {
|
||||||
|
padding: 16px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
padding-top: 0;
|
||||||
|
|
||||||
|
&-input {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
color: rgba(0, 0, 0, 0.38);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: rgba(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& /deep/ .mat-input-underline .mat-input-ripple {
|
||||||
|
height: 1px;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& /deep/ .adf-site-dropdown-list-element {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.mat-select-trigger {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-select-placeholder,
|
||||||
|
&.mat-select {
|
||||||
|
font-family: 'Muli', "Helvetica", "Arial", sans-serif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-list {
|
||||||
|
height: 200px;
|
||||||
|
overflow: auto;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.07);
|
||||||
|
|
||||||
|
& /deep/ .adf-data-table {
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
.adf-no-content-container {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.adf-data-table-cell {
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-top: none;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr {
|
||||||
|
height: auto !important;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
.adf-data-table-cell {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-actions {
|
||||||
|
padding: 8px;
|
||||||
|
background-color: rgb(250, 250, 250);
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
color: rgb(121, 121, 121);
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-cancel {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-choose {
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,377 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { DebugElement, EventEmitter } from '@angular/core';
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MD_DIALOG_DATA, MdDialogRef } from '@angular/material';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { MinimalNodeEntryEntity, NodePaging } from 'alfresco-js-api';
|
||||||
|
import { AlfrescoTranslationService, CoreModule, SearchService, SiteModel } from 'ng2-alfresco-core';
|
||||||
|
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||||
|
import { MaterialModule } from '../../material.module';
|
||||||
|
import { DocumentListService } from '../../services/document-list.service';
|
||||||
|
import { DocumentListComponent } from '../document-list.component';
|
||||||
|
import { DocumentMenuActionComponent } from '../document-menu-action.component';
|
||||||
|
import { EmptyFolderContentDirective } from '../empty-folder/empty-folder-content.directive';
|
||||||
|
import { DropdownSitesComponent } from '../site-dropdown/sites-dropdown.component';
|
||||||
|
import { ContentNodeSelectorComponent } from './content-node-selector.component';
|
||||||
|
|
||||||
|
const ONE_FOLDER_RESULT = {
|
||||||
|
list: {
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
entry: {
|
||||||
|
id: '123', name: 'MyFolder', isFile: false, isFolder: true,
|
||||||
|
createdByUser: { displayName: 'John Doe' },
|
||||||
|
modifiedByUser: { displayName: 'John Doe' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const NO_RESULT = {
|
||||||
|
list: {
|
||||||
|
entries: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('ContentNodeSelectorComponent', () => {
|
||||||
|
|
||||||
|
let component: ContentNodeSelectorComponent;
|
||||||
|
let fixture: ComponentFixture<ContentNodeSelectorComponent>;
|
||||||
|
let element: DebugElement;
|
||||||
|
let data: any;
|
||||||
|
let searchService: SearchService;
|
||||||
|
let searchSpy: jasmine.Spy;
|
||||||
|
|
||||||
|
let _resolve: Function;
|
||||||
|
let _reject: Function;
|
||||||
|
|
||||||
|
function typeToSearchBox(searchTerm = 'string-to-search') {
|
||||||
|
let searchInput = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-input"]'));
|
||||||
|
searchInput.nativeElement.value = searchTerm;
|
||||||
|
searchInput.triggerEventHandler('keyup', {});
|
||||||
|
fixture.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
function respondWithSearchResults(result) {
|
||||||
|
_resolve(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupTestbed(plusProviders) {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
CoreModule.forRoot(),
|
||||||
|
DataTableModule.forRoot(),
|
||||||
|
MaterialModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
DocumentListComponent,
|
||||||
|
DocumentMenuActionComponent,
|
||||||
|
EmptyFolderContentDirective,
|
||||||
|
DropdownSitesComponent,
|
||||||
|
ContentNodeSelectorComponent
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AlfrescoTranslationService,
|
||||||
|
DocumentListService,
|
||||||
|
SearchService,
|
||||||
|
...plusProviders
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
TestBed.resetTestingModule();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Dialog features', () => {
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
data = {
|
||||||
|
title: 'Move along citizen...',
|
||||||
|
select: new EventEmitter<MinimalNodeEntryEntity>()
|
||||||
|
};
|
||||||
|
|
||||||
|
setupTestbed([{ provide: MD_DIALOG_DATA, useValue: data }]);
|
||||||
|
TestBed.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ContentNodeSelectorComponent);
|
||||||
|
element = fixture.debugElement;
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Data injecting with the "Material dialog way"', () => {
|
||||||
|
|
||||||
|
it('should show the INJECTED title', () => {
|
||||||
|
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-title"]'));
|
||||||
|
expect(titleElement).not.toBeNull();
|
||||||
|
expect(titleElement.nativeElement.innerText).toBe('Move along citizen...');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should trigger the INJECTED select event when selection has been made', (done) => {
|
||||||
|
const expectedNode = <MinimalNodeEntryEntity> {};
|
||||||
|
data.select.subscribe((node) => {
|
||||||
|
expect(node).toBe(expectedNode);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.chosenNode = expectedNode;
|
||||||
|
component.choose();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Cancel button', () => {
|
||||||
|
|
||||||
|
let dummyMdDialogRef;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
dummyMdDialogRef = <MdDialogRef<ContentNodeSelectorComponent>> { close: () => {} };
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be shown if dialogRef is injected', () => {
|
||||||
|
const componentInstance = new ContentNodeSelectorComponent(null, null, data, dummyMdDialogRef);
|
||||||
|
expect(componentInstance.inDialog).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should should call the close method in the injected dialogRef', () => {
|
||||||
|
spyOn(dummyMdDialogRef, 'close');
|
||||||
|
const componentInstance = new ContentNodeSelectorComponent(null, null, data, dummyMdDialogRef);
|
||||||
|
|
||||||
|
componentInstance.close();
|
||||||
|
|
||||||
|
expect(dummyMdDialogRef.close).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('General component features', () => {
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
setupTestbed([]);
|
||||||
|
TestBed.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ContentNodeSelectorComponent);
|
||||||
|
element = fixture.debugElement;
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
|
searchService = TestBed.get(SearchService);
|
||||||
|
searchSpy = spyOn(searchService, 'getQueryNodesPromise').and.callFake(() => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
_resolve = resolve;
|
||||||
|
_reject = reject;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Parameters', () => {
|
||||||
|
|
||||||
|
it('should show the title', () => {
|
||||||
|
component.title = 'Move along citizen...';
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-title"]'));
|
||||||
|
expect(titleElement).not.toBeNull();
|
||||||
|
expect(titleElement.nativeElement.innerText).toBe('Move along citizen...');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should trigger the select event when selection has been made', (done) => {
|
||||||
|
const expectedNode = <MinimalNodeEntryEntity> {};
|
||||||
|
component.select.subscribe((node) => {
|
||||||
|
expect(node).toBe(expectedNode);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.chosenNode = expectedNode;
|
||||||
|
component.choose();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Search functionality', () => {
|
||||||
|
|
||||||
|
it('should load the results by calling the search api on search change', () => {
|
||||||
|
typeToSearchBox('kakarot');
|
||||||
|
|
||||||
|
expect(searchSpy).toHaveBeenCalledWith('kakarot*', {
|
||||||
|
include: ['path'],
|
||||||
|
skipCount: 0,
|
||||||
|
rootNodeId: undefined,
|
||||||
|
nodeType: 'cm:folder',
|
||||||
|
maxItems: 40,
|
||||||
|
orderBy: null
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT call the search api if the searchTerm length is less than 4 characters', () => {
|
||||||
|
typeToSearchBox('1');
|
||||||
|
typeToSearchBox('12');
|
||||||
|
typeToSearchBox('123');
|
||||||
|
|
||||||
|
expect(searchSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
xit('should debounce the search call by 500 ms', () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call the search api on changing the site selectbox\'s value', () => {
|
||||||
|
typeToSearchBox('vegeta');
|
||||||
|
expect(searchSpy.calls.count()).toBe(1, 'Search count should be one after only one search');
|
||||||
|
|
||||||
|
component.siteChanged(<SiteModel> { guid: 'namek' });
|
||||||
|
|
||||||
|
expect(searchSpy.calls.count()).toBe(2, 'Search count should be two after the site change');
|
||||||
|
expect(searchSpy.calls.argsFor(1)).toEqual(['vegeta*', {
|
||||||
|
include: ['path'],
|
||||||
|
skipCount: 0,
|
||||||
|
rootNodeId: 'namek',
|
||||||
|
nodeType: 'cm:folder',
|
||||||
|
maxItems: 40,
|
||||||
|
orderBy: null
|
||||||
|
}]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the search icon by default without the X (clear) icon', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let searchIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-icon"]'));
|
||||||
|
let clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
|
||||||
|
|
||||||
|
expect(searchIcon).not.toBeNull('Search icon should be in the DOM');
|
||||||
|
expect(clearIcon).toBeNull('Clear icon should NOT be in the DOM');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the X (clear) icon without the search icon when the search contains at least one character', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
typeToSearchBox('123');
|
||||||
|
|
||||||
|
let searchIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-icon"]'));
|
||||||
|
let clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
|
||||||
|
|
||||||
|
expect(searchIcon).toBeNull('Search icon should NOT be in the DOM');
|
||||||
|
expect(clearIcon).not.toBeNull('Clear icon should be in the DOM');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear the search field, nodes and chosenNode when clicking on the X (clear) icon', () => {
|
||||||
|
component.chosenNode = <MinimalNodeEntryEntity> {};
|
||||||
|
component.nodes = [ component.chosenNode ];
|
||||||
|
component.searchTerm = 'whatever';
|
||||||
|
component.searched = true;
|
||||||
|
|
||||||
|
component.clear();
|
||||||
|
|
||||||
|
expect(component.searched).toBe(false);
|
||||||
|
expect(component.searchTerm).toBe('');
|
||||||
|
expect(component.nodes).toEqual([]);
|
||||||
|
expect(component.chosenNode).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the default text instead of result list if search was not performed', () => {
|
||||||
|
let documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
|
||||||
|
expect(documentList).toBeNull('Document list should not be shown by default');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the result list when search was performed', async(() => {
|
||||||
|
typeToSearchBox();
|
||||||
|
respondWithSearchResults(ONE_FOLDER_RESULT);
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
|
||||||
|
expect(documentList).not.toBeNull('Document list should be shown after search');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should show the default text instead of result list if search was cleared', async(() => {
|
||||||
|
typeToSearchBox();
|
||||||
|
respondWithSearchResults(ONE_FOLDER_RESULT);
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let clearButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
|
||||||
|
expect(clearButton).not.toBeNull('Clear button should be in DOM');
|
||||||
|
clearButton.triggerEventHandler('click', {});
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
let documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
|
||||||
|
expect(documentList).toBeNull('Document list should NOT be shown after clearing the search');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
xit('should do something with pagination or with many results', () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
xit('should trigger some kind of error when error happened during search', () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Cancel button', () => {
|
||||||
|
|
||||||
|
it('should not be shown if dialogRef is NOT injected', () => {
|
||||||
|
const closeButton = fixture.debugElement.query(By.css('[content-node-selector-actions-cancel]'));
|
||||||
|
expect(closeButton).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Choose button', () => {
|
||||||
|
|
||||||
|
it('should be disabled by default', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'));
|
||||||
|
expect(chooseButton.nativeElement.disabled).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be enabled when clicking on one element in the list (onNodeSelect)', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
component.onNodeSelect({ detail: { node: { entry: <MinimalNodeEntryEntity> {} } } });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'));
|
||||||
|
expect(chooseButton.nativeElement.disabled).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be disabled when deselecting the previously selected element in the list (onNodeUnselect)', () => {
|
||||||
|
component.onNodeSelect({ detail: { node: { entry: <MinimalNodeEntryEntity> {} } } });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
component.onNodeUnselect();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'));
|
||||||
|
expect(chooseButton.nativeElement.disabled).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Mini integration test', () => {
|
||||||
|
|
||||||
|
xit('should trigger the select event properly when search results are loaded, one element is selected and choose button is clicked', () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,152 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { Component, EventEmitter, Inject, Input, Optional, Output, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { MD_DIALOG_DATA, MdDialogRef } from '@angular/material';
|
||||||
|
import { MinimalNodeEntryEntity, NodePaging } from 'alfresco-js-api';
|
||||||
|
import { AlfrescoTranslationService, SearchOptions, SearchService, SiteModel } from 'ng2-alfresco-core';
|
||||||
|
|
||||||
|
export interface ContentNodeSelectorComponentData {
|
||||||
|
title: string;
|
||||||
|
select: EventEmitter<MinimalNodeEntryEntity>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-content-node-selector',
|
||||||
|
styleUrls: ['./content-node-selector.component.scss'],
|
||||||
|
templateUrl: './content-node-selector.component.html',
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
|
})
|
||||||
|
export class ContentNodeSelectorComponent {
|
||||||
|
|
||||||
|
nodes: NodePaging|Array<any>;
|
||||||
|
siteId: null|string;
|
||||||
|
searchTerm: string = '';
|
||||||
|
searched: boolean = false;
|
||||||
|
inDialog: boolean = false;
|
||||||
|
chosenNode: MinimalNodeEntryEntity | null = null;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
select: EventEmitter<MinimalNodeEntryEntity> = new EventEmitter<MinimalNodeEntryEntity>();
|
||||||
|
|
||||||
|
constructor(private searchService: SearchService,
|
||||||
|
@Optional() private translateService: AlfrescoTranslationService,
|
||||||
|
@Optional() @Inject(MD_DIALOG_DATA) public data?: ContentNodeSelectorComponentData,
|
||||||
|
@Optional() private containingDialog?: MdDialogRef<ContentNodeSelectorComponent>) {
|
||||||
|
|
||||||
|
if (translateService) {
|
||||||
|
translateService.addTranslationFolder('ng2-alfresco-documentlist', 'assets/ng2-alfresco-documentlist');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
this.title = data.title;
|
||||||
|
this.select = data.select;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containingDialog) {
|
||||||
|
this.inDialog = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the site attribute and starts a new search
|
||||||
|
*
|
||||||
|
* @param chosenSite Sitemodel to search within
|
||||||
|
*/
|
||||||
|
siteChanged(chosenSite: SiteModel): void {
|
||||||
|
this.siteId = chosenSite.guid;
|
||||||
|
this.querySearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the searchTerm attribute and starts a new search
|
||||||
|
*
|
||||||
|
* @param searchTerm string value to search against
|
||||||
|
*/
|
||||||
|
search(searchTerm: string): void {
|
||||||
|
this.searchTerm = searchTerm;
|
||||||
|
this.querySearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the search input
|
||||||
|
*/
|
||||||
|
clear(): void {
|
||||||
|
this.searched = false;
|
||||||
|
this.searchTerm = '';
|
||||||
|
this.nodes = [];
|
||||||
|
this.chosenNode = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the call to searchService with the proper parameters
|
||||||
|
*/
|
||||||
|
private querySearch(): void {
|
||||||
|
if (this.searchTerm.length > 3) {
|
||||||
|
const searchTerm = this.searchTerm + '*';
|
||||||
|
let searchOpts: SearchOptions = {
|
||||||
|
include: ['path'],
|
||||||
|
skipCount: 0,
|
||||||
|
rootNodeId: this.siteId,
|
||||||
|
nodeType: 'cm:folder',
|
||||||
|
maxItems: 40,
|
||||||
|
orderBy: null
|
||||||
|
};
|
||||||
|
this.searchService
|
||||||
|
.getNodeQueryResults(searchTerm, searchOpts)
|
||||||
|
.subscribe(
|
||||||
|
results => {
|
||||||
|
this.searched = true;
|
||||||
|
this.nodes = results;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when user selects a node
|
||||||
|
*
|
||||||
|
* @param event CustomEvent for node-select
|
||||||
|
*/
|
||||||
|
onNodeSelect(event: any): void {
|
||||||
|
this.chosenNode = event.detail.node.entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * Invoked when user unselects a node
|
||||||
|
*/
|
||||||
|
onNodeUnselect(): void {
|
||||||
|
this.chosenNode = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit event with the chosen node
|
||||||
|
*/
|
||||||
|
choose(): void {
|
||||||
|
this.select.next(this.chosenNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the dialog
|
||||||
|
*/
|
||||||
|
close(): void {
|
||||||
|
this.containingDialog.close();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
<div id="site-dropdown-container" class="adf-site-dropdown-container">
|
<div id="site-dropdown-container" class="adf-site-dropdown-container">
|
||||||
<md-select class="adf-site-dropdown-list-element" id="site-dropdown"
|
<md-select class="adf-site-dropdown-list-element" id="site-dropdown"
|
||||||
placeholder="{{'DROPDOWN.PLACEHOLDER_LABEL' | translate}}"
|
placeholder="{{'DROPDOWN.PLACEHOLDER_LABEL' | translate}}"
|
||||||
|
floatPlaceholder="never"
|
||||||
[(ngModel)]="siteSelected"
|
[(ngModel)]="siteSelected"
|
||||||
(ngModelChange)="selectedSite()">
|
(ngModelChange)="selectedSite()">
|
||||||
<md-option id="default_site_option" [value]="DEFAULT_VALUE">{{'DROPDOWN.DEFAULT_OPTION' | translate}}</md-option>
|
<md-option id="default_site_option" [value]="DEFAULT_VALUE">{{'DROPDOWN.DEFAULT_OPTION' | translate}}</md-option>
|
||||||
|
@@ -1,10 +1,7 @@
|
|||||||
@import 'theming';
|
@import 'theming';
|
||||||
|
|
||||||
.adf-site-dropdown {
|
.adf-site-dropdown {
|
||||||
|
|
||||||
&-list-element {
|
&-list-element {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -15,5 +15,26 @@
|
|||||||
"DROPDOWN": {
|
"DROPDOWN": {
|
||||||
"PLACEHOLDER_LABEL": "Site List",
|
"PLACEHOLDER_LABEL": "Site List",
|
||||||
"DEFAULT_OPTION": "No Site Chosen"
|
"DEFAULT_OPTION": "No Site Chosen"
|
||||||
|
},
|
||||||
|
"NODE_SELECTOR": {
|
||||||
|
"CANCEL": "Cancel",
|
||||||
|
"CHOOSE": "Choose",
|
||||||
|
"NO_RESULTS": "No results found"
|
||||||
|
},
|
||||||
|
"OPERATION": {
|
||||||
|
"SUCCES": {
|
||||||
|
"CONTENT": {
|
||||||
|
"COPY": "Content was copied successfully.",
|
||||||
|
"MOVE": "Content was moved successfully."
|
||||||
|
},
|
||||||
|
"FOLDER": {
|
||||||
|
"COPY": "Folder was copied successfully.",
|
||||||
|
"MOVE": "Folder was moved successfully."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ERROR": {
|
||||||
|
"CONFLICT": "Name already exists in target location.",
|
||||||
|
"UNKNOWN": "Unknown error happened."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,15 +16,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { MdButtonModule, MdIconModule, MdMenuModule, MdProgressSpinnerModule, MdSelectModule } from '@angular/material';
|
import { MdButtonModule, MdDialogModule, MdIconModule, MdInputModule, MdMenuModule, MdProgressSpinnerModule, MdRippleModule, MdSelectModule } from '@angular/material';
|
||||||
|
|
||||||
export function modules() {
|
export function modules() {
|
||||||
return [
|
return [
|
||||||
MdMenuModule,
|
MdMenuModule,
|
||||||
|
MdDialogModule,
|
||||||
MdButtonModule,
|
MdButtonModule,
|
||||||
MdIconModule,
|
MdIconModule,
|
||||||
|
MdInputModule,
|
||||||
MdProgressSpinnerModule,
|
MdProgressSpinnerModule,
|
||||||
MdSelectModule
|
MdSelectModule,
|
||||||
|
MdRippleModule
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,23 +15,32 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AlfrescoContentService } from 'ng2-alfresco-core';
|
import { MdDialog } from '@angular/material';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { AlfrescoContentService, AlfrescoTranslationService, NotificationService } from 'ng2-alfresco-core';
|
||||||
import { FileNode, FolderNode } from '../assets/document-library.model.mock';
|
import { FileNode, FolderNode } from '../assets/document-library.model.mock';
|
||||||
import { DocumentListServiceMock } from '../assets/document-list.service.mock';
|
import { DocumentListServiceMock } from '../assets/document-list.service.mock';
|
||||||
import { ContentActionHandler } from '../models/content-action.model';
|
import { ContentActionHandler } from '../models/content-action.model';
|
||||||
import { DocumentActionsService } from './document-actions.service';
|
import { DocumentActionsService } from './document-actions.service';
|
||||||
import { DocumentListService } from './document-list.service';
|
import { DocumentListService } from './document-list.service';
|
||||||
|
import { NodeActionsService } from './node-actions.service';
|
||||||
|
|
||||||
describe('DocumentActionsService', () => {
|
describe('DocumentActionsService', () => {
|
||||||
|
|
||||||
let service: DocumentActionsService;
|
let service: DocumentActionsService;
|
||||||
let documentListService: DocumentListService;
|
let documentListService: DocumentListService;
|
||||||
let contentService: AlfrescoContentService;
|
let contentService: AlfrescoContentService;
|
||||||
|
let translateService: AlfrescoTranslationService;
|
||||||
|
let notificationService: NotificationService;
|
||||||
|
let nodeActionsService: NodeActionsService;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
documentListService = new DocumentListServiceMock();
|
documentListService = new DocumentListServiceMock();
|
||||||
contentService = new AlfrescoContentService(null, null, null);
|
contentService = new AlfrescoContentService(null, null, null);
|
||||||
service = new DocumentActionsService(documentListService, contentService);
|
translateService = <AlfrescoTranslationService> { addTranslationFolder: () => {}};
|
||||||
|
nodeActionsService = new NodeActionsService(null, translateService, null, null);
|
||||||
|
notificationService = new NotificationService(null);
|
||||||
|
service = new DocumentActionsService(translateService, notificationService, nodeActionsService, documentListService, contentService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should register default download action', () => {
|
it('should register default download action', () => {
|
||||||
@@ -63,7 +72,7 @@ describe('DocumentActionsService', () => {
|
|||||||
let file = new FileNode();
|
let file = new FileNode();
|
||||||
expect(service.canExecuteAction(file)).toBeTruthy();
|
expect(service.canExecuteAction(file)).toBeTruthy();
|
||||||
|
|
||||||
service = new DocumentActionsService(null);
|
service = new DocumentActionsService(translateService, notificationService, nodeActionsService);
|
||||||
expect(service.canExecuteAction(file)).toBeFalsy();
|
expect(service.canExecuteAction(file)).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -80,23 +89,6 @@ describe('DocumentActionsService', () => {
|
|||||||
expect(service.setHandler('my-handler', handler)).toBeTruthy();
|
expect(service.setHandler('my-handler', handler)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: to be removed once demo handlers are removed
|
|
||||||
it('should execute demo actions', () => {
|
|
||||||
spyOn(window, 'alert').and.stub();
|
|
||||||
|
|
||||||
service.getHandler('system1')(null);
|
|
||||||
expect(window.alert).toHaveBeenCalledWith('standard document action 1');
|
|
||||||
|
|
||||||
service.getHandler('system2')(null);
|
|
||||||
expect(window.alert).toHaveBeenCalledWith('standard document action 2');
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: to be removed once demo handlers are removed
|
|
||||||
it('should register demo handlers', () => {
|
|
||||||
expect(service.getHandler('system1')).toBeDefined();
|
|
||||||
expect(service.getHandler('system2')).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should register delete action', () => {
|
it('should register delete action', () => {
|
||||||
expect(service.getHandler('delete')).toBeDefined();
|
expect(service.getHandler('delete')).toBeDefined();
|
||||||
});
|
});
|
||||||
@@ -201,7 +193,7 @@ describe('DocumentActionsService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should require internal service for download action', () => {
|
it('should require internal service for download action', () => {
|
||||||
let actionService = new DocumentActionsService(null, contentService);
|
let actionService = new DocumentActionsService(translateService, notificationService, nodeActionsService, null, contentService);
|
||||||
let file = new FileNode();
|
let file = new FileNode();
|
||||||
let result = actionService.getHandler('download')(file);
|
let result = actionService.getHandler('download')(file);
|
||||||
result.subscribe((value) => {
|
result.subscribe((value) => {
|
||||||
@@ -210,7 +202,7 @@ describe('DocumentActionsService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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(translateService, notificationService, nodeActionsService, documentListService, null);
|
||||||
let file = new FileNode();
|
let file = new FileNode();
|
||||||
let result = actionService.getHandler('download')(file);
|
let result = actionService.getHandler('download')(file);
|
||||||
result.subscribe((value) => {
|
result.subscribe((value) => {
|
||||||
|
@@ -16,12 +16,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { AlfrescoContentService } from 'ng2-alfresco-core';
|
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||||
|
import { AlfrescoContentService, AlfrescoTranslationService, NotificationService } from 'ng2-alfresco-core';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Subject } from 'rxjs/Rx';
|
import { Subject } from 'rxjs/Rx';
|
||||||
|
import { ContentNodeSelectorComponent } from '../components/content-node-selector/content-node-selector.component';
|
||||||
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 { NodeActionsService } from './node-actions.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DocumentActionsService {
|
export class DocumentActionsService {
|
||||||
@@ -30,9 +33,15 @@ export class DocumentActionsService {
|
|||||||
|
|
||||||
private handlers: { [id: string]: ContentActionHandler; } = {};
|
private handlers: { [id: string]: ContentActionHandler; } = {};
|
||||||
|
|
||||||
constructor(private documentListService?: DocumentListService,
|
constructor(private translateService: AlfrescoTranslationService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private nodeActionsService: NodeActionsService,
|
||||||
|
private documentListService?: DocumentListService,
|
||||||
private contentService?: AlfrescoContentService) {
|
private contentService?: AlfrescoContentService) {
|
||||||
this.setupActionHandlers();
|
this.setupActionHandlers();
|
||||||
|
if (translateService) {
|
||||||
|
translateService.addTranslationFolder('ng2-alfresco-documentlist', 'assets/ng2-alfresco-documentlist');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getHandler(key: string): ContentActionHandler {
|
getHandler(key: string): ContentActionHandler {
|
||||||
@@ -58,35 +67,9 @@ export class DocumentActionsService {
|
|||||||
|
|
||||||
private setupActionHandlers() {
|
private setupActionHandlers() {
|
||||||
this.handlers['download'] = this.download.bind(this);
|
this.handlers['download'] = this.download.bind(this);
|
||||||
|
this.handlers['copy'] = this.copyNode.bind(this);
|
||||||
|
this.handlers['move'] = this.moveNode.bind(this);
|
||||||
this.handlers['delete'] = this.deleteNode.bind(this);
|
this.handlers['delete'] = this.deleteNode.bind(this);
|
||||||
|
|
||||||
// TODO: for demo purposes only, will be removed during future revisions
|
|
||||||
this.handlers['system1'] = this.handleStandardAction1.bind(this);
|
|
||||||
this.handlers['system2'] = this.handleStandardAction2.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: for demo purposes only, will be removed during future revisions
|
|
||||||
/**
|
|
||||||
* @deprecated in 1.7.0
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @memberof DocumentActionsService
|
|
||||||
*/
|
|
||||||
private handleStandardAction1(/*obj: any*/) {
|
|
||||||
console.log('handleStandardAction1 is deprecated in 1.7.0 and will be removed in future versions');
|
|
||||||
window.alert('standard document action 1');
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: for demo purposes only, will be removed during future revisions
|
|
||||||
/**
|
|
||||||
* @deprecated in 1.7.0
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @memberof DocumentActionsService
|
|
||||||
*/
|
|
||||||
private handleStandardAction2(/*obj: any*/) {
|
|
||||||
console.log('handleStandardAction2 is deprecated in 1.7.0 and will be removed in future versions');
|
|
||||||
window.alert('standard document action 2');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private download(obj: any): Observable<boolean> {
|
private download(obj: any): Observable<boolean> {
|
||||||
@@ -102,6 +85,43 @@ export class DocumentActionsService {
|
|||||||
return Observable.of(false);
|
return Observable.of(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private copyNode(obj: MinimalNodeEntity, target?: any, permission?: string) {
|
||||||
|
const actionObservable = this.nodeActionsService.copyContent(obj.entry, permission);
|
||||||
|
this.prepareHandlers(actionObservable, 'content', 'copy', target, permission);
|
||||||
|
return actionObservable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveNode(obj: MinimalNodeEntity, target?: any, permission?: string) {
|
||||||
|
const actionObservable = this.nodeActionsService.moveContent(obj.entry, permission);
|
||||||
|
this.prepareHandlers(actionObservable, 'content', 'move', target, permission);
|
||||||
|
return actionObservable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private prepareHandlers(actionObservable, type: string, action: string, target?: any, permission?: string): void {
|
||||||
|
actionObservable.subscribe(
|
||||||
|
(fileOperationMessage) => {
|
||||||
|
this.notificationService.openSnackMessage(fileOperationMessage, 3000);
|
||||||
|
if (target && typeof target.reload === 'function') {
|
||||||
|
target.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(errorStatusCode) => {
|
||||||
|
switch (errorStatusCode) {
|
||||||
|
case 403:
|
||||||
|
this.permissionEvent.next(new PermissionModel({type, action, permission}));
|
||||||
|
break;
|
||||||
|
case 409:
|
||||||
|
let conflictError: any = this.translateService.get('OPERATION.ERROR.CONFLICT');
|
||||||
|
this.notificationService.openSnackMessage(conflictError.value, 3000);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
let unknownError: any = this.translateService.get('OPERATION.ERROR.UNKNOWN');
|
||||||
|
this.notificationService.openSnackMessage(unknownError.value, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private deleteNode(obj: any, target?: any, permission?: string): Observable<any> {
|
private deleteNode(obj: any, target?: any, permission?: string): Observable<any> {
|
||||||
let handlerObservable;
|
let handlerObservable;
|
||||||
|
|
||||||
|
@@ -177,4 +177,24 @@ describe('DocumentListService', () => {
|
|||||||
contentType: 'json'
|
contentType: 'json'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should copy a node', (done) => {
|
||||||
|
service.copyNode('node-id', 'parent-id').subscribe(done);
|
||||||
|
|
||||||
|
expect(jasmine.Ajax.requests.mostRecent().method).toBe('POST');
|
||||||
|
expect(jasmine.Ajax.requests.mostRecent().url).toContain('/nodes/node-id/copy');
|
||||||
|
expect(jasmine.Ajax.requests.mostRecent().params).toEqual(JSON.stringify({ targetParentId: 'parent-id' }));
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, contentType: 'json' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move a node', (done) => {
|
||||||
|
service.moveNode('node-id', 'parent-id').subscribe(done);
|
||||||
|
|
||||||
|
expect(jasmine.Ajax.requests.mostRecent().method).toBe('POST');
|
||||||
|
expect(jasmine.Ajax.requests.mostRecent().url).toContain('/nodes/node-id/move');
|
||||||
|
expect(jasmine.Ajax.requests.mostRecent().params).toEqual(JSON.stringify({ targetParentId: 'parent-id' }));
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, contentType: 'json' });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -65,6 +65,28 @@ export class DocumentListService {
|
|||||||
return Observable.fromPromise(this.apiService.getInstance().nodes.deleteNode(nodeId));
|
return Observable.fromPromise(this.apiService.getInstance().nodes.deleteNode(nodeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy a node to destination node
|
||||||
|
*
|
||||||
|
* @param nodeId The id of the node to be copied
|
||||||
|
* @param targetParentId The id of the folder-node where the node have to be copied to
|
||||||
|
*/
|
||||||
|
copyNode(nodeId: string, targetParentId: string) {
|
||||||
|
return Observable.fromPromise(this.apiService.getInstance().nodes.copyNode(nodeId, { targetParentId }))
|
||||||
|
.catch(err => this.handleError(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a node to destination node
|
||||||
|
*
|
||||||
|
* @param nodeId The id of the node to be moved
|
||||||
|
* @param targetParentId The id of the folder-node where the node have to be moved to
|
||||||
|
*/
|
||||||
|
moveNode(nodeId: string, targetParentId: string) {
|
||||||
|
return Observable.fromPromise(this.apiService.getInstance().nodes.moveNode(nodeId, { targetParentId }))
|
||||||
|
.catch(err => this.handleError(err));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new folder in the path.
|
* Create a new folder in the path.
|
||||||
* @param name Folder name
|
* @param name Folder name
|
||||||
|
@@ -16,12 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
import { AppConfigModule, CoreModule } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, AppConfigModule, CoreModule, NotificationService } from 'ng2-alfresco-core';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
import { FileNode, FolderNode } from '../assets/document-library.model.mock';
|
import { FileNode, FolderNode } from '../assets/document-library.model.mock';
|
||||||
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 { FolderActionsService } from './folder-actions.service';
|
import { FolderActionsService } from './folder-actions.service';
|
||||||
|
import { NodeActionsService } from './node-actions.service';
|
||||||
|
|
||||||
describe('FolderActionsService', () => {
|
describe('FolderActionsService', () => {
|
||||||
|
|
||||||
@@ -38,7 +39,10 @@ describe('FolderActionsService', () => {
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
DocumentListService,
|
DocumentListService,
|
||||||
FolderActionsService
|
FolderActionsService,
|
||||||
|
NodeActionsService,
|
||||||
|
AlfrescoTranslationService,
|
||||||
|
NotificationService
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
@@ -90,23 +94,6 @@ describe('FolderActionsService', () => {
|
|||||||
expect(service.setHandler('my-handler', handler)).toBeTruthy();
|
expect(service.setHandler('my-handler', handler)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: to be removed once demo handlers are removed
|
|
||||||
it('should execute demo actions', () => {
|
|
||||||
spyOn(window, 'alert').and.stub();
|
|
||||||
|
|
||||||
service.getHandler('system1')(null);
|
|
||||||
expect(window.alert).toHaveBeenCalledWith('standard folder action 1');
|
|
||||||
|
|
||||||
service.getHandler('system2')(null);
|
|
||||||
expect(window.alert).toHaveBeenCalledWith('standard folder action 2');
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: to be removed once demo handlers are removed
|
|
||||||
it('should register demo handlers', () => {
|
|
||||||
expect(service.getHandler('system1')).toBeDefined();
|
|
||||||
expect(service.getHandler('system2')).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should register delete action', () => {
|
it('should register delete action', () => {
|
||||||
expect(service.getHandler('delete')).toBeDefined();
|
expect(service.getHandler('delete')).toBeDefined();
|
||||||
});
|
});
|
||||||
|
@@ -16,11 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { AlfrescoContentService } from 'ng2-alfresco-core';
|
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||||
|
import { AlfrescoContentService, AlfrescoTranslationService, NotificationService } from 'ng2-alfresco-core';
|
||||||
import { Observable, Subject } from 'rxjs/Rx';
|
import { Observable, Subject } from 'rxjs/Rx';
|
||||||
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 { NodeActionsService } from './node-actions.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FolderActionsService {
|
export class FolderActionsService {
|
||||||
@@ -29,7 +31,10 @@ export class FolderActionsService {
|
|||||||
|
|
||||||
private handlers: { [id: string]: ContentActionHandler; } = {};
|
private handlers: { [id: string]: ContentActionHandler; } = {};
|
||||||
|
|
||||||
constructor(private documentListService: DocumentListService,
|
constructor(private translateService: AlfrescoTranslationService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private nodeActionsService: NodeActionsService,
|
||||||
|
private documentListService: DocumentListService,
|
||||||
private contentService: AlfrescoContentService) {
|
private contentService: AlfrescoContentService) {
|
||||||
this.setupActionHandlers();
|
this.setupActionHandlers();
|
||||||
}
|
}
|
||||||
@@ -56,36 +61,46 @@ export class FolderActionsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setupActionHandlers() {
|
private setupActionHandlers() {
|
||||||
|
this.handlers['copy'] = this.copyNode.bind(this);
|
||||||
|
this.handlers['move'] = this.moveNode.bind(this);
|
||||||
this.handlers['delete'] = this.deleteNode.bind(this);
|
this.handlers['delete'] = this.deleteNode.bind(this);
|
||||||
|
|
||||||
// TODO: for demo purposes only, will be removed during future revisions
|
|
||||||
this.handlers['system1'] = this.handleStandardAction1.bind(this);
|
|
||||||
this.handlers['system2'] = this.handleStandardAction2.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: for demo purposes only, will be removed during future revisions
|
private copyNode(obj: MinimalNodeEntity, target?: any, permission?: string) {
|
||||||
/**
|
const actionObservable = this.nodeActionsService.copyFolder(obj.entry, permission);
|
||||||
* @deprecated in 1.7.0
|
this.prepareHandlers(actionObservable, 'folder', 'copy', target, permission);
|
||||||
*
|
return actionObservable;
|
||||||
* @private
|
|
||||||
* @param {*} document
|
|
||||||
* @memberof FolderActionsService
|
|
||||||
*/
|
|
||||||
private handleStandardAction1(/*document: any*/) {
|
|
||||||
console.log('handleStandardAction1 is deprecated in 1.7.0 and will be removed in future versions');
|
|
||||||
window.alert('standard folder action 1');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: for demo purposes only, will be removed during future revisions
|
private moveNode(obj: MinimalNodeEntity, target?: any, permission?: string) {
|
||||||
/**
|
const actionObservable = this.nodeActionsService.moveFolder(obj.entry, permission);
|
||||||
* @deprecated in 1.7.0
|
this.prepareHandlers(actionObservable, 'folder', 'move', target, permission);
|
||||||
*
|
return actionObservable;
|
||||||
* @private
|
}
|
||||||
* @memberof FolderActionsService
|
|
||||||
*/
|
private prepareHandlers(actionObservable, type: string, action: string, target?: any, permission?: string): void {
|
||||||
private handleStandardAction2(/*document: any*/) {
|
actionObservable.subscribe(
|
||||||
console.log('handleStandardAction1 is deprecated in 1.7.0 and will be removed in future versions');
|
(fileOperationMessage) => {
|
||||||
window.alert('standard folder action 2');
|
this.notificationService.openSnackMessage(fileOperationMessage, 3000);
|
||||||
|
if (target && typeof target.reload === 'function') {
|
||||||
|
target.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(errorStatusCode) => {
|
||||||
|
switch (errorStatusCode) {
|
||||||
|
case 403:
|
||||||
|
this.permissionEvent.next(new PermissionModel({type, action, permission}));
|
||||||
|
break;
|
||||||
|
case 409:
|
||||||
|
let conflictError: any = this.translateService.get('OPERATION.ERROR.CONFLICT');
|
||||||
|
this.notificationService.openSnackMessage(conflictError.value, 3000);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
let unknownError: any = this.translateService.get('OPERATION.ERROR.UNKNOWN');
|
||||||
|
this.notificationService.openSnackMessage(unknownError.value, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private deleteNode(obj: any, target?: any, permission?: string): Observable<any> {
|
private deleteNode(obj: any, target?: any, permission?: string): Observable<any> {
|
||||||
|
@@ -0,0 +1,121 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { EventEmitter, Injectable } from '@angular/core';
|
||||||
|
import { MdDialog } from '@angular/material';
|
||||||
|
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||||
|
import { AlfrescoContentService, AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { Subject } from 'rxjs/Rx';
|
||||||
|
import { ContentNodeSelectorComponent } from '../components/content-node-selector/content-node-selector.component';
|
||||||
|
import { DocumentListService } from './document-list.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class NodeActionsService {
|
||||||
|
|
||||||
|
constructor(private dialog: MdDialog,
|
||||||
|
private translateService: AlfrescoTranslationService,
|
||||||
|
private documentListService?: DocumentListService,
|
||||||
|
private contentService?: AlfrescoContentService) {
|
||||||
|
if (translateService) {
|
||||||
|
translateService.addTranslationFolder('ng2-alfresco-documentlist', 'assets/ng2-alfresco-documentlist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy content node
|
||||||
|
*
|
||||||
|
* @param contentEntry node to copy
|
||||||
|
* @param permission permission which is needed to apply the action
|
||||||
|
*/
|
||||||
|
public copyContent(contentEntry: MinimalNodeEntryEntity, permission?: string): Subject<string> {
|
||||||
|
return this.doFileOperation('copy', 'content', contentEntry, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy folder node
|
||||||
|
*
|
||||||
|
* @param contentEntry node to copy
|
||||||
|
* @param permission permission which is needed to apply the action
|
||||||
|
*/
|
||||||
|
public copyFolder(contentEntry: MinimalNodeEntryEntity, permission?: string): Subject<string> {
|
||||||
|
return this.doFileOperation('copy', 'folder', contentEntry, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move content node
|
||||||
|
*
|
||||||
|
* @param contentEntry node to move
|
||||||
|
* @param permission permission which is needed to apply the action
|
||||||
|
*/
|
||||||
|
public moveContent(contentEntry: MinimalNodeEntryEntity, permission?: string): Subject<string> {
|
||||||
|
return this.doFileOperation('move', 'content', contentEntry, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move folder node
|
||||||
|
*
|
||||||
|
* @param contentEntry node to move
|
||||||
|
* @param permission permission which is needed to apply the action
|
||||||
|
*/
|
||||||
|
public moveFolder(contentEntry: MinimalNodeEntryEntity, permission?: string): Subject<string> {
|
||||||
|
return this.doFileOperation('move', 'folder', contentEntry, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General method for performing the given operation (copy|move)
|
||||||
|
*
|
||||||
|
* @param action the action to perform (copy|move)
|
||||||
|
* @param type type of the content (content|folder)
|
||||||
|
* @param contentEntry the contentEntry which has to have the action performed on
|
||||||
|
* @param permission permission which is needed to apply the action
|
||||||
|
*/
|
||||||
|
private doFileOperation(action: string, type: string, contentEntry: MinimalNodeEntryEntity, permission?: string): Subject<string> {
|
||||||
|
const observable: Subject<string> = new Subject<string>();
|
||||||
|
|
||||||
|
if (this.contentService.hasPermission(contentEntry, permission)) {
|
||||||
|
const title = `${action} ${contentEntry.name} to ...`,
|
||||||
|
select: EventEmitter<MinimalNodeEntryEntity> = new EventEmitter<MinimalNodeEntryEntity>();
|
||||||
|
|
||||||
|
this.dialog.open(ContentNodeSelectorComponent, {
|
||||||
|
data: { title, select },
|
||||||
|
panelClass: 'adf-content-node-selector-dialog',
|
||||||
|
width: '576px'
|
||||||
|
});
|
||||||
|
|
||||||
|
select.subscribe((parent: MinimalNodeEntryEntity) => {
|
||||||
|
this.documentListService[`${action}Node`].call(this.documentListService, contentEntry.id, parent.id)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
let fileOperationMessage: any = this.translateService.get(`OPERATION.SUCCES.${type.toUpperCase()}.${action.toUpperCase()}`);
|
||||||
|
observable.next(fileOperationMessage.value);
|
||||||
|
},
|
||||||
|
(errors) => {
|
||||||
|
const errorStatusCode = JSON.parse(errors.message).error.statusCode;
|
||||||
|
observable.error(errorStatusCode);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.dialog.closeAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
return observable;
|
||||||
|
} else {
|
||||||
|
observable.error(403);
|
||||||
|
return observable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,25 +17,24 @@
|
|||||||
|
|
||||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { CoreModule } from 'ng2-alfresco-core';
|
import { CoreModule, SearchService } from 'ng2-alfresco-core';
|
||||||
import { DocumentListModule } from 'ng2-alfresco-documentlist';
|
import { DocumentListModule } from 'ng2-alfresco-documentlist';
|
||||||
import { SearchAutocompleteComponent } from './src/components/search-autocomplete.component';
|
import { SearchAutocompleteComponent } from './src/components/search-autocomplete.component';
|
||||||
import { SearchControlComponent } from './src/components/search-control.component';
|
import { SearchControlComponent } from './src/components/search-control.component';
|
||||||
import { SearchComponent } from './src/components/search.component';
|
import { SearchComponent } from './src/components/search.component';
|
||||||
import { SearchService } from './src/services/search.service';
|
|
||||||
|
|
||||||
// services
|
// services
|
||||||
export * from './src/services/search.service';
|
export { SearchOptions, SearchService } from 'ng2-alfresco-core';
|
||||||
export * from './src/components/search.component';
|
export * from './src/components/search.component';
|
||||||
export * from './src/components/search-control.component';
|
export * from './src/components/search-control.component';
|
||||||
export * from './src/components/search-autocomplete.component';
|
export * from './src/components/search-autocomplete.component';
|
||||||
|
|
||||||
// Old Deprecated export
|
// Old Deprecated export
|
||||||
|
import { SearchService as AlfrescoSearchService } from 'ng2-alfresco-core';
|
||||||
import { SearchAutocompleteComponent as AlfrescoSearchAutocompleteComponent } from './src/components/search-autocomplete.component';
|
import { SearchAutocompleteComponent as AlfrescoSearchAutocompleteComponent } from './src/components/search-autocomplete.component';
|
||||||
import { SearchControlComponent as AlfrescoSearchControlComponent } from './src/components/search-control.component';
|
import { SearchControlComponent as AlfrescoSearchControlComponent } from './src/components/search-control.component';
|
||||||
import { SearchComponent as AlfrescoSearchComponent } from './src/components/search.component';
|
import { SearchComponent as AlfrescoSearchComponent } from './src/components/search.component';
|
||||||
import { SearchService as AlfrescoSearchService } from './src/services/search.service';
|
export { SearchService as AlfrescoSearchService } from 'ng2-alfresco-core';
|
||||||
export { SearchService as AlfrescoSearchService } from './src/services/search.service';
|
|
||||||
export { SearchComponent as AlfrescoSearchComponent } from './src/components/search.component';
|
export { SearchComponent as AlfrescoSearchComponent } from './src/components/search.component';
|
||||||
export { SearchControlComponent as AlfrescoSearchControlComponent } from './src/components/search-control.component';
|
export { SearchControlComponent as AlfrescoSearchControlComponent } from './src/components/search-control.component';
|
||||||
export { SearchAutocompleteComponent as AlfrescoSearchAutocompleteComponent } from './src/components/search-autocomplete.component';
|
export { SearchAutocompleteComponent as AlfrescoSearchAutocompleteComponent } from './src/components/search-autocomplete.component';
|
||||||
|
@@ -23,9 +23,9 @@ import {
|
|||||||
AlfrescoContentService,
|
AlfrescoContentService,
|
||||||
AlfrescoSettingsService,
|
AlfrescoSettingsService,
|
||||||
AlfrescoTranslationService,
|
AlfrescoTranslationService,
|
||||||
CoreModule
|
CoreModule,
|
||||||
|
SearchService
|
||||||
} from 'ng2-alfresco-core';
|
} from 'ng2-alfresco-core';
|
||||||
import { SearchService } from '../services/search.service';
|
|
||||||
import { errorJson, folderResult, noResult, result, results } from './../assets/search.component.mock';
|
import { errorJson, folderResult, noResult, result, results } from './../assets/search.component.mock';
|
||||||
import { TranslationMock } from './../assets/translation.service.mock';
|
import { TranslationMock } from './../assets/translation.service.mock';
|
||||||
import { SearchAutocompleteComponent } from './search-autocomplete.component';
|
import { SearchAutocompleteComponent } from './search-autocomplete.component';
|
||||||
|
@@ -17,9 +17,8 @@
|
|||||||
|
|
||||||
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core';
|
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||||
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, SearchOptions, SearchService } from 'ng2-alfresco-core';
|
||||||
import { ThumbnailService } from 'ng2-alfresco-core';
|
import { ThumbnailService } from 'ng2-alfresco-core';
|
||||||
import { SearchOptions, SearchService } from './../services/search.service';
|
|
||||||
|
|
||||||
declare var require: any;
|
declare var require: any;
|
||||||
|
|
||||||
|
@@ -17,8 +17,7 @@
|
|||||||
|
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ThumbnailService } from 'ng2-alfresco-core';
|
import { ThumbnailService } from 'ng2-alfresco-core';
|
||||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, CoreModule, SearchService } from 'ng2-alfresco-core';
|
||||||
import { SearchService } from '../services/search.service';
|
|
||||||
import { result } from './../assets/search.component.mock';
|
import { result } from './../assets/search.component.mock';
|
||||||
import { TranslationMock } from './../assets/translation.service.mock';
|
import { TranslationMock } from './../assets/translation.service.mock';
|
||||||
import { SearchAutocompleteComponent } from './search-autocomplete.component';
|
import { SearchAutocompleteComponent } from './search-autocomplete.component';
|
||||||
|
@@ -18,11 +18,10 @@
|
|||||||
import { DebugElement, ReflectiveInjector, SimpleChange } from '@angular/core';
|
import { DebugElement, ReflectiveInjector, SimpleChange } from '@angular/core';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { AlfrescoTranslationService, CoreModule, NotificationService } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, CoreModule, NotificationService, SearchService } from 'ng2-alfresco-core';
|
||||||
import { DocumentListModule } from 'ng2-alfresco-documentlist';
|
import { DocumentListModule } from 'ng2-alfresco-documentlist';
|
||||||
import { PermissionModel } from 'ng2-alfresco-documentlist';
|
import { PermissionModel } from 'ng2-alfresco-documentlist';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
import { SearchService } from '../services/search.service';
|
|
||||||
import { TranslationMock } from './../assets/translation.service.mock';
|
import { TranslationMock } from './../assets/translation.service.mock';
|
||||||
import { SearchComponent } from './search.component';
|
import { SearchComponent } from './search.component';
|
||||||
|
|
||||||
@@ -242,7 +241,7 @@ describe('SearchComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let errorEl = element.querySelector('[data-automation-id="search_error_message"]');
|
let errorEl = element.querySelector('[data-automation-id="search_error_message"]');
|
||||||
expect(errorEl).not.toBeNull();
|
expect(errorEl).not.toBeNull();
|
||||||
expect((<any>errorEl).innerText).toBe('SEARCH.RESULTS.ERROR');
|
expect((<any> errorEl).innerText).toBe('SEARCH.RESULTS.ERROR');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -18,9 +18,8 @@
|
|||||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Optional, Output, SimpleChanges } from '@angular/core';
|
import { Component, EventEmitter, Input, OnChanges, OnInit, Optional, Output, SimpleChanges } from '@angular/core';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
import { NodePaging, Pagination } from 'alfresco-js-api';
|
import { NodePaging, Pagination } from 'alfresco-js-api';
|
||||||
import { AlfrescoTranslationService, NotificationService } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, NotificationService, SearchOptions, SearchService } from 'ng2-alfresco-core';
|
||||||
import { PermissionModel } from 'ng2-alfresco-documentlist';
|
import { PermissionModel } from 'ng2-alfresco-documentlist';
|
||||||
import { SearchOptions, SearchService } from './../services/search.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-search, alfresco-search',
|
selector: 'adf-search, alfresco-search',
|
||||||
|
Reference in New Issue
Block a user