@uipath/maestro-builder-sdk 6.31.8 → 6.31.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-index.md +75 -73
- package/dist/api-members.md +251 -245
- package/dist/check.js +11 -1
- package/dist/core/actions.d.ts +50 -4
- package/dist/core/form-field-type.d.ts +80 -14
- package/dist/core/form-field-type.js +132 -28
- package/dist/decompile.js +7 -1
- package/dist/nodes/hitl/flow/check.js +7 -1
- package/dist/nodes/hitl/flow/node-type.js +13 -1
- package/dist/serialize.js +12 -7
- package/package.json +2 -2
package/dist/check.js
CHANGED
|
@@ -10,7 +10,7 @@ import { FlowNode } from './core/node-classes.js';
|
|
|
10
10
|
import { planContributionBindings } from './core/contribution-bindings.js';
|
|
11
11
|
import { definitionHasErrorPort, errorPortRefusal } from './core/error-port.js';
|
|
12
12
|
import { actionVersion, bundledActionNodeType, bundledContainerDefinition, bundledDefinition, perCallDefinition, resolveContributionDefinition } from './serialize.js';
|
|
13
|
-
import { FORM_FIELD_TYPES, formFieldTypeHint, formFieldTypeWhy, validFormFieldTypesText } from './core/form-field-type.js';
|
|
13
|
+
import { FORM_FIELD_TYPES, formFieldOptionsProblem, formFieldOptionsWhy, formFieldTypeHint, formFieldTypeWhy, validFormFieldTypesText } from './core/form-field-type.js';
|
|
14
14
|
import { AGENTIC_PROCESS_FORMS } from './core/agentic-process-forms.js';
|
|
15
15
|
import { checkEventResolution, checkEventSubscription, eventParamsFor, } from './core/event-checks.js';
|
|
16
16
|
import { checkCookedEscapes } from './flow-expr-check.js';
|
|
@@ -3418,6 +3418,16 @@ function checkInlineAgent(step, inputs, diags, opts = {}) {
|
|
|
3418
3418
|
+ `${JSON.stringify(f?.type)}, ${formFieldTypeWhy(f?.type, `which the form does not recognize — it would `
|
|
3419
3419
|
+ `be published as a plain string`)}. Valid: ${validFormFieldTypesText()}.`, formFieldTypeHint(f?.type));
|
|
3420
3420
|
}
|
|
3421
|
+
const optionsProblem = formFieldOptionsProblem(f?.type, f?.options);
|
|
3422
|
+
if (optionsProblem !== undefined) {
|
|
3423
|
+
const message = `Inline agent step "${step}"'s quick-form escalation field "${String(f?.id ?? '?')}" `
|
|
3424
|
+
+ `${formFieldOptionsWhy(optionsProblem, f?.type)}.`;
|
|
3425
|
+
if (optionsProblem === 'ignored')
|
|
3426
|
+
warn('INLINE_AGENT_ESCALATION_FIELD_OPTIONS_IGNORED', message);
|
|
3427
|
+
else {
|
|
3428
|
+
at('INLINE_AGENT_ESCALATION_FIELD_OPTIONS', message, `options: [{ id: 'opt-1', value: 'high', label: 'High' }, { id: 'opt-2', value: 'low', label: 'Low' }]`);
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3421
3431
|
}
|
|
3422
3432
|
continue;
|
|
3423
3433
|
}
|
package/dist/core/actions.d.ts
CHANGED
|
@@ -62,15 +62,46 @@ export interface ConnectorOpts {
|
|
|
62
62
|
*/
|
|
63
63
|
export type CanonicalFormFieldType = 'string' | 'number' | 'integer' | 'float' | 'double' | 'boolean' | 'date' | 'datetime' | 'file' | 'object' | 'array';
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
65
|
+
* The platform's choice-control spellings of a field type. Each names the data
|
|
66
|
+
* the field holds AND how it renders (`@uipath/hitl-schema-types`
|
|
67
|
+
* `resolveFieldType` + `controlForDeclaredType`): `singleSelect` is a `string`
|
|
68
|
+
* shown as a dropdown, `multiSelect` an `array` shown as a multi-select, and
|
|
69
|
+
* `enum` (what the designer's variable picker writes for a closed set) a
|
|
70
|
+
* `string` shown as a dropdown. The choices are the field's `options`.
|
|
71
|
+
*/
|
|
72
|
+
export type ControlFormFieldType = 'singleSelect' | 'multiSelect' | 'enum';
|
|
73
|
+
/**
|
|
74
|
+
* A form field's type: one of the platform's canonical types; `'text'` /
|
|
66
75
|
* `'date-time'`, the SDK's older spellings of `'string'` / `'datetime'` (the
|
|
67
|
-
* platform resolves both)
|
|
68
|
-
*
|
|
76
|
+
* platform resolves both); or a choice-control spelling (`'singleSelect'`,
|
|
77
|
+
* `'multiSelect'`, `'enum'`), which the form renders as a picker over the
|
|
78
|
+
* field's `options`. A quick form with any other type fails the platform's
|
|
79
|
+
* validation, which is why `check` rejects it.
|
|
69
80
|
*
|
|
70
81
|
* @example
|
|
71
82
|
* hitl({ fields: [{ id: 'dueOn', type: 'date', direction: 'output' }], outcomes: ['Done'] })
|
|
83
|
+
* hitl({
|
|
84
|
+
* fields: [{
|
|
85
|
+
* id: 'priority', type: 'singleSelect', direction: 'output',
|
|
86
|
+
* options: [{ id: 'opt-1', value: 'high', label: 'High' }, { id: 'opt-2', value: 'low', label: 'Low' }],
|
|
87
|
+
* }],
|
|
88
|
+
* outcomes: ['Done'],
|
|
89
|
+
* })
|
|
90
|
+
*/
|
|
91
|
+
export type FormFieldType = CanonicalFormFieldType | 'text' | 'date-time' | ControlFormFieldType;
|
|
92
|
+
/**
|
|
93
|
+
* One choice of a picker field (`@uipath/hitl-schema-types` `optionShape`):
|
|
94
|
+
* `value` is what the answer holds, `label` what the reviewer sees, and `id`
|
|
95
|
+
* the option's own stable id. All three are required by the platform.
|
|
72
96
|
*/
|
|
73
|
-
export
|
|
97
|
+
export interface FormFieldOption {
|
|
98
|
+
/** The option's own stable id, e.g. `'opt-1'`. */
|
|
99
|
+
id: string;
|
|
100
|
+
/** What the answer holds when the reviewer picks it, e.g. `'high'`. */
|
|
101
|
+
value: string;
|
|
102
|
+
/** What the reviewer sees, e.g. `'High'`. */
|
|
103
|
+
label: string;
|
|
104
|
+
}
|
|
74
105
|
/** A value the reviewer READS: shown on the form, filled in from the flow. */
|
|
75
106
|
export interface ShownField {
|
|
76
107
|
/** Field id — the key the answer object uses. Must be unique on the form. */
|
|
@@ -79,6 +110,11 @@ export interface ShownField {
|
|
|
79
110
|
label?: string;
|
|
80
111
|
type: FormFieldType;
|
|
81
112
|
direction: 'input';
|
|
113
|
+
/**
|
|
114
|
+
* The choices of a picker field — a `singleSelect` / `enum` dropdown or a
|
|
115
|
+
* `multiSelect`. Written to the form verbatim, in order.
|
|
116
|
+
*/
|
|
117
|
+
options?: FormFieldOption[];
|
|
82
118
|
/**
|
|
83
119
|
* What to show — a reference, e.g. `input('amount')` or
|
|
84
120
|
* `out('fetchInvoice', 'body.total')`. Required: a shown field with nothing
|
|
@@ -95,6 +131,11 @@ export interface AskedField {
|
|
|
95
131
|
label?: string;
|
|
96
132
|
type: FormFieldType;
|
|
97
133
|
direction: 'output';
|
|
134
|
+
/**
|
|
135
|
+
* The choices of a picker field — a `singleSelect` / `enum` dropdown or a
|
|
136
|
+
* `multiSelect`. Written to the form verbatim, in order.
|
|
137
|
+
*/
|
|
138
|
+
options?: FormFieldOption[];
|
|
98
139
|
/** Reviewer must fill it in before the task can be completed. */
|
|
99
140
|
required?: boolean;
|
|
100
141
|
}
|
|
@@ -111,6 +152,11 @@ export interface InOutField {
|
|
|
111
152
|
label?: string;
|
|
112
153
|
type: FormFieldType;
|
|
113
154
|
direction: 'inOut';
|
|
155
|
+
/**
|
|
156
|
+
* The choices of a picker field — a `singleSelect` / `enum` dropdown or a
|
|
157
|
+
* `multiSelect`. Written to the form verbatim, in order.
|
|
158
|
+
*/
|
|
159
|
+
options?: FormFieldOption[];
|
|
114
160
|
/** What to pre-fill — a reference, e.g. `out('fetchInvoice', 'body.total')`. */
|
|
115
161
|
value: Expr;
|
|
116
162
|
/** Reviewer must confirm/fill it before the task can be completed. */
|
|
@@ -14,35 +14,59 @@
|
|
|
14
14
|
* on it at runtime. This module is a transcription, and
|
|
15
15
|
* `tests/hitl-field-type-contract.test.ts` runs the real package against it:
|
|
16
16
|
* the canonical set, each type's JSON Schema, and every alias below must agree
|
|
17
|
-
* with the pinned `@uipath/hitl-schema-types`. A canonical-set
|
|
18
|
-
* change upstream fails there; a new alias does not.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* with the pinned `@uipath/hitl-schema-types`. A canonical-set, JSON Schema or
|
|
18
|
+
* control-spelling change upstream fails there; a new data alias does not.
|
|
19
|
+
*
|
|
20
|
+
* Besides data types, the product accepts three CHOICE-CONTROL spellings —
|
|
21
|
+
* `singleSelect`, `multiSelect`, `enum` — which name both the data the field
|
|
22
|
+
* holds and the control it renders with (#1235). The SDK accepts them in
|
|
23
|
+
* source and writes them as written, so a canvas dropdown stays a dropdown.
|
|
21
24
|
*
|
|
22
25
|
* Every SDK path reads field types from here: `check` (human tasks and inline
|
|
23
26
|
* agent quick-form escalations), decompile, and the serializers' output
|
|
24
27
|
* schemas.
|
|
25
28
|
*/
|
|
26
|
-
import type { CanonicalFormFieldType } from './actions.js';
|
|
29
|
+
import type { CanonicalFormFieldType, ControlFormFieldType, FormFieldOption } from './actions.js';
|
|
27
30
|
/** The product's 11 canonical quick-form field types, in its own order. */
|
|
28
31
|
export declare const CANONICAL_FORM_FIELD_TYPES: CanonicalFormFieldType[];
|
|
29
32
|
/** The SDK's legacy spellings (`text`, `date-time`), for diagnostics that list them. */
|
|
30
33
|
export declare const LEGACY_FORM_FIELD_TYPES: string[];
|
|
31
|
-
/**
|
|
34
|
+
/** The choice-control spellings, for `check`'s messages and the contract test. */
|
|
35
|
+
export declare const CONTROL_FORM_FIELD_TYPES: ControlFormFieldType[];
|
|
36
|
+
/**
|
|
37
|
+
* Every form-field type the SDK accepts in source: the 11 canonical ones, the
|
|
38
|
+
* SDK's legacy aliases, and the three choice-control spellings.
|
|
39
|
+
*/
|
|
32
40
|
export declare const FORM_FIELD_TYPES: string[];
|
|
33
41
|
/**
|
|
34
42
|
* The tail of a "Valid: …" diagnostic: the canonical types, then the legacy
|
|
35
|
-
* spellings in parentheses.
|
|
43
|
+
* spellings and the choice controls in parentheses.
|
|
36
44
|
*
|
|
37
45
|
* @example
|
|
38
|
-
* validFormFieldTypesText() // 'string,
|
|
46
|
+
* validFormFieldTypesText() // 'string, …, array (or the older text, date-time; or a choice control: singleSelect, …)'
|
|
39
47
|
*/
|
|
40
48
|
export declare function validFormFieldTypesText(): string;
|
|
49
|
+
/**
|
|
50
|
+
* The data type and control a choice-control spelling names, or `undefined`
|
|
51
|
+
* for any other type.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* controlFormFieldType('singleSelect') // { data: 'string', control: 'dropdown' }
|
|
55
|
+
* controlFormFieldType('multiSelect') // { data: 'array', control: 'multiSelect' }
|
|
56
|
+
* controlFormFieldType('string') // undefined
|
|
57
|
+
*/
|
|
58
|
+
export declare function controlFormFieldType(type: unknown): {
|
|
59
|
+
data: CanonicalFormFieldType;
|
|
60
|
+
control: string;
|
|
61
|
+
} | undefined;
|
|
41
62
|
/** The product aliases, for the contract test. */
|
|
42
63
|
export declare const FORM_FIELD_TYPE_ALIASES: Readonly<Record<string, CanonicalFormFieldType>>;
|
|
43
64
|
/**
|
|
44
65
|
* The canonical type a wire or source spelling names, or `undefined` when it
|
|
45
|
-
* names none the SDK models.
|
|
66
|
+
* names none the SDK models. A choice-control spelling is its own wire
|
|
67
|
+
* spelling, so it is `undefined` here too — its data type is
|
|
68
|
+
* `controlFormFieldType(t).data`; resolving it here would let a caller write
|
|
69
|
+
* `string` for a dropdown.
|
|
46
70
|
*
|
|
47
71
|
* @example
|
|
48
72
|
* canonicalFormFieldType('integer') // 'integer'
|
|
@@ -71,11 +95,9 @@ export declare function canonicalFormFieldType(type: unknown): CanonicalFormFiel
|
|
|
71
95
|
export declare function sourceFormFieldType(wire: unknown): string;
|
|
72
96
|
/**
|
|
73
97
|
* Why a form-field type is refused: a product alias the SDK does not accept in
|
|
74
|
-
* source (`"System.Int32"` is the platform's .NET name for `integer`), a
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* `unknownWhy` is the caller's reason for the last case; the default is a human
|
|
78
|
-
* task's.
|
|
98
|
+
* source (`"System.Int32"` is the platform's .NET name for `integer`), or a type
|
|
99
|
+
* the product does not recognize at all. `unknownWhy` is the caller's reason for
|
|
100
|
+
* the second case; the default is a human task's.
|
|
79
101
|
*/
|
|
80
102
|
export declare function formFieldTypeWhy(type: unknown, unknownWhy?: string): string;
|
|
81
103
|
/** The `suggestion` for an unknown form-field type: its canonical type, the nearest valid one, else `type: 'string'`. */
|
|
@@ -87,8 +109,52 @@ export declare function formFieldTypeHint(type: unknown): string;
|
|
|
87
109
|
* @example
|
|
88
110
|
* formFieldJsonSchema('date') // { type: 'string', format: 'date' }
|
|
89
111
|
* formFieldJsonSchema('text') // { type: 'string' }
|
|
112
|
+
* formFieldJsonSchema('multiSelect') // { type: 'array' }
|
|
90
113
|
*/
|
|
91
114
|
export declare function formFieldJsonSchema(type: unknown): {
|
|
92
115
|
type: string;
|
|
93
116
|
format?: string;
|
|
94
117
|
} | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* A picker field's choices as the form row carries them (`options`, each
|
|
120
|
+
* `{ id, value, label }` — the product's `optionShape`), copied so the wire
|
|
121
|
+
* never aliases the author's array. `undefined` when the field has none.
|
|
122
|
+
* Both serializers (human task, quick-form escalation) write through this.
|
|
123
|
+
*/
|
|
124
|
+
export declare function formFieldOptionsWire(options: readonly FormFieldOption[] | undefined): FormFieldOption[] | undefined;
|
|
125
|
+
/**
|
|
126
|
+
* A form row's `options` read back for source: the well-formed choices
|
|
127
|
+
* (string `id`, `value`, `label` — all three the product requires), or
|
|
128
|
+
* `undefined` when the row has no `options` array. A malformed entry is left
|
|
129
|
+
* out, not coerced: `{ id: 'o1', value: 1 }` is not rewritten to
|
|
130
|
+
* `value: '1', label: ''`. Decompile (human task and quick-form escalation)
|
|
131
|
+
* reads through this, so a canvas dropdown's choices survive an edit.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* liftFormFieldOptions([{ id: 'o1', value: 'a', label: 'A' }, { id: 'o2', value: 2 }])
|
|
135
|
+
* // [{ id: 'o1', value: 'a', label: 'A' }]
|
|
136
|
+
*/
|
|
137
|
+
export declare function liftFormFieldOptions(raw: unknown): FormFieldOption[] | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* What is wrong with a form field's `options`, or `undefined` when nothing is.
|
|
140
|
+
* `check` reports each (human task and quick-form escalation):
|
|
141
|
+
*
|
|
142
|
+
* - `'malformed'`: `options` is there but is not an array of `{ id, value,
|
|
143
|
+
* label }` strings. Serialize would throw or write rows the platform refuses.
|
|
144
|
+
* - `'missing'`: a choice-control type (`singleSelect`, `multiSelect`, `enum`)
|
|
145
|
+
* with no choices. The form publishes an empty picker.
|
|
146
|
+
* - `'ignored'`: choices on a type that is not a choice control. The form
|
|
147
|
+
* renders a plain input and never shows them.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* formFieldOptionsProblem('singleSelect', undefined) // 'missing'
|
|
151
|
+
* formFieldOptionsProblem('singleSelect', {}) // 'malformed'
|
|
152
|
+
* formFieldOptionsProblem('string', [{ id: 'o1', value: 'a', label: 'A' }]) // 'ignored'
|
|
153
|
+
* formFieldOptionsProblem('enum', [{ id: 'o1', value: 'a', label: 'A' }]) // undefined
|
|
154
|
+
*/
|
|
155
|
+
export declare function formFieldOptionsProblem(type: unknown, options: unknown): 'malformed' | 'missing' | 'ignored' | undefined;
|
|
156
|
+
/**
|
|
157
|
+
* The reason text for a `formFieldOptionsProblem`, worded for a diagnostic
|
|
158
|
+
* that starts "… the field "<id>" …".
|
|
159
|
+
*/
|
|
160
|
+
export declare function formFieldOptionsWhy(problem: 'malformed' | 'missing' | 'ignored', type: unknown): string;
|
|
@@ -32,17 +32,53 @@ const SDK_ALIASES = {
|
|
|
32
32
|
};
|
|
33
33
|
/** The SDK's legacy spellings (`text`, `date-time`), for diagnostics that list them. */
|
|
34
34
|
export const LEGACY_FORM_FIELD_TYPES = Object.keys(SDK_ALIASES);
|
|
35
|
-
/**
|
|
36
|
-
|
|
35
|
+
/**
|
|
36
|
+
* The product's choice-control spellings (#1235): the data type each holds
|
|
37
|
+
* (`resolveFieldType`) and the control the form renders it with
|
|
38
|
+
* (`controlForDeclaredType`, which sets the field's `controlType` when the row
|
|
39
|
+
* has none). The output schema is the data type's; the choices ride on the
|
|
40
|
+
* field's `options`, never in the schema.
|
|
41
|
+
*
|
|
42
|
+
* Kept as written on the wire — NOT resolved to the data type, which would
|
|
43
|
+
* drop the control: a `singleSelect` written as `string` renders as a text box.
|
|
44
|
+
*/
|
|
45
|
+
const CONTROL_TYPES = {
|
|
46
|
+
singleSelect: { data: 'string', control: 'dropdown' },
|
|
47
|
+
multiSelect: { data: 'array', control: 'multiSelect' },
|
|
48
|
+
enum: { data: 'string', control: 'dropdown' },
|
|
49
|
+
};
|
|
50
|
+
/** The choice-control spellings, for `check`'s messages and the contract test. */
|
|
51
|
+
export const CONTROL_FORM_FIELD_TYPES = Object.keys(CONTROL_TYPES);
|
|
52
|
+
/**
|
|
53
|
+
* Every form-field type the SDK accepts in source: the 11 canonical ones, the
|
|
54
|
+
* SDK's legacy aliases, and the three choice-control spellings.
|
|
55
|
+
*/
|
|
56
|
+
export const FORM_FIELD_TYPES = [
|
|
57
|
+
...CANONICAL_FORM_FIELD_TYPES, ...LEGACY_FORM_FIELD_TYPES, ...CONTROL_FORM_FIELD_TYPES,
|
|
58
|
+
];
|
|
37
59
|
/**
|
|
38
60
|
* The tail of a "Valid: …" diagnostic: the canonical types, then the legacy
|
|
39
|
-
* spellings in parentheses.
|
|
61
|
+
* spellings and the choice controls in parentheses.
|
|
40
62
|
*
|
|
41
63
|
* @example
|
|
42
|
-
* validFormFieldTypesText() // 'string,
|
|
64
|
+
* validFormFieldTypesText() // 'string, …, array (or the older text, date-time; or a choice control: singleSelect, …)'
|
|
43
65
|
*/
|
|
44
66
|
export function validFormFieldTypesText() {
|
|
45
|
-
return `${CANONICAL_FORM_FIELD_TYPES.join(', ')} (or the older ${LEGACY_FORM_FIELD_TYPES.join(', ')}
|
|
67
|
+
return `${CANONICAL_FORM_FIELD_TYPES.join(', ')} (or the older ${LEGACY_FORM_FIELD_TYPES.join(', ')}; `
|
|
68
|
+
+ `or a choice control: ${CONTROL_FORM_FIELD_TYPES.join(', ')})`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The data type and control a choice-control spelling names, or `undefined`
|
|
72
|
+
* for any other type.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* controlFormFieldType('singleSelect') // { data: 'string', control: 'dropdown' }
|
|
76
|
+
* controlFormFieldType('multiSelect') // { data: 'array', control: 'multiSelect' }
|
|
77
|
+
* controlFormFieldType('string') // undefined
|
|
78
|
+
*/
|
|
79
|
+
export function controlFormFieldType(type) {
|
|
80
|
+
const entry = typeof type === 'string' ? ownEntry(CONTROL_TYPES, type) : undefined;
|
|
81
|
+
return entry === undefined ? undefined : { ...entry };
|
|
46
82
|
}
|
|
47
83
|
/**
|
|
48
84
|
* The product's other data-type spellings, each with the canonical type it
|
|
@@ -53,10 +89,9 @@ export function validFormFieldTypesText() {
|
|
|
53
89
|
* resolve to `string`. `T[]` and `a | b` are matched by pattern in
|
|
54
90
|
* `canonicalFormFieldType`.
|
|
55
91
|
*
|
|
56
|
-
* Deliberately left out: the
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* renders. Decompile keeps them as written, and `check` reports them.
|
|
92
|
+
* Deliberately left out: the choice-control spellings (`singleSelect`,
|
|
93
|
+
* `multiSelect`, `enum` — `CONTROL_TYPES` above, kept as written because the
|
|
94
|
+
* product infers a `controlType` from them).
|
|
60
95
|
*/
|
|
61
96
|
const PRODUCT_ALIASES = {
|
|
62
97
|
...SDK_ALIASES,
|
|
@@ -104,18 +139,15 @@ const PRODUCT_ALIASES = {
|
|
|
104
139
|
ref: 'string',
|
|
105
140
|
any: 'string',
|
|
106
141
|
};
|
|
107
|
-
/**
|
|
108
|
-
* The product's control spellings: it accepts them as a field `type` and infers
|
|
109
|
-
* a picker control from them (`CONTROL_FOR_DECLARED_TYPE`). The SDK does not
|
|
110
|
-
* model them yet.
|
|
111
|
-
*/
|
|
112
|
-
const CONTROL_FORM_FIELD_TYPES = ['singleSelect', 'multiSelect', 'enum'];
|
|
113
142
|
/** The product aliases, for the contract test. */
|
|
114
143
|
export const FORM_FIELD_TYPE_ALIASES = PRODUCT_ALIASES;
|
|
115
144
|
const isCanonical = (t) => typeof t === 'string' && Object.hasOwn(CANONICAL_JSON_SCHEMA, t);
|
|
116
145
|
/**
|
|
117
146
|
* The canonical type a wire or source spelling names, or `undefined` when it
|
|
118
|
-
* names none the SDK models.
|
|
147
|
+
* names none the SDK models. A choice-control spelling is its own wire
|
|
148
|
+
* spelling, so it is `undefined` here too — its data type is
|
|
149
|
+
* `controlFormFieldType(t).data`; resolving it here would let a caller write
|
|
150
|
+
* `string` for a dropdown.
|
|
119
151
|
*
|
|
120
152
|
* @example
|
|
121
153
|
* canonicalFormFieldType('integer') // 'integer'
|
|
@@ -159,20 +191,15 @@ export function sourceFormFieldType(wire) {
|
|
|
159
191
|
}
|
|
160
192
|
/**
|
|
161
193
|
* Why a form-field type is refused: a product alias the SDK does not accept in
|
|
162
|
-
* source (`"System.Int32"` is the platform's .NET name for `integer`), a
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* `unknownWhy` is the caller's reason for the last case; the default is a human
|
|
166
|
-
* task's.
|
|
194
|
+
* source (`"System.Int32"` is the platform's .NET name for `integer`), or a type
|
|
195
|
+
* the product does not recognize at all. `unknownWhy` is the caller's reason for
|
|
196
|
+
* the second case; the default is a human task's.
|
|
167
197
|
*/
|
|
168
198
|
export function formFieldTypeWhy(type, unknownWhy = `which is not a quick-form field type: the platform rejects the form`) {
|
|
169
199
|
const canonical = canonicalFormFieldType(type);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return `which the platform accepts as a picker control but the SDK does not model yet`;
|
|
174
|
-
}
|
|
175
|
-
return unknownWhy;
|
|
200
|
+
return canonical !== undefined
|
|
201
|
+
? `which is the platform's alias of '${canonical}' — the SDK writes '${canonical}'`
|
|
202
|
+
: unknownWhy;
|
|
176
203
|
}
|
|
177
204
|
/** The `suggestion` for an unknown form-field type: its canonical type, the nearest valid one, else `type: 'string'`. */
|
|
178
205
|
export function formFieldTypeHint(type) {
|
|
@@ -189,9 +216,86 @@ export function formFieldTypeHint(type) {
|
|
|
189
216
|
* @example
|
|
190
217
|
* formFieldJsonSchema('date') // { type: 'string', format: 'date' }
|
|
191
218
|
* formFieldJsonSchema('text') // { type: 'string' }
|
|
219
|
+
* formFieldJsonSchema('multiSelect') // { type: 'array' }
|
|
192
220
|
*/
|
|
193
221
|
export function formFieldJsonSchema(type) {
|
|
194
|
-
const canonical = canonicalFormFieldType(type);
|
|
222
|
+
const canonical = canonicalFormFieldType(type) ?? controlFormFieldType(type)?.data;
|
|
195
223
|
const schema = canonical === undefined ? undefined : ownEntry(CANONICAL_JSON_SCHEMA, canonical);
|
|
196
224
|
return schema === undefined ? undefined : { ...schema };
|
|
197
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* A picker field's choices as the form row carries them (`options`, each
|
|
228
|
+
* `{ id, value, label }` — the product's `optionShape`), copied so the wire
|
|
229
|
+
* never aliases the author's array. `undefined` when the field has none.
|
|
230
|
+
* Both serializers (human task, quick-form escalation) write through this.
|
|
231
|
+
*/
|
|
232
|
+
export function formFieldOptionsWire(options) {
|
|
233
|
+
return options === undefined ? undefined : options.map((o) => ({ id: o.id, value: o.value, label: o.label }));
|
|
234
|
+
}
|
|
235
|
+
/** Whether a value is one well-formed choice: string `id`, `value` and `label`, all three the product requires. */
|
|
236
|
+
function isFormFieldOption(o) {
|
|
237
|
+
if (o === null || typeof o !== 'object')
|
|
238
|
+
return false;
|
|
239
|
+
const r = o;
|
|
240
|
+
return typeof r.id === 'string' && typeof r.value === 'string' && typeof r.label === 'string';
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* A form row's `options` read back for source: the well-formed choices
|
|
244
|
+
* (string `id`, `value`, `label` — all three the product requires), or
|
|
245
|
+
* `undefined` when the row has no `options` array. A malformed entry is left
|
|
246
|
+
* out, not coerced: `{ id: 'o1', value: 1 }` is not rewritten to
|
|
247
|
+
* `value: '1', label: ''`. Decompile (human task and quick-form escalation)
|
|
248
|
+
* reads through this, so a canvas dropdown's choices survive an edit.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* liftFormFieldOptions([{ id: 'o1', value: 'a', label: 'A' }, { id: 'o2', value: 2 }])
|
|
252
|
+
* // [{ id: 'o1', value: 'a', label: 'A' }]
|
|
253
|
+
*/
|
|
254
|
+
export function liftFormFieldOptions(raw) {
|
|
255
|
+
if (!Array.isArray(raw))
|
|
256
|
+
return undefined;
|
|
257
|
+
return raw.filter(isFormFieldOption).map((o) => ({ id: o.id, value: o.value, label: o.label }));
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* What is wrong with a form field's `options`, or `undefined` when nothing is.
|
|
261
|
+
* `check` reports each (human task and quick-form escalation):
|
|
262
|
+
*
|
|
263
|
+
* - `'malformed'`: `options` is there but is not an array of `{ id, value,
|
|
264
|
+
* label }` strings. Serialize would throw or write rows the platform refuses.
|
|
265
|
+
* - `'missing'`: a choice-control type (`singleSelect`, `multiSelect`, `enum`)
|
|
266
|
+
* with no choices. The form publishes an empty picker.
|
|
267
|
+
* - `'ignored'`: choices on a type that is not a choice control. The form
|
|
268
|
+
* renders a plain input and never shows them.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* formFieldOptionsProblem('singleSelect', undefined) // 'missing'
|
|
272
|
+
* formFieldOptionsProblem('singleSelect', {}) // 'malformed'
|
|
273
|
+
* formFieldOptionsProblem('string', [{ id: 'o1', value: 'a', label: 'A' }]) // 'ignored'
|
|
274
|
+
* formFieldOptionsProblem('enum', [{ id: 'o1', value: 'a', label: 'A' }]) // undefined
|
|
275
|
+
*/
|
|
276
|
+
export function formFieldOptionsProblem(type, options) {
|
|
277
|
+
if (options !== undefined && (!Array.isArray(options) || !options.every(isFormFieldOption)))
|
|
278
|
+
return 'malformed';
|
|
279
|
+
const isControl = controlFormFieldType(type) !== undefined;
|
|
280
|
+
if (isControl && (options === undefined || options.length === 0))
|
|
281
|
+
return 'missing';
|
|
282
|
+
if (!isControl && options !== undefined && options.length > 0)
|
|
283
|
+
return 'ignored';
|
|
284
|
+
return undefined;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The reason text for a `formFieldOptionsProblem`, worded for a diagnostic
|
|
288
|
+
* that starts "… the field "<id>" …".
|
|
289
|
+
*/
|
|
290
|
+
export function formFieldOptionsWhy(problem, type) {
|
|
291
|
+
switch (problem) {
|
|
292
|
+
case 'malformed':
|
|
293
|
+
return `has \`options\` that are not a list of { id, value, label } strings. Serialize cannot write them, `
|
|
294
|
+
+ `and the platform requires all three on every choice`;
|
|
295
|
+
case 'missing':
|
|
296
|
+
return `is a ${JSON.stringify(type)} picker with no \`options\`, so the form publishes an empty picker`;
|
|
297
|
+
case 'ignored':
|
|
298
|
+
return `has \`options\` but its type ${JSON.stringify(type)} is not a choice control, so the form renders a `
|
|
299
|
+
+ `plain input and never shows them. Use 'singleSelect' or 'enum' (a dropdown) or 'multiSelect'`;
|
|
300
|
+
}
|
|
301
|
+
}
|
package/dist/decompile.js
CHANGED
|
@@ -50,7 +50,7 @@ import { OUTCOME_HANDLE_NODE_TYPES } from './core/hitl-routing.js';
|
|
|
50
50
|
import { contributionPort, forwardFanOut } from './core/definition-handles.js';
|
|
51
51
|
import { STICKY_NOTE_TYPE } from './core/definitionless-node-types.js';
|
|
52
52
|
import { eventFilterFromTreeLeaf } from './core/event-filters.js';
|
|
53
|
-
import { sourceFormFieldType } from './core/form-field-type.js';
|
|
53
|
+
import { liftFormFieldOptions, sourceFormFieldType } from './core/form-field-type.js';
|
|
54
54
|
/**
|
|
55
55
|
* The trigger id of the flow currently being decompiled, so a reference through a
|
|
56
56
|
* RENAMED trigger is still recognized as `input('x')` rather than falling back to
|
|
@@ -1306,6 +1306,12 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1306
1306
|
['id', tsText(f.id)],
|
|
1307
1307
|
['type', tsLiteral(sourceFormFieldType(f.type ?? 'string'))],
|
|
1308
1308
|
['direction', tsLiteral(String(f.direction ?? 'output'))],
|
|
1309
|
+
['options', (() => {
|
|
1310
|
+
const options = liftFormFieldOptions(f.options);
|
|
1311
|
+
return options === undefined ? undefined : `[${options.map((o) => opts([
|
|
1312
|
+
['id', tsLiteral(o.id)], ['value', tsLiteral(o.value)], ['label', tsLiteral(o.label)],
|
|
1313
|
+
])).join(', ')}]`;
|
|
1314
|
+
})()],
|
|
1309
1315
|
])).join(', ')}]` : undefined],
|
|
1310
1316
|
['app', app === undefined ? undefined : opts([
|
|
1311
1317
|
['key', tsText(app.key)],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Expr } from '../../../core/expr.js';
|
|
2
2
|
import { nearestName } from '../../../core/edit-distance.js';
|
|
3
|
-
import { FORM_FIELD_TYPES, formFieldTypeHint, formFieldTypeWhy, validFormFieldTypesText } from '../../../core/form-field-type.js';
|
|
3
|
+
import { FORM_FIELD_TYPES, formFieldOptionsProblem, formFieldOptionsWhy, formFieldTypeHint, formFieldTypeWhy, validFormFieldTypesText } from '../../../core/form-field-type.js';
|
|
4
4
|
import { isAnswerField } from '../../../core/hitl-answers.js';
|
|
5
5
|
import { hitlDerivesOutcomeHandles, outcomeIdOf } from '../../../core/hitl-routing.js';
|
|
6
6
|
export const HITL_DIAGNOSTICS = {
|
|
@@ -23,6 +23,8 @@ export const HITL_DIAGNOSTICS = {
|
|
|
23
23
|
HITL_DUP_FIELD: { severity: 'error', summary: 'a form field id declared twice' },
|
|
24
24
|
HITL_FIELD_RESERVED_ID: { severity: 'error', summary: 'a form field id the result already uses' },
|
|
25
25
|
HITL_FIELD_TYPE_UNKNOWN: { severity: 'error', summary: 'a form field type the platform does not recognize' },
|
|
26
|
+
HITL_FIELD_OPTIONS: { severity: 'error', summary: 'a picker with no choices, or choices that are not { id, value, label } strings' },
|
|
27
|
+
HITL_FIELD_OPTIONS_IGNORED: { severity: 'warning', summary: 'choices on a field type that does not render them' },
|
|
26
28
|
HITL_FIELD_NO_VALUE: { severity: 'error', summary: 'a shown field with no value' },
|
|
27
29
|
HITL_FIELD_VALUE_NOT_REF: { severity: 'error', summary: 'a shown field filled from a literal' },
|
|
28
30
|
HITL_FIELD_VALUE_NOT_PATH: { severity: 'error', summary: 'a shown field filled from a computed expression' },
|
|
@@ -215,6 +217,10 @@ export function checkHitl(inputs, ctx) {
|
|
|
215
217
|
at('HITL_FIELD_TYPE_UNKNOWN', `Human task "${step}" gives the form field "${id}" the type ${JSON.stringify(f?.type)}, `
|
|
216
218
|
+ `${formFieldTypeWhy(f?.type)}. Valid: ${validFormFieldTypesText()}.`, formFieldTypeHint(f?.type));
|
|
217
219
|
}
|
|
220
|
+
const optionsProblem = formFieldOptionsProblem(f?.type, f.options);
|
|
221
|
+
if (optionsProblem !== undefined) {
|
|
222
|
+
at(optionsProblem === 'ignored' ? 'HITL_FIELD_OPTIONS_IGNORED' : 'HITL_FIELD_OPTIONS', `Human task "${step}"'s form field "${id}" ${formFieldOptionsWhy(optionsProblem, f?.type)}.`, `options: [{ id: 'opt-1', value: 'high', label: 'High' }, { id: 'opt-2', value: 'low', label: 'Low' }]`);
|
|
223
|
+
}
|
|
218
224
|
if (isAnswerField(f))
|
|
219
225
|
answers++; // an `output`, or an `inOut` whose reviewed value comes back
|
|
220
226
|
if (f?.direction === 'input' || f?.direction === 'inOut') {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* every edge out of an outcome-handle node to.
|
|
14
14
|
*/
|
|
15
15
|
import { Expr, toExpr } from '../../../core/expr.js';
|
|
16
|
-
import { formFieldJsonSchema, sourceFormFieldType } from '../../../core/form-field-type.js';
|
|
16
|
+
import { formFieldJsonSchema, formFieldOptionsWire, liftFormFieldOptions, sourceFormFieldType } from '../../../core/form-field-type.js';
|
|
17
17
|
import { isAnswerField } from '../../../core/hitl-answers.js';
|
|
18
18
|
import { OUTCOME_HANDLE_NODE_TYPES, hitlExitModel, outcomeIdOf, outcomeSlug } from '../../../core/hitl-routing.js';
|
|
19
19
|
import { jsonClone } from '../../../core/json-clone.js';
|
|
@@ -86,6 +86,11 @@ function hitlInputs(inputs, nodeType, ctx) {
|
|
|
86
86
|
if (f.required)
|
|
87
87
|
base.required = true;
|
|
88
88
|
}
|
|
89
|
+
// A picker's choices (a `singleSelect` dropdown, a `multiSelect`), as the
|
|
90
|
+
// canvas stores them on the row (#1235).
|
|
91
|
+
const options = formFieldOptionsWire(f.options);
|
|
92
|
+
if (options !== undefined)
|
|
93
|
+
base.options = options;
|
|
89
94
|
return base;
|
|
90
95
|
});
|
|
91
96
|
const outcomes = (inputs?.outcomes ?? []).map((o, i) => {
|
|
@@ -326,6 +331,7 @@ function liftHitl(node, typeName, ctx) {
|
|
|
326
331
|
const id = String(f.id ?? '');
|
|
327
332
|
const direction = String(f.direction ?? 'output');
|
|
328
333
|
const value = direction === 'input' || direction === 'inOut' ? bindingExpr(f.binding) : undefined;
|
|
334
|
+
const options = liftFormFieldOptions(f.options);
|
|
329
335
|
return {
|
|
330
336
|
id,
|
|
331
337
|
// serialize defaults a row's label to its id.
|
|
@@ -336,6 +342,7 @@ function liftHitl(node, typeName, ctx) {
|
|
|
336
342
|
direction,
|
|
337
343
|
...(value !== undefined ? { value } : {}),
|
|
338
344
|
...(f.required === true ? { required: true } : {}),
|
|
345
|
+
...(options !== undefined ? { options } : {}),
|
|
339
346
|
};
|
|
340
347
|
});
|
|
341
348
|
const outcomeRows = (Array.isArray(schema.outcomes) ? schema.outcomes : []);
|
|
@@ -498,6 +505,11 @@ function printHitl({ inputs }, ctx) {
|
|
|
498
505
|
['direction', ctx.string(f.direction)],
|
|
499
506
|
['value', f.value !== undefined ? ctx.value(f.value) : undefined],
|
|
500
507
|
['required', f.required ? 'true' : undefined],
|
|
508
|
+
['options', f.options !== undefined ? `[${f.options.map((o) => obj([
|
|
509
|
+
['id', ctx.string(o.id)],
|
|
510
|
+
['value', ctx.string(o.value)],
|
|
511
|
+
['label', ctx.string(o.label)],
|
|
512
|
+
], ctx)).join(', ')}]` : undefined],
|
|
501
513
|
], ctx));
|
|
502
514
|
const outcomes = h.outcomes.map((o) => (typeof o === 'string' ? ctx.string(o) : obj([
|
|
503
515
|
['name', ctx.string(o.name)],
|
package/dist/serialize.js
CHANGED
|
@@ -20,7 +20,7 @@ import { FLOW_NODE_TYPES } from './flow-node-registry.js';
|
|
|
20
20
|
import { stepExits } from './flow-step-exits.js';
|
|
21
21
|
import { resolveVersionCarried } from './core/nodes/versioned.js';
|
|
22
22
|
import { indexCarriedDefinitions } from './core/carried-definitions.js';
|
|
23
|
-
import { formFieldJsonSchema } from './core/form-field-type.js';
|
|
23
|
+
import { formFieldJsonSchema, formFieldOptionsWire } from './core/form-field-type.js';
|
|
24
24
|
import { ConnectorResolveError } from './core/connector-resolve-error.js';
|
|
25
25
|
import { connectionConnectors } from './bindings-v2.js';
|
|
26
26
|
import { BindingRefusal, GUID_RE, bindingLabelRefusal, bindingMissingMessage, missingBindingLabels } from './core/binding-messages.js';
|
|
@@ -5533,12 +5533,17 @@ export function serialize(built, opts = {}) {
|
|
|
5533
5533
|
const qnode = makeNode(qdef.nodeType, qid, esc.name, { parentId, def: qdef });
|
|
5534
5534
|
qnode.display = { ...qnode.display, shape: 'circle' };
|
|
5535
5535
|
delete qnode.model;
|
|
5536
|
-
const rows = (esc.fields ?? []).map((f) =>
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5536
|
+
const rows = (esc.fields ?? []).map((f) => {
|
|
5537
|
+
const options = formFieldOptionsWire(f.options);
|
|
5538
|
+
return {
|
|
5539
|
+
id: f.id,
|
|
5540
|
+
label: f.label ?? f.id,
|
|
5541
|
+
type: f.type,
|
|
5542
|
+
direction: f.direction,
|
|
5543
|
+
// A picker's choices, as the human task's rows carry them (#1235).
|
|
5544
|
+
...(options !== undefined ? { options } : {}),
|
|
5545
|
+
};
|
|
5546
|
+
});
|
|
5542
5547
|
const qsource = fnv1aX4Uuid(`${built.id}/${step.name}/escalation/${esc.name}`);
|
|
5543
5548
|
qnode.inputs = {
|
|
5544
5549
|
source: qsource,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.31.
|
|
3
|
+
"version": "6.31.9",
|
|
4
4
|
"description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://docs.uipath.com/maestro",
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"@types/node": "^22.7.0",
|
|
94
94
|
"esbuild": "^0.28.1"
|
|
95
95
|
},
|
|
96
|
-
"gitref": "
|
|
96
|
+
"gitref": "e812e24ab6455bcc1ffeb6f806e9cd0d09cbe389"
|
|
97
97
|
}
|