Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ jobs:
echo "integration_test_folder_key=${{ secrets.UIPATH_INTEGRATION_TEST_FOLDER_KEY_DEV || secrets.UIPATH_INTEGRATION_TEST_FOLDER_KEY }}" >> $GITHUB_OUTPUT
echo "integration_test_folder_path=${{ secrets.UIPATH_INTEGRATION_TEST_FOLDER_PATH_DEV || secrets.UIPATH_INTEGRATION_TEST_FOLDER_PATH }}" >> $GITHUB_OUTPUT
echo "orchestrator_test_process_key=${{ secrets.UIPATH_INTEGRATION_TEST_PROCESS_KEY_DEV || secrets.UIPATH_INTEGRATION_TEST_PROCESS_KEY }}" >> $GITHUB_OUTPUT
echo "queues_test_queue_name=${{ secrets.UIPATH_QUEUES_TEST_QUEUE_NAME_DEV || secrets.UIPATH_QUEUES_TEST_QUEUE_NAME }}" >> $GITHUB_OUTPUT
echo "data_fabric_test_entity_id=${{ secrets.UIPATH_DATA_FABRIC_TEST_ENTITY_ID_DEV || secrets.UIPATH_DATA_FABRIC_TEST_ENTITY_ID }}" >> $GITHUB_OUTPUT
echo "data_fabric_test_choiceset_id=${{ secrets.UIPATH_DATA_FABRIC_TEST_CHOICESET_ID_DEV || secrets.UIPATH_DATA_FABRIC_TEST_CHOICESET_ID }}" >> $GITHUB_OUTPUT
echo "data_fabric_test_attachment_field=${{ secrets.UIPATH_DATA_FABRIC_TEST_ATTACHMENT_FIELD_DEV || secrets.UIPATH_DATA_FABRIC_TEST_ATTACHMENT_FIELD }}" >> $GITHUB_OUTPUT
Expand Down Expand Up @@ -102,6 +103,7 @@ jobs:
DATA_FABRIC_TEST_JOIN_RELATED_ENTITY_NAME=${{ steps.config.outputs.data_fabric_test_join_related_entity_name }}
DATA_FABRIC_TEST_JOIN_RELATED_FIELD_NAME=${{ steps.config.outputs.data_fabric_test_join_related_field_name }}
ORCHESTRATOR_TEST_PROCESS_KEY=${{ steps.config.outputs.orchestrator_test_process_key }}
QUEUES_TEST_QUEUE_NAME=${{ steps.config.outputs.queues_test_queue_name }}
ORCHESTRATOR_ATTACHMENT_ID=${{ steps.config.outputs.orchestrator_attachment_id }}
JOBS_TEST_FOLDER_ID=${{ steps.config.outputs.jobs_test_folder_id }}
TRACES_TEST_TRACE_ID=${{ steps.config.outputs.traces_test_trace_id }}
Expand Down
2 changes: 1 addition & 1 deletion agent_docs/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ The method attachment pattern:

- **Not every service method gets bound.** Only bind methods that operate ON a specific entity after retrieval — state-changing operations (assign, cancel, complete, insert, update, delete) and contextual reads that need the entity's ID.
- **NEVER** bind `getAll()`, `getById()`, `create()`, or cross-entity queries — these are service-level entry points. Binding them creates circular nonsense (an entity that retrieves itself).
- **Read-only services don't bind at all** — Assets, Buckets, Queues, Processes, ChoiceSets, Cases, and ProcessIncidents have no `{Entity}Methods` interface.
- **Read-only services don't bind at all** — Assets, Buckets, Processes, ChoiceSets, Cases, and ProcessIncidents have no `{Entity}Methods` interface. (Queues binds `getAllItems`/`insertItem` since queue-item support landed.)

## Response transformation pipeline

Expand Down
2 changes: 2 additions & 0 deletions docs/oauth-scopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ The `ConversationalAgents` scope is required for real-time WebSocket sessions (`
|--------|-------------|
| `getAll()` | `OR.Queues` or `OR.Queues.Read` |
| `getById()` | `OR.Queues` or `OR.Queues.Read` |
| `getAllItems()` / `queue.getAllItems()` | `OR.Queues` or `OR.Queues.Read` |
| `insertItemByName()` / `queue.insertItem()` | `OR.Queues` or `OR.Queues.Write` |

## Tasks

Expand Down
1 change: 1 addition & 0 deletions docs/pagination.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ console.log(`Total count: ${allAssets.totalCount}`);
| CaseInstances | `getActionTasks()` | ✅ Yes |
| CaseInstances | `getSlaSummary()` | ✅ Yes |
| Queues | `getAll()` | ✅ Yes |
| Queues | `getAllItems()` | ✅ Yes |
| Tasks | `getAll()` | ✅ Yes |
| Tasks | `getUsers()` | ✅ Yes |
| ConversationalAgent.conversations | `getAll()` | ❌ No |
Expand Down
29 changes: 25 additions & 4 deletions src/models/orchestrator/queues.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,28 @@
* Maps fields for Queue entities to ensure consistent naming
*/
export const QueueMap: { [key: string]: string } = {
creationTime: 'createdTime',
organizationUnitId: 'folderId',
organizationUnitFullyQualifiedName: 'folderName'
};
creationTime: 'createdTime',
organizationUnitId: 'folderId',
organizationUnitFullyQualifiedName: 'folderName'
};

/**
* Maps fields for Queue item entities to ensure consistent naming.
* Keys are camelCase — the map runs after `pascalToCamelCaseKeys()`.
*/
export const QueueItemMap: { [key: string]: string } = {
queueDefinitionId: 'queueId',
creationTime: 'createdTime',
organizationUnitId: 'folderId',
organizationUnitFullyQualifiedName: 'folderName',
startProcessing: 'processingStartTime',
endProcessing: 'processingEndTime',
processingException: 'processingError'
};

/**
* Maps fields nested inside a queue item's processing error.
*/
export const QueueProcessingErrorMap: { [key: string]: string } = {
creationTime: 'createdTime'
};
181 changes: 173 additions & 8 deletions src/models/orchestrator/queues.models.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { QueueGetAllOptions, QueueGetByIdOptions, QueueGetResponse } from './queues.types';
import {
QueueGetAllOptions,
QueueGetByIdOptions,
RawQueueGetResponse,
QueueGetAllItemsOptions,
QueueInsertItemOptions,
QueueItem,
QueueItemValue
} from './queues.types';
import { PaginatedResponse, NonPaginatedResponse, HasPaginationOptions } from '../../utils/pagination';

/** Combined response type for queue data with bound methods. */
export type QueueGetResponse = RawQueueGetResponse & QueueMethods;

/**
* Service for managing UiPath Queues
*
Expand All @@ -20,11 +31,9 @@ import { PaginatedResponse, NonPaginatedResponse, HasPaginationOptions } from '.
export interface QueueServiceModel {
/**
* Gets all queues across folders with optional filtering and folder scoping
*
* @signature getAll(options?) → Promise<QueueGetResponse[]>
*
* @param options Query options including optional folderId and pagination options
* @returns Promise resolving to either an array of queues NonPaginatedResponse<QueueGetResponse> or a PaginatedResponse<QueueGetResponse> when pagination options are used.
* {@link QueueGetResponse}
* @returns Promise resolving to either a {@link QueueGetResponse} array (`NonPaginatedResponse`) or a `PaginatedResponse<QueueGetResponse>` when pagination options are used. Each queue has methods attached for operating on its items.
* @example
* ```typescript
* // Standard array return
Expand Down Expand Up @@ -63,15 +72,171 @@ export interface QueueServiceModel {

/**
* Gets a single queue by ID
*
*
* @param id - Queue ID
* @param folderId - Required folder ID
* @returns Promise resolving to a queue definition
* @returns Promise resolving to a {@link QueueGetResponse} — the queue definition with methods attached for operating on its items
* @example
* ```typescript
* // Get queue by ID
* const queue = await queues.getById(<queueId>, <folderId>);
*
* // Operate on the queue directly via the attached methods
* const items = await queue.getAllItems();
* const item = await queue.insertItem({
* invoiceId: 'INV-1001',
* amount: 1520
* });
* ```
*/
Comment on lines 82 to +91

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add a insertItem example as well?

getById(id: number, folderId: number, options?: QueueGetByIdOptions): Promise<QueueGetResponse>;
}

/**
* Gets the items of a queue with optional filtering and pagination
*
* Returns the queue's work items including their status, business payload
* (`specificData`), output, timing fields, and failure details.
*
* @param queueId - Queue ID
* @param folderId - Required folder ID
* @param options Query options including filtering and pagination options
* @returns Promise resolving to either a {@link QueueItem} array (`NonPaginatedResponse`) or a `PaginatedResponse<QueueItem>` when pagination options are used.
* @example
* ```typescript
* const items = await queues.getAllItems(<queueId>, <folderId>);
*
* // Failed items only, newest first
* const failed = await queues.getAllItems(<queueId>, <folderId>, {
* filter: "status eq 'Failed'",
* orderby: 'createdTime desc',
* pageSize: 25
* });
* ```
* @example
* ```typescript
* // Or operate on a queue returned by getById/getAll
* const queue = await queues.getById(<queueId>, <folderId>);
* const items = await queue.getAllItems();
* ```
*/
getAllItems<T extends QueueGetAllItemsOptions = QueueGetAllItemsOptions>(
queueId: number,
folderId: number,
options?: T
): Promise<
T extends HasPaginationOptions<T>
? PaginatedResponse<QueueItem>
: NonPaginatedResponse<QueueItem>
>;

/**
* Inserts a new item into a queue by queue name
*
* Returns the created queue item including its id, status, and the stored
* payload. The payload keys are user-defined and are stored and returned
* exactly as provided.
*
* The payload must be flat — values are simple scalars (see
* {@link QueueItemValue}); nested objects and arrays are rejected.
*
* @param queueName - Name of the queue to insert into
* @param folderId - Required folder ID
* @param specificData - The item's business payload (stored as the queue item's specific content)
* @param options Optional item metadata (priority, reference, defer/due dates)
* @returns Promise resolving to the created {@link QueueItem}
* @example
* ```typescript
* import { QueuePriority } from '@uipath/uipath-typescript/queues';
*
* // Minimal insert
* const item = await queues.insertItemByName('<queueName>', <folderId>, {
* invoiceId: 'INV-1001',
* amount: 1520
* });
*
* // With metadata
* const rushItem = await queues.insertItemByName('<queueName>', <folderId>, {
* invoiceId: 'INV-1002'
* }, {
* priority: QueuePriority.High,
* reference: 'INV-1002',
* dueDate: new Date('2026-08-15')
* });
* ```
*/
insertItemByName(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@deepeshrai-tech please help refresh my memory. For CRUD naming conventions, we decided to drop the byName/ byId prefix?

queueName: string,
folderId: number,
specificData: Record<string, QueueItemValue>,
options?: QueueInsertItemOptions
): Promise<QueueItem>;
}

/**
* Queue methods interface - operations bound to a queue returned by
* getAll/getById. The queue's own id, name, and folder are filled in
* automatically.
*/
export interface QueueMethods {
/**
* Gets this queue's items with optional filtering and pagination.
*
* @param options Query options including filtering and pagination options
* @returns Promise resolving to the queue's {@link QueueItem} entries
*/
getAllItems<T extends QueueGetAllItemsOptions = QueueGetAllItemsOptions>(options?: T): Promise<
T extends HasPaginationOptions<T>
? PaginatedResponse<QueueItem>
: NonPaginatedResponse<QueueItem>
>;

/**
* Inserts a new item into this queue.
*
* The payload must be flat — nested objects and arrays are rejected.
*
* @param specificData - The item's business payload (keys are stored exactly as provided)
* @param options Optional item metadata (priority, reference, defer/due dates)
* @returns Promise resolving to the created {@link QueueItem}
*/
insertItem(
specificData: Record<string, QueueItemValue>,
options?: QueueInsertItemOptions
): Promise<QueueItem>;
}

/**
* Creates queue methods bound to a specific queue's data
* @param queueData - The queue data
* @param service - The queue service instance
* @returns Object containing queue methods
*/
function createQueueMethods(queueData: RawQueueGetResponse, service: QueueServiceModel): QueueMethods {
return {
async getAllItems<T extends QueueGetAllItemsOptions = QueueGetAllItemsOptions>(options?: T): Promise<
T extends HasPaginationOptions<T>
? PaginatedResponse<QueueItem>
: NonPaginatedResponse<QueueItem>
> {
if (queueData.id === undefined) throw new Error('Queue ID is undefined');
if (queueData.folderId === undefined) throw new Error('Folder ID is undefined');
return service.getAllItems(queueData.id, queueData.folderId, options);
},

async insertItem(specificData: Record<string, QueueItemValue>, options?: QueueInsertItemOptions): Promise<QueueItem> {
if (!queueData.name) throw new Error('Queue name is undefined');
if (queueData.folderId === undefined) throw new Error('Folder ID is undefined');
return service.insertItemByName(queueData.name, queueData.folderId, specificData, options);
}
};
}

/**
* Creates a queue object with methods attached
* @param queueData - The queue data
* @param service - The queue service instance
* @returns Queue data with bound methods
*/
export function createQueueWithMethods(queueData: RawQueueGetResponse, service: QueueServiceModel): QueueGetResponse {
return Object.assign({}, queueData, createQueueMethods(queueData, service));
}
Loading
Loading