From 38f4916e0685a0f0bbe390244e767abf0f48b0ee Mon Sep 17 00:00:00 2001 From: Maurizio Vitale Date: Fri, 26 Oct 2018 14:39:06 +0100 Subject: [PATCH] [ADF-3538] [ADF-3547] Migration - Task Filters - Task List - New Process cloud page on demoshell (#3914) * [ADF-3538] start creating new folder for cloud components * [ADF-3538] added new package to the script and the builds * [ADF-3538] added some more changes to scripts * [ADF-3538] - starting the new package * change index * fix package * Fix module structure with Cli * add basic structure * Create a library with angular cli * Add a cloud component as example * Skip the scss style * add the import scss * remove useless codes * Add i18n example * remove useless code * Simplify the hello component Fix the wrong path * add the app-list-cloud-component add the app-details-cloud-component * Expose and use the new component * Consume the new package and component from the demoshell * Fix process service cloud path * [ADF-3538] Alfresco Process Service Cloud - new package with CLI (#3872) * [ADF-3538] start creating new folder for cloud components * [ADF-3538] added new package to the script and the builds * [ADF-3538] added some more changes to scripts * [ADF-3538] - starting the new package * change index * fix package * Fix module structure with Cli * add basic structure * Create a library with angular cli * Add a cloud component as example * Skip the scss style * add the import scss * remove useless codes * Add i18n example * remove useless code * Simplify the hello component Fix the wrong path * Fix process service cloud path * Download process-service-cloud from the CS * [ADF-3538] generated task-list cloud by cli * [ADF-3550] Added Task Filter Cloud component * [ADF-3550] Task Filter Cloud component relocated * [ADF-3538] rebased task list cloud 2.0 * [ADF-3538] fixed ng-package.json * [ADF-3538] reverted worng changes * [ADF-3538] removed wrong rebased files * [ADF-3538] forcing update of app-list file * [ADF-3538] wrong file after rebase removed * [ADF-3538] wrong file after rebase fixe * Merge the applist component with task list * [ADF-3550] Added Task Filter Cloud component * emit the event * Add the route process cloud and fix the page issues * fixed wrong pagination initialisation * improved initialisation of page size * removed unused import * fixed tsconfig with double definition * Use standard name for scss * fix sorting issue and remove useless models * Fix tslint * Use 1 single testing module file * [ADF-3538] [ADF-3547] Fix selected task filter and unit tests * Fix unit tests and remove useless imports * Uncomment unit tests * Remove useless component * Use main module instead of submodules * Remove useless jsdoc and improve doc * Remove useless jsdoc * Remove useless interface * remove AfterViewInit import * remove js doc params --- demo-shell/resources/i18n/en.json | 3 +- demo-shell/src/app/app.module.ts | 8 +- demo-shell/src/app/app.routes.ts | 12 +- .../app-layout/app-layout.component.ts | 1 + .../app/components/cloud/cloud.component.html | 2 +- .../app/components/cloud/cloud.component.ts | 8 +- .../task-list-cloud-demo.component.html | 86 +++++ .../task-list-cloud-demo.component.scss | 15 + .../task-list-cloud-demo.component.ts | 126 ++++++ .../process-services-cloud/task-list-cloud.md | 217 +++++++++++ lib/core/assets/images/ft_ic_link_folder.svg | 19 + lib/core/context-menu/public-api.ts | 1 + lib/process-services-cloud/.npmignore | 30 -- lib/process-services-cloud/index.ts | 2 +- lib/process-services-cloud/material.module.ts | 44 --- lib/process-services-cloud/ng-package.json | 2 +- .../process-cloud.module.ts | 99 ----- .../app-details-cloud.component.spec.ts | 5 +- .../app-list-cloud.component.spec.ts | 7 +- .../{public_api.ts => public-api.ts} | 2 +- .../apps-process-cloud.service.spec.ts | 4 +- .../src/lib/hello/hello.component.css | 0 .../src/lib/hello/hello.component.html | 4 - .../src/lib/hello/hello.component.spec.ts | 25 -- .../src/lib/hello/hello.component.ts | 15 - .../src/lib/hello/hello.module.spec.ts | 13 - .../src/lib/hello/hello.module.ts | 13 - .../src/lib/process-services-cloud.module.ts | 8 +- .../src/lib/styles/_index.scss | 2 + .../task-cloud/mock/task-list-service.mock.ts | 267 +++++++++++++ .../task-cloud/models/filter-cloud.model.ts | 52 +++ .../{ => src/lib/task-cloud}/public-api.ts | 4 +- .../services/task-filter-cloud.service.ts | 181 +++++++++ .../lib/task-cloud/task-cloud.module.spec.ts | 13 + .../src/lib/task-cloud/task-cloud.module.ts | 26 ++ .../task-filters-cloud.component.html | 17 + .../task-filters-cloud.component.scss | 34 ++ .../task-filters-cloud.component.spec.ts | 359 ++++++++++++++++++ .../task-filters-cloud.component.ts | 156 ++++++++ .../components/task-list-cloud.component.css | 4 + .../components/task-list-cloud.component.html | 33 ++ .../task-list-cloud.component.spec.ts | 312 +++++++++++++++ .../components/task-list-cloud.component.ts | 260 +++++++++++++ .../mock/fakeTaskResponseMock.ts | 145 +++++++ .../models/filter-cloud-model.ts | 70 ++++ .../models/task-list-sorting.model.ts | 28 ++ .../models/task-preset-cloud.model.ts | 41 ++ .../src/lib/task-list-cloud/public-api.ts | 24 ++ .../services/task-list-cloud.service.spec.ts | 134 +++++++ .../services/task-list-cloud.service.ts | 92 +++++ .../task-list-cloud.module.spec.ts | 13 + .../task-list-cloud/task-list-cloud.module.ts | 26 ++ .../testing/task-list.testing.module.ts | 51 +++ .../process-service-cloud.testing.module.ts} | 12 +- .../src/{public_api.ts => public-api.ts} | 4 +- lib/process-services-cloud/test.ts | 41 -- lib/process-services-cloud/tsconfig.spec.json | 2 +- 57 files changed, 2862 insertions(+), 312 deletions(-) create mode 100644 demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.html create mode 100644 demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.scss create mode 100644 demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.ts create mode 100644 docs/process-services-cloud/task-list-cloud.md create mode 100644 lib/core/assets/images/ft_ic_link_folder.svg delete mode 100644 lib/process-services-cloud/.npmignore delete mode 100644 lib/process-services-cloud/material.module.ts delete mode 100644 lib/process-services-cloud/process-cloud.module.ts rename lib/process-services-cloud/src/lib/app-list-cloud/{public_api.ts => public-api.ts} (94%) delete mode 100644 lib/process-services-cloud/src/lib/hello/hello.component.css delete mode 100644 lib/process-services-cloud/src/lib/hello/hello.component.html delete mode 100644 lib/process-services-cloud/src/lib/hello/hello.component.spec.ts delete mode 100644 lib/process-services-cloud/src/lib/hello/hello.component.ts delete mode 100644 lib/process-services-cloud/src/lib/hello/hello.module.spec.ts delete mode 100644 lib/process-services-cloud/src/lib/hello/hello.module.ts create mode 100644 lib/process-services-cloud/src/lib/task-cloud/mock/task-list-service.mock.ts create mode 100644 lib/process-services-cloud/src/lib/task-cloud/models/filter-cloud.model.ts rename lib/process-services-cloud/{ => src/lib/task-cloud}/public-api.ts (80%) create mode 100644 lib/process-services-cloud/src/lib/task-cloud/services/task-filter-cloud.service.ts create mode 100644 lib/process-services-cloud/src/lib/task-cloud/task-cloud.module.spec.ts create mode 100644 lib/process-services-cloud/src/lib/task-cloud/task-cloud.module.ts create mode 100644 lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.html create mode 100644 lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.scss create mode 100644 lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.spec.ts create mode 100644 lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.css create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.html create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.spec.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/mock/fakeTaskResponseMock.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/models/filter-cloud-model.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/models/task-list-sorting.model.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/models/task-preset-cloud.model.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/public-api.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/services/task-list-cloud.service.spec.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/services/task-list-cloud.service.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/task-list-cloud.module.spec.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/task-list-cloud.module.ts create mode 100644 lib/process-services-cloud/src/lib/task-list-cloud/testing/task-list.testing.module.ts rename lib/process-services-cloud/src/lib/{app-list-cloud/testing/app-list.testing.module.ts => testing/process-service-cloud.testing.module.ts} (87%) rename lib/process-services-cloud/src/{public_api.ts => public-api.ts} (82%) delete mode 100644 lib/process-services-cloud/test.ts diff --git a/demo-shell/resources/i18n/en.json b/demo-shell/resources/i18n/en.json index 9344de7d8b..72433c7b3b 100644 --- a/demo-shell/resources/i18n/en.json +++ b/demo-shell/resources/i18n/en.json @@ -61,6 +61,7 @@ "NOTIFICATIONS": "Notifications", "TASK_LIST": "Task List", "PROCESS_LIST": "Process List", + "PROCESS_CLOUD": "Process Cloud", "CARD_VIEW": "CardView", "PROCESS_SERVICES": "Process Services", "LOGIN": "Login", @@ -256,4 +257,4 @@ }, "GROUP-TITLE1-TRANSLATION-KEY": "CUSTOM TITLE TRANSLATION ONE", "GROUP-TITLE2-TRANSLATION-KEY": "CUSTOM TITLE TRANSLATION TWO" -} \ No newline at end of file +} diff --git a/demo-shell/src/app/app.module.ts b/demo-shell/src/app/app.module.ts index 06f7c64b25..ac4e5fcb82 100644 --- a/demo-shell/src/app/app.module.ts +++ b/demo-shell/src/app/app.module.ts @@ -63,8 +63,9 @@ import { ContentModule } from '@alfresco/adf-content-services'; import { InsightsModule } from '@alfresco/adf-insights'; import { ProcessModule } from '@alfresco/adf-process-services'; import { AuthBearerInterceptor } from './services'; -import { AppListCloudModule } from '@alfresco/adf-process-services-cloud'; +import { ProcessServicesCloudModule } from '@alfresco/adf-process-services-cloud'; import { CloudComponent } from './components/cloud/cloud.component'; +import { TaskListCloudDemoComponent } from './components/task-list-cloud-demo/task-list-cloud-demo.component'; @NgModule({ imports: [ @@ -83,7 +84,7 @@ import { CloudComponent } from './components/cloud/cloud.component'; ThemePickerModule, ChartsModule, MonacoEditorModule.forRoot(), - AppListCloudModule + ProcessServicesCloudModule ], declarations: [ AppComponent, @@ -113,7 +114,8 @@ import { CloudComponent } from './components/cloud/cloud.component'; FormLoadingComponent, DemoPermissionComponent, FormLoadingComponent, - ReportIssueComponent + ReportIssueComponent, + TaskListCloudDemoComponent ], providers: [ { diff --git a/demo-shell/src/app/app.routes.ts b/demo-shell/src/app/app.routes.ts index 09e8157b3b..b6e4f5fa2c 100644 --- a/demo-shell/src/app/app.routes.ts +++ b/demo-shell/src/app/app.routes.ts @@ -41,6 +41,7 @@ import { DemoPermissionComponent } from './components/permissions/demo-permissio import { ReportIssueComponent } from './components/report-issue/report-issue.component'; import { AppComponent } from './app.component'; import { CloudComponent } from './components/cloud/cloud.component'; +import { TaskListCloudDemoComponent } from './components/task-list-cloud-demo/task-list-cloud-demo.component'; export const appRoutes: Routes = [ { path: 'login', component: LoginComponent }, @@ -135,7 +136,16 @@ export const appRoutes: Routes = [ }, { path: 'cloud', - component: CloudComponent + children: [ + { + path: '', + component: CloudComponent + }, + { + path: ':applicationName/tasks', + component: TaskListCloudDemoComponent + } + ] }, { path: 'node-selector', diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.ts b/demo-shell/src/app/components/app-layout/app-layout.component.ts index c0869d8e57..2ee3efe301 100644 --- a/demo-shell/src/app/components/app-layout/app-layout.component.ts +++ b/demo-shell/src/app/components/app-layout/app-layout.component.ts @@ -40,6 +40,7 @@ export class AppLayoutComponent implements OnInit { { href: '/node-selector', icon: 'attachment', title: 'APP_LAYOUT.NODE-SELECTOR' }, { href: '/task-list', icon: 'assignment', title: 'APP_LAYOUT.TASK_LIST' }, { href: '/process-list', icon: 'assignment', title: 'APP_LAYOUT.PROCESS_LIST' }, + { href: '/cloud', icon: 'cloud', title: 'APP_LAYOUT.PROCESS_CLOUD' }, { href: '/activiti', icon: 'device_hub', title: 'APP_LAYOUT.PROCESS_SERVICES' }, { href: '/login', icon: 'vpn_key', title: 'APP_LAYOUT.LOGIN' }, { href: '/trashcan', icon: 'delete', title: 'APP_LAYOUT.TRASHCAN' }, diff --git a/demo-shell/src/app/components/cloud/cloud.component.html b/demo-shell/src/app/components/cloud/cloud.component.html index 193a1d7d44..68ddc07330 100644 --- a/demo-shell/src/app/components/cloud/cloud.component.html +++ b/demo-shell/src/app/components/cloud/cloud.component.html @@ -1,2 +1,2 @@ - + diff --git a/demo-shell/src/app/components/cloud/cloud.component.ts b/demo-shell/src/app/components/cloud/cloud.component.ts index 74dbfda479..8217d6735a 100644 --- a/demo-shell/src/app/components/cloud/cloud.component.ts +++ b/demo-shell/src/app/components/cloud/cloud.component.ts @@ -16,7 +16,7 @@ */ import { Component, OnInit } from '@angular/core'; - +import { Router } from '@angular/router'; @Component({ selector: 'app-cloud', templateUrl: './cloud.component.html', @@ -24,9 +24,13 @@ import { Component, OnInit } from '@angular/core'; }) export class CloudComponent implements OnInit { - constructor() { + constructor(private router: Router) { } ngOnInit() { } + + onAppClick(app) { + this.router.navigate([`/cloud/${app.name}/tasks/`]); + } } diff --git a/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.html b/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.html new file mode 100644 index 0000000000..45b2b60caf --- /dev/null +++ b/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.html @@ -0,0 +1,86 @@ +

TASK LIST CLOUD DEMO

+ + + + + + + + {{filterName}} + + + Customise your filter + + +
+ + + + ALL + + + CREATED + + + CANCELLED + + + ASSIGNED + + + SUSPENDED + + + COMPLETED + + + DELETED + + + + + + Select a column + + {{column.label}} + + + + + + Select a direction + + ASC + + + DESC + + + +
+ +
+
+
+ + + + + + + + + + + + +
diff --git a/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.scss b/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.scss new file mode 100644 index 0000000000..18d1293053 --- /dev/null +++ b/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.scss @@ -0,0 +1,15 @@ +.task-cloud-demo-select { + padding: 10px; +} + +.task-cloud-demo-select .mat-expansion-panel-body { + display: flex; +} + +.app-task-list-cloud-demo-selection{ + display: flex; +} + +.task-row-clicked { + align-self: center; +} diff --git a/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.ts b/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.ts new file mode 100644 index 0000000000..f2a953ea3e --- /dev/null +++ b/demo-shell/src/app/components/task-list-cloud-demo/task-list-cloud-demo.component.ts @@ -0,0 +1,126 @@ +/*! + * @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, ViewChild, OnInit } from '@angular/core'; +import { TaskListCloudComponent, TaskListCloudSortingModel } from '@alfresco/adf-process-services-cloud'; +import { UserPreferencesService } from '@alfresco/adf-core'; +import { Observable } from 'rxjs'; +import { ActivatedRoute, Router } from '@angular/router'; +import { FormControl } from '@angular/forms'; + +@Component({ + selector: 'app-task-list-cloud-demo', + templateUrl: 'task-list-cloud-demo.component.html', + styleUrls: ['task-list-cloud-demo.component.scss'] +}) +export class TaskListCloudDemoComponent implements OnInit { + + @ViewChild('taskCloud') + taskCloud: TaskListCloudComponent; + + sortFormControl: FormControl; + sortDirectionFormControl: FormControl; + + appDefinitionList: Observable; + applicationName: string = ''; + status: string = ''; + sort: string = ''; + isFilterLoaded = false; + sortDirection: string = 'ASC'; + filterName: string; + clickedRow: string = ''; + selectTask: string = ''; + sortArray: TaskListCloudSortingModel []; + + columns = [ + {key: 'id', label: 'ID'}, + {key: 'name', label: 'NAME'}, + {key: 'createdDate', label: 'Created Date'}, + {key: 'priority', label: 'PRIORITY'}, + {key: 'processDefinitionId', label: 'PROCESS DEFINITION ID'} + ]; + + constructor( + private route: ActivatedRoute, + private router: Router, + private userPreference: UserPreferencesService) { + } + + ngOnInit() { + this.isFilterLoaded = false; + this.route.params.subscribe(params => { + this.applicationName = params.applicationName; + }); + + this.sortFormControl = new FormControl(''); + + this.sortFormControl.valueChanges.subscribe( + (sortValue) => { + this.sort = sortValue; + + this.sortArray = [{ + orderBy: this.sort, + direction: this.sortDirection + }]; + } + ); + this.sortDirectionFormControl = new FormControl(''); + + this.sortDirectionFormControl.valueChanges.subscribe( + (sortDirectionValue) => { + this.sortDirection = sortDirectionValue; + + this.sortArray = [{ + orderBy: this.sort, + direction: this.sortDirection + }]; + } + ); + + this.route.queryParams + .subscribe(params => { + if (params.status) { + this.status = params.status; + this.sort = params.sort; + this.sortDirection = params.order; + this.filterName = params.filterName; + this.isFilterLoaded = true; + this.sortDirectionFormControl.setValue(this.sortDirection); + this.sortFormControl.setValue(this.sort); + } + }); + } + + onFilterSelected(filter) { + const queryParams = { + status: filter.query.state, + filterName: filter.name, + sort: filter.query.sort, + order: filter.query.order + }; + this.router.navigate([`/cloud/${this.applicationName}/tasks/`], {queryParams: queryParams}); + } + + onChangePageSize(event) { + this.userPreference.paginationSize = event.maxItems; + } + + onRowClick($event) { + this.clickedRow = $event; + } + +} diff --git a/docs/process-services-cloud/task-list-cloud.md b/docs/process-services-cloud/task-list-cloud.md new file mode 100644 index 0000000000..236564397d --- /dev/null +++ b/docs/process-services-cloud/task-list-cloud.md @@ -0,0 +1,217 @@ +--- +Added: v2.0.0 +Status: Active +Last reviewed: 2018-04-16 +--- + +# Task List component + +Renders a list containing all the tasks matched by the parameters specified. + +## Contents + +- [Basic Usage](#basic-usage) + - [Transclusions](#transclusions) +- [Class members](#class-members) + - [Properties](#properties) + - [Events](#events) +- [Details](#details) + - [Setting the column schema](#setting-the-column-schema) + - [Setting Sorting Order for the list](#setting-sorting-order-for-the-list) + - [Pagination strategy](#pagination-strategy) + - [DataTableAdapter example](#datatableadapter-example) + - [DataColumn Features](#datacolumn-features) +- [See also](#see-also) + +## Basic Usage + +```html + + +``` + +### [Transclusions](../user-guide/transclusion.md) + +Any content inside an `` sub-component will be shown +when the task list is empty: + +```html + + + Your Content + + +``` + +## Class members + +### Properties + +| Name | Type | Default value | Description | +| ---- | ---- | ------------- | ----------- | +| applicationName | `string` | | The name of the application. | +| assignee | `string` | | The assigee of the process. Possible values are: "assignee" (the current user is the assignee), candidate (the current user is a task candidate", "group_x" (the task is assigned to a group where the current user is a member, no value(the current user is involved). | +| createdDate | `Date` | | filter the tasks for the date when the task should have been created | +| dueDate | `Date` | | Filter the tasks. Display only tasks with dueDate equal to the one insterted. | +| id | `string` | | Filter the tasks. Display only tasks with id equal to the one insterted. | +| name | `string` | | Filter the tasks. Display only tasks with name equal to the one insterted. | +| parentTaskId | `string` | | Filter the tasks. Display only tasks with parentTaskId equal to the one insterted. | +| processDefinitionId | `string` | | Filter the tasks. Display only tasks with processDefinitionId equal to the one insterted. | +| processInstanceId | `string` | | Filter the tasks. Display only tasks with processInstanceId equal to the one insterted. | +| status | `string` | | Filter the tasks. Display only tasks with status equal to the one insterted. | +| processDefinitionId | `string` | | Filter the tasks. Display only tasks with processDefinitionId equal to the one insterted. | +| landingTaskId | `string` | | Define which task id should be selected after reloading. If the task id doesn't exist or nothing is passed then the first task will be selected. | +| selectFirstRow | `boolean` | true | Toggles default selection of the first row | +| selectionMode | `string` | "single" | Row selection mode. Can be none, `single` or `multiple`. For `multiple` mode, you can use Cmd (macOS) or Ctrl (Win) modifier key to toggle selection for multiple rows. | +| multiselect | `boolean` | false | Toggles multiple row selection, renders checkboxes at the beginning of each row | +| sorting | `[TaskListCloudSortingModel]` | | This array of `TaskListCloudSortingModel` specify how the sorting on our table should be provided. This parameters are for BE sorting. | + +### Events + +| Name | Type | Description | +| ---- | ---- | ----------- | +| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when an error occurs. | +| rowClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when a task in the list is clicked | +| rowsSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when rows are selected/unselected | +| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when the task list is loaded | + +## Details + +This component displays lists of tasks related to the application name insterted. Extra filtering can be provided by applying extra input parameters + +### Setting the column schema + +You can use an HTML-based schema declaration to set a column schema for the tasklist as shown below : + +```html + + + + + + +``` + +You can also set a static custom schema declaration in `app.config.json` as shown below: + +```json +"adf-cloud-task-list": { + "presets": { + "customSchema": [ + { + "key": "name", + "type": "text", + "title": "name", + "sortable": true + }], + "default": [ + { + "key": "name", + "type": "text", + "title": "name", + "sortable": true + }], + } +} +``` + +```html + + +``` + +You can use an HTML-based schema and an `app.config.json` custom schema declaration at the same time: + +```json +"adf-cloud-task-list": { + "presets": { + "customSchema": [ + { + "key": "id", + "type": "text", + "title": "Id", + "sortable": true + }], + "default": [ + { + "key": "name", + "type": "text", + "title": "name", + "sortable": true + }], + } +} +``` + + + +```html + + + + +
{{getFullName(entry.row.obj.assignee)}}
+
+
+
+
+``` + +### Setting Sorting Order for the list + +you can pass sorting order as shown in the example below: + +```ts +let sorting = { orderBy: 'created', direction: 'desc' }; +``` + +```html + + +``` + + + +### Pagination strategy + +The Tasklist also supports pagination as shown in the example below: + +```html + + + + +``` + +### DataTableAdapter example + +See the [`DataTableAdapter`](../../lib/core/datatable/data/datatable-adapter.ts) page for full details of the interface and its standard +implementation, [`ObjectDataTableAdapter`](../../lib/core/datatable/data/object-datatable-adapter.ts). Below is an example of how you can set up the adapter for a +typical tasklist. + +```json +[ + {"type": "text", "key": "id", "title": "Id"}, + {"type": "text", "key": "name", "title": "Name", "cssClass": "full-width name-column", "sortable": true}, + {"type": "text", "key": "formKey", "title": "Form Key", "sortable": true}, + {"type": "text", "key": "created", "title": "Created", "sortable": true} +] +``` + +### DataColumn Features + +You can customize the styling of a column and also add features like tooltips and automatic translation of column titles. See the [`DataColumn`](../../lib/core/datatable/data/data-column.model.ts) page for more information about these features. + +## See also + +- [Data column component](../core/data-column.component.md) +- [`DataTableAdapter`](../../lib/core/datatable/data/datatable-adapter.ts) +- [Pagination component](../core/pagination.component.md) diff --git a/lib/core/assets/images/ft_ic_link_folder.svg b/lib/core/assets/images/ft_ic_link_folder.svg new file mode 100644 index 0000000000..2b00d3c1f4 --- /dev/null +++ b/lib/core/assets/images/ft_ic_link_folder.svg @@ -0,0 +1,19 @@ + + + + System Icon Links + Created with Sketch. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/core/context-menu/public-api.ts b/lib/core/context-menu/public-api.ts index a98fa40c6b..ed9031c322 100644 --- a/lib/core/context-menu/public-api.ts +++ b/lib/core/context-menu/public-api.ts @@ -18,5 +18,6 @@ export * from './context-menu-holder.component'; export * from './context-menu.directive'; export * from './context-menu.service'; +export * from './context-menu-overlay.service'; export * from './context-menu.module'; diff --git a/lib/process-services-cloud/.npmignore b/lib/process-services-cloud/.npmignore deleted file mode 100644 index b79b6054fb..0000000000 --- a/lib/process-services-cloud/.npmignore +++ /dev/null @@ -1,30 +0,0 @@ -npm-debug.log -.idea -.npmrc - -/.editorconfig -/.travis.yml -/*.json -/karma-test-shim.js -/karma.conf.js -/gulpfile.ts -/.npmignore -/.happypack -**/*.html -**/*.js -**/*.ts -!**/*.d.ts -!**/adf-process-services-cloud.js - -**/*.scss -**/*.css -!**/_theming.scss - -coverage/ -demo/ -dist/ -node_modules -typings/ -fonts/ -i18n/ -assets/ diff --git a/lib/process-services-cloud/index.ts b/lib/process-services-cloud/index.ts index 7930436002..6b147d9ba9 100644 --- a/lib/process-services-cloud/index.ts +++ b/lib/process-services-cloud/index.ts @@ -15,4 +15,4 @@ * limitations under the License. */ -export * from './src/public_api'; +export * from './src/public-api'; diff --git a/lib/process-services-cloud/material.module.ts b/lib/process-services-cloud/material.module.ts deleted file mode 100644 index 76c04b2672..0000000000 --- a/lib/process-services-cloud/material.module.ts +++ /dev/null @@ -1,44 +0,0 @@ -/*! - * @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 { NgModule } from '@angular/core'; -import { - MAT_LABEL_GLOBAL_OPTIONS, MatAutocompleteModule, MatButtonModule, MatCardModule, MatCheckboxModule, - MatChipsModule, MatDatepickerModule, MatDialogModule, MatGridListModule, MatIconModule, - MatInputModule, MatListModule, MatNativeDateModule, MatOptionModule, MatProgressSpinnerModule, MatRadioModule, - MatRippleModule, MatSelectModule, MatSlideToggleModule, MatTableModule, MatTabsModule, - MatTooltipModule, MatMenuModule -} from '@angular/material'; - -export function modules() { - return [ - MatAutocompleteModule, MatButtonModule, MatCardModule, MatDialogModule, - MatCheckboxModule, MatDatepickerModule, MatGridListModule, MatIconModule, MatInputModule, - MatListModule, MatOptionModule, MatRadioModule, MatSelectModule, MatSlideToggleModule, MatTableModule, - MatTabsModule, MatProgressSpinnerModule, MatNativeDateModule, MatRippleModule, MatTooltipModule, - MatChipsModule, MatMenuModule - ]; -} - -@NgModule({ - providers: [ - {provide: MAT_LABEL_GLOBAL_OPTIONS, useValue: { float: 'never' }} - ], - imports: modules(), - exports: modules() -}) -export class MaterialModule {} diff --git a/lib/process-services-cloud/ng-package.json b/lib/process-services-cloud/ng-package.json index 541ec59bc7..6091859edc 100644 --- a/lib/process-services-cloud/ng-package.json +++ b/lib/process-services-cloud/ng-package.json @@ -3,7 +3,7 @@ "dest": "../dist/process-services-cloud", "lib": { "languageLevel": ["dom", "es2017"], - "entryFile": "src/public_api.ts", + "entryFile": "src/public-api.ts", "flatModuleFile": "adf-process-services-cloud", "umdModuleIds": { "alfresco-js-api": "alfresco-js-api" diff --git a/lib/process-services-cloud/process-cloud.module.ts b/lib/process-services-cloud/process-cloud.module.ts deleted file mode 100644 index 6ee7dd03ef..0000000000 --- a/lib/process-services-cloud/process-cloud.module.ts +++ /dev/null @@ -1,99 +0,0 @@ -/*! - * @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 { CommonModule } from '@angular/common'; -import { NgModule, ModuleWithProviders } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { CoreModule, TRANSLATION_PROVIDER } from '@alfresco/adf-core'; - -import { MaterialModule } from './material.module'; -import { HelloCloudModule } from './hello/hello.module'; - -export function providers() { - return [ - ]; -} - -@NgModule({ - imports: [ - CoreModule.forChild(), - CommonModule, - FormsModule, - ReactiveFormsModule, - MaterialModule, - HelloCloudModule - ], - providers: [ - ...providers(), - { - provide: TRANSLATION_PROVIDER, - multi: true, - useValue: { - name: 'adf-process-services-cloud', - source: 'assets/adf-process-services-cloud' - } - } - ], - exports: [ - CommonModule, - FormsModule, - ReactiveFormsModule, - HelloCloudModule - ] -}) -export class ProcessCloudModule { - static forRoot(): ModuleWithProviders { - return { - ngModule: ProcessCloudModule, - providers: [ - ...providers(), - { - provide: TRANSLATION_PROVIDER, - multi: true, - useValue: { - name: 'adf-process-services-cloud', - source: 'assets/adf-process-services-cloud' - } - } - ] - }; - } - - static forChild(): ModuleWithProviders { - return { - ngModule: ProcessCloudModuleLazy - }; - } -} - -@NgModule({ - imports: [ - CoreModule.forChild(), - CommonModule, - FormsModule, - ReactiveFormsModule, - MaterialModule, - HelloCloudModule - ], - exports: [ - CommonModule, - FormsModule, - ReactiveFormsModule, - HelloCloudModule - ] -}) -export class ProcessCloudModuleLazy {} diff --git a/lib/process-services-cloud/src/lib/app-list-cloud/components/app-details-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/app-list-cloud/components/app-details-cloud.component.spec.ts index 7e7874293e..abcc6448c4 100644 --- a/lib/process-services-cloud/src/lib/app-list-cloud/components/app-details-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/app-list-cloud/components/app-details-cloud.component.spec.ts @@ -20,7 +20,8 @@ import { setupTestBed } from '@alfresco/adf-core'; import { fakeApplicationInstance } from '../mock/app-model.mock'; import { AppDetailsCloudComponent } from './app-details-cloud.component'; -import { AppListTestingModule } from '../testing/app-list.testing.module'; +import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; +import { AppListCloudModule } from '../app-list-cloud.module'; describe('AppDetailsCloudComponent', () => { @@ -28,7 +29,7 @@ describe('AppDetailsCloudComponent', () => { let fixture: ComponentFixture; setupTestBed({ - imports: [AppListTestingModule] + imports: [ProcessServiceCloudTestingModule, AppListCloudModule] }); beforeEach(() => { diff --git a/lib/process-services-cloud/src/lib/app-list-cloud/components/app-list-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/app-list-cloud/components/app-list-cloud.component.spec.ts index bab5dadfe1..2524c2e73c 100644 --- a/lib/process-services-cloud/src/lib/app-list-cloud/components/app-list-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/app-list-cloud/components/app-list-cloud.component.spec.ts @@ -23,8 +23,9 @@ import { of } from 'rxjs'; import { fakeApplicationInstance } from '../mock/app-model.mock'; import { AppListCloudComponent } from './app-list-cloud.component'; import { AppsProcessCloudService } from '../services/apps-process-cloud.service'; -import { AppListTestingModule } from '../testing/app-list.testing.module'; +import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; import { ApplicationInstanceModel } from '../models/application-instance.model'; +import { AppListCloudModule } from '../app-list-cloud.module'; describe('AppListCloudComponent', () => { @@ -34,7 +35,7 @@ describe('AppListCloudComponent', () => { let getAppsSpy: jasmine.Spy; setupTestBed({ - imports: [AppListTestingModule], + imports: [ProcessServiceCloudTestingModule, AppListCloudModule], providers: [AppsProcessCloudService] }); @@ -184,7 +185,7 @@ describe('Custom CustomEmptyAppListCloudTemplateComponent', () => { let fixture: ComponentFixture; setupTestBed({ - imports: [AppListTestingModule], + imports: [ProcessServiceCloudTestingModule], declarations: [CustomEmptyAppListCloudTemplateComponent], schemas: [ CUSTOM_ELEMENTS_SCHEMA ] }); diff --git a/lib/process-services-cloud/src/lib/app-list-cloud/public_api.ts b/lib/process-services-cloud/src/lib/app-list-cloud/public-api.ts similarity index 94% rename from lib/process-services-cloud/src/lib/app-list-cloud/public_api.ts rename to lib/process-services-cloud/src/lib/app-list-cloud/public-api.ts index 79e933acb9..26104e7698 100644 --- a/lib/process-services-cloud/src/lib/app-list-cloud/public_api.ts +++ b/lib/process-services-cloud/src/lib/app-list-cloud/public-api.ts @@ -17,4 +17,4 @@ export * from './components/app-list-cloud.component'; export * from './models/application-instance.model'; -export * from './apps-list-cloud.module'; +export * from './app-list-cloud.module'; diff --git a/lib/process-services-cloud/src/lib/app-list-cloud/services/apps-process-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/app-list-cloud/services/apps-process-cloud.service.spec.ts index e42b5e8093..b70b1b9cff 100644 --- a/lib/process-services-cloud/src/lib/app-list-cloud/services/apps-process-cloud.service.spec.ts +++ b/lib/process-services-cloud/src/lib/app-list-cloud/services/apps-process-cloud.service.spec.ts @@ -22,14 +22,14 @@ import { HttpErrorResponse } from '@angular/common/http'; import { AppsProcessCloudService } from './apps-process-cloud.service'; import { fakeApplicationInstance } from '../mock/app-model.mock'; import { ApplicationInstanceModel } from '../models/application-instance.model'; -import { AppListTestingModule } from '../testing/app-list.testing.module'; +import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; describe('AppsProcessCloudService', () => { let service: AppsProcessCloudService; setupTestBed({ - imports: [AppListTestingModule], + imports: [ProcessServiceCloudTestingModule], providers: [AppsProcessCloudService] }); diff --git a/lib/process-services-cloud/src/lib/hello/hello.component.css b/lib/process-services-cloud/src/lib/hello/hello.component.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lib/process-services-cloud/src/lib/hello/hello.component.html b/lib/process-services-cloud/src/lib/hello/hello.component.html deleted file mode 100644 index bf41ce5952..0000000000 --- a/lib/process-services-cloud/src/lib/hello/hello.component.html +++ /dev/null @@ -1,4 +0,0 @@ -

- hello cloud world! -

- diff --git a/lib/process-services-cloud/src/lib/hello/hello.component.spec.ts b/lib/process-services-cloud/src/lib/hello/hello.component.spec.ts deleted file mode 100644 index 68758e3fea..0000000000 --- a/lib/process-services-cloud/src/lib/hello/hello.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HelloComponent } from './hello.component'; - -describe('HelloComponent', () => { - let component: HelloComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HelloComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HelloComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/lib/process-services-cloud/src/lib/hello/hello.component.ts b/lib/process-services-cloud/src/lib/hello/hello.component.ts deleted file mode 100644 index f8ffeeacca..0000000000 --- a/lib/process-services-cloud/src/lib/hello/hello.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'adf-cloud-hello', - templateUrl: './hello.component.html', - styleUrls: ['./hello.component.css'] -}) -export class HelloComponent implements OnInit { - - constructor() { } - - ngOnInit() { - } - -} diff --git a/lib/process-services-cloud/src/lib/hello/hello.module.spec.ts b/lib/process-services-cloud/src/lib/hello/hello.module.spec.ts deleted file mode 100644 index e94e9ad59e..0000000000 --- a/lib/process-services-cloud/src/lib/hello/hello.module.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HelloModule } from './hello.module'; - -describe('HelloModule', () => { - let helloModule: HelloModule; - - beforeEach(() => { - helloModule = new HelloModule(); - }); - - it('should create an instance', () => { - expect(helloModule).toBeTruthy(); - }); -}); diff --git a/lib/process-services-cloud/src/lib/hello/hello.module.ts b/lib/process-services-cloud/src/lib/hello/hello.module.ts deleted file mode 100644 index b85573aedd..0000000000 --- a/lib/process-services-cloud/src/lib/hello/hello.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { HelloComponent } from './hello.component'; -import { TranslateModule } from '@ngx-translate/core'; -@NgModule({ - imports: [ - CommonModule, - TranslateModule - ], - declarations: [HelloComponent], - exports: [HelloComponent] -}) -export class HelloModule { } diff --git a/lib/process-services-cloud/src/lib/process-services-cloud.module.ts b/lib/process-services-cloud/src/lib/process-services-cloud.module.ts index 02678564bc..f6f61b741b 100644 --- a/lib/process-services-cloud/src/lib/process-services-cloud.module.ts +++ b/lib/process-services-cloud/src/lib/process-services-cloud.module.ts @@ -1,10 +1,14 @@ import { NgModule } from '@angular/core'; import { TRANSLATION_PROVIDER } from '@alfresco/adf-core'; import { AppListCloudModule } from './app-list-cloud/app-list-cloud.module'; +import { TaskListCloudModule } from './task-list-cloud/task-list-cloud.module'; +import { TaskCloudModule } from './task-cloud/task-cloud.module'; @NgModule({ imports: [ - AppListCloudModule + AppListCloudModule, + TaskListCloudModule, + TaskCloudModule ], providers: [ { @@ -17,6 +21,6 @@ import { AppListCloudModule } from './app-list-cloud/app-list-cloud.module'; } ], declarations: [], - exports: [AppListCloudModule] + exports: [AppListCloudModule, TaskListCloudModule, TaskCloudModule] }) export class ProcessServicesCloudModule { } diff --git a/lib/process-services-cloud/src/lib/styles/_index.scss b/lib/process-services-cloud/src/lib/styles/_index.scss index 7ca16547f9..4da0dabfd5 100644 --- a/lib/process-services-cloud/src/lib/styles/_index.scss +++ b/lib/process-services-cloud/src/lib/styles/_index.scss @@ -1,7 +1,9 @@ @import './../app-list-cloud/components/app-details-cloud.component'; @import './../app-list-cloud/components/app-list-cloud.component'; +@import './../task-cloud/task-filters-cloud/task-filters-cloud.component.scss'; @mixin adf-process-services-cloud-theme($theme) { @include adf-cloud-app-list-theme($theme); @include adf-cloud-app-details-theme($theme); + @include adf-cloud-task-filters-theme($theme); } diff --git a/lib/process-services-cloud/src/lib/task-cloud/mock/task-list-service.mock.ts b/lib/process-services-cloud/src/lib/task-cloud/mock/task-list-service.mock.ts new file mode 100644 index 0000000000..ae93e92b3d --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/mock/task-list-service.mock.ts @@ -0,0 +1,267 @@ +/*! + * @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 { FilterRepresentationModel, AppDefinitionRepresentationModel } from '../models/filter-cloud.model'; + +export let fakeFilters = { + size: 2, total: 2, start: 0, + data: [ + new AppDefinitionRepresentationModel( + { + id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left', + filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' } + } + ), + { + id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left', + filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee' } + } + ] +}; + +export let fakeAppFilter = { + size: 1, total: 1, start: 0, + data: [ + { + id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left', + filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' } + } + ] +}; + +export let fakeApps = { + size: 2, total: 2, start: 0, + data: [ + { + id: 1, defaultAppId: null, name: 'Sales-Fakes-App', description: 'desc-fake1', modelId: 22, + theme: 'theme-1-fake', icon: 'glyphicon-asterisk', 'deploymentId': '111', 'tenantId': null + }, + { + id: 2, defaultAppId: null, name: 'health-care-Fake', description: 'desc-fake2', modelId: 33, + theme: 'theme-2-fake', icon: 'glyphicon-asterisk', 'deploymentId': '444', 'tenantId': null + } + ] +}; + +export let fakeFilter = { + sort: 'created-desc', text: '', state: 'open', assignment: 'fake-assignee' +}; + +export let fakeUser1 = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' }; + +export let fakeUser2 = { id: 1001, email: 'some-one@somegroup.com', firstName: 'some', lastName: 'one' }; + +export let fakeTaskList = { + size: 1, total: 1, start: 0, + data: [ + { + id: '1', name: 'FakeNameTask', description: null, category: null, + assignee: fakeUser1, + created: '2016-07-15T11:19:17.440+0000' + } + ] +}; + +export let fakeTaskListDifferentProcessDefinitionKey = { + size: 2, total: 1, start: 0, + data: [ + { + id: '1', name: 'FakeNameTask', description: null, category: null, + assignee: fakeUser1, + processDefinitionKey: '1', + created: '2016-07-15T11:19:17.440+0000' + }, + { + id: '2', name: 'FakeNameTask2', description: null, category: null, + assignee: fakeUser1, + processDefinitionKey: '2', + created: '2016-07-15T11:19:17.440+0000' + } + ] +}; + +export let secondFakeTaskList = { + size: 1, total: 1, start: 0, + data: [ + { + id: '200', name: 'FakeNameTask', description: null, category: null, + assignee: fakeUser1, + created: '2016-07-15T11:19:17.440+0000' + } + ] +}; + +export let mockErrorTaskList = { + error: 'wrong request' +}; + +export let fakeTaskDetails = { id: '999', name: 'fake-task-name', formKey: '99', assignee: fakeUser1 }; + +export let fakeTasksComment = { + size: 2, total: 2, start: 0, + data: [ + { + id: 1, message: 'fake-message-1', created: '', createdBy: fakeUser1 + }, + { + id: 2, message: 'fake-message-2', created: '', createdBy: fakeUser1 + } + ] +}; + +export let fakeTasksChecklist = { + size: 1, total: 1, start: 0, + data: [ + { + id: 1, name: 'FakeCheckTask1', description: null, category: null, + assignee: fakeUser1, + created: '2016-07-15T11:19:17.440+0000' + }, + { + id: 2, name: 'FakeCheckTask2', description: null, category: null, + assignee: fakeUser1, + created: '2016-07-15T11:19:17.440+0000' + } + ] +}; + +export let fakeRepresentationFilter1: FilterRepresentationModel = new FilterRepresentationModel({ + appId: 1, + name: 'CONTAIN FILTER', + recent: true, + icon: 'glyphicon-align-left', + filter: { + processDefinitionId: null, + processDefinitionKey: null, + name: null, + state: 'open', + sort: 'created-desc', + assignment: 'involved', + dueAfter: null, + dueBefore: null + } +}); + +export let fakeRepresentationFilter2: FilterRepresentationModel = new FilterRepresentationModel({ + appId: 2, + name: 'NO TASK FILTER', + recent: false, + icon: 'glyphicon-inbox', + filter: { + processDefinitionId: null, + processDefinitionKey: null, + name: null, + state: 'open', + sort: 'created-desc', + assignment: 'assignee', + dueAfter: null, + dueBefore: null + } +}); + +export let fakeAppPromise = new Promise(function (resolve, reject) { + resolve(fakeAppFilter); +}); + +export let fakeFormList = { + size: 2, + total: 2, + start: 0, + data: [{ + id: 1, + name: 'form with all widgets', + description: '', + createdBy: 2, + createdByFullName: 'Admin Admin', + lastUpdatedBy: 2, + lastUpdatedByFullName: 'Admin Admin', + lastUpdated: 1491400951205, + latestVersion: true, + version: 4, + comment: null, + stencilSet: null, + referenceId: null, + modelType: 2, + favorite: null, + permission: 'write', + tenantId: null + }, { + id: 2, + name: 'uppy', + description: '', + createdBy: 2, + createdByFullName: 'Admin Admin', + lastUpdatedBy: 2, + lastUpdatedByFullName: 'Admin Admin', + lastUpdated: 1490951054477, + latestVersion: true, + version: 2, + comment: null, + stencilSet: null, + referenceId: null, + modelType: 2, + favorite: null, + permission: 'write', + tenantId: null + }] +}; + +export let fakeTaskOpen1 = { + id: '1', name: 'FakeOpenTask1', description: null, category: null, + assignee: fakeUser1, + created: '2017-07-15T11:19:17.440+0000', + dueDate: null, + endDate: null + }; + +export let fakeTaskOpen2 = { + id: '1', name: 'FakeOpenTask2', description: null, category: null, + assignee: { id: 1, email: 'fake-open-email@dom.com', firstName: 'firstName', lastName: 'lastName' }, + created: '2017-07-15T11:19:17.440+0000', + dueDate: null, + endDate: null + }; + +export let fakeTaskCompleted1 = { + id: '1', name: 'FakeCompletedTaskName1', description: null, category: null, + assignee: { id: 1, email: 'fake-completed-email@dom.com', firstName: 'firstName', lastName: 'lastName' }, + created: '2016-07-15T11:19:17.440+0000', + dueDate: null, + endDate: '2016-11-03T15:25:42.749+0000' + }; + +export let fakeTaskCompleted2 = { + id: '1', name: 'FakeCompletedTaskName2', description: null, category: null, + assignee: fakeUser1, + created: null, + dueDate: null, + endDate: '2016-11-03T15:25:42.749+0000' + }; + +export let fakeOpenTaskList = { + size: 2, + total: 2, + start: 0, + data: [fakeTaskOpen1, fakeTaskOpen2] +}; + +export let fakeCompletedTaskList = { + size: 2, + total: 2, + start: 0, + data: [fakeTaskCompleted1, fakeTaskCompleted2] +}; diff --git a/lib/process-services-cloud/src/lib/task-cloud/models/filter-cloud.model.ts b/lib/process-services-cloud/src/lib/task-cloud/models/filter-cloud.model.ts new file mode 100644 index 0000000000..76a46323c1 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/models/filter-cloud.model.ts @@ -0,0 +1,52 @@ +/*! + * @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 class QueryModel { + processDefinitionId: string; + appName: string; + state: string; + sort: string; + assignment: string; + order: string; + + constructor(obj?: any) { + if (obj) { + this.appName = obj.appName || null; + this.processDefinitionId = obj.processDefinitionId || null; + this.state = obj.state || null; + this.sort = obj.sort || null; + this.assignment = obj.assignment || null; + this.order = obj.order || null; + } + } +} +export class FilterRepresentationModel { + name: string; + icon: string; + query: QueryModel; + + constructor(obj?: any) { + if (obj) { + this.name = obj.name || null; + this.icon = obj.icon || null; + this.query = new QueryModel(obj.query); + } + } + + hasFilter() { + return !!this.query; + } +} diff --git a/lib/process-services-cloud/public-api.ts b/lib/process-services-cloud/src/lib/task-cloud/public-api.ts similarity index 80% rename from lib/process-services-cloud/public-api.ts rename to lib/process-services-cloud/src/lib/task-cloud/public-api.ts index f25adc0c31..31364da8b6 100644 --- a/lib/process-services-cloud/public-api.ts +++ b/lib/process-services-cloud/src/lib/task-cloud/public-api.ts @@ -15,4 +15,6 @@ * limitations under the License. */ -export * from './index'; +export * from './task-filters-cloud/task-filters-cloud.component'; +export * from './models/filter-cloud.model'; +export * from './task-cloud.module'; diff --git a/lib/process-services-cloud/src/lib/task-cloud/services/task-filter-cloud.service.ts b/lib/process-services-cloud/src/lib/task-cloud/services/task-filter-cloud.service.ts new file mode 100644 index 0000000000..1eff2b6d43 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/services/task-filter-cloud.service.ts @@ -0,0 +1,181 @@ +/*! + * @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 { LogService, StorageService } from '@alfresco/adf-core'; +import { Injectable } from '@angular/core'; +import { Observable, forkJoin } from 'rxjs'; +import { FilterRepresentationModel, QueryModel } from '../models/filter-cloud.model'; + +@Injectable() +export class TaskFilterCloudService { + + constructor(private logService: LogService, + private storage: StorageService) { + } + + /** + * Creates and returns the default filters for a process app. + * @param appName Name of the target app + * @returns Observable of default filters just created + */ + public createDefaultFilters(appName: string): Observable { + let involvedTasksFilter = this.getInvolvedTasksFilterInstance(appName); + let involvedObservable = this.addFilter(involvedTasksFilter); + + let myTasksFilter = this.getMyTasksFilterInstance(appName); + let myTaskObservable = this.addFilter(myTasksFilter); + + let queuedTasksFilter = this.getQueuedTasksFilterInstance(appName); + let queuedObservable = this.addFilter(queuedTasksFilter); + + let completedTasksFilter = this.getCompletedTasksFilterInstance(appName); + let completeObservable = this.addFilter(completedTasksFilter); + + return new Observable(observer => { + forkJoin( + involvedObservable, + myTaskObservable, + queuedObservable, + completeObservable + ).subscribe( + (filters) => { + observer.next(filters); + observer.complete(); + }, + (err: any) => { + this.logService.error(err); + }); + }); + } + + /** + * Gets all task filters for a process app. + * @param appName Name of the target app + * @returns Observable of task filter details + */ + getTaskListFilters(appName?: string): Observable { + let key = 'task-filters-' + appName; + const filters = JSON.parse(this.storage.getItem(key) || '[]'); + return new Observable(function(observer) { + observer.next(filters); + observer.complete(); + }); + } + + /** + * Adds a new task filter + * @param filter The new filter to add + * @returns Details of task filter just added + */ + addFilter(filter: FilterRepresentationModel): Observable { + const key = 'task-filters-' + filter.query.appName || '0'; + let filters = JSON.parse(this.storage.getItem(key) || '[]'); + + filters.push(filter); + + this.storage.setItem(key, JSON.stringify(filters)); + + return new Observable(function(observer) { + observer.next(filter); + observer.complete(); + }); + } + + /** + * Creates and returns a filter for "Involved" task instances. + * @param appName Name of the target app + * @returns The newly created filter + */ + getInvolvedTasksFilterInstance(appName: string): FilterRepresentationModel { + return new FilterRepresentationModel({ + name: 'Cancelled Tasks', + icon: 'view_headline', + query: new QueryModel( + { + appName: appName, + sort: 'id', + state: 'CANCELLED', + assignment: 'involved', + order: 'DESC' + } + ) + }); + } + + /** + * Creates and returns a filter for "My Tasks" task instances. + * @param appName Name of the target app + * @returns The newly created filter + */ + getMyTasksFilterInstance(appName: string): FilterRepresentationModel { + return new FilterRepresentationModel({ + name: 'My Tasks', + icon: 'inbox', + query: new QueryModel( + { + appName: appName, + sort: 'id', + state: 'CREATED', + assignment: 'assignee', + order: 'ASC' + } + ) + }); + } + + /** + * Creates and returns a filter for "Queued Tasks" task instances. + * @param appName Name of the target app + * @returns The newly created filter + */ + getQueuedTasksFilterInstance(appName: string): FilterRepresentationModel { + return new FilterRepresentationModel({ + name: 'Suspended Tasks', + icon: 'adjust', + query: new QueryModel( + { + appName: appName, + sort: 'createdDate', + state: 'SUSPENDED', + assignment: 'candidate', + order: 'DESC' + } + ) + }); + } + + /** + * Creates and returns a filter for "Completed" task instances. + * @param appName Name of the target app + * @returns The newly created filter + */ + getCompletedTasksFilterInstance(appName: string): FilterRepresentationModel { + return new FilterRepresentationModel({ + name: 'Completed Tasks', + icon: 'done', + query: new QueryModel( + { + appName: appName, + sort: 'createdDate', + state: 'COMPLETED', + assignment: 'involved', + order: 'ASC' + } + ) + }); + } +} diff --git a/lib/process-services-cloud/src/lib/task-cloud/task-cloud.module.spec.ts b/lib/process-services-cloud/src/lib/task-cloud/task-cloud.module.spec.ts new file mode 100644 index 0000000000..a7f9cf3e27 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/task-cloud.module.spec.ts @@ -0,0 +1,13 @@ +import { TaskCloudModule } from './task-cloud.module'; + +describe('TaskCloudModule', () => { + let taskCloudModule: TaskCloudModule; + + beforeEach(() => { + taskCloudModule = new TaskCloudModule(); + }); + + it('should create an instance', () => { + expect(taskCloudModule).toBeTruthy(); + }); +}); diff --git a/lib/process-services-cloud/src/lib/task-cloud/task-cloud.module.ts b/lib/process-services-cloud/src/lib/task-cloud/task-cloud.module.ts new file mode 100644 index 0000000000..0c65160f49 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/task-cloud.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TaskFiltersCloudComponent } from './task-filters-cloud/task-filters-cloud.component'; +import { MaterialModule } from '../material.module'; +import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; +import { TranslateLoaderService, LogService, StorageService } from '@alfresco/adf-core'; +import { TaskFilterCloudService } from './services/task-filter-cloud.service'; +import { HttpClientModule } from '@angular/common/http'; +@NgModule({ + imports: [ + HttpClientModule, + CommonModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderService + } + }), + MaterialModule + ], + declarations: [TaskFiltersCloudComponent], + + exports: [TaskFiltersCloudComponent], + providers: [TaskFilterCloudService, LogService, StorageService] +}) +export class TaskCloudModule { } diff --git a/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.html b/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.html new file mode 100644 index 0000000000..37e3f1aa22 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.html @@ -0,0 +1,17 @@ + diff --git a/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.scss b/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.scss new file mode 100644 index 0000000000..2452577d5e --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.scss @@ -0,0 +1,34 @@ +@mixin adf-cloud-task-filters-theme($theme) { + $primary: map-get($theme, primary); + + .adf { + + &-filters__entry { + cursor: pointer; + font-size: 14px!important; + font-weight: bold; + opacity: .54; + padding-left: 30px; + + .mat-list-item-content { + height: 34px; + } + } + + &-filters__entry-icon { + padding-right: 12px !important; + padding-left: 0px !important; + } + + &-filters__entry { + &.active, &:hover { + color: mat-color($primary); + opacity: 1; + } + } + + &-menu-list { + padding-top: 0px!important; + } + } +} diff --git a/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.spec.ts new file mode 100644 index 0000000000..4acddc3426 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.spec.ts @@ -0,0 +1,359 @@ +/*! + * @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 { SimpleChange } from '@angular/core'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { setupTestBed } from '@alfresco/adf-core'; +import { from, Observable } from 'rxjs'; +import { FilterRepresentationModel } from '../models/filter-cloud.model'; +import { TaskFilterCloudService } from '../services/task-filter-cloud.service'; +import { TaskFiltersCloudComponent } from './task-filters-cloud.component'; +import { By } from '@angular/platform-browser'; +import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; +import { TaskCloudModule } from '../task-cloud.module'; + +describe('TaskFiltersCloudComponent', () => { + + let taskFilterService: TaskFilterCloudService; + + let fakeGlobalFilter = [ + new FilterRepresentationModel({ + name: 'FakeInvolvedTasks', + icon: 'adjust', + id: 10, + filter: {state: 'open', assignment: 'fake-involved'} + }), + new FilterRepresentationModel({ + name: 'FakeMyTasks1', + icon: 'done', + id: 11, + filter: {state: 'open', assignment: 'fake-assignee'} + }), + new FilterRepresentationModel({ + name: 'FakeMyTasks2', + icon: 'inbox', + id: 12, + filter: {state: 'open', assignment: 'fake-assignee'} + }) + ]; + + let fakeGlobalFilterObservable = + new Observable(function(observer) { + observer.next(fakeGlobalFilter); + observer.complete(); + }); + + let fakeGlobalFilterPromise = new Promise(function (resolve, reject) { + resolve(fakeGlobalFilter); + }); + + let fakeGlobalEmptyFilter = { + message: 'invalid data' + }; + + let fakeGlobalEmptyFilterPromise = new Promise(function (resolve, reject) { + resolve(fakeGlobalEmptyFilter); + }); + + let mockErrorFilterList = { + error: 'wrong request' + }; + + let mockErrorFilterPromise = Promise.reject(mockErrorFilterList); + + let component: TaskFiltersCloudComponent; + let fixture: ComponentFixture; + + setupTestBed({ + imports: [ProcessServiceCloudTestingModule, TaskCloudModule], + providers: [TaskFilterCloudService] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TaskFiltersCloudComponent); + component = fixture.componentInstance; + + taskFilterService = TestBed.get(TaskFilterCloudService); + }); + + it('should attach specific icon for each filter if hasIcon is true', async(() => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); + let change = new SimpleChange(undefined, 'my-app-1', true); + component.ngOnChanges({'appName': change}); + fixture.detectChanges(); + component.showIcons = true; + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(component.filters.length).toBe(3); + let filters = fixture.nativeElement.querySelectorAll('.adf-filters__entry-icon'); + expect(filters.length).toBe(3); + expect(filters[0].innerText).toContain('adjust'); + expect(filters[1].innerText).toContain('done'); + expect(filters[2].innerText).toContain('inbox'); + }); + })); + + it('should not attach icons for each filter if hasIcon is false', (done) => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(from(fakeGlobalFilterPromise)); + + component.showIcons = false; + let change = new SimpleChange(undefined, 'my-app-1', true); + component.ngOnChanges({'appName': change}); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + let filters: any = fixture.debugElement.queryAll(By.css('.adf-filters__entry-icon')); + expect(filters.length).toBe(0); + done(); + }); + }); + + it('should display the filters', async(() => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); + let change = new SimpleChange(undefined, 'my-app-1', true); + component.ngOnChanges({'appName': change}); + fixture.detectChanges(); + component.showIcons = true; + fixture.whenStable().then(() => { + fixture.detectChanges(); + let filters = fixture.debugElement.queryAll(By.css('mat-list-item[class*="adf-filters__entry"]')); + expect(component.filters.length).toBe(3); + expect(filters.length).toBe(3); + expect(filters[0].nativeElement.innerText).toContain('FakeInvolvedTasks'); + expect(filters[1].nativeElement.innerText).toContain('FakeMyTasks1'); + expect(filters[2].nativeElement.innerText).toContain('FakeMyTasks2'); + }); + })); + + it('should emit an error with a bad response', (done) => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(from(mockErrorFilterPromise)); + + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + component.ngOnChanges({'appName': change}); + + component.error.subscribe((err) => { + expect(err).toBeDefined(); + done(); + }); + }); + + it('should return the filter task list', (done) => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(from(fakeGlobalFilterPromise)); + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + component.ngOnChanges({ 'appName': change }); + + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.filters).toBeDefined(); + expect(component.filters.length).toEqual(3); + done(); + }); + }); + + it('should return the filter task list, filtered By Name', (done) => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(from(fakeGlobalFilterPromise)); + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + component.ngOnChanges({ 'appName': change }); + + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.filters).toBeDefined(); + expect(component.filters[0].name).toEqual('FakeInvolvedTasks'); + expect(component.filters[1].name).toEqual('FakeMyTasks1'); + expect(component.filters[2].name).toEqual('FakeMyTasks2'); + done(); + }); + }); + + it('should select the first filter as default', async(() => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); + + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + + fixture.detectChanges(); + component.ngOnChanges({ 'appName': change }); + + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.currentFilter).toBeDefined(); + expect(component.currentFilter.name).toEqual('FakeInvolvedTasks'); + }); + + })); + + it('should be able to fetch and select the default filters if the input filter is not valid', (done) => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(from(fakeGlobalEmptyFilterPromise)); + spyOn(component, 'createFilters').and.callThrough(); + + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + component.ngOnChanges({ 'appName': change }); + + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.createFilters).not.toHaveBeenCalled(); + done(); + }); + }); + + it('should select the task filter based on the input by name param', async(() => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); + + component.filterParam = new FilterRepresentationModel({ name: 'FakeMyTasks1' }); + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + + fixture.detectChanges(); + component.ngOnChanges({ 'appName': change }); + + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.currentFilter).toBeDefined(); + expect(component.currentFilter.name).toEqual('FakeMyTasks1'); + }); + + })); + + it('should select the default task filter if filter input does not exist', async(() => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); + + component.filterParam = new FilterRepresentationModel({ name: 'UnexistableFilter' }); + + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + + fixture.detectChanges(); + component.ngOnChanges({ 'appName': change }); + + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.currentFilter).toBeDefined(); + expect(component.currentFilter.name).toEqual('FakeInvolvedTasks'); + }); + + })); + + it('should select the task filter based on the input by index param', async(() => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); + + component.filterParam = new FilterRepresentationModel({ index: 2 }); + + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + + fixture.detectChanges(); + component.ngOnChanges({ 'appName': change }); + + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.currentFilter).toBeDefined(); + expect(component.currentFilter.name).toEqual('FakeMyTasks2'); + }); + + })); + + it('should select the task filter based on the input by id param', async(() => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); + + component.filterParam = new FilterRepresentationModel({ id: 12 }); + + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + + fixture.detectChanges(); + component.ngOnChanges({ 'appName': change }); + + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.currentFilter).toBeDefined(); + expect(component.currentFilter.name).toEqual('FakeMyTasks2'); + }); + + })); + + it('should emit an event when a filter is selected', async(() => { + spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); + + component.filterParam = new FilterRepresentationModel({ id: 12 }); + + const appName = 'my-app-1'; + let change = new SimpleChange(null, appName, true); + component.ngOnChanges({ 'appName': change }); + + fixture.detectChanges(); + spyOn(component, 'selectFilterAndEmit').and.stub(); + let filterButton = fixture.debugElement.nativeElement.querySelector('span[data-automation-id="FakeMyTasks1_filter"]'); + filterButton.click(); + expect(component.selectFilterAndEmit).toHaveBeenCalledWith(fakeGlobalFilter[1]); + })); + + it('should reload filters by appName on binding changes', () => { + spyOn(component, 'getFilters').and.stub(); + const appName = 'my-app-1'; + + let change = new SimpleChange(null, appName, true); + component.ngOnChanges({ 'appName': change }); + + expect(component.getFilters).toHaveBeenCalledWith(appName); + }); + + it('should not reload filters by appName null on binding changes', () => { + spyOn(component, 'getFilters').and.stub(); + const appName = null; + + let change = new SimpleChange(undefined, appName, true); + component.ngOnChanges({ 'appName': change }); + + expect(component.getFilters).not.toHaveBeenCalledWith(appName); + }); + + it('should change current filter when filterParam (name) changes', () => { + component.filters = fakeGlobalFilter; + component.currentFilter = null; + + fixture.whenStable().then(() => { + expect(component.currentFilter.name).toEqual(fakeGlobalFilter[2].name); + }); + + const change = new SimpleChange(null, { name: fakeGlobalFilter[2].name }, true); + component.ngOnChanges({ 'filterParam': change }); + }); + + it('should reload filters by app name on binding changes', () => { + spyOn(component, 'getFilters').and.stub(); + const appName = 'fake-app-name'; + + let change = new SimpleChange(null, appName, true); + component.ngOnChanges({ 'appName': change }); + + expect(component.getFilters).toHaveBeenCalledWith(appName); + }); + + it('should return the current filter after one is selected', () => { + let filter = fakeGlobalFilter[1]; + component.filters = fakeGlobalFilter; + + expect(component.currentFilter).toBeUndefined(); + component.selectFilter(filter); + expect(component.getCurrentFilter()).toBe(filter); + }); +}); diff --git a/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.ts new file mode 100644 index 0000000000..979727a431 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-cloud/task-filters-cloud/task-filters-cloud.component.ts @@ -0,0 +1,156 @@ +/*! + * @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, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; +import { Observable } from 'rxjs'; +import { TaskFilterCloudService } from '../services/task-filter-cloud.service'; +import { FilterRepresentationModel } from '../models/filter-cloud.model'; +@Component({ + selector: 'adf-cloud-task-filters', + templateUrl: './task-filters-cloud.component.html', + styleUrls: ['task-filters-cloud.component.scss'] +}) +export class TaskFiltersCloudComponent implements OnChanges { + + @Input() + appName: string; + + @Input() + filterParam: FilterRepresentationModel; + + @Input() + showIcons: boolean = false; + + @Output() + filterClick: EventEmitter = new EventEmitter(); + + @Output() + success: EventEmitter = new EventEmitter(); + + @Output() + error: EventEmitter = new EventEmitter(); + + filters$: Observable; + + currentFilter: FilterRepresentationModel; + + filters: FilterRepresentationModel [] = []; + + constructor(private taskFilterCloudService: TaskFilterCloudService) { + } + + ngOnChanges(changes: SimpleChanges) { + const appName = changes['appName']; + const filter = changes['filterParam']; + if (appName && appName.currentValue) { + this.getFilters(appName.currentValue); + } else if (filter && filter.currentValue !== filter.previousValue) { + this.selectFilter(filter.currentValue); + } + } + + /** + * Return the filter list filtered by appName + */ + getFilters(appName: string) { + this.filters$ = this.taskFilterCloudService.getTaskListFilters(appName); + + this.filters$.subscribe( + (res: FilterRepresentationModel[]) => { + if (res.length === 0) { + this.createFilters(appName); + } else { + this.resetFilter(); + this.filters = res; + } + this.selectFilterAndEmit(this.filterParam); + this.success.emit(res); + }, + (err: any) => { + this.error.emit(err); + } + ); + } + + /** + * Create default filters by appId + */ + createFilters(appName?: string) { + this.filters$ = this.taskFilterCloudService.createDefaultFilters(appName); + + this.filters$.subscribe( + (resDefault: FilterRepresentationModel[]) => { + this.resetFilter(); + this.filters = resDefault; + }, + (errDefault: any) => { + this.error.emit(errDefault); + } + ); + } + + /** + * Pass the selected filter as next + */ + public selectFilter(newFilter: FilterRepresentationModel) { + if (newFilter) { + this.currentFilter = this.filters.find((filter) => + (newFilter.name && + (newFilter.name.toLocaleLowerCase() === filter.name.toLocaleLowerCase()) + )); + } + if (!this.currentFilter) { + this.selectDefaultTaskFilter(); + } + } + + public selectFilterAndEmit(newFilter: FilterRepresentationModel) { + this.selectFilter(newFilter); + this.filterClick.emit(this.currentFilter); + } + + /** + * Select as default task filter the first in the list + */ + public selectDefaultTaskFilter() { + if (!this.isFilterListEmpty()) { + this.currentFilter = this.filters[0]; + } + } + + /** + * Return the current task + */ + getCurrentFilter(): FilterRepresentationModel { + return this.currentFilter; + } + + /** + * Check if the filter list is empty + */ + isFilterListEmpty(): boolean { + return this.filters === undefined || (this.filters && this.filters.length === 0); + } + + /** + * Reset the filters properties + */ + private resetFilter() { + this.filters = []; + this.currentFilter = undefined; + } +} diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.css b/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.css new file mode 100644 index 0000000000..0f285da50b --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.css @@ -0,0 +1,4 @@ +.adf-cloud-task-list-loading-margin { + margin-left: calc((100% - 100px) / 2); + margin-right: calc((100% - 100px) / 2); +} diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.html b/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.html new file mode 100644 index 0000000000..34119d1314 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.html @@ -0,0 +1,33 @@ +
{{ 'ADF_TASK_LIST.FILTERS.MESSAGES.NONE' | translate }}
+ + + + + + + + + + + + + + + + + + diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.spec.ts new file mode 100644 index 0000000000..a3416b8dba --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.spec.ts @@ -0,0 +1,312 @@ +/*! + * @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, SimpleChange, ViewChild, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { AppConfigService, setupTestBed, CoreModule } from '@alfresco/adf-core'; +import { DataRowEvent, ObjectDataRow } from '@alfresco/adf-core'; +import { TaskListCloudService } from '../services/task-list-cloud.service'; +import { TaskListCloudComponent } from './task-list-cloud.component'; +import { fakeGlobalTask, fakeCustomSchema, fakeTaskCloudList } from '../mock/fakeTaskResponseMock'; +import { of } from 'rxjs'; +import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; +import { TaskListCloudModule } from '../task-list-cloud.module'; +@Component({ + template: ` + + + + + + +
{{getFullName(entry.row.obj.startedBy)}}
+
+
+
+
` +}) +class CustomTaskListComponent { + @ViewChild(TaskListCloudComponent) + taskList: TaskListCloudComponent; +} +@Component({ + template: ` + + +

+
+
+ ` +}) +class EmptyTemplateComponent { +} +describe('TaskListCloudComponent', () => { + let component: TaskListCloudComponent; + let fixture: ComponentFixture; + let appConfig: AppConfigService; + let taskListCloudService: TaskListCloudService; + + setupTestBed({ + imports: [ + ProcessServiceCloudTestingModule, TaskListCloudModule + ], + providers: [TaskListCloudService] + }); + + beforeEach(() => { + appConfig = TestBed.get(AppConfigService); + taskListCloudService = TestBed.get(TaskListCloudService); + fixture = TestBed.createComponent(TaskListCloudComponent); + component = fixture.componentInstance; + appConfig.config = Object.assign(appConfig.config, { + 'adf-cloud-task-list': { + 'presets': { + 'fakeCustomSchema': [ + { + 'key': 'fakeName', + 'type': 'text', + 'title': 'ADF_TASK_LIST.PROPERTIES.FAKE', + 'sortable': true + }, + { + 'key': 'fakeTaskName', + 'type': 'text', + 'title': 'ADF_TASK_LIST.PROPERTIES.TASK_FAKE', + 'sortable': true + } + ] + } + } + }); + }); + + afterEach(() => { + fixture.destroy(); + }); + + it('should use the default schemaColumn as default', () => { + component.ngAfterContentInit(); + expect(component.columns).toBeDefined(); + expect(component.columns.length).toEqual(3); + }); + + it('should use the custom schemaColumn from app.config.json', () => { + component.presetColumn = 'fakeCustomSchema'; + component.ngAfterContentInit(); + fixture.detectChanges(); + expect(component.columns).toEqual(fakeCustomSchema); + }); + + it('should fetch custom schemaColumn when the input presetColumn is defined', () => { + component.presetColumn = 'fakeCustomSchema'; + fixture.detectChanges(); + expect(component.columns).toBeDefined(); + expect(component.columns.length).toEqual(2); + }); + + it('should return an empty task list when no input parameters are passed', () => { + component.ngAfterContentInit(); + expect(component.rows).toBeDefined(); + expect(component.isListEmpty()).toBeTruthy(); + }); + + it('should return the results if an application name is given', (done) => { + spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTask)); + let appName = new SimpleChange(null, 'FAKE-APP-NAME', true); + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.rows).toBeDefined(); + expect(component.isListEmpty()).not.toBeTruthy(); + expect(component.rows.length).toEqual(1); + expect(component.rows[0].entry['serviceName']).toEqual('test-ciprian2-rb'); + expect(component.rows[0].entry['serviceFullName']).toEqual('test-ciprian2-rb'); + expect(component.rows[0].entry['serviceVersion']).toBe(''); + expect(component.rows[0].entry['appName']).toBe('test-ciprian2'); + expect(component.rows[0].entry['appVersion']).toBe(''); + expect(component.rows[0].entry['serviceType']).toBeNull(); + expect(component.rows[0].entry['id']).toBe('11fe013d-c263-11e8-b75b-0a5864600540'); + expect(component.rows[0].entry['assignee']).toBeNull(); + expect(component.rows[0].entry['name']).toEqual('standalone-subtask'); + expect(component.rows[0].entry['description']).toBeNull(); + expect(component.rows[0].entry['createdDate']).toBe(1538059139420); + expect(component.rows[0].entry['dueDate']).toBeNull(); + expect(component.rows[0].entry['claimedDate']).toBeNull(); + expect(component.rows[0].entry['priority']).toBe(0); + expect(component.rows[0].entry['category']).toBeNull(); + expect(component.rows[0].entry['processDefinitionId']).toBeNull(); + expect(component.rows[0].entry['processInstanceId']).toBeNull(); + expect(component.rows[0].entry['status']).toBe('CREATED'); + expect(component.rows[0].entry['owner']).toBe('devopsuser'); + expect(component.rows[0].entry['parentTaskId']).toBe('71fda20b-c25b-11e8-b75b-0a5864600540'); + expect(component.rows[0].entry['lastModified']).toBe(1538059139420); + expect(component.rows[0].entry['lastModifiedTo']).toBeNull(); + expect(component.rows[0].entry['lastModifiedFrom']).toBeNull(); + expect(component.rows[0].entry['standAlone']).toBeTruthy(); + done(); + }); + component.applicationName = appName.currentValue; + component.ngOnChanges({ 'appName': appName }); + fixture.detectChanges(); + }); + + it('should return a currentId null when the taskList is empty', () => { + component.selectTask(null); + expect(component.getCurrentId()).toBeNull(); + }); + + it('should return selected id for the selected task', () => { + component.rows = [ + { entry: { id: '999', name: 'Fake-name' } }, + { entry: { id: '888', name: 'Fake-name-888' } } + ]; + component.selectTask('888'); + expect(component.rows).toBeDefined(); + expect(component.currentInstanceId).toEqual('888'); + }); + + it('should reload tasks when reload() is called', (done) => { + component.applicationName = 'fake'; + spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTask)); + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.rows).toBeDefined(); + expect(component.isListEmpty()).not.toBeTruthy(); + done(); + }); + fixture.detectChanges(); + component.reload(); + }); + + it('should emit row click event', (done) => { + let row = new ObjectDataRow({ + entry: { + id: '999' + } + }); + let rowEvent = new DataRowEvent(row, null); + component.rowClick.subscribe(taskId => { + expect(taskId).toEqual('999'); + expect(component.getCurrentId()).toEqual('999'); + done(); + }); + component.onRowClick(rowEvent); + }); + + describe('component changes', () => { + + beforeEach(() => { + component.rows = fakeGlobalTask.list.entries; + fixture.detectChanges(); + }); + + it('should NOT reload the tasks if the landingTaskId is the same of the current task', () => { + spyOn(component, 'reload').and.stub(); + component.currentInstanceId = '999'; + component.rows = [{ entry: { id: '999', name: 'Fake-name' } }]; + const landingTaskId = '999'; + let change = new SimpleChange('999', landingTaskId, true); + component.ngOnChanges({ 'landingTaskId': change }); + expect(component.reload).not.toHaveBeenCalled(); + expect(component.rows.length).toEqual(1); + }); + + it('should reload the tasks if the loadingTaskId is different from the current task', (done) => { + component.currentInstanceId = '999'; + component.rows = [{ id: '999', name: 'Fake-name' }]; + const landingTaskId = '888'; + let change = new SimpleChange(null, landingTaskId, true); + component.applicationName = 'fake'; + spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeTaskCloudList)); + component.success.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.rows).toBeDefined(); + expect(component.rows.length).toEqual(2); + done(); + }); + component.ngOnChanges({ 'landingTaskId': change }); + }); + + it('should NOT reload the task list when no parameters changed', () => { + component.rows = null; + component.ngOnChanges({}); + fixture.detectChanges(); + expect(component.isListEmpty()).toBeTruthy(); + }); + }); + + describe('Injecting custom colums for tasklist - CustomTaskListComponent', () => { + let fixtureCustom: ComponentFixture; + let componentCustom: CustomTaskListComponent; + + setupTestBed({ + imports: [CoreModule.forRoot()], + declarations: [TaskListCloudComponent, CustomTaskListComponent], + providers: [TaskListCloudService] + }); + + beforeEach(() => { + fixtureCustom = TestBed.createComponent(CustomTaskListComponent); + fixtureCustom.detectChanges(); + componentCustom = fixtureCustom.componentInstance; + }); + + afterEach(() => { + fixtureCustom.destroy(); + }); + + it('should create instance of CustomTaskListComponent', () => { + expect(componentCustom instanceof CustomTaskListComponent).toBe(true, 'should create CustomTaskListComponent'); + }); + + it('should fetch custom schemaColumn from html', () => { + fixture.detectChanges(); + expect(componentCustom.taskList.columnList).toBeDefined(); + expect(componentCustom.taskList.columns[0]['title']).toEqual('ADF_TASK_LIST.PROPERTIES.NAME'); + expect(componentCustom.taskList.columns[1]['title']).toEqual('ADF_TASK_LIST.PROPERTIES.CREATED'); + expect(componentCustom.taskList.columns.length).toEqual(3); + }); + + }); + + describe('Creating an empty custom template - EmptyTemplateComponent', () => { + let fixtureEmpty: ComponentFixture; + + setupTestBed({ + imports: [ProcessServiceCloudTestingModule, TaskListCloudModule], + declarations: [EmptyTemplateComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }); + + beforeEach(() => { + fixtureEmpty = TestBed.createComponent(EmptyTemplateComponent); + fixtureEmpty.detectChanges(); + }); + + afterEach(() => { + fixtureEmpty.destroy(); + }); + + it('should render the custom template', async(() => { + fixtureEmpty.whenStable().then(() => { + fixtureEmpty.detectChanges(); + expect(fixtureEmpty.debugElement.query(By.css('#custom-id'))).not.toBeNull(); + expect(fixtureEmpty.debugElement.query(By.css('.adf-empty-content'))).toBeNull(); + }); + })); + }); +}); diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.ts b/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.ts new file mode 100644 index 0000000000..8958de402d --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/components/task-list-cloud.component.ts @@ -0,0 +1,260 @@ +/*! + * @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, ViewEncapsulation, OnChanges, Input, SimpleChanges, Output, EventEmitter, ContentChild, AfterContentInit, SimpleChange } from '@angular/core'; +import { AppConfigService, UserPreferencesService, + DataTableSchema, UserPreferenceValues, + PaginatedComponent, PaginationModel, + DataRowEvent, EmptyCustomContentDirective } from '@alfresco/adf-core'; +import { taskPresetsCloudDefaultModel } from '../models/task-preset-cloud.model'; +import { TaskQueryCloudRequestModel } from '../models/filter-cloud-model'; +import { BehaviorSubject } from 'rxjs'; +import { TaskListCloudService } from '../services/task-list-cloud.service'; +import { MinimalNodeEntity } from 'alfresco-js-api'; +import { TaskListCloudSortingModel } from '../models/task-list-sorting.model'; + +@Component({ + selector: 'adf-cloud-task-list', + templateUrl: './task-list-cloud.component.html', + styleUrls: ['./task-list-cloud.component.css'], + encapsulation: ViewEncapsulation.None +}) + +export class TaskListCloudComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent { + + static PRESET_KEY = 'adf-cloud-task-list.presets'; + + @ContentChild(EmptyCustomContentDirective) + emptyCustomContent: EmptyCustomContentDirective; + + @Input() + applicationName: string = ''; + + @Input() + assignee: string = ''; + + @Input() + createdDate: string = ''; + + @Input() + dueDate: string = ''; + + @Input() + id: string = ''; + + @Input() + name: string = ''; + + @Input() + parentTaskId: string = ''; + + @Input() + processDefinitionId: string = ''; + + @Input() + processInstanceId: string = ''; + + @Input() + status: string = ''; + + @Input() + selectFirstRow: boolean = true; + + @Input() + landingTaskId: string; + + @Input() + selectionMode: string = 'single'; // none|single|multiple + + /** Toggles multiple row selection, renders checkboxes at the beginning of each row */ + @Input() + multiselect: boolean = false; + + @Input() + sorting: TaskListCloudSortingModel[]; + + /** Emitted when a task in the list is clicked */ + @Output() + rowClick: EventEmitter = new EventEmitter(); + + /** Emitted when rows are selected/unselected */ + @Output() + rowsSelected: EventEmitter = new EventEmitter(); + + /** Emitted when the task list is loaded */ + @Output() + success: EventEmitter = new EventEmitter(); + + /** Emitted when an error occurs. */ + @Output() + error: EventEmitter = new EventEmitter(); + + pagination: BehaviorSubject; + + requestNode: TaskQueryCloudRequestModel; + rows: any[] = []; + size: number; + skipCount: number = 0; + currentInstanceId: any; + isLoading = false; + selectedInstances: any[]; + + constructor(private taskListCloudService: TaskListCloudService, + appConfigService: AppConfigService, + private userPreferences: UserPreferencesService) { + super(appConfigService, TaskListCloudComponent.PRESET_KEY, taskPresetsCloudDefaultModel); + this.size = userPreferences.paginationSize; + this.userPreferences.select(UserPreferenceValues.PaginationSize).subscribe((pageSize) => { + this.size = pageSize; + }); + + this.pagination = new BehaviorSubject( { + maxItems: this.size, + skipCount: 0, + totalItems: 0 + }); + + } + + ngOnChanges(changes: SimpleChanges) { + if (this.isPropertyChanged(changes) && + !this.isEqualToCurrentId(changes['landingTaskId'])) { + this.reload(); + } + } + + ngAfterContentInit() { + this.createDatatableSchema(); + } + + getCurrentId(): string { + return this.currentInstanceId; + } + + isEqualToCurrentId(landingTaskChanged: SimpleChange): boolean { + return landingTaskChanged && this.currentInstanceId === landingTaskChanged.currentValue; + } + + private isPropertyChanged(changes: SimpleChanges): boolean { + for (let property in changes) { + if (changes.hasOwnProperty(property)) { + if (changes[property] && + (changes[property].currentValue !== changes[property].previousValue)) { + return true; + } + } + } + return false; + } + + reload() { + this.requestNode = this.createRequestNode(); + if (this.requestNode.appName) { + this.load(this.requestNode); + } else { + this.rows = []; + } + } + + private load(requestNode: TaskQueryCloudRequestModel) { + this.isLoading = true; + this.taskListCloudService.getTaskByRequest(requestNode).subscribe( + (tasks) => { + this.rows = tasks.list.entries; + this.selectTask(this.landingTaskId); + this.success.emit(tasks); + this.isLoading = false; + this.pagination.next(tasks.list.pagination); + }, (error) => { + this.error.emit(error); + this.isLoading = false; + }); + } + + selectTask(taskIdSelected: string) { + if (!this.isListEmpty()) { + let dataRow: any = null; + if (taskIdSelected) { + dataRow = this.rows.find((currentRow: MinimalNodeEntity) => { + return currentRow.entry.id === taskIdSelected; + }); + } + if (!dataRow && this.selectFirstRow) { + dataRow = this.rows[0]; + } + if (dataRow) { + dataRow.isSelected = true; + this.currentInstanceId = dataRow.entry.id; + } + } else { + this.currentInstanceId = null; + } + } + + isListEmpty(): boolean { + return !this.rows || this.rows.length === 0; + } + + updatePagination(pagination: PaginationModel) { + this.size = pagination.maxItems; + this.skipCount = pagination.skipCount; + this.pagination.next(pagination); + this.reload(); + } + + onRowClick(item: DataRowEvent) { + this.currentInstanceId = item.value.getValue('entry.id'); + this.rowClick.emit(this.currentInstanceId); + } + + onRowSelect(event: CustomEvent) { + this.selectedInstances = [...event.detail.selection]; + this.rowsSelected.emit(this.selectedInstances); + } + + onRowUnselect(event: CustomEvent) { + this.selectedInstances = [...event.detail.selection]; + this.rowsSelected.emit(this.selectedInstances); + } + + onRowKeyUp(event: CustomEvent) { + if (event.detail.keyboardEvent.key === 'Enter') { + event.preventDefault(); + this.currentInstanceId = event.detail.row.getValue('entry.id'); + this.rowClick.emit(this.currentInstanceId); + } + } + + private createRequestNode() { + + let requestNode = { + appName: this.applicationName, + assignee: this.assignee, + id: this.id, + name: this.name, + parentTaskId: this.parentTaskId, + processDefinitionId: this.processDefinitionId, + processInstanceId: this.processInstanceId, + status: this.status, + maxItems: this.size, + skipCount: this.skipCount, + sorting: this.sorting + }; + return new TaskQueryCloudRequestModel(requestNode); + } + +} diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/mock/fakeTaskResponseMock.ts b/lib/process-services-cloud/src/lib/task-list-cloud/mock/fakeTaskResponseMock.ts new file mode 100644 index 0000000000..f31c013aca --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/mock/fakeTaskResponseMock.ts @@ -0,0 +1,145 @@ +/*! + * @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 { ObjectDataColumn } from '@alfresco/adf-core'; + +export const fakeTaskCloudList = { + list: { + entries: [ + { + entry: { + serviceName: 'maurizio-test-rb', + serviceFullName: 'maurizio-test-rb', + serviceVersion: '', + appName: 'save-the-cheerleader', + appVersion: '', + serviceType: null, + id: '890b0e1c-c252-11e8-b5c5-0a58646004c7', + assignee: null, + name: 'SimpleStandaloneTask', + description: 'Task description', + createdDate: 1538052037711, + dueDate: null, + claimedDate: null, + priority: 0, + category: null, + processDefinitionId: null, + processInstanceId: null, + status: 'CREATED', + owner: 'superadminuser', + parentTaskId: null, + lastModified: 1538052037711, + lastModifiedTo: null, + lastModifiedFrom: null, + standAlone: true + } + }, + { + entry: { + serviceName: 'maurizio-test-rb', + serviceFullName: 'maurizio-test-rb', + serviceVersion: '', + appName: 'save-the-cheerleader', + appVersion: '', + serviceType: null, + id: '8962cb0e-c252-11e8-b5c5-0a58646004c7', + assignee: null, + name: 'SimpleStandaloneTask', + description: 'Task description', + createdDate: 1538052038286, + dueDate: null, + claimedDate: null, + priority: 0, + category: null, + processDefinitionId: null, + processInstanceId: null, + status: 'CREATED', + owner: 'superadminuser', + parentTaskId: null, + lastModified: 1538052038286, + lastModifiedTo: null, + lastModifiedFrom: null, + standAlone: true + } + } + ], + pagination: { + skipCount: 0, + maxItems: 100, + count: 2, + hasMoreItems: false, + totalItems: 2 + } + } +}; + +export let fakeGlobalTask = { + list: { + entries: [ + { + entry: { + serviceName: 'test-ciprian2-rb', + serviceFullName: 'test-ciprian2-rb', + serviceVersion: '', + appName: 'test-ciprian2', + appVersion: '', + serviceType: null, + id: '11fe013d-c263-11e8-b75b-0a5864600540', + assignee: null, + name: 'standalone-subtask', + description: null, + createdDate: 1538059139420, + dueDate: null, + claimedDate: null, + priority: 0, + category: null, + processDefinitionId: null, + processInstanceId: null, + status: 'CREATED', + owner: 'devopsuser', + parentTaskId: '71fda20b-c25b-11e8-b75b-0a5864600540', + lastModified: 1538059139420, + lastModifiedTo: null, + lastModifiedFrom: null, + standAlone: true + } + } + ], + pagination: { + skipCount: 0, + maxItems: 100, + count: 1, + hasMoreItems: false, + totalItems: 1 + } + } +}; + +export let fakeCustomSchema = + [ + new ObjectDataColumn({ + 'key': 'fakeName', + 'type': 'text', + 'title': 'ADF_TASK_LIST.PROPERTIES.FAKE', + 'sortable': true + }), + new ObjectDataColumn({ + 'key': 'fakeTaskName', + 'type': 'text', + 'title': 'ADF_TASK_LIST.PROPERTIES.TASK_FAKE', + 'sortable': true + }) + ]; diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/models/filter-cloud-model.ts b/lib/process-services-cloud/src/lib/task-list-cloud/models/filter-cloud-model.ts new file mode 100644 index 0000000000..78896c6e31 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/models/filter-cloud-model.ts @@ -0,0 +1,70 @@ +/*! + * @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 { TaskListCloudSortingModel } from './task-list-sorting.model'; + +export class TaskQueryCloudRequestModel { + appName: string; + appVersion?: string; + assignee?: string; + claimedDate?: string; + createdDate?: Date; + description?: string; + dueDate?: null; + id?: string; + name?: string; + owner?: string; + parentTaskId?: string; + priority?: number; + processDefinitionId?: string; + processInstanceId?: string; + serviceFullName?: string; + serviceName?: string; + serviceType?: string; + serviceVersion?: string; + status?: string; + maxItems: number; + skipCount: number; + sorting?: TaskListCloudSortingModel[]; + + constructor(obj?: any) { + if (obj) { + this.appName = obj.appName; + this.appVersion = obj.appVersion; + this.assignee = obj.assignee; + this.claimedDate = obj.claimedDate; + this.createdDate = obj.createdDate; + this.description = obj.description; + this.dueDate = obj.dueDate; + this.id = obj.id; + this.name = obj.name; + this.owner = obj.owner; + this.parentTaskId = obj.parentTaskId; + this.priority = obj.priority; + this.processDefinitionId = obj.processDefinitionId; + this.processInstanceId = obj.processInstanceId; + this.serviceFullName = obj.serviceFullName; + this.serviceName = obj.serviceName; + this.serviceType = obj.serviceType; + this.serviceVersion = obj.serviceVersion; + this.status = obj.status; + this.maxItems = obj.maxItems; + this.skipCount = obj.skipCount; + this.sorting = obj.sorting; + } + } +} diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/models/task-list-sorting.model.ts b/lib/process-services-cloud/src/lib/task-list-cloud/models/task-list-sorting.model.ts new file mode 100644 index 0000000000..1436fb4576 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/models/task-list-sorting.model.ts @@ -0,0 +1,28 @@ +/*! + * @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 class TaskListCloudSortingModel { + orderBy: string; + direction: string; + + constructor(obj: any) { + if (obj) { + this.orderBy = obj.orderBy; + this.direction = obj.direction; + } + } +} diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/models/task-preset-cloud.model.ts b/lib/process-services-cloud/src/lib/task-list-cloud/models/task-preset-cloud.model.ts new file mode 100644 index 0000000000..4ff82490b5 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/models/task-preset-cloud.model.ts @@ -0,0 +1,41 @@ +/*! + * @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 taskPresetsCloudDefaultModel = { + 'default': [ + { + 'key': 'name', + 'type': 'text', + 'title': 'ADF_TASK_LIST.PROPERTIES.NAME', + 'sortable': true + }, + { + 'key': 'created', + 'type': 'text', + 'title': 'ADF_TASK_LIST.PROPERTIES.CREATED', + 'cssClass': 'hidden', + 'sortable': true + }, + { + 'key': 'assignee', + 'type': 'text', + 'title': 'ADF_TASK_LIST.PROPERTIES.ASSIGNEE', + 'cssClass': 'hidden', + 'sortable': true + } + ] +}; diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/public-api.ts b/lib/process-services-cloud/src/lib/task-list-cloud/public-api.ts new file mode 100644 index 0000000000..a47e80792d --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/public-api.ts @@ -0,0 +1,24 @@ +/*! + * @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 * from './components/task-list-cloud.component'; + +export * from './models/filter-cloud-model'; +export * from './models/task-list-sorting.model'; +export * from './models/task-preset-cloud.model'; + +export * from './task-list-cloud.module'; diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/services/task-list-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/task-list-cloud/services/task-list-cloud.service.spec.ts new file mode 100644 index 0000000000..6861c9a6fb --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/services/task-list-cloud.service.spec.ts @@ -0,0 +1,134 @@ +/*! + * @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 { async } from '@angular/core/testing'; +import { setupTestBed } from '@alfresco/adf-core'; +import { fakeTaskCloudList } from '../mock/fakeTaskResponseMock'; +import { AlfrescoApiServiceMock, LogService, AppConfigService, StorageService, CoreModule } from '@alfresco/adf-core'; +import { TaskListCloudService } from './task-list-cloud.service'; +import { TaskQueryCloudRequestModel } from '../models/filter-cloud-model'; + +describe('Activiti TaskList Cloud Service', () => { + + let service: TaskListCloudService; + let alfrescoApiMock: AlfrescoApiServiceMock; + + function returFakeTaskListResults() { + return { + oauth2Auth: { + callCustomApi : () => { + return Promise.resolve(fakeTaskCloudList); + } + } + }; + } + + function returnCallQueryParameters() { + return { + oauth2Auth: { + callCustomApi : (queryUrl, operation, context, queryParams) => { + return Promise.resolve(queryParams); + } + } + }; + } + + function returnCallUrl() { + return { + oauth2Auth: { + callCustomApi : (queryUrl, operation, context, queryParams) => { + return Promise.resolve(queryUrl); + } + } + }; + } + + setupTestBed({ + imports: [ + CoreModule.forRoot() + ] + }); + + beforeEach(async(() => { + alfrescoApiMock = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService() ); + service = new TaskListCloudService(alfrescoApiMock, + new AppConfigService(null), + new LogService(new AppConfigService(null))); + })); + + it('should return the tasks', (done) => { + let taskRequest: TaskQueryCloudRequestModel = { appName: 'fakeName' }; + spyOn(alfrescoApiMock, 'getInstance').and.callFake(returFakeTaskListResults); + service.getTaskByRequest(taskRequest).subscribe((res) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.list.entries.length).toBe(2); + expect(res.list.entries[0].entry.appName).toBe('save-the-cheerleader'); + expect(res.list.entries[1].entry.appName).toBe('save-the-cheerleader'); + done(); + }); + }); + + it('should append to the call all the parameters', (done) => { + let taskRequest: TaskQueryCloudRequestModel = { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service' }; + spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallQueryParameters); + service.getTaskByRequest(taskRequest).subscribe((res) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.skipCount).toBe(0); + expect(res.maxItems).toBe(20); + expect(res.service).toBe('fake-service'); + done(); + }); + }); + + it('should concat the app name to the request url', (done) => { + let taskRequest: TaskQueryCloudRequestModel = { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service' }; + spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallUrl); + service.getTaskByRequest(taskRequest).subscribe((requestUrl) => { + expect(requestUrl).toBeDefined(); + expect(requestUrl).not.toBeNull(); + expect(requestUrl).toContain('/fakeName-query/v1/tasks'); + done(); + }); + }); + + it('should concat the sorting to append as parameters', (done) => { + let taskRequest: TaskQueryCloudRequestModel = { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service', + sorting: [{ orderBy: 'NAME', direction: 'DESC'}, { orderBy: 'TITLE', direction: 'ASC'}] }; + spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallQueryParameters); + service.getTaskByRequest(taskRequest).subscribe((res) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.sort).toBe('NAME,DESC&TITLE,ASC'); + done(); + }); + }); + + it('should return an error when app name is not specified', (done) => { + let taskRequest: TaskQueryCloudRequestModel = { appName: null }; + spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallUrl); + service.getTaskByRequest(taskRequest).subscribe( + () => { }, + (error) => { + expect(error).toBe('Appname not configured'); + done(); + } + ); + }); + +}); diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/services/task-list-cloud.service.ts b/lib/process-services-cloud/src/lib/task-list-cloud/services/task-list-cloud.service.ts new file mode 100644 index 0000000000..ddfb7460f8 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/services/task-list-cloud.service.ts @@ -0,0 +1,92 @@ +/*! + * @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 { Injectable } from '@angular/core'; +import { AlfrescoApiService, AppConfigService, LogService } from '@alfresco/adf-core'; +import { TaskQueryCloudRequestModel } from '../models/filter-cloud-model'; +import { Observable, from, throwError } from 'rxjs'; +import { TaskListCloudSortingModel } from '../models/task-list-sorting.model'; + +@Injectable() +export class TaskListCloudService { + + constructor(private apiService: AlfrescoApiService, + private appConfigService: AppConfigService, + private logService: LogService) { + } + + contentTypes = ['application/json']; + accepts = ['application/json']; + + getTaskByRequest(requestNode: TaskQueryCloudRequestModel): Observable { + if (requestNode.appName) { + let queryUrl = this.buildQueryUrl(requestNode); + let queryParams = this.buildQueryParams(requestNode); + let sortingParams = this.buildSortingParam(requestNode.sorting); + if (sortingParams) { + queryParams['sort'] = sortingParams; + } + return from(this.apiService.getInstance() + .oauth2Auth.callCustomApi(queryUrl, 'GET', + null, queryParams, null, + null, null, null, ['application/json'], + ['application/json'], Object, null, null) + ); + } else { + this.logService.error('Appname is mandatory for querying task'); + return throwError('Appname not configured'); + } + } + + private buildQueryUrl(requestNode: TaskQueryCloudRequestModel) { + return `${this.appConfigService.get('bpmHost', '')}/${requestNode.appName}-query/v1/tasks`; + } + + private buildQueryParams(requestNode: TaskQueryCloudRequestModel) { + let queryParam = {}; + for (let property in requestNode) { + if (requestNode.hasOwnProperty(property) && + !this.isExcludedField(property) && + this.isPropertyValueValid(requestNode, property)) { + queryParam[property] = requestNode[property]; + } + } + return queryParam; + } + + private isExcludedField(property) { + return property === 'appName' || property === 'sorting'; + } + + private isPropertyValueValid(requestNode, property) { + return requestNode[property] !== '' && requestNode[property] !== null && requestNode[property] !== undefined; + } + + private buildSortingParam(sortings: TaskListCloudSortingModel[]): string { + let finalSorting: string = ''; + if (sortings) { + for (let sort of sortings) { + if (!finalSorting) { + finalSorting = `${sort.orderBy},${sort.direction}`; + } else { + finalSorting = `${finalSorting}&${sort.orderBy},${sort.direction}`; + } + } + } + return encodeURI(finalSorting); + } +} diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/task-list-cloud.module.spec.ts b/lib/process-services-cloud/src/lib/task-list-cloud/task-list-cloud.module.spec.ts new file mode 100644 index 0000000000..f652f24229 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/task-list-cloud.module.spec.ts @@ -0,0 +1,13 @@ +import { TaskListCloudModule } from './task-list-cloud.module'; + +describe('TaskListCloudModule', () => { + let taskListCloudModule: TaskListCloudModule; + + beforeEach(() => { + taskListCloudModule = new TaskListCloudModule(); + }); + + it('should create an instance', () => { + expect(taskListCloudModule).toBeTruthy(); + }); +}); diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/task-list-cloud.module.ts b/lib/process-services-cloud/src/lib/task-list-cloud/task-list-cloud.module.ts new file mode 100644 index 0000000000..3136cca8b2 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/task-list-cloud.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MaterialModule } from '../material.module'; +import { TaskListCloudComponent } from './components/task-list-cloud.component'; +import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; +import { TranslateLoaderService, DataTableModule, TemplateModule } from '@alfresco/adf-core'; +import { TaskListCloudService } from './services/task-list-cloud.service'; + +@NgModule({ + imports: [ + CommonModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderService + } + }), + MaterialModule, + DataTableModule, + TemplateModule + ], + declarations: [TaskListCloudComponent], + exports: [TaskListCloudComponent], + providers: [TaskListCloudService] +}) +export class TaskListCloudModule { } diff --git a/lib/process-services-cloud/src/lib/task-list-cloud/testing/task-list.testing.module.ts b/lib/process-services-cloud/src/lib/task-list-cloud/testing/task-list.testing.module.ts new file mode 100644 index 0000000000..33990f1618 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task-list-cloud/testing/task-list.testing.module.ts @@ -0,0 +1,51 @@ +/*! + * @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 { NgModule } from '@angular/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { HttpClientModule } from '@angular/common/http'; +import { TaskListCloudModule } from '../task-list-cloud.module'; +import { + AlfrescoApiService, + AlfrescoApiServiceMock, + AppConfigService, + AppConfigServiceMock, + StorageService, + LogService, + TranslationService, + TranslationMock, + UserPreferencesService, + ContextMenuModule +} from '@alfresco/adf-core'; + +@NgModule({ + imports: [ + HttpClientModule, + NoopAnimationsModule, + TaskListCloudModule, + ContextMenuModule + ], + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, + { provide: AppConfigService, useClass: AppConfigServiceMock }, + { provide: TranslationService, useClass: TranslationMock }, + StorageService, + LogService, + UserPreferencesService + ] +}) +export class TaskListTestingModule {} diff --git a/lib/process-services-cloud/src/lib/app-list-cloud/testing/app-list.testing.module.ts b/lib/process-services-cloud/src/lib/testing/process-service-cloud.testing.module.ts similarity index 87% rename from lib/process-services-cloud/src/lib/app-list-cloud/testing/app-list.testing.module.ts rename to lib/process-services-cloud/src/lib/testing/process-service-cloud.testing.module.ts index 365fe47900..af82fafecc 100644 --- a/lib/process-services-cloud/src/lib/app-list-cloud/testing/app-list.testing.module.ts +++ b/lib/process-services-cloud/src/lib/testing/process-service-cloud.testing.module.ts @@ -18,7 +18,6 @@ import { NgModule } from '@angular/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { HttpClientModule } from '@angular/common/http'; -import { AppListCloudModule } from '../app-list-cloud.module'; import { AlfrescoApiService, AlfrescoApiServiceMock, @@ -27,21 +26,24 @@ import { StorageService, LogService, TranslationService, - TranslationMock + TranslationMock, + UserPreferencesService, + ContextMenuModule } from '@alfresco/adf-core'; @NgModule({ imports: [ HttpClientModule, NoopAnimationsModule, - AppListCloudModule + ContextMenuModule ], providers: [ { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, { provide: AppConfigService, useClass: AppConfigServiceMock }, { provide: TranslationService, useClass: TranslationMock }, StorageService, - LogService + LogService, + UserPreferencesService ] }) -export class AppListTestingModule {} +export class ProcessServiceCloudTestingModule {} diff --git a/lib/process-services-cloud/src/public_api.ts b/lib/process-services-cloud/src/public-api.ts similarity index 82% rename from lib/process-services-cloud/src/public_api.ts rename to lib/process-services-cloud/src/public-api.ts index bef4379408..de7e278281 100644 --- a/lib/process-services-cloud/src/public_api.ts +++ b/lib/process-services-cloud/src/public-api.ts @@ -16,4 +16,6 @@ */ export * from './lib/process-services-cloud.module'; -export * from './lib/app-list-cloud/app-list-cloud.module'; +export * from './lib/app-list-cloud/public-api'; +export * from './lib/task-list-cloud/public-api'; +export * from './lib/task-cloud/public-api'; diff --git a/lib/process-services-cloud/test.ts b/lib/process-services-cloud/test.ts deleted file mode 100644 index d50ae6d3b5..0000000000 --- a/lib/process-services-cloud/test.ts +++ /dev/null @@ -1,41 +0,0 @@ -/*! - * @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 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; - -declare const require: any; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting() -); - -declare const pdfjsLib: any; -pdfjsLib.GlobalWorkerOptions.workerSrc = 'node_modules/pdfjs-dist/build/pdf.worker.min.js'; - -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); diff --git a/lib/process-services-cloud/tsconfig.spec.json b/lib/process-services-cloud/tsconfig.spec.json index 16da33db07..1e6bebd1a2 100644 --- a/lib/process-services-cloud/tsconfig.spec.json +++ b/lib/process-services-cloud/tsconfig.spec.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.json", + "extends": "./tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/spec", "types": [