Skip to content

Commit d23f29b

Browse files
feat(tasks): added GetTaskDataById API for DU-VS (#323)
* feat(tasks): added GetTaskDataById API for DU-VS * feat(tasks): added getAppTaskById API * test(tasks): fixed sonar issues * fix(tasks): taskGetFormOptions extends BaseOptions & removed SUPPORTED_TASK_TYPES
1 parent 0900e2d commit d23f29b

8 files changed

Lines changed: 407 additions & 91 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
"README.md"
153153
],
154154
"scripts": {
155+
"prepack": "rimraf *.tgz",
155156
"prebuild": "rimraf dist",
156157
"build": "rollup -c",
157158
"build:watch": "rollup -c -w",

src/models/action-center/tasks.internal-types.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1-
import { CollectionResponse } from "../common/types";
2-
import { TaskAssignmentOptions, TaskAssignmentResponse } from "./tasks.types";
1+
import { BaseOptions, CollectionResponse } from "../common/types";
2+
import { TaskAssignmentOptions, TaskAssignmentResponse, TaskType } from "./tasks.types";
3+
import { TASK_ENDPOINTS } from "../../utils/constants/endpoints";
4+
5+
export const TASK_TYPE_ENDPOINTS: Record<TaskType, string> = {
6+
[TaskType.Form]: TASK_ENDPOINTS.GET_TASK_FORM_BY_ID,
7+
[TaskType.App]: TASK_ENDPOINTS.GET_APP_TASK_BY_ID,
8+
[TaskType.DocumentValidation]: TASK_ENDPOINTS.GET_GENERIC_TASK_BY_ID,
9+
[TaskType.DocumentClassification]: TASK_ENDPOINTS.GET_GENERIC_TASK_BY_ID,
10+
[TaskType.External]: TASK_ENDPOINTS.GET_GENERIC_TASK_BY_ID,
11+
[TaskType.DataLabeling]: TASK_ENDPOINTS.GET_GENERIC_TASK_BY_ID,
12+
};
313

414
export enum ActionCenterEventNames {
515
TOKENREFRESHED = 'AC.tokenRefreshed',
@@ -29,6 +39,6 @@ export type TaskAssignmentResponseCollection = CollectionResponse<TaskAssignment
2939
/**
3040
* Options for getting a form task by ID
3141
*/
32-
export interface TaskGetFormOptions {
33-
expandOnFormLayout?: boolean;
34-
}
42+
export interface TaskGetFormOptions extends BaseOptions {
43+
expandOnFormLayout?: boolean;
44+
}

src/models/action-center/tasks.models.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,9 @@ export interface TaskServiceModel {
8585

8686
/**
8787
* Gets a task by ID
88-
* IMPORTANT: For form tasks, folderId must be provided.
8988
* @param id - The ID of the task to retrieve
90-
* @param options - Optional query parameters
91-
* @param folderId - Optional folder ID (REQUIRED for form tasks)
89+
* @param options - Optional query parameters including taskType for faster retrieval {@link TaskGetByIdOptions}
90+
* @param folderId - Optional folder ID (REQUIRED when options.taskType is provided)
9291
* @returns Promise resolving to the task
9392
* {@link TaskGetResponse}
9493
* @example
@@ -97,10 +96,13 @@ export interface TaskServiceModel {
9796
* const task = await tasks.getById(<taskId>);
9897
*
9998
* // Get a form task by ID
100-
* const formTask = await tasks.getById(<taskId>, <folderId>);
99+
* const formTask = await tasks.getById(<taskId>, {}, <folderId>);
101100
*
102101
* // Access form task properties
103102
* console.log(formTask.formLayout);
103+
*
104+
* // Get a document validation task by ID (faster with taskType provided in the options)
105+
* const dvTask = await tasks.getById(<taskId>, { taskType: TaskType.DocumentValidation }, <folderId>);
104106
* ```
105107
*/
106108
getById(id: number, options?: TaskGetByIdOptions, folderId?: number): Promise<TaskGetResponse>;

src/models/action-center/tasks.types.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,23 @@ export interface UserLoginInfo {
1111
id: number;
1212
}
1313

14+
/**
15+
* Types of tasks available in Action Center.
16+
* Each type determines the task's behavior, UI rendering, and completion requirements.
17+
*/
1418
export enum TaskType {
19+
/** A form-based task that renders a UiPath form layout for user input */
1520
Form = 'FormTask',
21+
/** An externally managed task handled outside of Action Center */
1622
External = 'ExternalTask',
17-
App = 'AppTask'
23+
/** A task powered by a UiPath App */
24+
App = 'AppTask',
25+
/** A document validation task for reviewing and correcting extracted document data */
26+
DocumentValidation = 'DocumentValidationTask',
27+
/** A document classification task for categorizing documents */
28+
DocumentClassification = 'DocumentClassificationTask',
29+
/** A data labeling task for annotating training data */
30+
DataLabeling = 'DataLabelingTask'
1831
}
1932

2033
export enum TaskPriority {
@@ -209,7 +222,11 @@ export interface TaskAssignmentResponse {
209222
*/
210223
export type TaskCompleteOptions =
211224
| { type: TaskType.External; data?: any; action?: string }
212-
| { type: Exclude<TaskType, TaskType.External>; data: any; action: string };
225+
| { type: TaskType.DocumentValidation; data?: any; action?: string }
226+
| { type: TaskType.DocumentClassification; data?: any; action?: string }
227+
| { type: TaskType.DataLabeling; data?: any; action?: string }
228+
| { type: TaskType.Form; data: any; action: string }
229+
| { type: TaskType.App; data: any; action: string }
213230

214231
/**
215232
* Options for completing a task when called from the service
@@ -236,9 +253,16 @@ export type TaskGetAllOptions = RequestOptions & PaginationOptions & {
236253
}
237254

238255
/**
239-
* Query options for getting a task by ID
256+
* Query options for getting a task by ID
240257
*/
241-
export interface TaskGetByIdOptions extends BaseOptions {}
258+
export interface TaskGetByIdOptions extends BaseOptions {
259+
/**
260+
* Optional task type. When not provided, method will automatically identify the
261+
* task type and resolve accordingly, but it will be slower.
262+
* When provided, it will skip the step to identify the task type, so it will be faster.
263+
*/
264+
taskType?: TaskType;
265+
}
242266

243267
/**
244268
* Options for getting users with task permissions

src/services/action-center/tasks.ts

Lines changed: 78 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
1-
import { BaseService } from '../base';
2-
import {
3-
TaskCreateOptions,
1+
import { ValidationError } from '../../core/errors';
2+
import { track } from '../../core/telemetry';
3+
import { DEFAULT_TASK_EXPAND, TaskMap, TaskStatusMap } from '../../models/action-center/tasks.constants';
4+
import { TASK_TYPE_ENDPOINTS, TaskAssignmentResponseCollection, TaskGetFormOptions, TasksAssignOptions } from '../../models/action-center/tasks.internal-types';
5+
import {
6+
TaskCreateResponse,
7+
TaskGetResponse,
8+
TaskServiceModel,
9+
createTaskWithMethods
10+
} from '../../models/action-center/tasks.models';
11+
import {
412
TaskAssignmentOptions,
513
TaskAssignmentResponse,
6-
TasksUnassignOptions,
714
TaskCompletionOptions,
8-
TaskType,
15+
TaskCreateOptions,
916
TaskGetAllOptions,
1017
TaskGetByIdOptions,
11-
UserLoginInfo,
1218
TaskGetUsersOptions,
19+
TaskType,
20+
TasksUnassignOptions,
21+
UserLoginInfo,
1322
} from '../../models/action-center/tasks.types';
14-
import {
15-
TaskServiceModel,
16-
TaskGetResponse,
17-
TaskCreateResponse,
18-
createTaskWithMethods
19-
} from '../../models/action-center/tasks.models';
20-
import { OperationResponse } from '../../models/common/types';
21-
import { pascalToCamelCaseKeys, camelToPascalCaseKeys, transformData, applyDataTransforms, addPrefixToKeys } from '../../utils/transform';
22-
import { TaskStatusMap, TaskMap, DEFAULT_TASK_EXPAND } from '../../models/action-center/tasks.constants';
23-
import { createHeaders } from '../../utils/http/headers';
24-
import { FOLDER_ID } from '../../utils/constants/headers';
23+
import { BaseOptions, OperationResponse } from '../../models/common/types';
24+
import { ODATA_OFFSET_PARAMS, ODATA_PAGINATION, ODATA_PREFIX } from '../../utils/constants/common';
2525
import { TASK_ENDPOINTS } from '../../utils/constants/endpoints';
26-
import { ODATA_PREFIX, ODATA_PAGINATION, ODATA_OFFSET_PARAMS } from '../../utils/constants/common';
27-
import { PaginatedResponse, NonPaginatedResponse, HasPaginationOptions } from '../../utils/pagination';
26+
import { FOLDER_ID } from '../../utils/constants/headers';
27+
import { createHeaders } from '../../utils/http/headers';
28+
import { processODataArrayResponse } from '../../utils/object';
29+
import { HasPaginationOptions, NonPaginatedResponse, PaginatedResponse } from '../../utils/pagination';
2830
import { PaginationHelpers } from '../../utils/pagination/helpers';
2931
import { PaginationType } from '../../utils/pagination/internal-types';
30-
import { TaskAssignmentResponseCollection, TaskGetFormOptions, TasksAssignOptions } from '../../models/action-center/tasks.internal-types';
31-
import { track } from '../../core/telemetry';
32-
import { processODataArrayResponse } from '../../utils/object';
32+
import { addPrefixToKeys, applyDataTransforms, camelToPascalCaseKeys, pascalToCamelCaseKeys, transformData } from '../../utils/transform';
33+
import { BaseService } from '../base';
3334

3435
/**
3536
* Service for interacting with UiPath Tasks API
@@ -234,52 +235,63 @@ export class TaskService extends BaseService implements TaskServiceModel {
234235

235236
/**
236237
* Gets a task by ID
237-
* IMPORTANT: For form tasks, folderId must be provided.
238-
*
239238
* @param id - The ID of the task to retrieve
240-
* @param options - Optional query parameters
241-
* @param folderId - Optional folder ID (REQUIRED for form tasks)
242-
* @returns Promise resolving to the task (form tasks will return form-specific data)
243-
*
239+
* @param options - Optional query parameters including taskType for faster retrieval {@link TaskGetByIdOptions}
240+
* @param folderId - Optional folder ID (REQUIRED when options.taskType is provided)
241+
* @returns Promise resolving to the task
242+
* {@link TaskGetResponse}
244243
* @example
245244
* ```typescript
246-
* import { Tasks } from '@uipath/uipath-typescript/tasks';
245+
* // Get a task by ID
246+
* const task = await tasks.getById(<taskId>);
247247
*
248-
* const tasks = new Tasks(sdk);
248+
* // Get a form task by ID
249+
* const formTask = await tasks.getById(<taskId>, {}, <folderId>);
249250
*
250-
* // Get task by ID
251-
* const task = await tasks.getById(123);
251+
* // Access form task properties
252+
* console.log(formTask.formLayout);
252253
*
253-
* // If the task is a form task, it will automatically return form-specific data
254+
* // Get a document validation task by ID (faster with taskType provided in the options)
255+
* const dvTask = await tasks.getById(<taskId>, { taskType: TaskType.DocumentValidation }, <folderId>);
254256
* ```
255257
*/
256258
@track('Tasks.GetById')
257259
async getById(id: number, options: TaskGetByIdOptions = {}, folderId?: number): Promise<TaskGetResponse> {
260+
const { taskType, ...restOptions } = options;
261+
262+
// If taskType is provided, skip the generic GET_BY_ID call and go directly to the type-specific endpoint
263+
if (taskType && taskType in TASK_TYPE_ENDPOINTS) {
264+
if (!folderId) {
265+
throw new ValidationError({ message: 'folderId is required when taskType is provided' });
266+
}
267+
return this.getByTaskType(id, folderId, taskType, restOptions);
268+
}
269+
258270
const headers = createHeaders({ [FOLDER_ID]: folderId });
259-
271+
260272
// Add default expand parameters
261-
const modifiedOptions = this.addDefaultExpand(options);
262-
273+
const modifiedOptions = this.addDefaultExpand(restOptions);
274+
263275
// prefix all keys in options
264276
const keysToPrefix = Object.keys(modifiedOptions);
265277
const apiOptions = addPrefixToKeys(modifiedOptions, ODATA_PREFIX, keysToPrefix);
266278
const response = await this.get<TaskGetResponse>(
267279
TASK_ENDPOINTS.GET_BY_ID(id),
268-
{
280+
{
269281
params: apiOptions,
270282
headers
271283
}
272284
);
273-
285+
274286
// Transform response from PascalCase to camelCase and normalize time fields
275287
const transformedTask = transformData(pascalToCamelCaseKeys(response.data) as TaskGetResponse, TaskMap);
276-
277-
// Check if this is a form task and get form-specific data if it is
278-
if (transformedTask.type === TaskType.Form) {
279-
const formOptions: TaskGetFormOptions = { expandOnFormLayout: true };
280-
return this.getFormTaskById(id, folderId || transformedTask.folderId, formOptions);
288+
289+
// Get task type from response and fetch type-specific data
290+
const resolvedFolderId = folderId || transformedTask.folderId;
291+
if (transformedTask.type in TASK_TYPE_ENDPOINTS) {
292+
return this.getByTaskType(id, resolvedFolderId, transformedTask.type, restOptions);
281293
}
282-
294+
283295
return createTaskWithMethods(
284296
applyDataTransforms(transformedTask, { field: 'status', valueMap: TaskStatusMap }),
285297
this
@@ -506,29 +518,39 @@ export class TaskService extends BaseService implements TaskServiceModel {
506518
}
507519

508520
/**
509-
* Gets a form task by ID (private method)
510-
*
511-
* @param id - The ID of the form task to retrieve
521+
* Routes to the type-specific endpoint based on task type.
522+
*/
523+
private getByTaskType(id: number, folderId: number, taskType: TaskType, options: BaseOptions = {}): Promise<TaskGetResponse> {
524+
const endpoint = TASK_TYPE_ENDPOINTS[taskType];
525+
const extraParams: TaskGetFormOptions = taskType === TaskType.Form ? { expandOnFormLayout: true, ...options } : options;
526+
return this.getTaskByTypeEndpoint(id, folderId, endpoint, extraParams);
527+
}
528+
529+
/**
530+
* Fetches a task from a type-specific endpoint.
531+
*
532+
* @param id - The task ID
512533
* @param folderId - Required folder ID
513-
* @param options - Optional query parameters
514-
* @returns Promise resolving to the form task
534+
* @param endpoint - The type-specific endpoint to call
535+
* @param extraParams - Additional query parameters (e.g. form options)
536+
* @returns Promise resolving to the task
515537
*/
516-
private async getFormTaskById(id: number, folderId: number, options: TaskGetFormOptions = {}): Promise<TaskGetResponse> {
538+
private async getTaskByTypeEndpoint(id: number, folderId: number, endpoint: string, extraParams: TaskGetFormOptions = {}): Promise<TaskGetResponse> {
517539
const headers = createHeaders({ [FOLDER_ID]: folderId });
518-
540+
519541
const response = await this.get<TaskGetResponse>(
520-
TASK_ENDPOINTS.GET_TASK_FORM_BY_ID,
521-
{
542+
endpoint,
543+
{
522544
params: {
523545
taskId: id,
524-
...options
546+
...extraParams
525547
},
526548
headers
527549
}
528550
);
529-
const transformedFormTask = transformData(response.data, TaskMap);
551+
const transformedTask = transformData(response.data, TaskMap);
530552
return createTaskWithMethods(
531-
applyDataTransforms(transformedFormTask, { field: 'status', valueMap: TaskStatusMap }),
553+
applyDataTransforms(transformedTask, { field: 'status', valueMap: TaskStatusMap }),
532554
this
533555
) as TaskGetResponse;
534556
}

src/utils/constants/endpoints/orchestrator.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export const TASK_ENDPOINTS = {
2020
COMPLETE_APP_TASK: `${ORCHESTRATOR_BASE}/tasks/AppTasks/CompleteAppTask`,
2121
COMPLETE_GENERIC_TASK: `${ORCHESTRATOR_BASE}/tasks/GenericTasks/CompleteTask`,
2222
GET_TASK_FORM_BY_ID: `${ORCHESTRATOR_BASE}/forms/TaskForms/GetTaskFormById`,
23+
GET_GENERIC_TASK_BY_ID: `${ORCHESTRATOR_BASE}/tasks/GenericTasks/GetTaskDataById`,
24+
GET_APP_TASK_BY_ID: `${ORCHESTRATOR_BASE}/tasks/AppTasks/GetAppTaskById`,
2325
} as const;
2426

2527
/**

0 commit comments

Comments
 (0)