21 KiB
Tasklist Service
Manage Task Instances.
Importing
import { TaskListService, TaskDetailsModel, TaskQueryRequestRepresentationModel, TaskListModel, Form } from '@alfresco/adf-process-services';
import { TaskUpdateRepresentation } from 'alfresco-js-api';
export class SomePageComponent implements OnInit {
constructor(private tasklistService: TaskListService) {
}
Methods
getTaskDetails(taskId: string): Observable<TaskDetailsModel>
Get Task Instance metadata for passed in Task Instance ID:
const taskInstanceId = '15303';
this.tasklistService.getTaskDetails(taskInstanceId).subscribe( (taskInstance: TaskDetailsModel) => {
console.log('TaskInstance: ', taskInstance);
}, error => {
console.log('Error: ', error);
});
The taskInstanceId
refers to a Task Instance identifier in APS.
The returned taskInstance
object is of type TaskDetailsModel
and looks like in this sample:
adhocTaskCanBeReassigned: false
assignee: UserProcessModel {pictureId: null, id: 1, email: "admin@app.activiti.com", firstName: null, lastName: "Administrator"}
category: null
created: Wed Oct 11 2017 09:07:14 GMT+0100 (BST) {}
description: null
dueDate: null
duration: null
endDate: null
executionId: "11337"
formKey: "9"
id: "15303"
initiatorCanCompleteTask: false
involvedPeople: []
managerOfCandidateGroup: false
memberOfCandidateGroup: false
memberOfCandidateUsers: false
name: "Clarify Invoice - Invoice-20302.pdf"
parentTaskId: null
parentTaskName: null
priority: 50
processDefinitionCategory: "http://www.activiti.org/processdef"
processDefinitionDeploymentId: "18"
processDefinitionDescription: "This is a simple invoice approval process that allows a person to assign a dedicated approver for the the invoice. It will then be routed to the Accounting department for payment preparation. Once payment is prepared the invoice will be stored in a specific folder and an email notification will be sent."
processDefinitionId: "InvoiceApprovalProcess:2:21"
processDefinitionKey: "InvoiceApprovalProcess"
processDefinitionName: "Invoice Approval Process"
processDefinitionVersion: 2
processInstanceId: "11337"
processInstanceName: null
processInstanceStartUserId: "1"
taskDefinitionKey: "clarifyInvoice"
getTaskChecklist(id: string): Observable<TaskDetailsModel[]>
Get all the sub-task instances for a Task Instance, also called the check list:
const parentTaskId = '15303';
this.tasklistService.getTaskChecklist(parentTaskId).subscribe( (subTasks: TaskDetailsModel[]) => {
console.log('Sub Tasks: ', subTasks);
}, error => {
console.log('Error: ', error);
});
The response is an array of TaskDetailsModel
representing the sub-tasks:
Sub Tasks:
0:
adhocTaskCanBeReassigned: false
assignee: UserProcessModel {pictureId: null, id: 1, email: "admin@app.activiti.com", firstName: null, lastName: "Administrator"}
category: "2"
created: "2017-10-29T07:29:28.881+0000"
description: null
dueDate: null
duration: null
endDate: null
executionId: null
formKey: null
id: "74745"
initiatorCanCompleteTask: false
involvedPeople: undefined
managerOfCandidateGroup: false
memberOfCandidateGroup: false
memberOfCandidateUsers: false
name: "Double check invoice amount"
parentTaskId: "15303"
parentTaskName: "Clarify Invoice - Invoice-10292.pdf"
priority: 50
processDefinitionCategory: null
processDefinitionDeploymentId: null
processDefinitionDescription: null
processDefinitionId: null
processDefinitionKey: null
processDefinitionName: null
processDefinitionVersion: 0
processInstanceId: null
processInstanceName: null
processInstanceStartUserId: null
taskDefinitionKey: null
1 :
{processDefinitionVersion: 0, id: "74746", name: "Verify with the person that did the purchase", priority: 50, assignee: UserProcessModel, …}
Looking at the TaskDetailsModel
for a sub-task we can see that it has a parent task ID that matches what we specified
when calling this method.
getTasks(requestNode: TaskQueryRequestRepresentationModel): Observable<TaskListModel>
Get tasks matching passed in query definition:
const taskQuery: TaskQueryRequestRepresentationModel = {
appDefinitionId: '2',
processInstanceId: null,
processDefinitionId: null,
text: null,
assignment: null,
state: 'open',
sort: 'created_asc',
page: 0,
size: 5,
start: null
};
this.tasklistService.getTasks(taskQuery).subscribe( (taskListModel: TaskListModel) => {
console.log('Task List Model: ', taskListModel);
}, error => {
console.log('Error: ', error);
});
In the above example we query for all Task Instances associated with a Process Application with
ID 2. We set size
to 5, which means that the query will return max 5 task instances.
We can mix and match the query parameters to narrow down the task list that is returned.
If you are just interested in Task Instances related to a specific Process Instance,
then set the processInstanceId
. If you want to see all tasks related to a specific type of processes,
then you should set the processDefinitionId
property.
You can use the state
property to define if only completed
or only open
tasks should be returned. If you
specify null
for state then open
will be assumed.
The assignment
property can be used to filter tasks based on how they are assigned (or not assigned yet).
Use assignee
if you are interested in tasks that are assigned to a user. If you want to see
pooled tasks (i.e. tasks that needs to be claimed by a user), then use candidate
.
A TaskListModel
object is returned for a successful query and the data
property is an array of
TaskDetailsModel
:
data:
0: {id: "75010", name: "Approve Invoice - Invoice-10202.pdf", description: null, category: null, assignee: {…}, …}
1: {id: "74746", name: "Verify with the person that did the purchase", description: null, category: "2", assignee: {…}, …}
2: {id: "74745", name: "Double check invoice amount", description: null, category: "2", assignee: {…}, …}
3: {id: "20686", name: "Sample checklist task 1", description: null, category: "2", assignee: {…}, …}
4: {id: "15303", name: "Clarify Invoice - Invoice-20302.pdf", description: null, category: null, assignee: {…}, …}
length: 5
size: 5
start: 0
total: 10
We can see that this query resulted in 10 tasks (see total
), but only 5 were returned as we set size
to 5
.
getTotalTasks(requestNode: TaskQueryRequestRepresentationModel): Observable<any>
Get total number of tasks matching passed in query definition:
const taskQuery: TaskQueryRequestRepresentationModel = {
appDefinitionId: '2',
processInstanceId: null,
processDefinitionId: null,
text: null,
assignment: null,
state: 'open',
sort: 'created_asc',
page: 0,
size: 5,
start: null
};
this.tasklistService.getTotalTasks(taskQuery).subscribe( (response: any) => {
console.log('Total: ', response);
}, error => {
console.log('Error: ', error);
});
This is pretty much the same type of query as the getTasks
method, except that here we just
return how many Task Instances it matched in the total
property:
data:[]
size: 0
start: 0
total: 10
When you call this method it always sets the size
property to 0
.
findTasksByState(requestNode: TaskQueryRequestRepresentationModel, state?: string): Observable<TaskListModel>
Find and return Task Instances by state open
or completed
and query model:
const taskState = 'open';
const taskQuery: TaskQueryRequestRepresentationModel = {
appDefinitionId: '2',
processInstanceId: null,
processDefinitionId: null,
text: null,
assignment: null,
state: 'open',
sort: 'created_asc',
page: 0,
size: 5,
start: null
};
this.tasklistService.findTasksByState(taskQuery, taskState).subscribe( (taskList: TaskListModel) => {
console.log('Task list: ', taskList);
}, error => {
console.log('Error: ', error);
});
The number of tasks that are returned is controlled by the size
property.
This is a convenience method on top of the getTasks
method. It overwrites the requestNode.state
property
with passed in state
before making the call to getTasks
.
For an example of the response see the getTasks
method.
findAllTaskByState(requestNode: TaskQueryRequestRepresentationModel, state?: string): Observable<TaskListModel>
Find and return all Task Instances by state open
or completed
and query model:
const taskState = 'open';
const taskQuery: TaskQueryRequestRepresentationModel = {
appDefinitionId: '2',
processInstanceId: null,
processDefinitionId: null,
text: null,
assignment: null,
state: 'open',
sort: 'created_asc',
page: 0,
size: 5,
start: null
};
this.tasklistService.findAllTaskByState(taskQuery, taskState).subscribe( (taskList: TaskListModel) => {
console.log('Task list: ', taskList);
}, error => {
console.log('Error: ', error);
});
This is a convenience method on top of the getTasks
method. It overwrites the requestNode.state
property with
passed in state
before making any other calls. Before making the getTasks
call it will first call the
getTotalTasks
method to get the total number of tasks that match query and state. It then overwrite the
requestNode.size
with the total so all matching tasks are returned when finnally making the getTasks
call.
Note that this can return a lot of data if you are not careful.
findAllTasksWithoutState(requestNode: TaskQueryRequestRepresentationModel): Observable<TaskListModel>
Find and return all Task Instances that matches query model, regardless of state:
const taskQuery: TaskQueryRequestRepresentationModel = {
appDefinitionId: '2',
processInstanceId: null,
processDefinitionId: null,
text: null,
assignment: null,
state: null,
sort: 'created_asc',
page: 0,
size: 5,
start: null
};
this.tasklistService.findAllTasksWithoutState(taskQuery).subscribe( (taskList: TaskListModel) => {
console.log('Task list: ', taskList);
}, error => {
console.log('Error: ', error);
});
This method can be used when you have a task query that should return all tasks regardless of the state they
are in. You cannot achieve this with the getTasks
method. If you specify a size
it is overwritten.
Internally it basically calls findTasksByState(requestNode, 'open')
and
findAllTaskByState(requestNode, 'completed')
.
Note that this can return a lot of data if you are not careful.
assignTaskByUserId(taskId: string, userId: number): Observable<TaskDetailsModel>
Assign a Task Instance to a user via the User ID:
const taskId = '15303';
const userId = 1;
this.tasklistService.assignTaskByUserId(taskId, userId).subscribe( (taskInstance: TaskDetailsModel) => {
console.log('Task instance: ', taskInstance);
}, error => {
console.log('Error: ', error);
});
The user ID identifies a User in APS.
assignTask(taskId: string, requestNode: any): Observable<TaskDetailsModel>
Assign a task to a user via a user object with an id
property, for example:
const taskId = '15303';
const user = { id: 1, email: 'admin@app.activiti.com', firstName: 'APS', lastName: 'Admin' };
this.tasklistService.assignTask(taskId, user).subscribe( (taskInstance: TaskDetailsModel) => {
console.log('Task instance: ', taskInstance);
}, error => {
console.log('Error: ', error);
});
This method does the same as the assignTaskByUserId
method, the only difference is that this
method can be used when you have an object where the User ID is contained in an id
property.
claimTask(taskId: string): Observable<TaskDetailsModel>
Claim a pooled task (i.e. candidate task) as current user so it can be worked on and later on completed:
const taskId = '15368';
this.tasklistService.claimTask(taskId).subscribe( (taskInstance: TaskDetailsModel) => {
console.log('Task instance: ', taskInstance);
}, error => {
console.log('Error: ', error);
});
The response will be null
if the task was claimed successfully.
The task assignment changes from candidate
to assignee
.
unclaimTask(taskId: string): Observable<TaskDetailsModel>
Return a claimed task to the pool (i.e. make it a candidate task):
const taskId = '15368';
this.tasklistService.unclaimTask(taskId).subscribe( (taskInstance: TaskDetailsModel) => {
console.log('Task instance: ', taskInstance);
}, error => {
console.log('Error: ', error);
});
The task assignment changes from assignee
to candidate
.
completeTask(taskId: string)
Complete a Task Instance as current user and progress Process Instance:
const taskId = '15176';
this.tasklistService.completeTask(taskId);
This only works if the Task Instance has only one Outcome (i.e. the default Complete
one).
If the Task Instance has multiple Outcomes, such as Approve and Reject, then this method does not
work, and the Task Instance has to be completed via its associated form. Otherwise you will see an error such as:
ERROR Error: Uncaught (in promise): Error: {"message":"Task must be completed using it's form","messageKey":"GENERAL.ERROR.BAD-REQUEST"}
updateTask(taskId: any, updated): Observable<TaskDetailsModel>
Update name, description, and due date for a Task Instance:
const taskId = '80002';
const updateData: TaskUpdateRepresentation = {
description: 'Updated description',
dueDate: new Date(2018, 1, 10, 11, 0, 0, 0),
name: 'Updated name'
};
this.tasklistService.updateTask(taskId, updateData).subscribe( (updatedTaskDetails: TaskDetailsModel) => {
console.log('Updated task: ', updatedTaskDetails);
}, error => {
console.log('Error: ', error);
});
The response is all info about the updated Task Instance, in this example a stand-alone task was updated so there is no associated process:
adhocTaskCanBeReassigned: false
assignee: undefined
category: null
created: Mon Nov 13 2017 16:34:49 GMT+0000 (GMT) {}
description: "Updated description"
dueDate: Sat Feb 10 2018 11:00:00 GMT+0000 (GMT) {}
duration: NaN
endDate: null
executionId: null
formKey: "5005"
id: "80002"
initiatorCanCompleteTask: false
managerOfCandidateGroup: false
memberOfCandidateGroup: false
memberOfCandidateUsers: false
name: "Updated name"
parentTaskId: null
parentTaskName: null
priority: 50
processDefinitionCategory: null
processDefinitionDeploymentId: null
processDefinitionDescription: null
processDefinitionId: null
processDefinitionKey: null
processDefinitionName: null
processDefinitionVersion: 0
processInstanceId: null
processInstanceName: null
processInstanceStartUserId: null
taskDefinitionKey: null
createNewTask(task: TaskDetailsModel): Observable<TaskDetailsModel>
Create a new stand-alone Task Instance that is not associated with a Process Instance:
const taskDetails = new TaskDetailsModel({
name: 'Some Task',
description: 'A new stand-alone task'
});
this.tasklistService.createNewTask(taskDetails).subscribe( (createdTaskDetails: TaskDetailsModel) => {
console.log('Created task details: ', createdTaskDetails);
}, error => {
console.log('Error: ', error);
});
In this case we are creating a disconnected Task Instance that is not associated with a form (i.e. formKey: null
)
and that is not assigned to a user (i.e. assignee: null
).
The response looks like this, we can see that an ID was generated for the Task Instance:
Created task details:
adhocTaskCanBeReassigned: false
assignee: null
category: null
created: Mon Nov 13 2017 16:34:49 GMT+0000 (GMT) {}
description: "A new stand-alone task"
dueDate: null
duration: null
endDate: null
executionId: null
formKey: null
id: "80002"
initiatorCanCompleteTask: false
involvedPeople: undefined
managerOfCandidateGroup: false
memberOfCandidateGroup: false
memberOfCandidateUsers: false
name: "Some Task"
parentTaskId: null
parentTaskName: null
priority: 50
processDefinitionCategory: null
processDefinitionDeploymentId: null
processDefinitionDescription: null
processDefinitionId: null
processDefinitionKey: null
processDefinitionName: null
processDefinitionVersion: 0
processInstanceId: null
processInstanceName: null
processInstanceStartUserId: null
taskDefinitionKey: null
See the attachFormToATask
method for how to attach a form to the User Task. And see the assignTaskByUserId
method
for how to assign a user to the new Task Instance.
attachFormToATask(taskId: string, formId: number): Observable<any>
Attach a form to a User Task:
const taskId = '80002';
const formId = 5005;
this.tasklistService.attachFormToATask(taskId, formId).subscribe( (response: any) => {
console.log('Assign form response: ', response);
}, error => {
console.log('Error: ', error);
});
In this case we need to have a task created and know the ID for it, such as with the createNewTask
method.
We also need to have a form defined in APS and know the ID for it (you can see the ID for a form in the URL
in APS when you work with it). See the getFormList
method for how fetch a list of available forms.
The response will be null
if form was attached successfully to task.
getFormList(): Observable<Form []>
Get a list of the available reusable forms:
this.tasklistService.getFormList().subscribe( (formList: Form[]) => {
console.log('Available forms: ', formList);
}, error => {
console.log('Error: ', error);
});
A successful response looks like this:
Available forms:
0:
id: 5005
name: "Name Info"
1: {name: "cm:folder", id: 3012}
2: {name: "Alfresco Node Form", id: 3011}
3: {name: "Employee", id: 3010}
The form id property can be used with the attachFormToATask
method.
Note. Referenced forms that are associated with specific tasks in a process are not included in this list. Only reusable forms are included.
addTask(task: TaskDetailsModel): Observable<TaskDetailsModel>
Add a Sub-Task (i.e. checklist task) to a parent Task Instance:
const parentTaskId = '80002';
const subTaskDetails = new TaskDetailsModel({
parentTaskId: parentTaskId,
name: 'Check the invoice amount'
});
this.tasklistService.addTask(subTaskDetails).subscribe( (updatedTaskDetails: TaskDetailsModel) => {
console.log('Sub-task info: ', updatedTaskDetails);
}, error => {
console.log('Error: ', error);
});
The response includes the new sub-task id and also parent task name. In this example the parent task was just a stand-alone task, so no process information is included:
adhocTaskCanBeReassigned: false
assignee: null
category: null
created: Tue Nov 14 2017 13:32:41 GMT+0000 (GMT) {}
description: null
dueDate: null
duration: null
endDate: null
executionId: null
formKey: null
id: "80003"
initiatorCanCompleteTask: false
involvedPeople: undefined
managerOfCandidateGroup: false
memberOfCandidateGroup: false
memberOfCandidateUsers: false
name: "Check the invoice amount"
parentTaskId: "80002"
parentTaskName: "Some Task"
priority: 50
processDefinitionCategory: null
processDefinitionDeploymentId: null
processDefinitionDescription: null
processDefinitionId: null
processDefinitionKey: null
processDefinitionName: null
processDefinitionVersion: 0
processInstanceId: null
processInstanceName: null
processInstanceStartUserId:null
taskDefinitionKey: null
deleteTask(taskId: string): Observable<TaskDetailsModel>
Delete a Sub-Task (i.e. checklist task):
const taskId = '75100'; // Sub-task ID
this.tasklistService.deleteTask(taskId).subscribe( (taskDetails: TaskDetailsModel) => {
console.log('Deleted task info: ', taskDetails);
}, error => {
console.log('Error: ', error);
});
Note. you can only delete so called checklist tasks with this method.
fetchTaskAuditJsonById(taskId: string): Observable<any>
Fetch Task Audit log as JSON for a Task Instance ID:
const taskId = '15368';
this.tasklistService.fetchTaskAuditJsonById(taskId)
.subscribe( auditJson => {
console.log('Task Audit: ', auditJson);
}, error => {
console.log('Error: ', error);
});
The response is JSON object with the Task Instance audit log:
{
taskId: "15368",
taskName: "Approve by someone in Accounting",
processInstanceId: "15361",
processDefinitionName: "Process With Pooled task",
processDefinitionVersion: 1,
…
}
fetchTaskAuditPdfById(taskId: string): Observable<Blob>
Fetch Task Audit log as JSON for a Task Instance ID:
this.tasklistService.fetchTaskAuditPdfById(taskId)
.subscribe( (auditPdf: Blob) => {
console.log('Task Audit: ', auditPdf);
}, error => {
console.log('Error: ', error);
});
The response is PDF with the Task Instance audit log.