Merge pull request #1312 from Alfresco/dev-mvitale-1305

Claim a task
This commit is contained in:
Mario Romano 2016-12-16 16:37:12 +00:00 committed by GitHub
commit 128d3af54a
11 changed files with 103 additions and 22 deletions

View File

@ -144,7 +144,7 @@ export class ActivitiProcessInstanceTasks implements OnInit, OnChanges {
? user.firstName + ' ' : '') +
user.lastName;
}
return '';
return 'Nobody';
}
getFormatDate(value, format: string) {

View File

@ -9,7 +9,10 @@
</div>
<div *ngIf="taskDetails">
<h2 class="mdl-card__title-text">{{taskDetails.name}}</h2>
<activiti-task-header [taskDetails]="taskDetails" [formName]="taskFormName"></activiti-task-header>
<activiti-task-header
[taskDetails]="taskDetails"
[formName]="taskFormName"
(claim)="onClaimTask($event)"></activiti-task-header>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<activiti-people [people]="taskPeople" [readOnly]="readOnlyForm"
@ -24,19 +27,24 @@
#activitichecklist></activiti-checklist>
</div>
</div>
<activiti-form *ngIf="hasFormKey()" [taskId]="taskDetails.id"
[showTitle]="showFormTitle"
[showRefreshButton]="showFormRefreshButton"
[showCompleteButton]="showFormCompleteButton"
[showSaveButton]="showFormSaveButton"
[readOnly]="readOnlyForm"
(formSaved)='onFormSaved($event)'
(formCompleted)='onFormCompleted($event)'
(formLoaded)='onFormLoaded($event)'
(onError)='onFormError($event)'
(executeOutcome)='onFormExecuteOutcome($event)'
#activitiForm>
</activiti-form>
<div *ngIf="isAssignedToMe()">
<activiti-form *ngIf="hasFormKey()" [taskId]="taskDetails.id"
[showTitle]="showFormTitle"
[showRefreshButton]="showFormRefreshButton"
[showCompleteButton]="showFormCompleteButton"
[showSaveButton]="showFormSaveButton"
[readOnly]="readOnlyForm"
(formSaved)='onFormSaved($event)'
(formCompleted)='onFormCompleted($event)'
(formLoaded)='onFormLoaded($event)'
(onError)='onFormError($event)'
(executeOutcome)='onFormExecuteOutcome($event)'
#activitiForm>
</activiti-form>
</div>
<div *ngIf="!isAssignedToMe()">
{{ 'TASK_DETAILS.MESSAGES.CLAIM' | translate }}
</div>
<button type="button" class="mdl-button" *ngIf="!hasFormKey() && isTaskActive()" (click)="onComplete()">
{{ 'TASK_DETAILS.BUTTON.COMPLETE' | translate }}
</button>

View File

@ -178,6 +178,10 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
}
}
isAssignedToMe(): boolean {
return this.taskDetails.assignee ? true : false;
}
/**
* Retrieve the next open task
* @param processInstanceId
@ -243,4 +247,8 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
closeErrorDialog(): void {
this.errorDialog.nativeElement.close();
}
onClaimTask(taskId: string) {
this.loadDetails(taskId);
}
}

View File

@ -15,5 +15,10 @@
<span class="activiti-task-header__value" *ngIf="formName">{{ formName }}</span>
<span class="activiti-task-header__value" *ngIf="!formName">{{ 'TASK_DETAILS.FORM.NONE' | translate }}</span>
</div>
<button *ngIf="!isAssignedToMe()" data-automation-id="header-claim-button" type="button" id="claim-task"
(click)="claimTask(taskDetails.id)" class="mdl-button">{{ 'TASK_DETAILS.BUTTON.CLAIM' | translate }}
</button>
</div>
</div>

View File

@ -24,9 +24,11 @@ import { ActivitiTaskHeader } from './activiti-task-header.component';
import { TranslationMock } from './../assets/translation.service.mock';
import { taskDetailsMock } from './../assets/task-details.mock';
import { TaskDetailsModel } from '../models/task-details.model';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
describe('ActivitiTaskHeader', () => {
let service: ActivitiTaskListService;
let componentHandler: any;
let component: ActivitiTaskHeader;
let fixture: ComponentFixture<ActivitiTaskHeader>;
@ -40,7 +42,8 @@ describe('ActivitiTaskHeader', () => {
ActivitiTaskHeader
],
providers: [
{ provide: AlfrescoTranslationService, useClass: TranslationMock }
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
ActivitiTaskListService
]
}).compileComponents();
}));
@ -49,6 +52,7 @@ describe('ActivitiTaskHeader', () => {
fixture = TestBed.createComponent(ActivitiTaskHeader);
component = fixture.componentInstance;
service = fixture.debugElement.injector.get(ActivitiTaskListService);
component.taskDetails = new TaskDetailsModel(taskDetailsMock);
@ -78,6 +82,13 @@ describe('ActivitiTaskHeader', () => {
expect(valueEl.nativeElement.innerText).toBe('TASK_DETAILS.ASSIGNEE.NONE');
});
it('should display the claim button if no assignee', () => {
component.taskDetails.assignee = null;
fixture.detectChanges();
let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-claim-button"]'));
expect(valueEl.nativeElement.innerText).toBe('TASK_DETAILS.BUTTON.CLAIM');
});
it('should display due date', () => {
component.taskDetails.dueDate = '2016-11-03T15:25:42.749+0000';
fixture.detectChanges();

View File

@ -15,9 +15,10 @@
* limitations under the License.
*/
import { Component, Input } from '@angular/core';
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { TaskDetailsModel } from '../models/task-details.model';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
@Component({
selector: 'activiti-task-header',
@ -33,7 +34,11 @@ export class ActivitiTaskHeader {
@Input()
taskDetails: TaskDetailsModel;
constructor(private translate: AlfrescoTranslationService) {
@Output()
claim: EventEmitter<any> = new EventEmitter<any>();
constructor(private translate: AlfrescoTranslationService,
private activitiTaskService: ActivitiTaskListService) {
if (translate) {
translate.addTranslationFolder('ng2-activiti-tasklist', 'node_modules/ng2-activiti-tasklist/src');
}
@ -42,4 +47,16 @@ export class ActivitiTaskHeader {
public hasAssignee(): boolean {
return (this.taskDetails && this.taskDetails.assignee) ? true : false;
}
isAssignedToMe(): boolean {
return this.taskDetails.assignee ? true : false;
}
claimTask(taskId: string) {
this.activitiTaskService.claimTask(taskId).subscribe(
(res: any) => {
console.log('Task claimed');
this.claim.emit(taskId);
});
}
}

View File

@ -14,10 +14,12 @@
"CHECKLIST": "Checklist"
},
"BUTTON": {
"COMPLETE": "Complete"
"COMPLETE": "Complete",
"CLAIM": "Claim"
},
"MESSAGES": {
"NONE": "No task details found."
"NONE": "No task details found.",
"CLAIM": "To work on this task, you need to claim it first. You can do that by pressing the Claim button above."
},
"FORM": {
"NONE": "No form."

View File

@ -13,8 +13,13 @@
"COMMENTS": "Commenti",
"CHECKLIST": "Checklist"
},
"BUTTON": {
"COMPLETE": "Completa",
"CLAIM": "Richiedi"
},
"MESSAGES": {
"NONE": "Nessun dettaglio task trovato."
"NONE": "Nessun dettaglio task trovato.",
"CLAIM": "Per lavorare con questo task, hai bisogno di richiederlo prima. Per richiedere il task basta premere il tasto Richiedi"
},
"FORM": {
"NONE": "Nessuna form."

View File

@ -61,7 +61,7 @@ export class TaskDetailsModel {
this.id = obj && obj.id || null;
this.name = obj && obj.name || null;
this.priority = obj && obj.priority;
this.assignee = new User(obj.assignee);
this.assignee = obj.assignee ? new User(obj.assignee) : null;
this.adhocTaskCanBeReassigned = obj && obj.adhocTaskCanBeReassigned;
this.category = obj && obj.category || null;
this.created = obj && obj.created || null;

View File

@ -513,4 +513,20 @@ describe('ActivitiTaskListService', () => {
});
});
it('should claim a task', (done) => {
let taskId = '111';
service.claimTask(taskId).subscribe(
(res: any) => {
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify({})
});
});
});

View File

@ -232,6 +232,15 @@ export class ActivitiTaskListService {
}).catch(this.handleError);
}
/**
* Claim a task
* @param id - taskId
*/
claimTask(taskId: string): Observable<TaskDetailsModel> {
return Observable.fromPromise(this.apiService.getInstance().activiti.taskApi.claimTask(taskId))
.catch(this.handleError);
}
private callApiTasksFiltered(requestNode: TaskQueryRequestRepresentationModel) {
return this.apiService.getInstance().activiti.taskApi.listTasks(requestNode);
}