#1517 - Added new behaviour when user create a new task (#1769)

* #1517 - added search task into filters by id feature

* #1517 - added test for tasklist service

* #1517 - Added test for filter component
This commit is contained in:
Vito 2017-03-27 06:32:22 -07:00 committed by Mario Romano
parent f323c4be75
commit 016f0b3c09
5 changed files with 234 additions and 27 deletions

View File

@ -162,8 +162,9 @@ export class ActivitiDemoComponent implements AfterViewInit {
} }
onStartTaskSuccess(event: any) { onStartTaskSuccess(event: any) {
this.activitifilter.selectFirstFilter(); this.activitifilter.selectFilterWithTask(event.id);
this.taskFilter = this.activitifilter.getCurrentFilter(); this.taskFilter = this.activitifilter.getCurrentFilter();
this.activititasklist.landingTaskId = event.id;
this.activititasklist.reload(); this.activititasklist.reload();
} }

View File

@ -16,6 +16,7 @@
*/ */
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
import { async } from '@angular/core/testing';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { LogServiceMock } from 'ng2-alfresco-core'; import { LogServiceMock } from 'ng2-alfresco-core';
import { ActivitiFilters } from './activiti-filters.component'; import { ActivitiFilters } from './activiti-filters.component';
@ -29,8 +30,18 @@ describe('ActivitiFilters', () => {
let logService: LogServiceMock; let logService: LogServiceMock;
let fakeGlobalFilter = []; let fakeGlobalFilter = [];
fakeGlobalFilter.push(new FilterRepresentationModel({name: 'FakeInvolvedTasks', filter: { state: 'open', assignment: 'fake-involved'}})); fakeGlobalFilter.push(new FilterRepresentationModel({
fakeGlobalFilter.push(new FilterRepresentationModel({name: 'FakeMyTasks', filter: { state: 'open', assignment: 'fake-assignee'}})); name: 'FakeInvolvedTasks',
filter: { state: 'open', assignment: 'fake-involved' }
}));
fakeGlobalFilter.push(new FilterRepresentationModel({
name: 'FakeMyTasks',
filter: { state: 'open', assignment: 'fake-assignee' }
}));
let fakeFilter = new FilterRepresentationModel({
name: 'FakeMyTasks',
filter: { state: 'open', assignment: 'fake-assignee' }
});
let fakeGlobalFilterPromise = new Promise(function (resolve, reject) { let fakeGlobalFilterPromise = new Promise(function (resolve, reject) {
resolve(fakeGlobalFilter); resolve(fakeGlobalFilter);
@ -121,7 +132,7 @@ describe('ActivitiFilters', () => {
}); });
it('should emit an event when a filter is selected', (done) => { it('should emit an event when a filter is selected', (done) => {
let currentFilter = new FilterRepresentationModel({filter: { state: 'open', assignment: 'fake-involved'}}); let currentFilter = new FilterRepresentationModel({ filter: { state: 'open', assignment: 'fake-involved' } });
filterList.filterClick.subscribe((filter: FilterRepresentationModel) => { filterList.filterClick.subscribe((filter: FilterRepresentationModel) => {
expect(filter).toBeDefined(); expect(filter).toBeDefined();
@ -164,7 +175,10 @@ describe('ActivitiFilters', () => {
}); });
it('should return the current filter after one is selected', () => { it('should return the current filter after one is selected', () => {
let filter = new FilterRepresentationModel({name: 'FakeMyTasks', filter: { state: 'open', assignment: 'fake-assignee'}}); let filter = new FilterRepresentationModel({
name: 'FakeMyTasks',
filter: { state: 'open', assignment: 'fake-assignee' }
});
expect(filterList.currentFilter).toBeUndefined(); expect(filterList.currentFilter).toBeUndefined();
filterList.selectFilter(filter); filterList.selectFilter(filter);
expect(filterList.getCurrentFilter()).toBe(filter); expect(filterList.getCurrentFilter()).toBe(filter);
@ -178,4 +192,25 @@ describe('ActivitiFilters', () => {
expect(filterList.getFiltersByAppId).toHaveBeenCalled(); expect(filterList.getFiltersByAppId).toHaveBeenCalled();
}); });
it('should change the current filter if a filter with taskid is found', async(() => {
spyOn(activitiService, 'isTaskRelatedToFilter').and.returnValue(Observable.of(fakeFilter));
filterList.filters = fakeGlobalFilter;
filterList.selectFilterWithTask('111');
expect(filterList.currentFilter).toBe(fakeFilter);
}));
it('should not change the current filter if no filter with taskid is found', async(() => {
let filter = new FilterRepresentationModel({
name: 'FakeMyTasks',
filter: { state: 'open', assignment: 'fake-assignee' }
});
filterList.filters = fakeGlobalFilter;
filterList.currentFilter = filter;
spyOn(activitiService, 'isTaskRelatedToFilter').and.returnValue(Observable.of(null));
filterList.selectFilterWithTask('111');
expect(filterList.currentFilter).toBe(filter);
}));
}); });

View File

@ -144,6 +144,24 @@ export class ActivitiFilters implements OnInit, OnChanges {
this.filterClick.emit(filter); this.filterClick.emit(filter);
} }
public selectFilterWithTask(taskId: string) {
let filteredFilterList: FilterRepresentationModel[] = [];
this.activiti.getFilterForTaskById(taskId, this.filters).subscribe(
(filter: FilterRepresentationModel) => {
filteredFilterList.push(filter);
},
(err) => {
this.logService.error(err);
this.onError.emit(err);
},
() => {
if (filteredFilterList.length > 0) {
let myTaskFilter = filteredFilterList.find(filter => filter.name === 'My Tasks');
this.currentFilter = myTaskFilter ? myTaskFilter : filteredFilterList[0];
}
});
}
/** /**
* Select the first filter of a list if present * Select the first filter of a list if present
*/ */

View File

@ -15,11 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
import { TestBed } from '@angular/core/testing'; import { TestBed, async } from '@angular/core/testing';
import { CoreModule } from 'ng2-alfresco-core'; import { CoreModule } from 'ng2-alfresco-core';
import { ActivitiTaskListService } from './activiti-tasklist.service'; import { ActivitiTaskListService } from './activiti-tasklist.service';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskDetailsModel } from '../models/task-details.model';
import { FilterRepresentationModel, AppDefinitionRepresentationModel, TaskQueryRequestRepresentationModel } from '../models/filter.model'; import {
FilterRepresentationModel,
AppDefinitionRepresentationModel,
TaskQueryRequestRepresentationModel
} from '../models/filter.model';
import { Comment } from '../models/comment.model'; import { Comment } from '../models/comment.model';
declare let AlfrescoApi: any; declare let AlfrescoApi: any;
@ -28,7 +32,7 @@ declare let jasmine: any;
describe('ActivitiTaskListService', () => { describe('ActivitiTaskListService', () => {
let fakeEmptyFilters = { let fakeEmptyFilters = {
size: 0, total: 0, start: 0, size: 0, total: 0, start: 0,
data: [ ] data: []
}; };
let fakeFilters = { let fakeFilters = {
@ -36,13 +40,13 @@ describe('ActivitiTaskListService', () => {
data: [ data: [
new AppDefinitionRepresentationModel( new AppDefinitionRepresentationModel(
{ {
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left', id: '1', name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved'} filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
} }
), ),
{ {
id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left', id: '2', name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee'} filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee' }
} }
] ]
}; };
@ -52,7 +56,7 @@ describe('ActivitiTaskListService', () => {
data: [ data: [
{ {
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left', id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved'} filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
} }
] ]
}; };
@ -75,13 +79,24 @@ describe('ActivitiTaskListService', () => {
sort: 'created-desc', text: '', state: 'open', assignment: 'fake-assignee' sort: 'created-desc', text: '', state: 'open', assignment: 'fake-assignee'
}; };
let fakeUser = {id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName'}; let fakeUser = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' };
let fakeTaskList = { let fakeTaskList = {
size: 1, total: 1, start: 0, size: 1, total: 1, start: 0,
data: [ data: [
{ {
id: 1, name: 'FakeNameTask', description: null, category: null, id: '1', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser,
created: '2016-07-15T11:19:17.440+0000'
}
]
};
let secondFakeTaskList = {
size: 1, total: 1, start: 0,
data: [
{
id: '200', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser, assignee: fakeUser,
created: '2016-07-15T11:19:17.440+0000' created: '2016-07-15T11:19:17.440+0000'
} }
@ -92,7 +107,7 @@ describe('ActivitiTaskListService', () => {
error: 'wrong request' error: 'wrong request'
}; };
let fakeTaskDetails = {id: '999', name: 'fake-task-name', formKey: '99', assignee: fakeUser}; let fakeTaskDetails = { id: '999', name: 'fake-task-name', formKey: '99', assignee: fakeUser };
let fakeTasksComment = { let fakeTasksComment = {
size: 2, total: 2, start: 0, size: 2, total: 2, start: 0,
@ -122,6 +137,40 @@ describe('ActivitiTaskListService', () => {
] ]
}; };
let fakeRepresentationFilter1: FilterRepresentationModel = new FilterRepresentationModel({
appId: 1,
name: 'CONTAIN FILTER',
recent: true,
icon: 'glyphicon-align-left',
filter: {
processDefinitionId: null,
processDefinitionKey: null,
name: null,
state: 'open',
sort: 'created-desc',
assignment: 'involved',
dueAfter: null,
dueBefore: null
}
});
let fakeRepresentationFilter2: FilterRepresentationModel = new FilterRepresentationModel({
appId: 2,
name: 'NO TASK FILTER',
recent: false,
icon: 'glyphicon-inbox',
filter: {
processDefinitionId: null,
processDefinitionKey: null,
name: null,
state: 'open',
sort: 'created-desc',
assignment: 'assignee',
dueAfter: null,
dueBefore: null
}
});
let fakeAppPromise = new Promise(function (resolve, reject) { let fakeAppPromise = new Promise(function (resolve, reject) {
resolve(fakeAppFilter); resolve(fakeAppFilter);
}); });
@ -195,7 +244,7 @@ describe('ActivitiTaskListService', () => {
it('should return the task list filtered', (done) => { it('should return the task list filtered', (done) => {
service.getTasks(<TaskQueryRequestRepresentationModel>fakeFilter).subscribe( service.getTasks(<TaskQueryRequestRepresentationModel>fakeFilter).subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(res.length).toEqual(1); expect(res.length).toEqual(1);
expect(res[0].name).toEqual('FakeNameTask'); expect(res[0].name).toEqual('FakeNameTask');
@ -367,7 +416,7 @@ describe('ActivitiTaskListService', () => {
it('should return the total number of tasks', (done) => { it('should return the total number of tasks', (done) => {
service.getTotalTasks(<TaskQueryRequestRepresentationModel>fakeFilter).subscribe( service.getTotalTasks(<TaskQueryRequestRepresentationModel>fakeFilter).subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(res.size).toEqual(1); expect(res.size).toEqual(1);
expect(res.total).toEqual(1); expect(res.total).toEqual(1);
@ -427,7 +476,7 @@ describe('ActivitiTaskListService', () => {
'status': 200, 'status': 200,
contentType: 'application/json', contentType: 'application/json',
responseText: JSON.stringify({ responseText: JSON.stringify({
id: '2233', name: 'FakeNameFilter', filter: {assignment: 'fake-assignement'} id: '2233', name: 'FakeNameFilter', filter: { assignment: 'fake-assignement' }
}) })
}); });
}); });
@ -522,4 +571,63 @@ describe('ActivitiTaskListService', () => {
}); });
}); });
it('should return the filter if it contains task id', (done) => {
let taskId = '1';
let filterFake = new FilterRepresentationModel({
name: 'FakeNameFilter',
assignment: 'fake-assignement',
filter: {
processDefinitionKey: '1',
assignment: 'fake',
state: 'none',
sort: 'asc'
}
});
service.isTaskRelatedToFilter(taskId, filterFake).subscribe(
(res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeTaskList)
});
});
it('should return the filters if it contains task id', async(() => {
let taskId = '1';
let fakeFilterList: FilterRepresentationModel[] = [];
fakeFilterList.push(fakeRepresentationFilter1, fakeRepresentationFilter2);
let resultFilter = null;
service.getFilterForTaskById(taskId, fakeFilterList).subscribe(
(res: FilterRepresentationModel) => {
resultFilter = res;
},
() => {
},
() => {
expect(resultFilter).toBeDefined();
expect(resultFilter).not.toBeNull();
expect(resultFilter.name).toBe('CONTAIN FILTER');
});
jasmine.Ajax.requests.at(0).respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeTaskList)
});
jasmine.Ajax.requests.at(1).respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(secondFakeTaskList)
});
}));
}); });

View File

@ -18,7 +18,10 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { AlfrescoApiService, LogService } from 'ng2-alfresco-core'; import { AlfrescoApiService, LogService } from 'ng2-alfresco-core';
import { FilterRepresentationModel, TaskQueryRequestRepresentationModel } from '../models/filter.model'; import {
FilterRepresentationModel,
TaskQueryRequestRepresentationModel
} from '../models/filter.model';
import { Comment } from '../models/comment.model'; import { Comment } from '../models/comment.model';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskDetailsModel } from '../models/task-details.model';
@ -65,6 +68,48 @@ export class ActivitiTaskListService {
}).catch(err => this.handleError(err)); }).catch(err => this.handleError(err));
} }
/**
* Return all the filters in the list where the task id belong
* @param taskId - string
* @param filter - FilterRepresentationModel []
* @returns {FilterRepresentationModel}
*/
getFilterForTaskById(taskId: string, filterList: FilterRepresentationModel[]): Observable<FilterRepresentationModel> {
return Observable.from(filterList)
.flatMap((filter: FilterRepresentationModel) => this.isTaskRelatedToFilter(taskId, filter))
.filter((filter: FilterRepresentationModel) => filter != null);
}
/**
* Return the search node for query task based on the given filter
* @param filter - FilterRepresentationModel
* @returns {TaskQueryRequestRepresentationModel}
*/
private generateTaskRequestNodeFromFilter(filter: FilterRepresentationModel): TaskQueryRequestRepresentationModel {
let requestNode = {
appDefinitionId: filter.appId,
processDefinitionKey: filter.filter.processDefinitionKey,
assignment: filter.filter.assignment,
state: filter.filter.state,
sort: filter.filter.sort
};
return new TaskQueryRequestRepresentationModel(requestNode);
}
/**
* Check if a taskId is filtered with the given filter
* @param taskId - string
* @param filter - FilterRepresentationModel
* @returns {FilterRepresentationModel}
*/
isTaskRelatedToFilter(taskId: string, filter: FilterRepresentationModel): Observable<FilterRepresentationModel> {
let requestNodeForFilter = this.generateTaskRequestNodeFromFilter(filter);
return Observable.fromPromise(this.callApiTasksFiltered(requestNodeForFilter))
.map((res: any) => {
return res.data.find(element => element.id === taskId) ? filter : null;
}).catch(err => this.handleError(err));
}
/** /**
* Retrive all the tasks filtered by filterModel * Retrive all the tasks filtered by filterModel
* @param filter - TaskFilterRepresentationModel * @param filter - TaskFilterRepresentationModel
@ -151,7 +196,7 @@ export class ActivitiTaskListService {
} }
attachFormToATask(taskId: string, formId: number): Observable<any> { attachFormToATask(taskId: string, formId: number): Observable<any> {
return Observable.fromPromise(this.apiService.getInstance().activiti.taskApi.attachForm(taskId, {'formId': formId})); return Observable.fromPromise(this.apiService.getInstance().activiti.taskApi.attachForm(taskId, { 'formId': formId }));
} }
/** /**
@ -273,7 +318,7 @@ export class ActivitiTaskListService {
callApiTaskFilters(appId?: string) { callApiTaskFilters(appId?: string) {
if (appId) { if (appId) {
return this.apiService.getInstance().activiti.userFiltersApi.getUserTaskFilters({appId: appId}); return this.apiService.getInstance().activiti.userFiltersApi.getUserTaskFilters({ appId: appId });
} else { } else {
return this.apiService.getInstance().activiti.userFiltersApi.getUserTaskFilters(); return this.apiService.getInstance().activiti.userFiltersApi.getUserTaskFilters();
} }
@ -288,7 +333,7 @@ export class ActivitiTaskListService {
} }
private callApiAddTaskComment(id: string, message: string) { private callApiAddTaskComment(id: string, message: string) {
return this.apiService.getInstance().activiti.taskApi.addTaskComment({message: message}, id); return this.apiService.getInstance().activiti.taskApi.addTaskComment({ message: message }, id);
} }
private callApiAddTask(task: TaskDetailsModel) { private callApiAddTask(task: TaskDetailsModel) {
@ -327,7 +372,7 @@ export class ActivitiTaskListService {
'appId': appId, 'appId': appId,
'recent': false, 'recent': false,
'icon': 'glyphicon-align-left', 'icon': 'glyphicon-align-left',
'filter': {'sort': 'created-desc', 'name': '', 'state': 'open', 'assignment': 'involved'} 'filter': { 'sort': 'created-desc', 'name': '', 'state': 'open', 'assignment': 'involved' }
}); });
} }
@ -342,7 +387,7 @@ export class ActivitiTaskListService {
'appId': appId, 'appId': appId,
'recent': false, 'recent': false,
'icon': 'glyphicon-inbox', 'icon': 'glyphicon-inbox',
'filter': {'sort': 'created-desc', 'name': '', 'state': 'open', 'assignment': 'assignee'} 'filter': { 'sort': 'created-desc', 'name': '', 'state': 'open', 'assignment': 'assignee' }
}); });
} }
@ -357,7 +402,7 @@ export class ActivitiTaskListService {
'appId': appId, 'appId': appId,
'recent': false, 'recent': false,
'icon': 'glyphicon-record', 'icon': 'glyphicon-record',
'filter': {'sort': 'created-desc', 'name': '', 'state': 'open', 'assignment': 'candidate'} 'filter': { 'sort': 'created-desc', 'name': '', 'state': 'open', 'assignment': 'candidate' }
}); });
} }
@ -372,7 +417,7 @@ export class ActivitiTaskListService {
'appId': appId, 'appId': appId,
'recent': true, 'recent': true,
'icon': 'glyphicon-ok-sign', 'icon': 'glyphicon-ok-sign',
'filter': {'sort': 'created-desc', 'name': '', 'state': 'completed', 'assignment': 'involved'} 'filter': { 'sort': 'created-desc', 'name': '', 'state': 'completed', 'assignment': 'involved' }
}); });
} }
} }