diff --git a/demo-shell/resources/i18n/en.json b/demo-shell/resources/i18n/en.json
index db0fe6fffa..cc4c439d2d 100644
--- a/demo-shell/resources/i18n/en.json
+++ b/demo-shell/resources/i18n/en.json
@@ -62,6 +62,7 @@
"TASK_LIST": "Task List",
"PROCESS_LIST": "Process List",
"PROCESS_CLOUD": "Process Cloud",
+ "PROCESS_LIST_CLOUD": "Process List Cloud",
"CARD_VIEW": "CardView",
"PROCESS_SERVICES": "Process Services",
"LOGIN": "Login",
@@ -269,5 +270,8 @@
"TEXT": "Back to home"
}
}
+ },
+ "PROCESS_LIST_CLOUD": {
+ "TITLE": "PROCESS LIST CLOUD DEMO"
}
}
diff --git a/demo-shell/src/app/app.routes.ts b/demo-shell/src/app/app.routes.ts
index fa10bb05d1..e751d0bcbe 100644
--- a/demo-shell/src/app/app.routes.ts
+++ b/demo-shell/src/app/app.routes.ts
@@ -150,7 +150,7 @@ export const appRoutes: Routes = [
]
},
{
- path: 'process-cloud',
+ path: 'process-list-cloud',
component: ProcessListCloudExampleComponent
},
{
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 950a0e67e7..704fc1fc80 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
@@ -41,6 +41,7 @@ export class AppLayoutComponent implements OnInit {
{ 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: '/process-list-cloud', icon: 'cloud', title: 'APP_LAYOUT.PROCESS_LIST_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/process-list-cloud-example.component.html b/demo-shell/src/app/components/cloud/process-list-cloud-example.component.html
index 36a6ad350f..9d562c10bc 100644
--- 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
@@ -1,4 +1,11 @@
-
PROCESS LIST CLOUD
+{{'PROCESS_LIST_CLOUD.TITLE' | translate}}
+
+
+
@@ -6,13 +13,13 @@
- Process Example Filters
+ {{filterName | translate}}
- Apply one of the filters to the process list
+ Customise your filter
-
+
@@ -21,60 +28,32 @@
RUNNING
-
- SUSPENDED
+
+ COMPLETED
-
- CANCELLED
+
+
+
+
+ Select a column
+
+ {{column.label}}
+
+
+
+
+
+ Select a direction
+
+ ASC
+
+
+ DESC
-
-
-
-
-
-
-
-
- Sorting Panel
-
-
- Choose how to sort your tasks
-
-
-
-
-
-
- ID
-
-
- NAME
-
-
- STATUS
-
-
-
-
-
-
-
-
- ASC
-
-
- DESC
-
-
-
-
-
-
-
{
+ 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
+ }];
+ }
+ );
+ }
+
onAppClick(appClicked: any) {
this.currentAppName = appClicked.name;
}
@@ -51,16 +91,16 @@ export class ProcessListCloudExampleComponent {
this.userPreference.paginationSize = event.maxItems;
}
- onFilterButtonClick($event) {
- let newSortParam: any = {
- orderBy: this.sortField,
- direction: this.sortDirection };
- this.sortArray.push(newSortParam);
+ onClearFilters() {
this.processCloud.reload();
}
- onClearFilters() {
- this.sortArray = [];
- this.processCloud.reload();
+ onFilterSelected(filter) {
+ this.status = filter.query.state || '';
+ this.sort = filter.query.sort;
+ this.sortDirection = filter.query.order;
+ this.filterName = filter.name;
+ this.sortDirectionFormControl.setValue(this.sortDirection);
+ this.sortFormControl.setValue(this.sort);
}
}
diff --git a/docs/process-services-cloud/process-filter-cloud.component.md b/docs/process-services-cloud/process-filter-cloud.component.md
new file mode 100644
index 0000000000..d03f85a324
--- /dev/null
+++ b/docs/process-services-cloud/process-filter-cloud.component.md
@@ -0,0 +1,63 @@
+---
+Added: v3.0.0
+Status: Active
+Last reviewed: 2018-21-11
+---
+
+# Process Filter Cloud Component
+
+Lists all available process filters and allows to select a filter.
+
+## Contents
+
+- [Basic Usage](#basic-usage)
+- [Class members](#class-members)
+ - [Properties](#properties)
+ - [Events](#events)
+
+
+## Basic Usage
+
+```html
+
+
+```
+
+## Class members
+
+### Properties
+
+| Name | Type | Default value | Description |
+| ---- | ---- | ------------- | ----------- |
+| appName | `string` | | (required) The application name |
+| filterParam | `ProcessFilterParamModel` | | (optional) The filter to be selected by default |
+| showIcons | `boolean` | false | (optional) The flag hides/shows icon against each filter |
+
+### Events
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| filterClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessFilterRepresentationModel`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts)`>` | Emitted when a filter is selected/clicked. |
+| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when filters are loaded successfully. |
+| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when any error occurs while loading the filters. |
+
+### Details
+
+The `filterParam` input can be used to select a filter as mentioned below.
+
+```html
+
+
+```
+
+A filter can be selected by using any of the `ProcessFilterParamModel` property.
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| id | string | The id of the filter |
+| name | string | The name of the filter |
+| key | string | The key of the filter |
+| index | string | The zero-based position of the filter in the array |
\ No newline at end of file
diff --git a/lib/process-services-cloud/src/lib/i18n/en.json b/lib/process-services-cloud/src/lib/i18n/en.json
index 89212ea91e..56b60c3e9e 100644
--- a/lib/process-services-cloud/src/lib/i18n/en.json
+++ b/lib/process-services-cloud/src/lib/i18n/en.json
@@ -9,5 +9,10 @@
"ADF_CLOUD_TASK_FILTERS": {
"MY_TASKS": "My Tasks",
"COMPLETED_TASKS": "Completed Tasks"
+ },
+ "ADF_CLOUD_PROCESS_FILTERS": {
+ "ALL_PROCESSES": "All Processes",
+ "RUNNING_PROCESSES": "Running Processes",
+ "COMPLETED_PROCESSES": "Completed Processes"
}
}
diff --git a/lib/process-services-cloud/src/lib/i18n/it.json b/lib/process-services-cloud/src/lib/i18n/it.json
index 6d56150df4..45edab80f4 100644
--- a/lib/process-services-cloud/src/lib/i18n/it.json
+++ b/lib/process-services-cloud/src/lib/i18n/it.json
@@ -1,5 +1,5 @@
{
- "ADF_CLOUD_TASK_PROCESS_LIST": {
+ "ADF_CLOUD_PROCESS_LIST": {
"MESSAGES": {
"TITLE": "Nessun processo trovato",
"SUBTITLE":"Crea un nuovo processo",
diff --git a/lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts b/lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts
new file mode 100644
index 0000000000..ebc37e1b73
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts
@@ -0,0 +1,71 @@
+/*!
+ * @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 ProcessQueryModel {
+ 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 ProcessFilterRepresentationModel {
+ id: string;
+ name: string;
+ key: string;
+ icon: string;
+ query: ProcessQueryModel;
+
+ constructor(obj?: any) {
+ if (obj) {
+ this.id = obj.id || Math.random().toString(36).substring(2, 9);
+ this.name = obj.name || null;
+ this.key = obj.key || null;
+ this.icon = obj.icon || null;
+ this.query = new ProcessQueryModel(obj.query);
+ }
+ }
+
+ hasFilter() {
+ return !!this.query;
+ }
+}
+
+export class ProcessFilterParamModel {
+ id: string;
+ name: string;
+ key: string;
+ index: number;
+ constructor(obj?: any) {
+ if (obj) {
+ this.id = obj.id || null;
+ this.name = obj.name || null;
+ this.key = obj.key || null;
+ this.index = obj.index || null;
+ }
+ }
+}
diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-cloud.module.ts b/lib/process-services-cloud/src/lib/process-cloud/process-cloud.module.ts
new file mode 100644
index 0000000000..f5290f353f
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-cloud/process-cloud.module.ts
@@ -0,0 +1,43 @@
+/*!
+ * @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 { CommonModule } from '@angular/common';
+import { ProcessFiltersCloudComponent } from './process-filters-cloud/process-filters-cloud.component';
+import { MaterialModule } from '../material.module';
+import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
+import { TranslateLoaderService, LogService, StorageService } from '@alfresco/adf-core';
+import { ProcessFilterCloudService } from './services/process-filter-cloud.service';
+import { HttpClientModule } from '@angular/common/http';
+@NgModule({
+ imports: [
+ HttpClientModule,
+ CommonModule,
+ TranslateModule.forRoot({
+ loader: {
+ provide: TranslateLoader,
+ useClass: TranslateLoaderService
+ }
+ }),
+ MaterialModule
+ ],
+ declarations: [ProcessFiltersCloudComponent],
+
+ exports: [ProcessFiltersCloudComponent],
+ providers: [ProcessFilterCloudService, LogService, StorageService]
+})
+export class ProcessCloudModule { }
diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.html b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.html
new file mode 100644
index 0000000000..1d0aec6d7e
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.html
@@ -0,0 +1,17 @@
+
diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.scss b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.scss
new file mode 100644
index 0000000000..c225a1dc27
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.scss
@@ -0,0 +1,34 @@
+@mixin adf-cloud-process-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/process-cloud/process-filters-cloud/process-filters-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.spec.ts
new file mode 100644
index 0000000000..8b554c86f3
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.spec.ts
@@ -0,0 +1,375 @@
+/*!
+ * @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 { ProcessFilterRepresentationModel, ProcessFilterParamModel } from '../models/process-filter-cloud.model';
+import { ProcessFilterCloudService } from '../services/process-filter-cloud.service';
+import { ProcessFiltersCloudComponent } from './process-filters-cloud.component';
+import { By } from '@angular/platform-browser';
+import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
+import { ProcessCloudModule } from '../process-cloud.module';
+
+describe('ProcessFiltersCloudComponent', () => {
+
+ let processFilterService: ProcessFilterCloudService;
+
+ let fakeGlobalFilter = [
+ new ProcessFilterRepresentationModel({
+ name: 'FakeAllProcesses',
+ icon: 'adjust',
+ id: '10',
+ query: {state: ''}
+ }),
+ new ProcessFilterRepresentationModel({
+ name: 'FakeRunningProcesses',
+ icon: 'inbox',
+ id: '11',
+ query: {state: 'RUNNING'}
+ }),
+ new ProcessFilterRepresentationModel({
+ name: 'FakeCompletedProcesses',
+ key: 'completed-processes',
+ icon: 'done',
+ id: '12',
+ query: {state: 'COMPLETED'}
+ })
+ ];
+
+ 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: ProcessFiltersCloudComponent;
+ let fixture: ComponentFixture;
+
+ setupTestBed({
+ imports: [ProcessServiceCloudTestingModule, ProcessCloudModule],
+ providers: [ProcessFilterCloudService]
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ProcessFiltersCloudComponent);
+ component = fixture.componentInstance;
+
+ processFilterService = TestBed.get(ProcessFilterCloudService);
+ });
+
+ it('should attach specific icon for each filter if hasIcon is true', async(() => {
+ spyOn(processFilterService, 'getProcessFilters').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('inbox');
+ expect(filters[2].innerText).toContain('done');
+ });
+ }));
+
+ it('should not attach icons for each filter if hasIcon is false', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').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(processFilterService, 'getProcessFilters').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('FakeAllProcesses');
+ expect(filters[1].nativeElement.innerText).toContain('FakeRunningProcesses');
+ expect(filters[2].nativeElement.innerText).toContain('FakeCompletedProcesses');
+ });
+ }));
+
+ it('should emit an error with a bad response', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').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 emit success with the filters when filters are loaded', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').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('FakeAllProcesses');
+ expect(component.filters[1].name).toEqual('FakeRunningProcesses');
+ expect(component.filters[2].name).toEqual('FakeCompletedProcesses');
+ done();
+ });
+ });
+
+ it('should select the first filter as default', async(() => {
+ spyOn(processFilterService, 'getProcessFilters').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('FakeAllProcesses');
+ });
+
+ }));
+
+ it('should be able to fetch and select the default filters if the input filter is not valid', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').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 filter based on the input by name param', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
+
+ component.filterParam = new ProcessFilterParamModel({ name: 'FakeRunningProcesses' });
+ const appName = 'my-app-1';
+ let change = new SimpleChange(null, appName, true);
+
+ component.filterClick.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.currentFilter).toBeDefined();
+ expect(component.currentFilter.name).toEqual('FakeRunningProcesses');
+ done();
+ });
+
+ fixture.detectChanges();
+ component.ngOnChanges({ 'appName': change });
+
+ });
+
+ it('should select the filter based on the input by key param', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
+
+ component.filterParam = new ProcessFilterParamModel({ key: 'completed-processes' });
+ const appName = 'my-app-1';
+ let change = new SimpleChange(null, appName, true);
+
+ fixture.detectChanges();
+
+ component.filterClick.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.currentFilter).toBeDefined();
+ expect(component.currentFilter.name).toEqual('FakeCompletedProcesses');
+ done();
+ });
+
+ component.ngOnChanges({ 'appName': change });
+
+ });
+
+ it('should select the default filter if filter input does not exist', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
+
+ component.filterParam = new ProcessFilterParamModel({ name: 'UnexistableFilter' });
+
+ const appName = 'my-app-1';
+ let change = new SimpleChange(null, appName, true);
+
+ fixture.detectChanges();
+
+ component.filterClick.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.currentFilter).toBeDefined();
+ expect(component.currentFilter.name).toEqual('FakeAllProcesses');
+ done();
+ });
+
+ component.ngOnChanges({ 'appName': change });
+
+ });
+
+ it('should select the filter based on the input by index param', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
+
+ component.filterParam = new ProcessFilterParamModel({ index: 2 });
+
+ const appName = 'my-app-1';
+ let change = new SimpleChange(null, appName, true);
+ fixture.detectChanges();
+
+ component.filterClick.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.currentFilter).toBeDefined();
+ expect(component.currentFilter.name).toEqual('FakeCompletedProcesses');
+ done();
+ });
+
+ component.ngOnChanges({ 'appName': change });
+
+ });
+
+ it('should select the filter based on the input by id param', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
+
+ component.filterParam = new ProcessFilterParamModel({ id: '12' });
+
+ const appName = 'my-app-1';
+ let change = new SimpleChange(null, appName, true);
+ fixture.detectChanges();
+
+ component.filterClick.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.currentFilter).toBeDefined();
+ expect(component.currentFilter.name).toEqual('FakeCompletedProcesses');
+ done();
+ });
+
+ component.ngOnChanges({ 'appName': change });
+ });
+
+ it('should emit an event when a filter is selected', (done) => {
+ spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
+
+ component.filterParam = new ProcessFilterParamModel({ id: '10' });
+
+ const appName = 'my-app-1';
+ let change = new SimpleChange(null, appName, true);
+ component.ngOnChanges({ 'appName': change });
+ fixture.detectChanges();
+
+ component.filterClick.subscribe((res) => {
+ expect(res).toBeDefined();
+ expect(component.currentFilter).toBeDefined();
+ expect(component.currentFilter.name).toEqual('FakeRunningProcesses');
+ done();
+ });
+
+ let filterButton = fixture.debugElement.nativeElement.querySelector('span[data-automation-id="FakeRunningProcesses_filter"]');
+ filterButton.click();
+ });
+
+ 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( {id: filter.id});
+ expect(component.getCurrentFilter()).toBe(filter);
+ });
+});
diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.ts
new file mode 100644
index 0000000000..79ce89fbd1
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.ts
@@ -0,0 +1,186 @@
+/*!
+ * @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 { ProcessFilterCloudService } from '../services/process-filter-cloud.service';
+import { ProcessFilterRepresentationModel, ProcessFilterParamModel } from '../models/process-filter-cloud.model';
+import { TranslationService } from '@alfresco/adf-core';
+@Component({
+ selector: 'adf-cloud-process-filters',
+ templateUrl: './process-filters-cloud.component.html',
+ styleUrls: ['process-filters-cloud.component.scss']
+})
+export class ProcessFiltersCloudComponent implements OnChanges {
+
+ /** (required) The application name */
+ @Input()
+ appName: string;
+
+ /** (optional) The filter to be selected by default */
+ @Input()
+ filterParam: ProcessFilterParamModel;
+
+ /** (optional) The flag hides/shows icon against each filter */
+ @Input()
+ showIcons: boolean = false;
+
+ /** Emitted when a filter is selected/clicked */
+ @Output()
+ filterClick: EventEmitter = new EventEmitter();
+
+ /** Emitted when filters are loaded successfully */
+ @Output()
+ success: EventEmitter = new EventEmitter();
+
+ /** Emitted when any error occurs while loading the filters */
+ @Output()
+ error: EventEmitter = new EventEmitter();
+
+ filters$: Observable;
+
+ currentFilter: ProcessFilterRepresentationModel;
+
+ filters: ProcessFilterRepresentationModel [] = [];
+
+ constructor(
+ private processFilterCloudService: ProcessFilterCloudService,
+ private translate: TranslationService ) { }
+
+ 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.selectFilterAndEmit(filter.currentValue);
+ }
+ }
+
+ /**
+ * Fetch the filter list based on appName
+ */
+ getFilters(appName: string) {
+ this.filters$ = this.processFilterCloudService.getProcessFilters(appName);
+
+ this.filters$.subscribe(
+ (res: ProcessFilterRepresentationModel[]) => {
+ 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 appName
+ */
+ createFilters(appName?: string) {
+ this.filters$ = this.processFilterCloudService.createDefaultFilters(appName);
+
+ this.filters$.subscribe(
+ (resDefault: ProcessFilterRepresentationModel[]) => {
+ this.resetFilter();
+ this.filters = resDefault;
+ },
+ (errDefault: any) => {
+ this.error.emit(errDefault);
+ }
+ );
+ }
+
+ /**
+ * Pass the selected filter as next
+ */
+ public selectFilter(filterParam: ProcessFilterParamModel) {
+ if (filterParam) {
+ this.currentFilter = this.filters.find((filter, index) => {
+ return filterParam.id === filter.id ||
+ (filterParam.name && this.checkFilterNamesEquality(filterParam.name, filter.name)) ||
+ (filterParam.key && (filterParam.key === filter.key)) ||
+ filterParam.index === index;
+ });
+ }
+ if (!this.currentFilter) {
+ this.selectDefaultProcessFilter();
+ }
+ }
+
+ /**
+ * Check equality of the filter names by translating the given name strings
+ */
+ private checkFilterNamesEquality(name1: string, name2: string ): boolean {
+ const translatedName1 = this.translate.instant(name1);
+ const translatedName2 = this.translate.instant(name2);
+
+ return translatedName1.toLocaleLowerCase() === translatedName2.toLocaleLowerCase();
+ }
+
+ /**
+ * Select and emit the given filter
+ */
+ public selectFilterAndEmit(newFilter: ProcessFilterParamModel) {
+ this.selectFilter(newFilter);
+ this.filterClick.emit(this.currentFilter);
+ }
+
+ /**
+ * Select filter with the id
+ */
+ public selectFilterById(id: string) {
+ this.selectFilterAndEmit( {id: id});
+ }
+
+ /**
+ * Select as default process filter the first in the list
+ */
+ public selectDefaultProcessFilter() {
+ if (!this.isFilterListEmpty()) {
+ this.currentFilter = this.filters[0];
+ }
+ }
+
+ /**
+ * Return the current process
+ */
+ getCurrentFilter(): ProcessFilterRepresentationModel {
+ 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
+ */
+ private resetFilter() {
+ this.filters = [];
+ this.currentFilter = undefined;
+ }
+}
diff --git a/lib/process-services-cloud/src/lib/process-cloud/public-api.ts b/lib/process-services-cloud/src/lib/process-cloud/public-api.ts
new file mode 100644
index 0000000000..2438eb04b6
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-cloud/public-api.ts
@@ -0,0 +1,20 @@
+/*!
+ * @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 './process-filters-cloud/process-filters-cloud.component';
+export * from './models/process-filter-cloud.model';
+export * from './process-cloud.module';
diff --git a/lib/process-services-cloud/src/lib/process-cloud/services/process-filter-cloud.service.ts b/lib/process-services-cloud/src/lib/process-cloud/services/process-filter-cloud.service.ts
new file mode 100644
index 0000000000..d56f916ea2
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/process-cloud/services/process-filter-cloud.service.ts
@@ -0,0 +1,133 @@
+/*!
+ * @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 { StorageService } from '@alfresco/adf-core';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { ProcessFilterRepresentationModel, ProcessQueryModel } from '../models/process-filter-cloud.model';
+
+@Injectable()
+export class ProcessFilterCloudService {
+
+ constructor(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 {
+ const allProcessesFilter = this.getAllProcessesFilter(appName);
+ this.addFilter(allProcessesFilter);
+ const runningProcessesFilter = this.getRunningProcessesFilter(appName);
+ this.addFilter(runningProcessesFilter);
+ const completedProcessesFilter = this.getCompletedProcessesFilter(appName);
+ this.addFilter(completedProcessesFilter);
+
+ return this.getProcessFilters(appName);
+ }
+
+ /**
+ * Gets all process instance filters for a process app.
+ * @param appName Name of the target app
+ * @returns Observable of process filter details
+ */
+ getProcessFilters(appName: string): Observable {
+ let key = 'process-filters-' + appName;
+ const filters = JSON.parse(this.storage.getItem(key) || '[]');
+ return new Observable(function(observer) {
+ observer.next(filters);
+ observer.complete();
+ });
+ }
+
+ /**
+ * Adds a new process instance filter
+ * @param filter The new filter to add
+ * @returns Details of process filter just added
+ */
+ addFilter(filter: ProcessFilterRepresentationModel) {
+ const key = 'process-filters-' + filter.query.appName;
+ const storedFilters = JSON.parse(this.storage.getItem(key) || '[]');
+
+ storedFilters.push(filter);
+ this.storage.setItem(key, JSON.stringify(storedFilters));
+ }
+
+ /**
+ * Creates and returns a filter for "All" Process instances.
+ * @param appName Name of the target app
+ * @returns The newly created filter
+ */
+ getAllProcessesFilter(appName: string): ProcessFilterRepresentationModel {
+ return new ProcessFilterRepresentationModel({
+ name: 'ADF_CLOUD_PROCESS_FILTERS.ALL_PROCESSES',
+ key: 'all-processes',
+ icon: 'adjust',
+ query: new ProcessQueryModel(
+ {
+ appName: appName,
+ sort: 'startDate',
+ order: 'DESC'
+ }
+ )
+ });
+ }
+
+ /**
+ * Creates and returns a filter for "Running" Process instances.
+ * @param appName Name of the target app
+ * @returns The newly created filter
+ */
+ getRunningProcessesFilter(appName: string): ProcessFilterRepresentationModel {
+ return new ProcessFilterRepresentationModel({
+ name: 'ADF_CLOUD_PROCESS_FILTERS.RUNNING_PROCESSES',
+ icon: 'inbox',
+ key: 'running-processes',
+ query: new ProcessQueryModel(
+ {
+ appName: appName,
+ sort: 'startDate',
+ state: 'RUNNING',
+ order: 'DESC'
+ }
+ )
+ });
+ }
+
+ /**
+ * Creates and returns a filter for "Completed" Process instances.
+ * @param appName Name of the target app
+ * @returns The newly created filter
+ */
+ getCompletedProcessesFilter(appName: string): ProcessFilterRepresentationModel {
+ return new ProcessFilterRepresentationModel({
+ name: 'ADF_CLOUD_PROCESS_FILTERS.COMPLETED_PROCESSES',
+ icon: 'done',
+ key: 'completed-processes',
+ query: new ProcessQueryModel(
+ {
+ appName: appName,
+ sort: 'startDate',
+ state: 'COMPLETED',
+ order: 'DESC'
+ }
+ )
+ });
+ }
+}
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
index e2e8f3ca93..81b905e4d1 100644
--- 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
@@ -19,8 +19,8 @@
+ [title]="'ADF_CLOUD_PROCESS_LIST.MESSAGES.TITLE' | translate"
+ [subtitle]="'ADF_CLOUD_PROCESS_LIST.MESSAGES.SUBTITLE'| translate">
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 8e8c894323..a6cac373ee 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,16 +1,35 @@
+/*!
+ * @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 { 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';
+import { ProcessCloudModule } from './process-cloud/process-cloud.module';
@NgModule({
imports: [
AppListCloudModule,
TaskListCloudModule,
TaskCloudModule,
- ProcessListCloudModule
+ ProcessListCloudModule,
+ ProcessCloudModule
],
providers: [
{
@@ -23,6 +42,11 @@ import { ProcessListCloudModule } from './process-list-cloud/process-list-cloud.
}
],
declarations: [],
- exports: [AppListCloudModule, TaskListCloudModule, TaskCloudModule, ProcessListCloudModule]
+ exports: [
+ AppListCloudModule,
+ TaskListCloudModule,
+ TaskCloudModule,
+ ProcessListCloudModule,
+ ProcessCloudModule]
})
export class ProcessServicesCloudModule { }