Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
899502d
feat(data-fabric): add folderKey support to entities.getAll and Choic…
AditiGoyalUipath Jun 10, 2026
dd49734
fix: address review comments — JSDoc sync, single afterAll, folderKey…
AditiGoyalUipath Jun 10, 2026
1c01d28
feat(data-fabric): cross-folder reference support + folder-scoped int…
AditiGoyalUipath Jun 11, 2026
831553f
revert: roll tests/.env.integration.example back to template
AditiGoyalUipath Jun 11, 2026
fc04d3e
ci: add DATA_FABRIC_TEST_FOLDER_ENTITY_ID to integration test config
Sarath1018 Jun 11, 2026
e6ee264
refactor(data-fabric): extract ChoiceSet entityType/Id to module-leve…
AditiGoyalUipath Jun 11, 2026
a3f83ae
feat(data-fabric): add includeAllFolders option to entities.getAll (#…
amrit-agarwal-1 Jun 11, 2026
321987e
refactor(data-fabric): rename includeAllFolders to includeAllScopes o…
AditiGoyalUipath Jun 11, 2026
19093c2
docs(data-fabric): inline tenant folder UUID literal in referenceFold…
AditiGoyalUipath Jun 11, 2026
5e605fb
feat(data-fabric): add includeFolderChoiceSets opt-in + address Sarat…
AditiGoyalUipath Jun 12, 2026
2f13c3a
refactor(data-fabric): rename entities.getAll option includeAllScopes…
AditiGoyalUipath Jun 12, 2026
c92063a
test(data-fabric): skip includeFolderEntities CI test that requires O…
AditiGoyalUipath Jun 12, 2026
2c33c16
test(data-fabric): re-enable includeFolderEntities integration test
AditiGoyalUipath Jun 12, 2026
f5b277e
fix(data-fabric): address SonarCloud issues on PR #504
AditiGoyalUipath Jun 12, 2026
1e6f6ab
docs(data-fabric): mark folder scope as experimental across Entities
AditiGoyalUipath Jun 15, 2026
bdf6e98
docs(data-fabric): clarify choicesets.getAll JSDoc per PR review
AditiGoyalUipath Jun 15, 2026
9e77c91
docs(data-fabric): apply same JSDoc clarifications to entities.getAll
AditiGoyalUipath Jun 15, 2026
4ca6879
docs(data-fabric): add @experimental tag to folderKey-bearing methods
AditiGoyalUipath Jun 15, 2026
c6aa0d5
docs(data-fabric): drop OR.Users OAuth scope mentions from JSDoc
AditiGoyalUipath Jun 15, 2026
1bffc19
docs(data-fabric): scope experimental marker to folderKey argument only
AditiGoyalUipath Jun 15, 2026
5aba6cc
docs(data-fabric): drop OR.Users folder-scope blockquotes from oauth-…
AditiGoyalUipath Jun 15, 2026
ef5bf97
docs(data-fabric): address PR review comments
AditiGoyalUipath Jun 15, 2026
bae2fba
chore(data-fabric): tighten ReferenceEntityPayload.entityType + scrub…
AditiGoyalUipath Jun 15, 2026
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/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ jobs:
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
echo "data_fabric_test_folder_entity_id=${{ secrets.UIPATH_DATA_FABRIC_TEST_FOLDER_ENTITY_ID_DEV || secrets.UIPATH_DATA_FABRIC_TEST_FOLDER_ENTITY_ID }}" >> $GITHUB_OUTPUT
echo "orchestrator_attachment_id=${{ secrets.UIPATH_ORCHESTRATOR_ATTACHMENT_ID_DEV || secrets.UIPATH_ORCHESTRATOR_ATTACHMENT_ID }}" >> $GITHUB_OUTPUT
echo "jobs_test_folder_id=${{ secrets.UIPATH_JOBS_TEST_FOLDER_ID_DEV || secrets.UIPATH_JOBS_TEST_FOLDER_ID }}" >> $GITHUB_OUTPUT
echo "traces_test_trace_id=${{ secrets.UIPATH_TRACES_TEST_TRACE_ID_DEV || secrets.UIPATH_TRACES_TEST_TRACE_ID }}" >> $GITHUB_OUTPUT
Expand All @@ -88,6 +89,7 @@ jobs:
DATA_FABRIC_TEST_ENTITY_ID=${{ steps.config.outputs.data_fabric_test_entity_id }}
DATA_FABRIC_TEST_CHOICESET_ID=${{ steps.config.outputs.data_fabric_test_choiceset_id }}
DATA_FABRIC_TEST_ATTACHMENT_FIELD=${{ steps.config.outputs.data_fabric_test_attachment_field }}
DATA_FABRIC_TEST_FOLDER_ENTITY_ID=${{ steps.config.outputs.data_fabric_test_folder_entity_id }}
ORCHESTRATOR_TEST_PROCESS_KEY=${{ steps.config.outputs.orchestrator_test_process_key }}
ORCHESTRATOR_ATTACHMENT_ID=${{ steps.config.outputs.orchestrator_attachment_id }}
JOBS_TEST_FOLDER_ID=${{ steps.config.outputs.jobs_test_folder_id }}
Expand Down
75 changes: 51 additions & 24 deletions src/models/data-fabric/choicesets.models.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import {
ChoiceSetGetAllOptions,
ChoiceSetGetAllResponse,
ChoiceSetGetResponse,
ChoiceSetGetByIdOptions,
ChoiceSetCreateOptions,
ChoiceSetUpdateOptions,
ChoiceSetDeleteByIdOptions,
ChoiceSetValueInsertOptions,
ChoiceSetValueInsertResponse,
ChoiceSetValueUpdateResponse
ChoiceSetValueUpdateOptions,
ChoiceSetValueUpdateResponse,
ChoiceSetValueDeleteOptions,
} from './choicesets.types';
import { PaginatedResponse, NonPaginatedResponse, HasPaginationOptions } from '../../utils/pagination/types';

Expand All @@ -28,33 +32,32 @@ import { PaginatedResponse, NonPaginatedResponse, HasPaginationOptions } from '.
*/
export interface ChoiceSetServiceModel {
/**
* Gets all choice sets in the org
* Gets choice sets in the tenant.
*
* Three call modes:
* - `getAll()` — default. Returns only tenant-level choice sets.
* - `getAll({ folderKey: "<uuid>" })` — preferred for folder-scoped data. Returns only choice sets in that folder.
* - `getAll({ includeFolderChoiceSets: true })` — returns tenant-level **and** folder-level choice sets together. `folderKey` is preferred over `includeFolderChoiceSets` when both are set.
*
* @param options - Optional {@link ChoiceSetGetAllOptions} (`folderKey` to list a single folder's choice sets — preferred when scoping to a folder; `includeFolderChoiceSets: true` to list tenant + folder choice sets together) The `folderKey` property is **experimental**.
* @returns Promise resolving to an array of choice set metadata
* {@link ChoiceSetGetAllResponse}
* @example
* ```typescript
* // Get all choice sets
* const allChoiceSets = await choicesets.getAll();
* // Tenant-only (default)
* const tenantChoiceSets = await choicesets.getAll();
*
* // Iterate through choice sets
* allChoiceSets.forEach(choiceSet => {
* console.log(`ChoiceSet: ${choiceSet.displayName} (${choiceSet.name})`);
* console.log(`Description: ${choiceSet.description}`);
* console.log(`Created by: ${choiceSet.createdBy}`);
* });
* // A single folder's choice sets (preferred when targeting a specific folder)
* const folderChoiceSets = await choicesets.getAll({ folderKey: "<folderKey>" });
*
* // Find a specific choice set by name
* const expenseTypes = allChoiceSets.find(cs => cs.name === 'ExpenseTypes');
* // Tenant + folder choice sets together
* const allChoiceSets = await choicesets.getAll({ includeFolderChoiceSets: true });
*
* // Check choice set details
* if (expenseTypes) {
* console.log(`Last updated: ${expenseTypes.updatedTime}`);
* console.log(`Updated by: ${expenseTypes.updatedBy}`);
* }
* // Find a specific choice set by name
* const expenseTypes = tenantChoiceSets.find(cs => cs.name === 'ExpenseTypes');
* ```
*/
getAll(): Promise<ChoiceSetGetAllResponse[]>;
getAll(options?: ChoiceSetGetAllOptions): Promise<ChoiceSetGetAllResponse[]>;

/**
* Gets choice set values by choice set ID with optional pagination
Expand All @@ -64,7 +67,7 @@ export interface ChoiceSetServiceModel {
* - A PaginatedResponse with navigation cursors (when any pagination parameter is provided)
*
* @param choiceSetId - UUID of the choice set
* @param options - Pagination options
* @param options - Pagination options and optional `folderKey` (omit for tenant-level choice sets) The `folderKey` property is **experimental**.
* @returns Promise resolving to choice set values or paginated result
* {@link ChoiceSetGetResponse}
* @example
Expand All @@ -89,6 +92,9 @@ export interface ChoiceSetServiceModel {
* if (page1.hasNextPage) {
* const page2 = await choicesets.getById(choiceSetId, { cursor: page1.nextCursor });
* }
*
* // Folder-scoped choice set
* const folderValues = await choicesets.getById(choiceSetId, { folderKey: "<folderKey>" });
* ```
*/
getById<T extends ChoiceSetGetByIdOptions = ChoiceSetGetByIdOptions>(
Expand All @@ -106,7 +112,7 @@ export interface ChoiceSetServiceModel {
* @param name - Choice set name. Must start with a
* letter, may contain only letters, numbers, and underscores, length
* 3–100 characters (e.g., `"expenseTypes"`).
* @param options - Optional choice-set-level settings ({@link ChoiceSetCreateOptions})
* @param options - Optional choice-set-level settings ({@link ChoiceSetCreateOptions}) The `folderKey` property is **experimental**.
* @returns Promise resolving to the UUID of the created choice set
*
* @example
Expand All @@ -131,7 +137,7 @@ export interface ChoiceSetServiceModel {
* the call throws `ValidationError` if both are omitted.
*
* @param choiceSetId - UUID of the choice set to update
* @param options - Metadata fields to change ({@link ChoiceSetUpdateOptions})
* @param options - Metadata fields to change ({@link ChoiceSetUpdateOptions}) The `folderKey` property is **experimental**.
* @returns Promise resolving when the update is complete
*
* @example
Expand All @@ -153,6 +159,7 @@ export interface ChoiceSetServiceModel {
* Deletes a Data Fabric choice set and all its values.
*
* @param choiceSetId - UUID of the choice set to delete
* @param options - Optional {@link ChoiceSetDeleteByIdOptions} — pass `folderKey` for folder-scoped choice sets; omit for tenant-level The `folderKey` property is **experimental**.
* @returns Promise resolving when the choice set is deleted
*
* @example
Expand All @@ -162,17 +169,20 @@ export interface ChoiceSetServiceModel {
* const expenseTypes = allChoiceSets.find(cs => cs.name === 'expense_types');
*
* await choicesets.deleteById(expenseTypes.id);
*
* // Folder-scoped choice set
* await choicesets.deleteById(expenseTypes.id, { folderKey: "<folderKey>" });
* ```
* @internal
*/
deleteById(choiceSetId: string): Promise<void>;
deleteById(choiceSetId: string, options?: ChoiceSetDeleteByIdOptions): Promise<void>;

/**
* Inserts a single value into a choice set.
*
* @param choiceSetId - UUID of the parent choice set
* @param name - Identifier name of the new value (e.g., `"TRAVEL"`)
* @param options - Optional fields ({@link ChoiceSetValueInsertOptions})
* @param options - Optional fields ({@link ChoiceSetValueInsertOptions}) The `folderKey` property is **experimental**.
* @returns Promise resolving to the inserted value ({@link ChoiceSetValueInsertResponse})
*
* @example
Expand All @@ -185,6 +195,12 @@ export interface ChoiceSetServiceModel {
* displayName: 'Travel',
* });
* console.log(inserted.id);
*
* // Folder-scoped choice set: folderKey is required on the wire
* await choicesets.insertValueById(expenseTypes.id, 'TRAVEL', {
* displayName: 'Travel',
* folderKey: "<folderKey>",
* });
* ```
* @internal
*/
Expand All @@ -203,6 +219,7 @@ export interface ChoiceSetServiceModel {
* @param choiceSetId - UUID of the parent choice set
* @param valueId - UUID of the value to update
* @param displayName - New human-readable display name for the value
* @param options - Optional {@link ChoiceSetValueUpdateOptions} — pass `folderKey` for folder-scoped choice sets; omit for tenant-level. The `folderKey` property is **experimental**.
* @returns Promise resolving to the updated value ({@link ChoiceSetValueUpdateResponse})
*
* @example
Expand All @@ -214,20 +231,27 @@ export interface ChoiceSetServiceModel {
* const travel = values.items.find(v => v.name === 'TRAVEL');
*
* await choicesets.updateValueById(expenseTypes.id, travel.id, 'Business Travel');
*
* // Folder-scoped choice set: folderKey is required on the wire
* await choicesets.updateValueById(expenseTypes.id, travel.id, 'Business Travel', {
* folderKey: "<folderKey>",
* });
* ```
* @internal
*/
updateValueById(
choiceSetId: string,
valueId: string,
displayName: string,
options?: ChoiceSetValueUpdateOptions,
): Promise<ChoiceSetValueUpdateResponse>;

/**
* Deletes one or more values from a choice set.
*
* @param choiceSetId - UUID of the parent choice set
* @param valueIds - Array of value UUIDs to delete
* @param options - Optional {@link ChoiceSetValueDeleteOptions} — pass `folderKey` for folder-scoped choice sets; omit for tenant-level The `folderKey` property is **experimental**.
* @returns Promise resolving when the values are deleted
*
* @example
Expand All @@ -237,9 +261,12 @@ export interface ChoiceSetServiceModel {
* const idsToDelete = values.items.slice(0, 2).map(v => v.id);
*
* await choicesets.deleteValuesById('<choiceSetId>', idsToDelete);
*
* // Folder-scoped choice set
* await choicesets.deleteValuesById('<choiceSetId>', idsToDelete, { folderKey: "<folderKey>" });
* ```
* @internal
*/
deleteValuesById(choiceSetId: string, valueIds: string[]): Promise<void>;
deleteValuesById(choiceSetId: string, valueIds: string[], options?: ChoiceSetValueDeleteOptions): Promise<void>;
}

28 changes: 22 additions & 6 deletions src/models/data-fabric/choicesets.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PaginationOptions } from '../../utils/pagination/types';
import { EntityFolderScopedOptions } from './data-fabric.types';

/**
* ChoiceSet Get All Response
Expand Down Expand Up @@ -49,44 +50,59 @@ export interface ChoiceSetGetResponse {
recordOwner?: string;
}

export interface ChoiceSetGetAllOptions extends EntityFolderScopedOptions {
/**
* When `true`, also returns folder-level choice sets alongside tenant ones.
* Omit (or `false`, the default) to return only tenant-level choice sets.
* Ignored when `folderKey` is provided — `folderKey` is preferred over `includeFolderChoiceSets` when both are set.
*
* @experimental Folder-scoped Data Fabric is in preview — the contract may change.
*/
includeFolderChoiceSets?: boolean;
Comment thread
vnaren23 marked this conversation as resolved.
}

/**
* Options for getting choice set values by choice set ID
*/
export type ChoiceSetGetByIdOptions = PaginationOptions;
export type ChoiceSetGetByIdOptions = PaginationOptions & EntityFolderScopedOptions;

/**
* Options for creating a new choice set
*/
export interface ChoiceSetCreateOptions {
export interface ChoiceSetCreateOptions extends EntityFolderScopedOptions {
/** Human-readable display name */
displayName?: string;
/** Optional choice set description */
description?: string;
/** UUID of the folder to place the choice set in (defaults to the tenant-level folder) */
folderKey?: string;
}

/**
* Options for updating an existing choice set's metadata
*/
export interface ChoiceSetUpdateOptions {
export interface ChoiceSetUpdateOptions extends EntityFolderScopedOptions {
/** New display name for the choice set */
displayName?: string;
/** New description for the choice set */
description?: string;
}

export interface ChoiceSetDeleteByIdOptions extends EntityFolderScopedOptions {}

/**
* Optional fields when inserting a single value into a choice set.
*
* The required `name` identifier is passed as a positional argument to
* `insertValueById`.
*/
export interface ChoiceSetValueInsertOptions {
export interface ChoiceSetValueInsertOptions extends EntityFolderScopedOptions {
/** Human-readable display name */
displayName?: string;
}

export interface ChoiceSetValueUpdateOptions extends EntityFolderScopedOptions {}

export interface ChoiceSetValueDeleteOptions extends EntityFolderScopedOptions {}

/**
* Response returned after inserting a choice-set value — the full value object.
*/
Expand Down
18 changes: 18 additions & 0 deletions src/models/data-fabric/data-fabric.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Shared types for the Data Fabric domain — used by both Entities and ChoiceSets.
* Lives here (not in either service's `*.types.ts`) to avoid cross-domain coupling
* between sibling services.
*/

/**
* Common shape for every folder-scoped Data Fabric operation.
* Forwarded on the wire as the `X-UIPATH-FolderKey` header.
*/
export interface EntityFolderScopedOptions {
/**
* Key identifying the folder the entity belongs to. Omit for tenant-level entities.
*
* @experimental Folder-scoped Data Fabric is in preview — the contract may change.
*/
folderKey?: string;
}
11 changes: 10 additions & 1 deletion src/models/data-fabric/entities.constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EntityFieldDataType, FieldDisplayType } from "./entities.types";
import { EntityFieldDataType, EntityType, FieldDisplayType } from "./entities.types";
import {
EntitySchemaFieldMapping,
SqlFieldType,
Expand All @@ -7,6 +7,15 @@ import {
} from "./entities.internal-types";
export { SqlFieldType } from "./entities.internal-types";

/**
* Numeric type IDs that pair with {@link EntityType} on reference payloads
* (entityType + entityTypeId travel together in `referenceEntity` /
* `referenceChoiceSet` bodies on cross-folder schema upserts).
*/
export const ENTITY_TYPE_IDS = {
[EntityType.ChoiceSet]: 1,
} as const;

/**
* Maps fields for Entities
*/
Expand Down
19 changes: 17 additions & 2 deletions src/models/data-fabric/entities.internal-types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FieldDisplayType, EntityRecord, ReferenceType, SqlType } from './entities.types';
import { EntityType, FieldDisplayType, EntityRecord, ReferenceType, SqlType } from './entities.types';

/**
* Write-side payload shape for creating a new field in a schema upsert call.
Expand All @@ -20,10 +20,25 @@ export interface FieldSchemaPayload {
defaultValue?: string;
choiceSetId?: string;
referenceType?: ReferenceType;
referenceEntity?: { id: string };
referenceEntity?: ReferenceEntityPayload;
referenceChoiceSet?: ReferenceEntityPayload;
referenceField?: { id: string };
}

/** Body embedded in `referenceEntity` / `referenceChoiceSet` on cross-folder field payloads. */
export interface ReferenceEntityPayload {
id: string;
name?: string;
folderId?: string;
entityType?: EntityType;
entityTypeId?: number;
}

export interface ResolvedReferenceMeta {
referenceEntity?: ReferenceEntityPayload;
referenceChoiceSet?: ReferenceEntityPayload;
}

/**
* Shape of each entry in EntitySchemaFieldTypeMap — internal only.
*/
Expand Down
Loading
Loading