[ADF-1143] [TaskList] - Not able to start a task when changing the assignee from the 'Start Task' form (#2164)

* [ADF-1143] [TaskList] - Not able to start a task when changing the assignee from the 'Start Task' form

* Create task has been split into three diffrent service calls to replicate the ecxact behaviour of APS

* Current API call sequence is create-task -> attach-form -> assign-user

* Added a new service assign task

* Modified tests according to the API calls

* [ADF-1143] [TaskList] - Not able to start a task when changing the assignee from the 'Start Task' form

* Added responsive behaviour for APIs

* [ADF-1143] [TaskList] - Not able to start a task when changing the assignee from the 'Start Task' form

*Code refactoring
This commit is contained in:
Deepak Paul 2017-08-02 22:02:47 +05:30 committed by Mario Romano
parent c85bf05cb2
commit 152e7805bc
7 changed files with 224 additions and 100 deletions

View File

@ -18,9 +18,9 @@
export let startTaskMock = {
'name': 'fakeName',
'description': 'fakeDescription',
'assignee': {'id': 2001, 'firstName': 'Jhon', 'lastName': 'Adams', 'email': 'jhon@app.activiti.com'},
'assignee': null,
'dueDate': '2017-11-03T15:25:42.749+0000',
'formKey': '11201',
'formKey': null,
'category': 'fakeAppId'
};

View File

@ -68,14 +68,16 @@ export let fakeFilterWithProcessDefinitionKey = {
sort: 'created-desc', text: '', state: 'open', assignment: 'fake-assignee', processDefinitionKey: '1'
};
export let fakeUser = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' };
export let fakeUser1 = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' };
export let fakeUser2 = { id: 1001, email: 'some-one@somegroup.com', firstName: 'some', lastName: 'one' };
export let fakeTaskList = {
size: 1, total: 1, start: 0,
data: [
{
id: '1', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
}
]
@ -86,13 +88,13 @@ export let fakeTaskListDifferentProcessDefinitionKey = {
data: [
{
id: '1', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser,
assignee: fakeUser1,
processDefinitionKey: '1',
created: '2016-07-15T11:19:17.440+0000'
},
{
id: '2', name: 'FakeNameTask2', description: null, category: null,
assignee: fakeUser,
assignee: fakeUser1,
processDefinitionKey: '2',
created: '2016-07-15T11:19:17.440+0000'
}
@ -104,7 +106,7 @@ export let secondFakeTaskList = {
data: [
{
id: '200', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
}
]
@ -114,16 +116,16 @@ export let fakeErrorTaskList = {
error: 'wrong request'
};
export let fakeTaskDetails = { id: '999', name: 'fake-task-name', formKey: '99', assignee: fakeUser };
export let fakeTaskDetails = { id: '999', name: 'fake-task-name', formKey: '99', assignee: fakeUser1 };
export let fakeTasksComment = {
size: 2, total: 2, start: 0,
data: [
{
id: 1, message: 'fake-message-1', created: '', createdBy: fakeUser
id: 1, message: 'fake-message-1', created: '', createdBy: fakeUser1
},
{
id: 2, message: 'fake-message-2', created: '', createdBy: fakeUser
id: 2, message: 'fake-message-2', created: '', createdBy: fakeUser1
}
]
};
@ -133,12 +135,12 @@ export let fakeTasksChecklist = {
data: [
{
id: 1, name: 'FakeCheckTask1', description: null, category: null,
assignee: fakeUser,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
},
{
id: 2, name: 'FakeCheckTask2', description: null, category: null,
assignee: fakeUser,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
}
]

View File

@ -34,7 +34,7 @@
<md-datepicker #taskDatePicker [touchUi]="true"></md-datepicker>
</md-grid-tile>
<md-grid-tile>
<md-select placeholder="{{'START_TASK.FORM.LABEL.ASSIGNEE'|translate}}" id="assignee_id" class="adf-start-task-input-container" [(ngModel)]="startTaskmodel.assignee">
<md-select placeholder="{{'START_TASK.FORM.LABEL.ASSIGNEE'|translate}}" id="assignee_id" class="adf-start-task-input-container" [(ngModel)]="assignee">
<md-option>{{'START_TASK.FORM.LABEL.NONE'|translate}}</md-option>
<span *ngFor="let user of people">
<md-option [value]="user" *ngIf="!isUserNameEmpty(user)">{{ getDisplayUser(user.firstName, user.lastName, ' ')}}</md-option>
@ -44,7 +44,7 @@
</md-grid-list>
<md-grid-list cols="2" rowHeight="80px">
<md-grid-tile>
<md-select placeholder="{{'START_TASK.FORM.LABEL.FORM'|translate}}" id="form_id" [(ngModel)]="startTaskmodel.formKey" class="adf-start-task-input-container">
<md-select placeholder="{{'START_TASK.FORM.LABEL.FORM'|translate}}" id="form_id" [(ngModel)]="formKey" class="adf-start-task-input-container">
<md-option>{{'START_TASK.FORM.LABEL.NONE'|translate}}</md-option>
<md-option *ngFor="let form of forms" [value]="form.id">{{ form.name }}</md-option>
</md-select>

View File

@ -20,6 +20,7 @@ import { MdButtonModule, MdDatepickerModule, MdGridListModule, MdIconModule, MdI
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { StartTaskModel } from '../models/start-task.model';
import { User } from '../models/user.model';
import { PeopleService } from '../services/people.service';
import { TaskListService } from '../services/tasklist.service';
import { startTaskMock } from './../assets/start-task.mock';
@ -34,9 +35,11 @@ describe('StartTaskComponent', () => {
let service: TaskListService;
let peopleService: PeopleService;
let element: HTMLElement;
let getformlistSpy: jasmine.Spy;
let getFormlistSpy: jasmine.Spy;
let getWorkflowUsersSpy: jasmine.Spy;
let getcreateNewTaskSpy: jasmine.Spy;
let createNewTaskSpy: jasmine.Spy;
let attachFormSpy: jasmine.Spy;
let assignUserSpy: jasmine.Spy;
let fakeForms = [
{
id: 123,
@ -47,6 +50,7 @@ describe('StartTaskComponent', () => {
name: 'Employee Info'
}
];
let testUser = {id: 1001, firstName: 'fakeName', email: 'fake@app.activiti.com'};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
@ -81,7 +85,7 @@ describe('StartTaskComponent', () => {
beforeEach(() => {
service = fixture.debugElement.injector.get(TaskListService);
peopleService = fixture.debugElement.injector.get(PeopleService);
getformlistSpy = spyOn(service, 'getFormList').and.returnValue(Observable.of(fakeForms));
getFormlistSpy = spyOn(service, 'getFormList').and.returnValue(Observable.of(fakeForms));
getWorkflowUsersSpy = spyOn(peopleService, 'getWorkflowUsers').and.returnValue(Observable.of([
{
id: 1,
@ -111,37 +115,30 @@ describe('StartTaskComponent', () => {
expect(activitiStartTaskComponent.forms[0].name).toEqual('Display Data');
expect(activitiStartTaskComponent.forms[1].name).toEqual('Employee Info');
expect(activitiStartTaskComponent.forms[1].id).toEqual(1111);
expect(getformlistSpy).toHaveBeenCalled();
expect(getFormlistSpy).toHaveBeenCalled();
});
describe('create task', () => {
beforeEach(() => {
jasmine.Ajax.install();
getcreateNewTaskSpy = spyOn(service, 'createNewTask').and.returnValue(Observable.of(
createNewTaskSpy = spyOn(service, 'createNewTask').and.returnValue(Observable.of(
{
id: 91,
name: 'fakeName',
formKey: '4',
assignee: {id: 1001, firstName: 'fakeName', email: 'fake@app.activiti.com'}
formKey: null,
assignee: null
}
));
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should create new task when start is clicked', async(() => {
activitiStartTaskComponent.success.subscribe((res) => {
expect(res).toBeDefined();
});
activitiStartTaskComponent.appId = 'fakeAppId';
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(startTaskMock);
activitiStartTaskComponent.start();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200
});
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
}));
it('should send on success event when the task is started', async(() => {
@ -149,30 +146,13 @@ describe('StartTaskComponent', () => {
expect(res).toBeDefined();
expect(res.id).toBe(91);
expect(res.name).toBe('fakeName');
expect(res.formKey).toBe('4');
expect(res.assignee.id).toBe(1001);
expect(res.formKey).toBe(null);
expect(res.assignee).toBe(null);
});
activitiStartTaskComponent.appId = 'fakeAppId';
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(startTaskMock);
activitiStartTaskComponent.start();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'json',
responseText:
{
id: '91',
name: 'fakeName',
description: 'fakeDescription',
formKey: '4',
assignee: {id: 1001, firstName: 'fakeName', email: 'fake@app.activiti.com'},
dueDate: null,
endDate: null,
duration: null,
priority: 50,
parentTaskId: null,
parentTaskName: null
}
});
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
}));
it('should send on success event when only name is given', async(() => {
@ -181,36 +161,108 @@ describe('StartTaskComponent', () => {
});
activitiStartTaskComponent.appId = 'fakeAppId';
activitiStartTaskComponent.startTaskmodel.name = 'fakeName';
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(startTaskMock);
activitiStartTaskComponent.start();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'json',
responseText: {}
});
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
}));
it('should attach a task when a form id selected', () => {
activitiStartTaskComponent.success.subscribe((res) => {
expect(res).toBeDefined();
expect(res.formKey).toBe('4');
});
activitiStartTaskComponent.appId = 'fakeAppId';
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(startTaskMock);
activitiStartTaskComponent.start();
expect(getcreateNewTaskSpy).toHaveBeenCalled();
});
it('should not emit success event when data not present', async(() => {
let successSpy: jasmine.Spy = spyOn(activitiStartTaskComponent.success, 'emit');
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(null);
activitiStartTaskComponent.start();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
fixture.detectChanges();
expect(getcreateNewTaskSpy).not.toHaveBeenCalled();
expect(createNewTaskSpy).not.toHaveBeenCalled();
expect(successSpy).not.toHaveBeenCalled();
}));
});
describe('assign form', () => {
beforeEach(() => {
attachFormSpy = spyOn(service, 'attachFormToATask').and.returnValue(Observable.of(
{
id: 91,
name: 'fakeName',
formKey: 1204,
assignee: null
}
));
});
it('should attach form to the task when a form is selected', () => {
activitiStartTaskComponent.success.subscribe((res) => {
expect(res).toBeDefined();
expect(res.id).toBe(91);
expect(res.name).toBe('fakeName');
expect(res.formKey).toBe(1204);
expect(res.assignee).toBe(null);
});
activitiStartTaskComponent.appId = 'fakeAppId';
activitiStartTaskComponent.formKey = 1204;
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(startTaskMock);
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
});
it('should not attach form to the task when a no form is selected', () => {
activitiStartTaskComponent.success.subscribe((res) => {
expect(res).toBeDefined();
expect(res.id).toBe(91);
expect(res.name).toBe('fakeName');
expect(res.formKey).toBe(null);
});
activitiStartTaskComponent.appId = 'fakeAppId';
activitiStartTaskComponent.formKey = null;
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(startTaskMock);
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
});
});
describe('assign task', () => {
beforeEach(() => {
assignUserSpy = spyOn(service, 'assignTask').and.returnValue(Observable.of(
{
id: 91,
name: 'fakeName',
formKey: 1204,
assignee: testUser
}
));
});
it('should assign task when an assignee is selected', () => {
activitiStartTaskComponent.success.subscribe((res) => {
expect(res).toBeDefined();
expect(res.id).toBe(91);
expect(res.name).toBe('fakeName');
expect(res.formKey).toBe(1204);
expect(res.assignee).toBe(testUser);
});
activitiStartTaskComponent.appId = 'fakeAppId';
activitiStartTaskComponent.formKey = 1204;
activitiStartTaskComponent.assignee = new User(testUser);
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(startTaskMock);
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
});
it('should not assign task when no assignee is selected', () => {
activitiStartTaskComponent.success.subscribe((res) => {
expect(res).toBeDefined();
expect(res.id).toBe(91);
expect(res.name).toBe('fakeName');
expect(res.formKey).toBe(1204);
expect(res.assignee).toBe(null);
});
activitiStartTaskComponent.appId = 'fakeAppId';
activitiStartTaskComponent.formKey = 1204;
activitiStartTaskComponent.assignee = null;
activitiStartTaskComponent.startTaskmodel = new StartTaskModel(startTaskMock);
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
});
});
it('should not attach a task when a form id is not slected', () => {
let attachFormToATask = spyOn(service, 'attachFormToATask').and.returnValue(Observable.of());
spyOn(service, 'createNewTask').and.callFake(

View File

@ -17,6 +17,7 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { Form } from '../models/form.model';
import { StartTaskModel } from '../models/start-task.model';
import { TaskDetailsModel } from '../models/task-details.model';
@ -43,11 +44,17 @@ export class StartTaskComponent implements OnInit {
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
people: User [] = [];
people: User[] = [];
startTaskmodel: StartTaskModel = new StartTaskModel();
forms: Form [];
forms: Form[];
assignee: any;
formKey: number;
taskId: string;
/**
* Constructor
@ -70,48 +77,58 @@ export class StartTaskComponent implements OnInit {
this.getUsers();
}
public start() {
public start(): void {
if (this.startTaskmodel.name) {
this.startTaskmodel.category = this.appId;
this.taskService.createNewTask(new TaskDetailsModel(this.startTaskmodel)).subscribe(
this.taskService.createNewTask(new TaskDetailsModel(this.startTaskmodel))
.switchMap((createRes: any) =>
this.attachForm(createRes.id, this.formKey).defaultIfEmpty(createRes)
.switchMap((attachRes: any) =>
this.assignTask(createRes.id, this.assignee).defaultIfEmpty(attachRes ? attachRes : createRes)
)
)
.subscribe(
(res: any) => {
this.success.emit(res);
this.attachForm(res.id);
this.resetForm();
},
(err) => {
this.error.emit(err);
this.logService.error('An error occurred while trying to add the task');
}
);
this.logService.error('An error occurred while creating new task');
});
}
}
private attachForm(taskId: string) {
if (this.startTaskmodel.formKey && taskId) {
this.taskService.attachFormToATask(taskId, Number(this.startTaskmodel.formKey));
private attachForm(taskId: string, formKey: number): Observable<any> {
let response = Observable.of();
if (taskId && formKey) {
response = this.taskService.attachFormToATask(taskId, formKey);
}
return response;
}
public onCancel() {
private assignTask(taskId: string, assignee: any): Observable<any> {
let response = Observable.of();
if (taskId && assignee) {
response = this.taskService.assignTask(taskId, assignee);
}
return response;
}
public onCancel(): void {
this.cancel.emit();
}
private loadFormsTask() {
private loadFormsTask(): void {
this.taskService.getFormList().subscribe((res: Form[]) => {
this.forms = res;
},
this.forms = res;
},
(err) => {
this.error.emit(err);
this.logService.error('An error occurred while trying to get the forms');
});
}
private resetForm() {
this.startTaskmodel = null;
}
private getUsers() {
private getUsers(): void {
this.peopleService.getWorkflowUsers().subscribe((users) => {
this.people = users;
}, (err) => {
@ -120,15 +137,15 @@ export class StartTaskComponent implements OnInit {
});
}
isUserNameEmpty(user: any) {
public isUserNameEmpty(user: any): boolean {
return !user || (this.isEmpty(user.firstName) && this.isEmpty(user.lastName));
}
private isEmpty(data: string) {
private isEmpty(data: string): boolean {
return data === undefined || data === null || data.trim().length === 0;
}
getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {
public getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {
firstName = (firstName !== null ? firstName : '');
lastName = (lastName !== null ? lastName : '');
return firstName + delimiter + lastName;

View File

@ -33,12 +33,14 @@ import {
fakeTaskListDifferentProcessDefinitionKey,
fakeTasksChecklist,
fakeTasksComment,
fakeUser,
fakeUser1,
fakeUser2,
secondFakeTaskList
} from '../assets/tasklist-service.mock';
import { Comment } from '../models/comment.model';
import { FilterRepresentationModel, TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskDetailsModel } from '../models/task-details.model';
import { User } from '../models/user.model';
import { TaskListService } from './tasklist.service';
declare let jasmine: any;
@ -288,7 +290,7 @@ describe('Activiti TaskList Service', () => {
name: 'FakeNameTask',
description: null,
category: null,
assignee: fakeUser,
assignee: fakeUser1,
created: ''
});
@ -307,7 +309,7 @@ describe('Activiti TaskList Service', () => {
contentType: 'application/json',
responseText: JSON.stringify({
id: '777', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
})
});
@ -345,7 +347,7 @@ describe('Activiti TaskList Service', () => {
contentType: 'application/json',
responseText: JSON.stringify({
id: '111', message: 'fake-comment-message',
createdBy: fakeUser,
createdBy: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
})
});
@ -540,7 +542,40 @@ describe('Activiti TaskList Service', () => {
name: 'FakeNameTask',
description: 'FakeDescription',
category: '3',
assignee: fakeUser,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
})
});
});
it('should assign task to a user', (done) => {
let testTaskId = '8888';
service.assignTask(testTaskId, fakeUser2).subscribe(
(res: TaskDetailsModel) => {
expect(res).toBeDefined();
expect(res.id).toEqual(testTaskId);
expect(res.name).toEqual('FakeNameTask');
expect(res.description).toEqual('FakeDescription');
expect(res.category).toEqual('3');
expect(res.created).not.toEqual('');
expect(res.adhocTaskCanBeReassigned).toBe(true);
expect(res.assignee).toEqual(new User(fakeUser2));
expect(res.involvedPeople).toEqual([fakeUser1]);
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify({
id: testTaskId,
name: 'FakeNameTask',
description: 'FakeDescription',
adhocTaskCanBeReassigned: true,
category: '3',
assignee: fakeUser2,
involvedPeople: [fakeUser1],
created: '2016-07-15T11:19:17.440+0000'
})
});

View File

@ -366,6 +366,20 @@ export class TaskListService {
}).catch(err => this.handleError(err));
}
/**
* Assign task to user/group
* @param taskId - string
* @param requestNode - any
* @returns {TaskDetailsModel}
*/
assignTask(taskId: string, requestNode: any): Observable<TaskDetailsModel> {
return Observable.fromPromise(this.callApiAssignTask(taskId, requestNode))
.map(res => res)
.map((response: TaskDetailsModel) => {
return new TaskDetailsModel(response);
}).catch(err => this.handleError(err));
}
/**
* Claim a task
* @param id - taskId
@ -496,4 +510,8 @@ export class TaskListService {
'filter': { 'sort': 'created-desc', 'name': '', 'state': 'completed', 'assignment': 'involved' }
});
}
private callApiAssignTask(taskId: string, requestNode: any) {
return this.apiService.getInstance().activiti.taskApi.assignTask(taskId, requestNode);
}
}