From eb3a81252561a67d62833231d1457dc9e4b669f5 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 22 Sep 2016 14:45:03 +0100 Subject: [PATCH 1/4] Add property showNextTask and refactoring --- .../activiti-task-details.component.html | 8 +- .../activiti-task-details.component.ts | 74 ++++++++++++++++--- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.html b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.html index 6e91517b49..46992cb1b1 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.html +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.html @@ -22,11 +22,11 @@ { @@ -169,6 +177,31 @@ export class ActivitiTaskDetails implements OnInit, OnChanges { } } + /** + * Retrieve the next open task + * @param processInstanceId + * @param processDefinitionId + */ + loadNextTask(processInstanceId: string, processDefinitionId: string) { + let requestNode = new TaskQueryRequestRepresentationModel( + { + processInstanceId: processInstanceId, + processDefinitionId: processDefinitionId + } + ); + this.activitiTaskList.getTasks(requestNode).subscribe( + (response) => { + if (response.data && response.data.length > 0) { + this.taskDetails = response.data[0]; + } else { + this.reset(); + } + }, (error) => { + console.error(error); + this.onError.emit(error); + }); + } + /** * Complete the activiti task */ @@ -194,6 +227,9 @@ export class ActivitiTaskDetails implements OnInit, OnChanges { */ formCompletedEmitter(data: any) { this.formCompleted.emit(data); + if (this.isShowNextTask()) { + this.loadNextTask(this.taskDetails.processInstanceId, this.taskDetails.processDefinitionId); + } } /** @@ -204,11 +240,27 @@ export class ActivitiTaskDetails implements OnInit, OnChanges { this.formLoaded.emit(data); } + /** + * Emit the error event of the form + * @param data + */ onErrorEmitter(err: any) { this.onError.emit(err); } + /** + * Emit the execute outcome of the form + * @param data + */ executeOutcomeEmitter(data: any) { this.executeOutcome.emit(data); } + + /** + * Return the showNexTask value + * @returns {boolean} + */ + isShowNextTask(): boolean { + return this.showNextTask; + } } From 1dffc2d10029b10c58a5706db47a1e4e61237159 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 22 Sep 2016 14:45:12 +0100 Subject: [PATCH 2/4] Fix documentation --- ng2-components/ng2-activiti-tasklist/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ng2-components/ng2-activiti-tasklist/README.md b/ng2-components/ng2-activiti-tasklist/README.md index 374581a818..c8b225ebc9 100644 --- a/ng2-components/ng2-activiti-tasklist/README.md +++ b/ng2-components/ng2-activiti-tasklist/README.md @@ -106,8 +106,13 @@ The component shows the details of the task id passed in input #### Options -**taskId**: { string } required) The id of the task details that we -are asking for. +**taskId**: { string } required) The id of the task details that we are asking for. +**showNextTask**: { boolean } optional) Automatically render the next one, when the task is completed. +**showFormTitle**: { boolean } optional) Toggle rendering of the form title. +**readOnlyForm**: { boolean } optional) Toggle readonly state of the form. Enforces all form widgets render readonly if enabled. +**showFormRefreshButton**: { boolean } optional) Toggle rendering of the `Refresh` button. +**showFormSaveButton**: { boolean } optional) Toggle rendering of the `Save` outcome button. +**showFormCompleteButton**: { boolean } optional) Toggle rendering of the Form `Complete` outcome button ### Custom 'empty Activiti Task Details' template From 63a7b27eedf4caddba55010360af0f509957104d Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 22 Sep 2016 17:06:08 +0100 Subject: [PATCH 3/4] Refactoring and fix unit test --- .../components/activiti-filters.component.ts | 38 +++++++++----- .../activiti-filters.component.spec.ts | 52 ++++++++++++++++++- .../components/activiti-filters.component.ts | 40 +++++++++----- 3 files changed, 104 insertions(+), 26 deletions(-) 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 039c2571b3..46cb8178a6 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 @@ -77,30 +77,40 @@ export class ActivitiProcessFilters implements OnInit, OnChanges { this.filters.push(filter); }); - this.load(); + this.getFilters(this.appId, this.appName); } ngOnChanges(changes: SimpleChanges) { let appId = changes['appId']; if (appId && (appId.currentValue || appId.currentValue === null)) { - this.load(); + this.getFiltersByAppId(appId.currentValue); + return; + } + let appName = changes['appName']; + if (appName && appName.currentValue) { + this.getFiltersByAppName(appName.currentValue); return; } } /** - * The method call the adapter data table component for render the task list - * @param tasks + * Return the task list filtered by appId or by appName + * @param appId + * @param appName */ - private load() { - if (this.appName) { - this.filterByAppName(); + getFilters(appId?: string, appName?: string) { + if (appName) { + this.getFiltersByAppName(appName); } else { - this.filterByAppId(this.appId); + this.getFiltersByAppId(appId); } } - private filterByAppId(appId) { + /** + * Return the filter list filtered by appId + * @param appId - optional + */ + getFiltersByAppId(appId?: string) { this.activiti.getProcessFilters(appId).subscribe( (res: FilterRepresentationModel[]) => { this.resetFilter(); @@ -117,10 +127,14 @@ export class ActivitiProcessFilters implements OnInit, OnChanges { ); } - private filterByAppName() { - this.activiti.getDeployedApplications(this.appName).subscribe( + /** + * Return the filter list filtered by appName + * @param appName + */ + getFiltersByAppName(appName: string) { + this.activiti.getDeployedApplications(appName).subscribe( application => { - this.filterByAppId(application.id); + this.getFiltersByAppId(application.id); this.selectFirstFilter(); }, (err) => { 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 04c5783015..4ca2831f56 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 { expect, beforeEach } from '@angular/core/testing'; - +import { SimpleChange } from '@angular/core'; import { ActivitiFilters } from './activiti-filters.component'; import { ActivitiTaskListService } from '../services/activiti-tasklist.service'; import { Observable } from 'rxjs/Rx'; @@ -89,6 +89,7 @@ describe('ActivitiFilters', () => { }); it('should emit an error with a bad response', (done) => { + filterList.appId = '1'; spyOn(filterList.activiti, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise)); filterList.onError.subscribe((err) => { @@ -99,6 +100,18 @@ describe('ActivitiFilters', () => { filterList.ngOnInit(); }); + it('should emit an error with a bad response', (done) => { + filterList.appName = 'fake-app'; + spyOn(filterList.activiti, 'getDeployedApplications').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise)); + + filterList.onError.subscribe((err) => { + expect(err).toBeDefined(); + done(); + }); + + filterList.ngOnInit(); + }); + it('should emit an event when a filter is selected', (done) => { let currentFilter = new FilterRepresentationModel({filter: { state: 'open', assignment: 'fake-involved'}}); @@ -112,4 +125,41 @@ describe('ActivitiFilters', () => { filterList.selectFilter(currentFilter); }); + it('should reload filters by appId on binding changes', () => { + spyOn(filterList, 'getFiltersByAppId').and.stub(); + const appId = '1'; + + let change = new SimpleChange(null, appId); + filterList.ngOnChanges({ 'appId': change }); + + expect(filterList.getFiltersByAppId).toHaveBeenCalledWith(appId); + }); + + it('should reload filters by appId null on binding changes', () => { + spyOn(filterList, 'getFiltersByAppId').and.stub(); + const appId = null; + + let change = new SimpleChange(null, appId); + filterList.ngOnChanges({ 'appId': change }); + + expect(filterList.getFiltersByAppId).toHaveBeenCalledWith(appId); + }); + + it('should reload filters by app name on binding changes', () => { + spyOn(filterList, 'getFiltersByAppName').and.stub(); + const appName = 'fake-app-name'; + + let change = new SimpleChange(null, appName); + filterList.ngOnChanges({ 'appName': change }); + + expect(filterList.getFiltersByAppName).toHaveBeenCalledWith(appName); + }); + + it('should return the current filter after one is selected', () => { + let filter = new FilterRepresentationModel({name: 'FakeMyTasks', filter: { state: 'open', assignment: 'fake-assignee'}}); + expect(filterList.currentFilter).toBeUndefined(); + filterList.selectFilter(filter); + expect(filterList.getCurrentFilter()).toBe(filter); + }); + }); 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 931e205783..9355ee363d 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 @@ -77,37 +77,47 @@ export class ActivitiFilters implements OnInit, OnChanges { this.filters.push(filter); }); - this.load(); + this.getFilters(this.appId, this.appName); } ngOnChanges(changes: SimpleChanges) { let appId = changes['appId']; if (appId && (appId.currentValue || appId.currentValue === null)) { - this.load(); + this.getFiltersByAppId(appId.currentValue); + return; + } + let appName = changes['appName']; + if (appName && appName.currentValue) { + this.getFiltersByAppName(appName.currentValue); return; } } /** - * The method call the adapter data table component for render the task list - * @param tasks + * Return the task list filtered by appId or by appName + * @param appId + * @param appName */ - private load() { - if (this.appName) { - this.filterByAppName(); + getFilters(appId?: string, appName?: string) { + if (appName) { + this.getFiltersByAppName(appName); } else { - this.filterByAppId(this.appId); + this.getFiltersByAppId(appId); } } - private filterByAppId(appId) { + /** + * Return the filter list filtered by appId + * @param appId - optional + */ + getFiltersByAppId(appId?: string) { this.activiti.getTaskListFilters(appId).subscribe( (res: FilterRepresentationModel[]) => { this.resetFilter(); res.forEach((filter) => { this.filterObserver.next(filter); - this.selectFirstFilter(); }); + this.selectFirstFilter(); this.onSuccess.emit(res); }, (err) => { @@ -117,10 +127,14 @@ export class ActivitiFilters implements OnInit, OnChanges { ); } - private filterByAppName() { - this.activiti.getDeployedApplications(this.appName).subscribe( + /** + * Return the filter list filtered by appName + * @param appName + */ + getFiltersByAppName(appName: string) { + this.activiti.getDeployedApplications(appName).subscribe( application => { - this.filterByAppId(application.id); + this.getFiltersByAppId(application.id); this.selectFirstFilter(); }, (err) => { From a2e5bca63e9d62fe90d14a33a7b8526729bdeaff Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 22 Sep 2016 17:06:17 +0100 Subject: [PATCH 4/4] Improve test coverage --- .../activiti-tasklist.component.spec.ts | 18 +++++++++++++++++- .../components/activiti-tasklist.component.ts | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-tasklist.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-tasklist.component.spec.ts index bea68053ea..6e0780a68f 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-tasklist.component.spec.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-tasklist.component.spec.ts @@ -21,7 +21,7 @@ import { expect, beforeEach } from '@angular/core/testing'; - +import { SimpleChange } from '@angular/core'; import { ActivitiTaskList } from './activiti-tasklist.component'; import { ActivitiTaskListService } from '../services/activiti-tasklist.service'; import { UserTaskFilterRepresentationModel } from '../models/filter.model'; @@ -120,6 +120,11 @@ describe('ActivitiTaskList', () => { taskList.ngOnInit(); }); + it('should return a currentId null when the taskList is empty', () => { + taskList.selectFirstTask(); + expect(taskList.getCurrentTaskId()).toBeNull(); + }); + it('should throw an exception when the response is wrong', (done) => { spyOn(taskList.activiti, 'getTotalTasks').and.returnValue(Observable.fromPromise(fakeErrorTaskPromise)); taskList.taskFilter = new UserTaskFilterRepresentationModel({filter: { state: 'open', assignment: 'fake-assignee'}}); @@ -140,10 +145,21 @@ describe('ActivitiTaskList', () => { taskList.rowClick.subscribe(taskId => { expect(taskId).toEqual(999); + expect(taskList.getCurrentTaskId()).toEqual(999); done(); }); taskList.onRowClick(rowEvent); }); + it('should reload task list by filter on binding changes', () => { + spyOn(taskList, 'load').and.stub(); + const taskFilter = new UserTaskFilterRepresentationModel({filter: { state: 'open', assignment: 'fake-assignee'}}); + + let change = new SimpleChange(null, taskFilter); + taskList.ngOnChanges({ 'taskFilter': change }); + + expect(taskList.load).toHaveBeenCalled(); + }); + }); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-tasklist.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-tasklist.component.ts index ae8da9b896..f825d9362f 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-tasklist.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-tasklist.component.ts @@ -146,7 +146,7 @@ export class ActivitiTaskList implements OnInit, OnChanges { /** * Select the first task of a tasklist if present */ - private selectFirstTask() { + selectFirstTask() { if (!this.isTaskListEmpty()) { this.currentTaskId = this.data.getRows()[0].getValue('id'); } else {