From c278fd99103c29e7d76327a733eb06461a77e8d3 Mon Sep 17 00:00:00 2001 From: Maurizio Vitale Date: Tue, 6 Jun 2017 15:29:45 +0100 Subject: [PATCH] [ADF-702] Task/Process Filter - Provide a way to change the default filter (#1932) * [ADF-702] Task/Process Filter - Provide a way to change the default filter * Provide a way to select a custom menu filter * Improve activiti process filter * Add internal link * Change link name * add link --- .../activiti/activiti-demo.component.html | 2 + .../ng2-activiti-processlist/README.md | 35 +++++- .../components/activiti-filters.component.ts | 38 ++++-- .../src/models/filter-process.model.ts | 19 +++ .../ng2-activiti-tasklist/README.md | 35 +++++- .../activiti-filters.component.spec.ts | 115 +++++++++++++++++- .../components/activiti-filters.component.ts | 41 +++++-- .../src/models/filter.model.ts | 19 +++ 8 files changed, 274 insertions(+), 30 deletions(-) diff --git a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html index 91a53fa0d8..a18ef2d259 100644 --- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html +++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html @@ -28,6 +28,7 @@ diff --git a/ng2-components/ng2-activiti-processlist/README.md b/ng2-components/ng2-activiti-processlist/README.md index 9c4e2f1250..4b4f657f97 100644 --- a/ng2-components/ng2-activiti-processlist/README.md +++ b/ng2-components/ng2-activiti-processlist/README.md @@ -233,10 +233,12 @@ process instances are displayed in the list. #### Options -| Name | Description | -| --- | --- | -| `appId` | Display filters available to the current user for the application with the specified ID | -| `appName` | Display filters available to the current user for the application with the specified name | +| Name | Type | Required | Description | +| --- | --- | --- | --- | +| `filterParam` | {[Filter Params models](#filter-params--models)} | optional | The params to filter the task filter. If there is no match the default one (first filter of the list) is selected | +| `appId` | {string} | optional | Display filters available to the current user for the application with the specified ID. | +| `appName` | {string} | optional | Display filters available to the current user for the application with the specified name. | +| `hasIcon` | {boolean} | optional | Toggle to show or not the filter's icon. | If both `appId` and `appName` are specified then `appName` will take precedence and `appId` will be ignored. @@ -246,7 +248,30 @@ If both `appId` and `appName` are specified then `appName` will take precedence | --- | --- | | `onSuccess` | Emitted when the list of filters hase been successfully loaded from the server | | `onError` | Emitted when an error occurs | -| `ilterClick` | Emitted when the user selects a filter from the list | +| `filterClick` | Emitted when the user selects a filter from the list | + +### How filter the activiti process filters + + ```html + + ``` + +You can use inside the filterParam one of the following property. +## Filter Params models +```json +{ + "id": "number", + "name": "string", + "index": "number" +} +``` + +| Name | Description | +| --- | --- | +| `id` | The id of the task filter | +| `name` | The name of the task filter, lowercase is checked | +| `index` | The position of the filter in the array. The first position is 0 | + ### How to create an accordion menu with the processes filter diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.ts index 76b1a2b902..ef62ca8d14 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.ts @@ -18,7 +18,7 @@ import { Component, Output, EventEmitter, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core'; import { Observable, Observer } from 'rxjs/Rx'; import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core'; -import { FilterProcessRepresentationModel } from './../models/filter-process.model'; +import { FilterProcessRepresentationModel, FilterParamsModel } from './../models/filter-process.model'; import { ActivitiProcessService } from './../services/activiti-process.service'; declare let componentHandler: any; @@ -30,6 +30,9 @@ declare let componentHandler: any; }) export class ActivitiProcessFilters implements OnInit, OnChanges { + @Input() + filterParam: FilterParamsModel; + @Output() filterClick: EventEmitter = new EventEmitter(); @@ -99,7 +102,7 @@ export class ActivitiProcessFilters implements OnInit, OnChanges { this.filterObserver.next(filter); }); - this.selectFirstFilter(); + this.selectTaskFilter(this.filterParam); this.onSuccess.emit(resDefault); }, (errDefault: any) => { @@ -112,7 +115,7 @@ export class ActivitiProcessFilters implements OnInit, OnChanges { this.filterObserver.next(filter); }); - this.selectFirstFilter(); + this.selectTaskFilter(this.filterParam); this.onSuccess.emit(res); } }, @@ -130,7 +133,7 @@ export class ActivitiProcessFilters implements OnInit, OnChanges { this.activiti.getDeployedApplications(appName).subscribe( application => { this.getFiltersByAppId(application.id); - this.selectFirstFilter(); + this.selectTaskFilter(this.filterParam); }, (err) => { this.onError.emit(err); @@ -149,11 +152,26 @@ export class ActivitiProcessFilters implements OnInit, OnChanges { /** * Select the first filter of a list if present */ - public selectFirstFilter() { + public selectTaskFilter(filterParam: FilterParamsModel) { + if (filterParam) { + this.filters.filter((taskFilter: FilterProcessRepresentationModel, index) => { + if (filterParam.name && filterParam.name.toLowerCase() === taskFilter.name.toLowerCase() || + filterParam.id === taskFilter.id || filterParam.index === index) { + this.currentFilter = taskFilter; + } + }); + } + if (this.isCurrentFilterEmpty()) { + this.selectDefaultTaskFilter(); + } + } + + /** + * Select as default task filter the first in the list + */ + public selectDefaultTaskFilter() { if (!this.isFilterListEmpty()) { this.currentFilter = this.filters[0]; - } else { - this.currentFilter = null; } } @@ -178,6 +196,10 @@ export class ActivitiProcessFilters implements OnInit, OnChanges { */ private resetFilter() { this.filters = []; - this.currentFilter = null; + this.currentFilter = undefined; + } + + private isCurrentFilterEmpty(): boolean { + return this.currentFilter === undefined || null ? true : false; } } diff --git a/ng2-components/ng2-activiti-processlist/src/models/filter-process.model.ts b/ng2-components/ng2-activiti-processlist/src/models/filter-process.model.ts index af4d9b8fb0..e14e98578c 100644 --- a/ng2-components/ng2-activiti-processlist/src/models/filter-process.model.ts +++ b/ng2-components/ng2-activiti-processlist/src/models/filter-process.model.ts @@ -46,6 +46,25 @@ export class FilterProcessRepresentationModel { } } +/** + * + * This object represent the parameters to filter a filter. + * + * + * @returns {FilterParamsModel} . + */ +export class FilterParamsModel { + id: string; + name: string; + index: number; + + constructor(obj?: any) { + this.id = obj && obj.id || null; + this.name = obj && obj.name || null; + this.index = obj && obj.index; + } +} + /** * * This object represent the parameters of a process filter. diff --git a/ng2-components/ng2-activiti-tasklist/README.md b/ng2-components/ng2-activiti-tasklist/README.md index 9885cbfbb1..b9dd95d991 100644 --- a/ng2-components/ng2-activiti-tasklist/README.md +++ b/ng2-components/ng2-activiti-tasklist/README.md @@ -351,10 +351,43 @@ The component shows all the available filters. | Name | Description | | --- | --- | | `filterClick` | The event is emitted when the filter in the list is clicked | +| `onSuccess` | The event is emitted when the list is loaded | +| `onError` | The event is emitted if there is an error during the loading | #### Options -No options +| Name | Type | Required | Description | +| --- | --- | --- | --- | +| `filterParam` | {[Filter Params models](#filter-params--models)} | optional | The params to filter the task filter. If there is no match the default one (first filter of the list) is selected | +| `appId` | {string} | optional | Display filters available to the current user for the application with the specified ID. | +| `appName` | {string} | optional | Display filters available to the current user for the application with the specified name. | +| `hasIcon` | {boolean} | optional | Toggle to show or not the filter's icon. | + +If both `appId` and `appName` are specified then `appName` will take precedence and `appId` will be ignored. + +### How filter the activiti task filters + + ```html + + ``` + +You can use inside the filterParam one of the following property. +## Filter Params models +```json +{ + "id": "number", + "name": "string", + "index": "number" +} +``` + +| Name | Description | +| --- | --- | +| `id` | The id of the task filter | +| `name` | The name of the task filter, lowercase is checked | +| `index` | The position of the filter in the array. The first position is 0 | + + ### How to create an accordion menu with the task filter diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-filters.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-filters.component.spec.ts index 34090ae886..bf9472ed19 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-filters.component.spec.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-filters.component.spec.ts @@ -21,7 +21,7 @@ import { Observable } from 'rxjs/Rx'; import { LogServiceMock } from 'ng2-alfresco-core'; import { ActivitiFilters } from './activiti-filters.component'; import { ActivitiTaskListService } from '../services/activiti-tasklist.service'; -import { FilterRepresentationModel } from '../models/filter.model'; +import { FilterRepresentationModel, FilterParamsModel } from '../models/filter.model'; describe('ActivitiFilters', () => { @@ -32,14 +32,22 @@ describe('ActivitiFilters', () => { let fakeGlobalFilter = []; fakeGlobalFilter.push(new FilterRepresentationModel({ name: 'FakeInvolvedTasks', + id: 10, filter: { state: 'open', assignment: 'fake-involved' } })); fakeGlobalFilter.push(new FilterRepresentationModel({ - name: 'FakeMyTasks', + name: 'FakeMyTasks1', + id: 11, filter: { state: 'open', assignment: 'fake-assignee' } })); + fakeGlobalFilter.push(new FilterRepresentationModel({ + name: 'FakeMyTasks2', + id: 12, + filter: { state: 'open', assignment: 'fake-assignee' } + })); + let fakeFilter = new FilterRepresentationModel({ - name: 'FakeMyTasks', + name: 'FakeMyTasks1', filter: { state: 'open', assignment: 'fake-assignee' } }); @@ -70,9 +78,10 @@ describe('ActivitiFilters', () => { filterList.onSuccess.subscribe((res) => { expect(res).toBeDefined(); expect(filterList.filters).toBeDefined(); - expect(filterList.filters.length).toEqual(2); + expect(filterList.filters.length).toEqual(3); expect(filterList.filters[0].name).toEqual('FakeInvolvedTasks'); - expect(filterList.filters[1].name).toEqual('FakeMyTasks'); + expect(filterList.filters[1].name).toEqual('FakeMyTasks1'); + expect(filterList.filters[2].name).toEqual('FakeMyTasks2'); done(); }); @@ -131,6 +140,99 @@ describe('ActivitiFilters', () => { filterList.ngOnInit(); }); + it('should select the first filter as default', (done) => { + spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); + + const appId = '1'; + let change = new SimpleChange(null, appId, true); + filterList.ngOnChanges({ 'appId': change }); + + filterList.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(filterList.currentFilter).toBeDefined(); + expect(filterList.currentFilter.name).toEqual('FakeInvolvedTasks'); + done(); + }); + + filterList.ngOnInit(); + }); + + it('should select the task filter based on the input by name param', (done) => { + spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); + + filterList.filterParam = new FilterParamsModel({name: 'FakeMyTasks1'}); + + const appId = '1'; + let change = new SimpleChange(null, appId, true); + filterList.ngOnChanges({ 'appId': change }); + + filterList.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(filterList.currentFilter).toBeDefined(); + expect(filterList.currentFilter.name).toEqual('FakeMyTasks1'); + done(); + }); + + filterList.ngOnInit(); + }); + + it('should select the default task filter if filter input does not exist', (done) => { + spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); + + filterList.filterParam = new FilterParamsModel({name: 'UnexistableFilter'}); + + const appId = '1'; + let change = new SimpleChange(null, appId, true); + filterList.ngOnChanges({ 'appId': change }); + + filterList.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(filterList.currentFilter).toBeDefined(); + expect(filterList.currentFilter.name).toEqual('FakeInvolvedTasks'); + done(); + }); + + filterList.ngOnInit(); + }); + + it('should select the task filter based on the input by index param', (done) => { + spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); + + filterList.filterParam = new FilterParamsModel({index: 2}); + + const appId = '1'; + let change = new SimpleChange(null, appId, true); + filterList.ngOnChanges({ 'appId': change }); + + filterList.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(filterList.currentFilter).toBeDefined(); + expect(filterList.currentFilter.name).toEqual('FakeMyTasks2'); + done(); + }); + + filterList.ngOnInit(); + }); + + it('should select the task filter based on the input by id param', (done) => { + spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); + + filterList.filterParam = new FilterParamsModel({id: 10}); + + const appId = '1'; + let change = new SimpleChange(null, appId, true); + filterList.ngOnChanges({ 'appId': change }); + + filterList.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(filterList.currentFilter).toBeDefined(); + expect(filterList.currentFilter.name).toEqual('FakeInvolvedTasks'); + done(); + }); + + filterList.ngOnInit(); + }); + it('should emit an event when a filter is selected', (done) => { let currentFilter = new FilterRepresentationModel({ filter: { state: 'open', assignment: 'fake-involved' } }); @@ -198,7 +300,8 @@ describe('ActivitiFilters', () => { filterList.filters = fakeGlobalFilter; filterList.selectFilterWithTask('111'); - expect(filterList.currentFilter).toBe(fakeFilter); + expect(filterList.currentFilter.landingTaskId).toBeDefined(); + expect(filterList.currentFilter.landingTaskId).toBe('111'); })); it('should not change the current filter if no filter with taskid is found', async(() => { diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-filters.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-filters.component.ts index 13b6c311e4..272c53f2a6 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-filters.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-filters.component.ts @@ -19,7 +19,7 @@ import { Component, Output, EventEmitter, OnInit, Input, SimpleChanges, OnChange import { Observer, Observable } from 'rxjs/Rx'; import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core'; import { ActivitiTaskListService } from './../services/activiti-tasklist.service'; -import { FilterRepresentationModel } from '../models/filter.model'; +import { FilterRepresentationModel, FilterParamsModel } from '../models/filter.model'; declare let componentHandler: any; @@ -31,6 +31,9 @@ declare let componentHandler: any; }) export class ActivitiFilters implements OnInit, OnChanges { + @Input() + filterParam: FilterParamsModel; + @Output() filterClick: EventEmitter = new EventEmitter(); @@ -115,7 +118,7 @@ export class ActivitiFilters implements OnInit, OnChanges { this.filterObserver.next(filter); }); - this.selectFirstFilter(); + this.selectTaskFilter(this.filterParam); this.onSuccess.emit(resDefault); }, (errDefault: any) => { @@ -128,7 +131,7 @@ export class ActivitiFilters implements OnInit, OnChanges { this.filterObserver.next(filter); }); - this.selectFirstFilter(); + this.selectTaskFilter(this.filterParam); this.onSuccess.emit(res); } }, @@ -146,7 +149,7 @@ export class ActivitiFilters implements OnInit, OnChanges { this.activiti.getDeployedApplications(appName).subscribe( application => { this.getFiltersByAppId(application.id); - this.selectFirstFilter(); + this.selectTaskFilter(this.filterParam); }, (err) => { this.onError.emit(err); @@ -173,8 +176,7 @@ export class ActivitiFilters implements OnInit, OnChanges { }, () => { if (filteredFilterList.length > 0) { - let myTaskFilter = filteredFilterList.find(filter => filter.name === 'My Tasks'); - this.currentFilter = myTaskFilter ? myTaskFilter : filteredFilterList[0]; + this.selectTaskFilter(new FilterParamsModel({name: 'My Tasks'})); this.currentFilter.landingTaskId = taskId; this.filterClick.emit(this.currentFilter); } @@ -184,11 +186,26 @@ export class ActivitiFilters implements OnInit, OnChanges { /** * Select the first filter of a list if present */ - public selectFirstFilter() { + public selectTaskFilter(filterParam: FilterParamsModel) { + if (filterParam) { + this.filters.filter((taskFilter: FilterRepresentationModel, index) => { + if (filterParam.name && filterParam.name.toLowerCase() === taskFilter.name.toLowerCase() || + filterParam.id === taskFilter.id || filterParam.index === index) { + this.currentFilter = taskFilter; + } + }); + } + if (this.isCurrentFilterEmpty()) { + this.selectDefaultTaskFilter(); + } + } + + /** + * Select as default task filter the first in the list + */ + public selectDefaultTaskFilter() { if (!this.isFilterListEmpty()) { this.currentFilter = this.filters[0]; - } else { - this.currentFilter = null; } } @@ -213,6 +230,10 @@ export class ActivitiFilters implements OnInit, OnChanges { */ private resetFilter() { this.filters = []; - this.currentFilter = null; + this.currentFilter = undefined; + } + + private isCurrentFilterEmpty(): boolean { + return this.currentFilter === undefined || null ? true : false; } } diff --git a/ng2-components/ng2-activiti-tasklist/src/models/filter.model.ts b/ng2-components/ng2-activiti-tasklist/src/models/filter.model.ts index 1de4733fc3..de1be72b89 100644 --- a/ng2-components/ng2-activiti-tasklist/src/models/filter.model.ts +++ b/ng2-components/ng2-activiti-tasklist/src/models/filter.model.ts @@ -46,6 +46,25 @@ export class AppDefinitionRepresentationModel { } } +/** + * + * This object represent the parameters to filter a filter. + * + * + * @returns {FilterParamsModel} . + */ +export class FilterParamsModel { + id: string; + name: string; + index: number; + + constructor(obj?: any) { + this.id = obj && obj.id || null; + this.name = obj && obj.name || null; + this.index = obj && obj.index; + } +} + /** * * This object represent the filter.