diff --git a/demo-shell/src/app/app.module.ts b/demo-shell/src/app/app.module.ts
index ac4e5fcb82..4e79298873 100644
--- a/demo-shell/src/app/app.module.ts
+++ b/demo-shell/src/app/app.module.ts
@@ -66,6 +66,7 @@ import { AuthBearerInterceptor } from './services';
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';
+import { ProcessListCloudExampleComponent } from './components/cloud/process-list-cloud-example.component';
@NgModule({
imports: [
@@ -115,7 +116,8 @@ import { TaskListCloudDemoComponent } from './components/task-list-cloud-demo/ta
DemoPermissionComponent,
FormLoadingComponent,
ReportIssueComponent,
- TaskListCloudDemoComponent
+ TaskListCloudDemoComponent,
+ ProcessListCloudExampleComponent
],
providers: [
{
diff --git a/demo-shell/src/app/app.routes.ts b/demo-shell/src/app/app.routes.ts
index b6e4f5fa2c..08a12bf7d7 100644
--- a/demo-shell/src/app/app.routes.ts
+++ b/demo-shell/src/app/app.routes.ts
@@ -42,6 +42,7 @@ import { ReportIssueComponent } from './components/report-issue/report-issue.com
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';
+import { ProcessListCloudExampleComponent } from './components/cloud/process-list-cloud-example.component';
export const appRoutes: Routes = [
{ path: 'login', component: LoginComponent },
@@ -147,6 +148,10 @@ export const appRoutes: Routes = [
}
]
},
+ {
+ path: 'process-cloud',
+ component: ProcessListCloudExampleComponent
+ },
{
path: 'node-selector',
loadChildren: 'app/components/content-node-selector/content-node-selector.module#AppContentNodeSelectorModule'
diff --git a/demo-shell/src/app/components/cloud/process-list-cloud-example.component.html b/demo-shell/src/app/components/cloud/process-list-cloud-example.component.html
new file mode 100644
index 0000000000..36a6ad350f
--- /dev/null
+++ b/demo-shell/src/app/components/cloud/process-list-cloud-example.component.html
@@ -0,0 +1,94 @@
+
PROCESS LIST CLOUD
+
+
+
+
+
+
+ Process Example Filters
+
+
+ Apply one of the filters to the process list
+
+
+
+
+
+
+ ALL
+
+
+ RUNNING
+
+
+ SUSPENDED
+
+
+ CANCELLED
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sorting Panel
+
+
+ Choose how to sort your tasks
+
+
+
+
+
+
+ ID
+
+
+ NAME
+
+
+ STATUS
+
+
+
+
+
+
+
+
+ ASC
+
+
+ DESC
+
+
+
+
+ Apply Filter
+ Clear Filter
+
+
+
+
+
+
+
+
+
+
+
+
Back
+
diff --git a/demo-shell/src/app/components/cloud/process-list-cloud-example.component.scss b/demo-shell/src/app/components/cloud/process-list-cloud-example.component.scss
new file mode 100644
index 0000000000..41a9e4b90c
--- /dev/null
+++ b/demo-shell/src/app/components/cloud/process-list-cloud-example.component.scss
@@ -0,0 +1,7 @@
+.adf-process-list-cloud-button {
+ margin: 15px;
+}
+
+.app-process-cloud-spacing {
+ margin: 10px;
+}
diff --git a/demo-shell/src/app/components/cloud/process-list-cloud-example.component.ts b/demo-shell/src/app/components/cloud/process-list-cloud-example.component.ts
new file mode 100644
index 0000000000..d202ba8aab
--- /dev/null
+++ b/demo-shell/src/app/components/cloud/process-list-cloud-example.component.ts
@@ -0,0 +1,66 @@
+/*!
+ * @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 } from '@angular/core';
+import { UserPreferencesService } from '@alfresco/adf-core';
+import { ProcessListCloudComponent } from '@alfresco/adf-process-services-cloud';
+
+@Component({
+ selector: 'app-process-list-example',
+ templateUrl: './process-list-cloud-example.component.html',
+ styleUrls: ['./process-list-cloud-example.component.scss']
+})
+export class ProcessListCloudExampleComponent {
+
+ @ViewChild('processCloud')
+ processCloud: ProcessListCloudComponent;
+
+ currentAppName: string = '';
+ status: string = '';
+ filterId: string = '';
+ sortArray: any = [];
+ sortField: string;
+ sortDirection: string;
+
+ constructor(private userPreference: UserPreferencesService) {
+ }
+
+ onAppClick(appClicked: any) {
+ this.currentAppName = appClicked.name;
+ }
+
+ onClick() {
+ this.currentAppName = '';
+ }
+
+ onChangePageSize(event) {
+ this.userPreference.paginationSize = event.maxItems;
+ }
+
+ onFilterButtonClick($event) {
+ let newSortParam: any = {
+ orderBy: this.sortField,
+ direction: this.sortDirection };
+ this.sortArray.push(newSortParam);
+ this.processCloud.reload();
+ }
+
+ onClearFilters() {
+ this.sortArray = [];
+ this.processCloud.reload();
+ }
+}
diff --git a/docs/process-services-cloud/process-list-cloud.component.md b/docs/process-services-cloud/process-list-cloud.component.md
new file mode 100644
index 0000000000..9754f3567f
--- /dev/null
+++ b/docs/process-services-cloud/process-list-cloud.component.md
@@ -0,0 +1,193 @@
+---
+Added: v2.0.0
+Status: Active
+Last reviewed: 2018-05-24
+---
+
+# Process Instance List
+
+Renders a list containing all the process instances matched by the parameters specified.
+
+## Contents
+
+- [Basic Usage](#basic-usage)
+ - [Transclusions](#transclusions)
+- [Class members](#class-members)
+ - [Properties](#properties)
+ - [Events](#events)
+- [Details](#details)
+ - [Setting Sorting Order for the list](#setting-sorting-order-for-the-list)
+ - [Pagination strategy](#pagination-strategy)
+- [See also](#see-also)
+
+## Basic Usage
+
+**[app.component](../../demo-shell/src/app/app.component.ts).html**
+
+```html
+
+
+```
+
+### [Transclusions](../user-guide/transclusion.md)
+
+Any content inside an `` sub-component will be shown
+when the process list is empty:
+
+```html
+
+
+ Your Content
+
+
+```
+
+## Class members
+
+### Properties
+
+| Name | Type | Default value | Description |
+| ---- | ---- | ------------- | ----------- |
+| applicationName | `string` | | The name of the application. |
+| appVersion | `string` | | The application related version |
+| initiator | `string` | | the name of the initiator of the process |
+| id | `string` | | Filter the processes. Display only processes with id equal to the one insterted. |
+| name | `string` | | Filter the processes. Display only processes with name equal to the one insterted. |
+| processDefinitionId | `string` | | Filter the processes. Display only processes with processDefinitionId equal to the one insterted. |
+| processDefinitionKey | `string` | | Filter the processes. Display only processes with processDefinitionKey equal to the one insterted. |
+| serviceFullName | `string` | | Filter the processes. Display only processes with serviceFullName equal to the one insterted. |
+| serviceName | `string` | | Filter the processes. Display only processes with serviceName equal to the one insterted. |
+| serviceType | `string` | | Filter the processes. Display only processes with serviceType equal to the one insterted. |
+| serviceVersion | `string` | | Filter the processes. Display only processes with serviceVersion equal to the one insterted. |
+| status | `string` | | Filter the tasks. Display only processes with status equal to the one insterted. |
+| businessKey | `string` | | Filter the tasks. Display only processes with businessKey equal to the one insterted. |
+| selectFirstRow | `boolean` | true | Toggles default selection of the first row |
+| 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. |
+| 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 | `[ProcessListCloudSortingModel]` | | This array of `ProcessListCloudSortingModel` 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 while loading the list of process instances from the server. |
+| rowClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when a row in the process 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 list of process instances has been loaded successfully from the server. |
+
+## Details
+
+You can define a custom schema for the list in the `app.config.json` file and access it with the
+`presetColumn` property as shown below:
+
+```json
+"adf-cloud-process-list": {
+ "presets": {
+ "customSchema": [
+ {
+ "key": "name",
+ "type": "text",
+ "title": "name",
+ "sortable": true
+ }],
+ "default": [
+ {
+ "key": "name",
+ "type": "text",
+ "title": "name",
+ "sortable": true
+ }],
+ }
+}
+```
+
+```html
+
+
+```
+
+You can also define the schema in the HTML using the
+[Data column component](../core/data-column.component.md). You can combine this with schema
+information defined in `app.config.json` as in the example below:
+
+```json
+"adf-cloud-process-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: 'status', direction: 'desc' }];
+```
+
+```html
+
+
+```
+
+
+
+### Pagination strategy
+
+The Process Instance List also supports pagination:
+
+```html
+
+
+
+
+```
+
+## See also
+
+- [Data column component](../core/data-column.component.md)
+- [Data Table Adapter interface](../core/datatable-adapter.interface.md)
+- [Pagination component](../core/pagination.component.md)
diff --git a/lib/process-services-cloud/src/lib/i18n/en.json b/lib/process-services-cloud/src/lib/i18n/en.json
index 4fc955a659..1c9901cb40 100644
--- a/lib/process-services-cloud/src/lib/i18n/en.json
+++ b/lib/process-services-cloud/src/lib/i18n/en.json
@@ -1,3 +1,10 @@
{
- "TEST_KEY": "MY TEST"
+ "TEST_KEY": "MY TEST",
+ "ADF-PROCESS-LIST-CLOUD": {
+ "MESSAGES": {
+ "TITLE": "No Processes Found",
+ "SUBTITLE":"Create a new process that you want to easily find later",
+ "NONE": "No process instance filter selected."
+ }
+ }
}
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.html b/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.html
new file mode 100644
index 0000000000..79522b8d1c
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.scss b/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.scss
new file mode 100644
index 0000000000..4ce7d0ede1
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.scss
@@ -0,0 +1,19 @@
+@mixin adf-process-filters-cloud-theme($theme) {
+
+ .adf {
+
+ &-cloud-process-list-loading-margin {
+ margin-left: calc((100% - 100px) / 2);
+ margin-right: calc((100% - 100px) / 2);
+ }
+ }
+
+
+ .no-content-message {
+ font-size: 16px;
+ font-weight: bold;
+ text-align: center;
+ opacity: 0.54;
+ }
+}
+
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.spec.ts
new file mode 100644
index 0000000000..9614c3f7cc
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.spec.ts
@@ -0,0 +1,279 @@
+/*!
+ * @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 } from '@angular/core';
+import { ComponentFixture, TestBed, async } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { AppConfigService, setupTestBed, CoreModule, DataTableModule } from '@alfresco/adf-core';
+import { DataRowEvent, ObjectDataRow } from '@alfresco/adf-core';
+import { ProcessListCloudService } from '../services/process-list-cloud.service';
+import { ProcessListCloudComponent } from './process-list-cloud.component';
+import { fakeProcessCloudList, fakeCustomSchema } from '../mock/process-list-service.mock';
+import { of } from 'rxjs';
+import { ProcessListCloudTestingModule } from '../testing/process-list.testing.module';
+import { ProcessListCloudModule } from '../process-list-cloud.module';
+
+@Component({
+ template: `
+
+
+
+
+
+
+ {{getFullName(entry.row.obj.startedBy)}}
+
+
+
+ `
+})
+class CustomTaskListComponent {
+ @ViewChild(ProcessListCloudComponent)
+ processListCloud: ProcessListCloudComponent;
+}
+
+@Component({
+ template: `
+
+
+ TEST
+
+
+ `
+})
+
+class EmptyTemplateComponent {
+}
+/*tslint:disable*/
+fdescribe('ProcessListCloudComponent', () => {
+ let component: ProcessListCloudComponent;
+ let fixture: ComponentFixture;
+ let appConfig: AppConfigService;
+ let processListCloudService: ProcessListCloudService;
+
+ setupTestBed({
+ imports: [
+ ProcessListCloudTestingModule, ProcessListCloudModule
+ ],
+ providers: [ProcessListCloudService]
+ });
+
+ beforeEach(() => {
+ appConfig = TestBed.get(AppConfigService);
+ processListCloudService = TestBed.get(ProcessListCloudService);
+ fixture = TestBed.createComponent(ProcessListCloudComponent);
+ component = fixture.componentInstance;
+ appConfig.config = Object.assign(appConfig.config, {
+ 'adf-cloud-process-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(2);
+ });
+
+ 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 the results if an application name is given', (done) => {
+ spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
+ let appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
+ component.success.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.rows).toBeDefined();
+ expect(component.rows.length).toEqual(3);
+ expect(component.rows[0].entry['serviceName']).toEqual('simple-app-rb');
+ expect(component.rows[0].entry['serviceFullName']).toEqual('simple-app-rb');
+ expect(component.rows[0].entry['serviceVersion']).toBe('');
+ expect(component.rows[0].entry['appName']).toBe('easy-peasy-japanesey');
+ expect(component.rows[0].entry['appVersion']).toBe('');
+ expect(component.rows[0].entry['serviceType']).toBeNull();
+ expect(component.rows[0].entry['id']).toBe('69eddfa7-d781-11e8-ae24-0a58646001fa');
+ expect(component.rows[0].entry['name']).toEqual('starring');
+ expect(component.rows[0].entry['description']).toBeNull();
+ expect(component.rows[0].entry['processDefinitionId']).toBe('BasicProcess:1:d05062f1-c6fb-11e8-ae24-0a58646001fa');
+ expect(component.rows[0].entry['processDefinitionKey']).toBe('BasicProcess');
+ expect(component.rows[0].entry['initiator']).toBe('devopsuser');
+ expect(component.rows[0].entry['startDate']).toBe(1540381146275);
+ expect(component.rows[0].entry['businessKey']).toBe('MyBusinessKey');
+ expect(component.rows[0].entry['status']).toBe('RUNNING');
+ expect(component.rows[0].entry['lastModified']).toBe(1540381146276);
+ expect(component.rows[0].entry['lastModifiedTo']).toBeNull();
+ expect(component.rows[0].entry['lastModifiedFrom']).toBeNull();
+
+ done();
+ });
+ component.applicationName = appName.currentValue;
+ component.ngOnChanges({ 'appName': appName });
+ fixture.detectChanges();
+ });
+
+ it('should reload tasks when reload() is called', (done) => {
+ component.applicationName = 'fake';
+ spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
+ component.success.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.rows).toBeDefined();
+ 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 = fakeProcessCloudList.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(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
+ component.success.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.rows).toBeDefined();
+ expect(component.rows.length).toEqual(3);
+ done();
+ });
+ component.ngOnChanges({ 'landingTaskId': change });
+ });
+ });
+ describe('Injecting custom colums for tasklist - CustomTaskListComponent', () => {
+
+ let fixtureCustom: ComponentFixture;
+ let componentCustom: CustomTaskListComponent;
+
+ setupTestBed({
+ imports: [CoreModule.forRoot()],
+ declarations: [ProcessListCloudComponent, CustomTaskListComponent],
+ providers: [ProcessListCloudService]
+ });
+
+ 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.processListCloud.columnList).toBeDefined();
+ expect(componentCustom.processListCloud.columns[0]['title']).toEqual('ADF_TASK_LIST.PROPERTIES.NAME');
+ expect(componentCustom.processListCloud.columns[1]['title']).toEqual('ADF_TASK_LIST.PROPERTIES.CREATED');
+ expect(componentCustom.processListCloud.columns.length).toEqual(3);
+ });
+ });
+
+ describe('Creating an empty custom template - EmptyTemplateComponent', () => {
+
+ let fixtureEmpty: ComponentFixture;
+
+ setupTestBed({
+ imports: [ProcessListCloudModule, ProcessListCloudTestingModule, DataTableModule],
+ declarations: [EmptyTemplateComponent]
+ });
+
+ 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/process-list-cloud/components/process-list-cloud.component.ts b/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.ts
new file mode 100644
index 0000000000..52cd4fd82c
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/components/process-list-cloud.component.ts
@@ -0,0 +1,247 @@
+import { Component, ViewEncapsulation, OnChanges, AfterContentInit, ContentChild, Output, EventEmitter, SimpleChanges, SimpleChange, Input } from '@angular/core';
+import { DataTableSchema, PaginatedComponent,
+ EmptyCustomContentDirective, AppConfigService,
+ UserPreferencesService, PaginationModel,
+ UserPreferenceValues, DataRowEvent } from '@alfresco/adf-core';
+import { ProcessListCloudService } from '../services/process-list-cloud.service';
+import { BehaviorSubject } from 'rxjs';
+import { processCloudPresetsDefaultModel } from '../models/process-cloud-preset.model';
+import { ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model';
+import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
+import { MinimalNodeEntity } from 'alfresco-js-api';
+@Component({
+ selector: 'adf-cloud-process-list',
+ templateUrl: './process-list-cloud.component.html',
+ styleUrls: ['./process-list-cloud.component.scss'],
+ encapsulation: ViewEncapsulation.None
+})
+export class ProcessListCloudComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent {
+
+ static PRESET_KEY = 'adf-cloud-process-list.presets';
+
+ @ContentChild(EmptyCustomContentDirective)
+ emptyCustomContent: EmptyCustomContentDirective;
+
+ @Input()
+ applicationName: string = '';
+
+ @Input()
+ appVersion: string = '';
+
+ @Input()
+ initiator: string = '';
+
+ @Input()
+ id: string = '';
+
+ @Input()
+ name: string = '';
+
+ @Input()
+ processDefinitionId: string = '';
+
+ @Input()
+ processDefinitionKey: string = '';
+
+ @Input()
+ serviceFullName: string = '';
+
+ @Input()
+ serviceName: string = '';
+
+ @Input()
+ serviceType: string = '';
+
+ @Input()
+ serviceVersion: string = '';
+
+ @Input()
+ status: string = '';
+
+ @Input()
+ businessKey: 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: ProcessListCloudSortingModel[];
+
+ @Output()
+ rowClick: EventEmitter = new EventEmitter();
+
+ @Output()
+ rowsSelected: EventEmitter = new EventEmitter();
+
+ @Output()
+ error: EventEmitter = new EventEmitter();
+
+ @Output()
+ success: EventEmitter = new EventEmitter();
+
+ pagination: BehaviorSubject;
+ size: number;
+ skipCount: number = 0;
+ currentInstanceId: string;
+ selectedInstances: any[];
+ isLoading = false;
+ rows: any[] = [];
+ requestNode: ProcessQueryCloudRequestModel;
+
+ constructor(private processListCloudService: ProcessListCloudService,
+ appConfigService: AppConfigService,
+ private userPreferences: UserPreferencesService) {
+ super(appConfigService, ProcessListCloudComponent.PRESET_KEY, processCloudPresetsDefaultModel);
+ 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
+ });
+ }
+
+ ngAfterContentInit() {
+ this.createDatatableSchema();
+ }
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (this.isPropertyChanged(changes) &&
+ !this.isEqualToCurrentId(changes['landingTaskId'])) {
+ this.reload();
+ }
+ }
+
+ getCurrentId(): string {
+ return this.currentInstanceId;
+ }
+
+ reload() {
+ this.requestNode = this.createRequestNode();
+ if (this.requestNode.appName) {
+ this.load(this.requestNode);
+ } else {
+ this.rows = [];
+ }
+ }
+
+ private load(requestNode: ProcessQueryCloudRequestModel) {
+ this.isLoading = true;
+ this.processListCloudService.getProcessByRequest(requestNode).subscribe(
+ (processes) => {
+ this.rows = processes.list.entries;
+ this.selectTask(this.landingTaskId);
+ this.success.emit(processes);
+ this.isLoading = false;
+ this.pagination.next(processes.list.pagination);
+ }, (error) => {
+ this.error.emit(error);
+ this.isLoading = false;
+ });
+ }
+
+ private 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;
+ }
+
+ 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(): ProcessQueryCloudRequestModel {
+ let requestNode = {
+ appName: this.applicationName,
+ appVersion: this.appVersion,
+ maxItems: this.size,
+ skipCount: this.skipCount,
+ initiator: this.initiator,
+ id: this.id,
+ name: this.name,
+ processDefinitionId: this.processDefinitionId,
+ processDefinitionKey: this.processDefinitionKey,
+ serviceFullName: this.serviceFullName,
+ serviceName: this.serviceName,
+ serviceType: this.serviceType,
+ serviceVersion: this.serviceVersion,
+ status: this.status,
+ businessKey: this.businessKey,
+ sorting: this.sorting
+ };
+ return new ProcessQueryCloudRequestModel(requestNode);
+ }
+
+}
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/mock/process-list-service.mock.ts b/lib/process-services-cloud/src/lib/process-list-cloud/mock/process-list-service.mock.ts
new file mode 100644
index 0000000000..aed6fe8489
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/mock/process-list-service.mock.ts
@@ -0,0 +1,114 @@
+/*!
+ * @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 fakeProcessCloudList = {
+ list: {
+ entries: [
+ {
+ entry: {
+ serviceName: 'simple-app-rb',
+ serviceFullName: 'simple-app-rb',
+ serviceVersion: '',
+ appName: 'easy-peasy-japanesey',
+ appVersion: '',
+ serviceType: null,
+ id: '69eddfa7-d781-11e8-ae24-0a58646001fa',
+ name: 'starring',
+ description: null,
+ processDefinitionId: 'BasicProcess:1:d05062f1-c6fb-11e8-ae24-0a58646001fa',
+ processDefinitionKey: 'BasicProcess',
+ initiator: 'devopsuser',
+ startDate: 1540381146275,
+ businessKey: 'MyBusinessKey',
+ status: 'RUNNING',
+ lastModified: 1540381146276,
+ lastModifiedTo: null,
+ lastModifiedFrom: null
+ }
+ },
+ {
+ entry: {
+ serviceName: 'simple-app-rb',
+ serviceFullName: 'simple-app-rb',
+ serviceVersion: '',
+ appName: 'easy-peasy-japanesey',
+ appVersion: '',
+ serviceType: null,
+ id: '8b3f625f-d781-11e8-ae24-0a58646001fa',
+ name: null,
+ description: null,
+ processDefinitionId: 'BasicProcess:1:d05062f1-c6fb-11e8-ae24-0a58646001fa',
+ processDefinitionKey: 'BasicProcess',
+ initiator: 'devopsuser',
+ startDate: 1540381202174,
+ businessKey: 'MyBusinessKey',
+ status: 'RUNNING',
+ lastModified: 1540381202174,
+ lastModifiedTo: null,
+ lastModifiedFrom: null
+ }
+ },
+ {
+ entry: {
+ serviceName: 'simple-app-rb',
+ serviceFullName: 'simple-app-rb',
+ serviceVersion: '',
+ appName: 'easy-peasy-japanesey',
+ appVersion: '',
+ serviceType: null,
+ id: '87c12637-d783-11e8-ae24-0a58646001fa',
+ name: null,
+ description: null,
+ processDefinitionId: 'BasicProcess:1:d05062f1-c6fb-11e8-ae24-0a58646001fa',
+ processDefinitionKey: 'BasicProcess',
+ initiator: 'superadminuser',
+ startDate: 1540382055307,
+ businessKey: 'MyBusinessKey',
+ status: 'RUNNING',
+ lastModified: 1540382055308,
+ lastModifiedTo: null,
+ lastModifiedFrom: null
+ }
+ }
+ ],
+ pagination: {
+ skipCount: 0,
+ maxItems: 100,
+ count: 3,
+ hasMoreItems: false,
+ totalItems: 3
+ }
+ }
+};
+
+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/process-list-cloud/models/process-cloud-preset.model.ts b/lib/process-services-cloud/src/lib/process-list-cloud/models/process-cloud-preset.model.ts
new file mode 100644
index 0000000000..a67923bfb9
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/models/process-cloud-preset.model.ts
@@ -0,0 +1,34 @@
+/*!
+ * @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 processCloudPresetsDefaultModel = {
+ 'default': [
+ {
+ 'key': 'name',
+ 'type': 'text',
+ 'title': 'ADF_PROCESS_LIST.PROPERTIES.NAME',
+ 'sortable': true
+ },
+ {
+ 'key': 'created',
+ 'type': 'text',
+ 'title': 'ADF_PROCESS_LIST.PROPERTIES.CREATED',
+ 'cssClass': 'hidden',
+ 'sortable': true
+ }
+ ]
+};
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/models/process-cloud-query-request.model.ts b/lib/process-services-cloud/src/lib/process-list-cloud/models/process-cloud-query-request.model.ts
new file mode 100644
index 0000000000..96c63096be
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/models/process-cloud-query-request.model.ts
@@ -0,0 +1,67 @@
+/*!
+ * @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 { ProcessListCloudSortingModel } from './process-list-sorting.model';
+
+export class ProcessQueryCloudRequestModel {
+ appName: string;
+ appVersion?: string;
+ description?: string;
+ initiator?: null;
+ id?: string;
+ name?: string;
+ processDefinitionId?: string;
+ processDefinitionKey?: string;
+ serviceFullName?: string;
+ serviceName?: string;
+ serviceType?: string;
+ serviceVersion?: string;
+ status?: string;
+ startDate?: string;
+ businessKey?: string;
+ lastModified?: string;
+ lastModifiedTo?: string;
+ lastModifiedFrom?: string;
+ maxItems: number;
+ skipCount: number;
+ sorting?: ProcessListCloudSortingModel[];
+ constructor(obj?: any) {
+ if (obj) {
+ this.appName = obj.appName;
+ this.appVersion = obj.appVersion;
+ this.description = obj.description;
+ this.initiator = obj.initiator;
+ this.id = obj.id;
+ this.name = obj.name;
+ this.processDefinitionId = obj.processDefinitionId;
+ this.processDefinitionKey = obj.processDefinitionKey;
+ this.serviceFullName = obj.serviceFullName;
+ this.serviceName = obj.serviceName;
+ this.serviceType = obj.serviceType;
+ this.serviceVersion = obj.serviceVersion;
+ this.status = obj.status;
+ this.startDate = obj.startDate;
+ this.businessKey = obj.businessKey;
+ this.lastModified = obj.lastModified;
+ this.lastModifiedTo = obj.lastModifiedTo;
+ this.lastModifiedFrom = obj.lastModifiedFrom;
+ this.maxItems = obj.maxItems;
+ this.skipCount = obj.skipCount;
+ this.sorting = obj.sorting;
+ }
+ }
+}
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/models/process-list-sorting.model.ts b/lib/process-services-cloud/src/lib/process-list-cloud/models/process-list-sorting.model.ts
new file mode 100644
index 0000000000..0e087948ba
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/models/process-list-sorting.model.ts
@@ -0,0 +1,27 @@
+/*!
+ * @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 ProcessListCloudSortingModel {
+ 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/process-list-cloud/process-list-cloud.module.spec.ts b/lib/process-services-cloud/src/lib/process-list-cloud/process-list-cloud.module.spec.ts
new file mode 100644
index 0000000000..1a890886f5
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/process-list-cloud.module.spec.ts
@@ -0,0 +1,13 @@
+import { ProcessListCloudModule } from './process-list-cloud.module';
+
+describe('ProcessListCloudModule', () => {
+ let processListCloudModule: ProcessListCloudModule;
+
+ beforeEach(() => {
+ processListCloudModule = new ProcessListCloudModule();
+ });
+
+ it('should create an instance', () => {
+ expect(processListCloudModule).toBeTruthy();
+ });
+});
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/process-list-cloud.module.ts b/lib/process-services-cloud/src/lib/process-list-cloud/process-list-cloud.module.ts
new file mode 100644
index 0000000000..4d65c566ac
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/process-list-cloud.module.ts
@@ -0,0 +1,26 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ProcessListCloudComponent } from './components/process-list-cloud.component';
+import { MaterialModule } from '../material.module';
+import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
+import { TranslateLoaderService, DataTableModule, TemplateModule } from '@alfresco/adf-core';
+import { ProcessListCloudService } from './services/process-list-cloud.service';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ TranslateModule.forRoot({
+ loader: {
+ provide: TranslateLoader,
+ useClass: TranslateLoaderService
+ }
+ }),
+ MaterialModule,
+ DataTableModule,
+ TemplateModule
+ ],
+ declarations: [ProcessListCloudComponent],
+ exports: [ProcessListCloudComponent],
+ providers: [ProcessListCloudService]
+})
+export class ProcessListCloudModule { }
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/public_api.ts b/lib/process-services-cloud/src/lib/process-list-cloud/public_api.ts
new file mode 100644
index 0000000000..a6e2fea333
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/public_api.ts
@@ -0,0 +1,22 @@
+/*!
+ * @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/process-list-cloud.component';
+export * from './models/process-cloud-query-request.model';
+export * from './models/process-cloud-preset.model';
+export * from './models/process-list-sorting.model';
+export * from './process-list-cloud.module';
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/services/process-list-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/process-list-cloud/services/process-list-cloud.service.spec.ts
new file mode 100644
index 0000000000..04faf1f040
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/services/process-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 { fakeProcessCloudList } from '../mock/process-list-service.mock';
+import { AlfrescoApiServiceMock, LogService, AppConfigService, StorageService, CoreModule } from '@alfresco/adf-core';
+import { ProcessListCloudService } from './process-list-cloud.service';
+import { ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model';
+
+describe('Activiti ProcessList Cloud Service', () => {
+ let service: ProcessListCloudService;
+ let alfrescoApiMock: AlfrescoApiServiceMock;
+
+ function returFakeProcessListResults() {
+ return {
+ oauth2Auth: {
+ callCustomApi: () => {
+ return Promise.resolve(fakeProcessCloudList);
+ }
+ }
+ };
+ }
+
+ 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 ProcessListCloudService(alfrescoApiMock,
+ new AppConfigService(null),
+ new LogService(new AppConfigService(null)));
+ }));
+
+ it('should return the processes', (done) => {
+ let processRequest: ProcessQueryCloudRequestModel = { appName: 'fakeName' };
+ spyOn(alfrescoApiMock, 'getInstance').and.callFake(returFakeProcessListResults);
+ service.getProcessByRequest(processRequest).subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(res).not.toBeNull();
+ expect(res.list.entries.length).toBe(3);
+ expect(res.list.entries[0].entry.appName).toBe('easy-peasy-japanesey');
+ expect(res.list.entries[1].entry.appName).toBe('easy-peasy-japanesey');
+ expect(res.list.entries[1].entry.appName).toBe('easy-peasy-japanesey');
+ done();
+ });
+ });
+
+ it('should append to the call all the parameters', (done) => {
+ let processRequest: ProcessQueryCloudRequestModel = { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service' };
+ spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallQueryParameters);
+ service.getProcessByRequest(processRequest).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 processRequest: ProcessQueryCloudRequestModel = { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service' };
+ spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallUrl);
+ service.getProcessByRequest(processRequest).subscribe((requestUrl) => {
+ expect(requestUrl).toBeDefined();
+ expect(requestUrl).not.toBeNull();
+ expect(requestUrl).toContain('/fakeName-query/v1/process-instances');
+ done();
+ });
+ });
+
+ it('should concat the sorting to append as parameters', (done) => {
+ let processRequest: ProcessQueryCloudRequestModel = {
+ 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.getProcessByRequest(processRequest).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 processRequest: ProcessQueryCloudRequestModel = { appName: null };
+ spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallUrl);
+ service.getProcessByRequest(processRequest).subscribe(
+ () => { },
+ (error) => {
+ expect(error).toBe('Appname not configured');
+ done();
+ }
+ );
+ });
+});
diff --git a/lib/process-services-cloud/src/lib/process-list-cloud/services/process-list-cloud.service.ts b/lib/process-services-cloud/src/lib/process-list-cloud/services/process-list-cloud.service.ts
new file mode 100644
index 0000000000..e489cdeea1
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/services/process-list-cloud.service.ts
@@ -0,0 +1,89 @@
+/*!
+ * @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 { ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model';
+import { Observable, from, throwError } from 'rxjs';
+import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
+@Injectable()
+export class ProcessListCloudService {
+
+ contentTypes = ['application/json'];
+ accepts = ['application/json'];
+
+ constructor(private apiService: AlfrescoApiService,
+ private appConfigService: AppConfigService,
+ private logService: LogService) {
+ }
+
+ getProcessByRequest(requestNode: ProcessQueryCloudRequestModel): 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, this.contentTypes,
+ this.accepts, Object, null, null)
+ );
+ } else {
+ this.logService.error('Appname is mandatory for querying task');
+ return throwError('Appname not configured');
+ }
+ }
+ private buildQueryUrl(requestNode: ProcessQueryCloudRequestModel) {
+ return `${this.appConfigService.get('bpmHost', '')}/${requestNode.appName}-query/v1/process-instances`;
+ }
+
+ private isPropertyValueValid(requestNode, property) {
+ return requestNode[property] !== '' && requestNode[property] !== null && requestNode[property] !== undefined;
+ }
+
+ private buildQueryParams(requestNode: ProcessQueryCloudRequestModel) {
+ 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 buildSortingParam(sortings: ProcessListCloudSortingModel[]): 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/process-list-cloud/testing/process-list.testing.module.ts b/lib/process-services-cloud/src/lib/process-list-cloud/testing/process-list.testing.module.ts
new file mode 100644
index 0000000000..feafdaf0b3
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-list-cloud/testing/process-list.testing.module.ts
@@ -0,0 +1,49 @@
+/*!
+ * @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 { ProcessListCloudModule } from '../process-list-cloud.module';
+import {
+ AlfrescoApiService,
+ AlfrescoApiServiceMock,
+ AppConfigService,
+ AppConfigServiceMock,
+ StorageService,
+ LogService,
+ TranslationService,
+ TranslationMock,
+ UserPreferencesService,
+ ContextMenuModule
+} from '@alfresco/adf-core';
+@NgModule({
+ imports: [
+ HttpClientModule,
+ NoopAnimationsModule,
+ ProcessListCloudModule,
+ ContextMenuModule
+ ],
+ providers: [
+ { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
+ { provide: AppConfigService, useClass: AppConfigServiceMock },
+ { provide: TranslationService, useClass: TranslationMock },
+ StorageService,
+ LogService,
+ UserPreferencesService
+ ]
+})
+export class ProcessListCloudTestingModule { }
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 f6f61b741b..8e8c894323 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
@@ -3,12 +3,14 @@ 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';
+import { ProcessListCloudModule } from './process-list-cloud/process-list-cloud.module';
@NgModule({
imports: [
AppListCloudModule,
TaskListCloudModule,
- TaskCloudModule
+ TaskCloudModule,
+ ProcessListCloudModule
],
providers: [
{
@@ -21,6 +23,6 @@ import { TaskCloudModule } from './task-cloud/task-cloud.module';
}
],
declarations: [],
- exports: [AppListCloudModule, TaskListCloudModule, TaskCloudModule]
+ exports: [AppListCloudModule, TaskListCloudModule, TaskCloudModule, ProcessListCloudModule]
})
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 4da0dabfd5..387e4d8920 100644
--- a/lib/process-services-cloud/src/lib/styles/_index.scss
+++ b/lib/process-services-cloud/src/lib/styles/_index.scss
@@ -1,9 +1,11 @@
@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';
+@import './../process-list-cloud/components/process-list-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);
+ @include adf-process-filters-cloud-theme($theme);
}
diff --git a/lib/process-services-cloud/src/public-api.ts b/lib/process-services-cloud/src/public-api.ts
index de7e278281..f2f374b5e0 100644
--- a/lib/process-services-cloud/src/public-api.ts
+++ b/lib/process-services-cloud/src/public-api.ts
@@ -19,3 +19,4 @@ export * from './lib/process-services-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';
+export * from './lib/process-list-cloud/public_api';
diff --git a/lib/process-services/mock/process/process-instances-list.mock.ts b/lib/process-services/mock/process/process-instances-list.mock.ts
index c86731e127..3d33e3271b 100644
--- a/lib/process-services/mock/process/process-instances-list.mock.ts
+++ b/lib/process-services/mock/process/process-instances-list.mock.ts
@@ -115,6 +115,13 @@ export let fakeProcessInstancesWithNoName = {
]
};
+export let fakeProcessInstancesEmpty = {
+ size: 0,
+ total: 0,
+ start: 0,
+ data: []
+};
+
export let fakeProcessCustomSchema = [
new ObjectDataColumn({
key: 'fakeName',
diff --git a/lib/process-services/mock/task/task-list.mock.ts b/lib/process-services/mock/task/task-list.mock.ts
index 799f94927b..5e8605428b 100644
--- a/lib/process-services/mock/task/task-list.mock.ts
+++ b/lib/process-services/mock/task/task-list.mock.ts
@@ -104,3 +104,10 @@ export let fakeColumnSchema = {
],
fakeCustomSchema
};
+
+export let fakeEmptyTask = {
+ size: 0,
+ start: 0,
+ total: 0,
+ data: []
+};
diff --git a/lib/process-services/process-list/components/process-list.component.spec.ts b/lib/process-services/process-list/components/process-list.component.spec.ts
index e7f8460cca..db27e934df 100644
--- a/lib/process-services/process-list/components/process-list.component.spec.ts
+++ b/lib/process-services/process-list/components/process-list.component.spec.ts
@@ -15,20 +15,21 @@
* limitations under the License.
*/
-import { Component, SimpleChange, ViewChild, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { Component, SimpleChange, ViewChild } from '@angular/core';
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { of, throwError } from 'rxjs';
import { By } from '@angular/platform-browser';
import { ProcessInstanceListComponent } from './process-list.component';
-import { AppConfigService, setupTestBed, CoreModule } from '@alfresco/adf-core';
+import { AppConfigService, setupTestBed, CoreModule, DataTableModule } from '@alfresco/adf-core';
import { DataRowEvent, ObjectDataRow, ObjectDataTableAdapter } from '@alfresco/adf-core';
-import { fakeProcessInstance, fakeProcessInstancesWithNoName } from '../../mock';
+import { fakeProcessInstance, fakeProcessInstancesWithNoName, fakeProcessInstancesEmpty } from '../../mock';
import { ProcessService } from '../services/process.service';
import { ProcessTestingModule } from '../../testing/process.testing.module';
import { fakeProcessCustomSchema } from '../../mock';
+import { ProcessListModule } from 'process-list/process-list.module';
describe('ProcessInstanceListComponent', () => {
@@ -506,27 +507,28 @@ describe('CustomProcessListComponent', () => {
@Component({
template: `
-
-
+
+
No Process Instance
-
+
`
})
class EmptyTemplateComponent {
}
-
describe('Process List: Custom EmptyTemplateComponent', () => {
let fixture: ComponentFixture;
+ let processService: ProcessService;
setupTestBed({
- imports: [ProcessTestingModule],
- declarations: [EmptyTemplateComponent],
- schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
+ imports: [ProcessTestingModule, ProcessListModule, DataTableModule],
+ declarations: [EmptyTemplateComponent]
});
beforeEach(() => {
fixture = TestBed.createComponent(EmptyTemplateComponent);
+ processService = TestBed.get(ProcessService);
+ spyOn(processService, 'getProcessInstances').and.returnValue(of(fakeProcessInstancesEmpty));
fixture.detectChanges();
});
@@ -534,13 +536,14 @@ describe('Process List: Custom EmptyTemplateComponent', () => {
fixture.destroy();
});
- it('should render the custom template', async(() => {
+ it('should render the custom template', (done) => {
fixture.whenStable().then(() => {
fixture.detectChanges();
let title = fixture.debugElement.query(By.css('#custom-id'));
expect(title).not.toBeNull();
expect(title.nativeElement.innerText).toBe('No Process Instance');
expect(fixture.debugElement.query(By.css('.adf-empty-content'))).toBeNull();
+ done();
});
- }));
+ });
});
diff --git a/lib/process-services/task-list/components/task-list.component.spec.ts b/lib/process-services/task-list/components/task-list.component.spec.ts
index dfdfacacde..af8834aec1 100644
--- a/lib/process-services/task-list/components/task-list.component.spec.ts
+++ b/lib/process-services/task-list/components/task-list.component.spec.ts
@@ -15,17 +15,18 @@
* limitations under the License.
*/
-import { Component, SimpleChange, ViewChild, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { Component, SimpleChange, ViewChild } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
-import { AppConfigService, setupTestBed, CoreModule } from '@alfresco/adf-core';
+import { AppConfigService, setupTestBed, CoreModule, DataTableModule } from '@alfresco/adf-core';
import { DataRowEvent, ObjectDataRow } from '@alfresco/adf-core';
import { TaskListService } from '../services/tasklist.service';
import { TaskListComponent } from './task-list.component';
import { ProcessTestingModule } from '../../testing/process.testing.module';
-import { fakeGlobalTask, fakeCustomSchema } from '../../mock';
+import { fakeGlobalTask, fakeCustomSchema, fakeEmptyTask } from '../../mock';
import { TranslateService } from '@ngx-translate/core';
import { of } from 'rxjs';
+import { TaskListModule } from 'task-list/task-list.module';
declare let jasmine: any;
@@ -567,10 +568,10 @@ describe('CustomTaskListComponent', () => {
@Component({
template: `
-
-
-
-
+
+
+ CUSTOM EMPTY
+
`
})
@@ -580,19 +581,20 @@ class EmptyTemplateComponent {
describe('Task List: Custom EmptyTemplateComponent', () => {
let fixture: ComponentFixture;
let translateService: TranslateService;
+ let taskListService: TaskListService;
setupTestBed({
- imports: [ProcessTestingModule],
- declarations: [EmptyTemplateComponent],
- schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
+ imports: [ProcessTestingModule, TaskListModule, DataTableModule],
+ declarations: [EmptyTemplateComponent]
});
beforeEach(() => {
translateService = TestBed.get(TranslateService);
+ taskListService = TestBed.get(TaskListService);
spyOn(translateService, 'get').and.callFake((key) => {
return of(key);
});
-
+ spyOn(taskListService, 'findTasksByState').and.returnValue(of(fakeEmptyTask));
fixture = TestBed.createComponent(EmptyTemplateComponent);
fixture.detectChanges();
});
@@ -601,10 +603,12 @@ describe('Task List: Custom EmptyTemplateComponent', () => {
fixture.destroy();
});
- it('should render the custom template', fakeAsync(() => {
+ it('should render the custom template', (done) => {
fixture.detectChanges();
- tick(100);
- expect(fixture.debugElement.query(By.css('#custom-id'))).not.toBeNull();
- expect(fixture.debugElement.query(By.css('.adf-empty-content'))).toBeNull();
- }));
+ fixture.whenStable().then(() => {
+ expect(fixture.debugElement.query(By.css('#custom-id'))).not.toBeNull();
+ expect(fixture.debugElement.query(By.css('.adf-empty-content'))).toBeNull();
+ done();
+ });
+ });
});