@uipath/maestro-builder-sdk 6.31.7 → 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 +76 -73
- package/dist/api-members.md +251 -245
- package/dist/check.js +12 -2
- package/dist/core/actions.d.ts +61 -4
- package/dist/core/form-field-type.d.ts +144 -33
- package/dist/core/form-field-type.js +284 -46
- package/dist/decompile.js +8 -2
- package/dist/nodes/hitl/flow/check.js +8 -2
- package/dist/nodes/hitl/flow/node-type.js +17 -5
- package/dist/serialize.js +13 -8
- package/package.json +2 -2
|
@@ -1,63 +1,301 @@
|
|
|
1
1
|
import { nearestName } from './edit-distance.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import { ownEntry } from './own-entry.js';
|
|
3
|
+
/**
|
|
4
|
+
* Each canonical type's JSON Schema, as `FIELD_TYPE_TO_JSON_SCHEMA` gives it.
|
|
5
|
+
* `Record<CanonicalFormFieldType, …>` makes tsc refuse a missing or extra one.
|
|
6
|
+
* `float` and `double` are both `number`: JSON Schema has no precision; `file`
|
|
7
|
+
* is `format: 'binary'` (the OpenAPI convention for an upload).
|
|
8
|
+
*/
|
|
9
|
+
const CANONICAL_JSON_SCHEMA = {
|
|
10
|
+
string: { type: 'string' },
|
|
11
|
+
number: { type: 'number' },
|
|
12
|
+
integer: { type: 'integer' },
|
|
13
|
+
float: { type: 'number' },
|
|
14
|
+
double: { type: 'number' },
|
|
15
|
+
boolean: { type: 'boolean' },
|
|
16
|
+
date: { type: 'string', format: 'date' },
|
|
17
|
+
datetime: { type: 'string', format: 'date-time' },
|
|
18
|
+
file: { type: 'string', format: 'binary' },
|
|
19
|
+
object: { type: 'object' },
|
|
20
|
+
array: { type: 'array' },
|
|
21
|
+
};
|
|
22
|
+
/** The product's 11 canonical quick-form field types, in its own order. */
|
|
23
|
+
export const CANONICAL_FORM_FIELD_TYPES = Object.keys(CANONICAL_JSON_SCHEMA);
|
|
24
|
+
/**
|
|
25
|
+
* The SDK's own legacy spellings, accepted in source: `text` (what the SDK,
|
|
26
|
+
* flow-v1's serializer and `uip maestro flow hitl add` have always written) and
|
|
27
|
+
* `date-time`. The product resolves both.
|
|
28
|
+
*/
|
|
29
|
+
const SDK_ALIASES = {
|
|
30
|
+
text: 'string',
|
|
31
|
+
'date-time': 'datetime',
|
|
32
|
+
};
|
|
33
|
+
/** The SDK's legacy spellings (`text`, `date-time`), for diagnostics that list them. */
|
|
34
|
+
export const LEGACY_FORM_FIELD_TYPES = Object.keys(SDK_ALIASES);
|
|
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
|
+
];
|
|
59
|
+
/**
|
|
60
|
+
* The tail of a "Valid: …" diagnostic: the canonical types, then the legacy
|
|
61
|
+
* spellings and the choice controls in parentheses.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* validFormFieldTypesText() // 'string, …, array (or the older text, date-time; or a choice control: singleSelect, …)'
|
|
65
|
+
*/
|
|
66
|
+
export function validFormFieldTypesText() {
|
|
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 };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The product's other data-type spellings, each with the canonical type it
|
|
85
|
+
* resolves to (`resolveFieldType` in `@uipath/hitl-schema-types` 1.2.0). The
|
|
86
|
+
* .NET names come from forms built by RPA / agent tooling. The scope-walker
|
|
87
|
+
* shapes (`union`, `intersection`, `ref`, `any`) reach `field.type` when a
|
|
88
|
+
* canvas author binds a Flow variable; they carry no narrower shape, so they
|
|
89
|
+
* resolve to `string`. `T[]` and `a | b` are matched by pattern in
|
|
90
|
+
* `canonicalFormFieldType`.
|
|
91
|
+
*
|
|
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).
|
|
95
|
+
*/
|
|
96
|
+
const PRODUCT_ALIASES = {
|
|
97
|
+
...SDK_ALIASES,
|
|
98
|
+
String: 'string',
|
|
99
|
+
'System.String': 'string',
|
|
100
|
+
'System.Char': 'string',
|
|
101
|
+
Char: 'string',
|
|
10
102
|
Number: 'number',
|
|
11
|
-
|
|
103
|
+
Int32: 'integer',
|
|
104
|
+
Int64: 'integer',
|
|
105
|
+
'System.Int32': 'integer',
|
|
106
|
+
'System.Int64': 'integer',
|
|
107
|
+
'System.Byte': 'integer',
|
|
108
|
+
'System.Int16': 'integer',
|
|
109
|
+
Byte: 'integer',
|
|
110
|
+
Int16: 'integer',
|
|
111
|
+
UInt16: 'integer',
|
|
112
|
+
UInt32: 'integer',
|
|
113
|
+
UInt64: 'integer',
|
|
114
|
+
Float: 'float',
|
|
115
|
+
Single: 'float',
|
|
116
|
+
'System.Single': 'float',
|
|
117
|
+
Double: 'double',
|
|
118
|
+
Decimal: 'double',
|
|
119
|
+
'System.Double': 'double',
|
|
120
|
+
'System.Decimal': 'double',
|
|
12
121
|
Boolean: 'boolean',
|
|
13
122
|
'System.Boolean': 'boolean',
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
123
|
+
Date: 'date',
|
|
124
|
+
'System.DateOnly': 'date',
|
|
125
|
+
DateOnly: 'date',
|
|
126
|
+
dateTime: 'datetime',
|
|
127
|
+
DateTime: 'datetime',
|
|
128
|
+
'System.DateTime': 'datetime',
|
|
129
|
+
File: 'file',
|
|
130
|
+
Object: 'object',
|
|
131
|
+
DataTable: 'object',
|
|
132
|
+
QueueItem: 'object',
|
|
133
|
+
Array: 'array',
|
|
134
|
+
GenericValue: 'array',
|
|
135
|
+
list: 'array',
|
|
136
|
+
List: 'array',
|
|
137
|
+
union: 'string',
|
|
138
|
+
intersection: 'string',
|
|
139
|
+
ref: 'string',
|
|
140
|
+
any: 'string',
|
|
19
141
|
};
|
|
142
|
+
/** The product aliases, for the contract test. */
|
|
143
|
+
export const FORM_FIELD_TYPE_ALIASES = PRODUCT_ALIASES;
|
|
144
|
+
const isCanonical = (t) => typeof t === 'string' && Object.hasOwn(CANONICAL_JSON_SCHEMA, t);
|
|
145
|
+
/**
|
|
146
|
+
* The canonical type a wire or source spelling names, or `undefined` when it
|
|
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.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* canonicalFormFieldType('integer') // 'integer'
|
|
154
|
+
* canonicalFormFieldType('text') // 'string'
|
|
155
|
+
* canonicalFormFieldType('System.Int32') // 'integer'
|
|
156
|
+
* canonicalFormFieldType('string[]') // 'array'
|
|
157
|
+
* canonicalFormFieldType('string | null') // 'string'
|
|
158
|
+
* canonicalFormFieldType('singleSelect') // undefined
|
|
159
|
+
*/
|
|
160
|
+
export function canonicalFormFieldType(type) {
|
|
161
|
+
if (isCanonical(type))
|
|
162
|
+
return type;
|
|
163
|
+
if (typeof type !== 'string')
|
|
164
|
+
return undefined;
|
|
165
|
+
// The package's own order: the two scope-walker patterns before the names.
|
|
166
|
+
if (type.endsWith('[]'))
|
|
167
|
+
return 'array';
|
|
168
|
+
if (type.includes(' | '))
|
|
169
|
+
return 'string';
|
|
170
|
+
return Object.hasOwn(PRODUCT_ALIASES, type) ? PRODUCT_ALIASES[type] : undefined;
|
|
171
|
+
}
|
|
20
172
|
/**
|
|
21
|
-
* The
|
|
22
|
-
*
|
|
173
|
+
* The spelling decompile writes into source for a wire field type: a canonical
|
|
174
|
+
* type or an SDK alias stays as written, so a canvas form (`"integer"`,
|
|
175
|
+
* `"date"`) and a classic-CLI form (`"text"`) both compile back to the bytes
|
|
176
|
+
* they came from; a product alias the SDK does not accept in source
|
|
177
|
+
* (`"System.Int32"`, `"string[]"`) becomes its canonical type; anything else
|
|
178
|
+
* stays verbatim for `check` to report.
|
|
23
179
|
*
|
|
24
180
|
* @example
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
181
|
+
* sourceFormFieldType('date') // 'date'
|
|
182
|
+
* sourceFormFieldType('text') // 'text'
|
|
183
|
+
* sourceFormFieldType('System.String') // 'string'
|
|
184
|
+
* sourceFormFieldType('string[]') // 'array'
|
|
185
|
+
* sourceFormFieldType('singleSelect') // 'singleSelect'
|
|
28
186
|
*/
|
|
29
|
-
export function
|
|
30
|
-
|
|
187
|
+
export function sourceFormFieldType(wire) {
|
|
188
|
+
if (typeof wire === 'string' && FORM_FIELD_TYPES.includes(wire))
|
|
189
|
+
return wire;
|
|
190
|
+
return canonicalFormFieldType(wire) ?? String(wire);
|
|
31
191
|
}
|
|
32
192
|
/**
|
|
33
|
-
* Why a form-field type is refused: a product
|
|
34
|
-
*
|
|
35
|
-
* the
|
|
36
|
-
* second case; the default is a human task's.
|
|
193
|
+
* Why a form-field type is refused: a product alias the SDK does not accept in
|
|
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.
|
|
37
197
|
*/
|
|
38
|
-
export function formFieldTypeWhy(type, unknownWhy = `which
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
? `which is the platform's spelling of the SDK's '${alias}' — the SDK writes '${alias}'`
|
|
198
|
+
export function formFieldTypeWhy(type, unknownWhy = `which is not a quick-form field type: the platform rejects the form`) {
|
|
199
|
+
const canonical = canonicalFormFieldType(type);
|
|
200
|
+
return canonical !== undefined
|
|
201
|
+
? `which is the platform's alias of '${canonical}' — the SDK writes '${canonical}'`
|
|
43
202
|
: unknownWhy;
|
|
44
203
|
}
|
|
45
|
-
/**
|
|
46
|
-
const FORM_FIELD_TYPE_SET = { text: true, number: true, boolean: true, 'date-time': true };
|
|
47
|
-
/** The form-field types the SDK models. */
|
|
48
|
-
export const FORM_FIELD_TYPES = Object.keys(FORM_FIELD_TYPE_SET);
|
|
49
|
-
/** The `suggestion` for an unknown form-field type: the nearest valid one, else `type: 'text'`. */
|
|
204
|
+
/** The `suggestion` for an unknown form-field type: its canonical type, the nearest valid one, else `type: 'string'`. */
|
|
50
205
|
export function formFieldTypeHint(type) {
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
53
|
-
return `type: '${
|
|
206
|
+
const canonical = canonicalFormFieldType(type);
|
|
207
|
+
if (canonical !== undefined)
|
|
208
|
+
return `type: '${canonical}'`;
|
|
54
209
|
const nearest = nearestName(String(type), FORM_FIELD_TYPES);
|
|
55
|
-
return nearest !== undefined ? `type: '${nearest}'` : `type: '
|
|
210
|
+
return nearest !== undefined ? `type: '${nearest}'` : `type: 'string'`;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* The JSON Schema of a field's value, for the output (and escalation input)
|
|
214
|
+
* schemas the serializers write; `undefined` for a type the SDK does not model.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* formFieldJsonSchema('date') // { type: 'string', format: 'date' }
|
|
218
|
+
* formFieldJsonSchema('text') // { type: 'string' }
|
|
219
|
+
* formFieldJsonSchema('multiSelect') // { type: 'array' }
|
|
220
|
+
*/
|
|
221
|
+
export function formFieldJsonSchema(type) {
|
|
222
|
+
const canonical = canonicalFormFieldType(type) ?? controlFormFieldType(type)?.data;
|
|
223
|
+
const schema = canonical === undefined ? undefined : ownEntry(CANONICAL_JSON_SCHEMA, canonical);
|
|
224
|
+
return schema === undefined ? undefined : { ...schema };
|
|
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
|
+
}
|
|
56
301
|
}
|
|
57
|
-
/** JSON-Schema type per form-field type, as flow-v1's form serializer maps them (quick-form escalations and human tasks). */
|
|
58
|
-
export const FORM_FIELD_JSON_TYPE = {
|
|
59
|
-
text: { type: 'string' },
|
|
60
|
-
number: { type: 'number' },
|
|
61
|
-
boolean: { type: 'boolean' },
|
|
62
|
-
'date-time': { type: 'string', format: 'date-time' },
|
|
63
|
-
};
|
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 {
|
|
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
|
|
@@ -1304,8 +1304,14 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1304
1304
|
['description', rPlain(e, 'description') !== undefined ? tsLiteral(rPlain(e, 'description')) : undefined],
|
|
1305
1305
|
['fields', rows.length ? `[${rows.map((f) => opts([
|
|
1306
1306
|
['id', tsText(f.id)],
|
|
1307
|
-
['type', tsLiteral(
|
|
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 } 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' },
|
|
@@ -213,7 +215,11 @@ export function checkHitl(inputs, ctx) {
|
|
|
213
215
|
}
|
|
214
216
|
if (!FORM_FIELD_TYPES.includes(String(f?.type))) {
|
|
215
217
|
at('HITL_FIELD_TYPE_UNKNOWN', `Human task "${step}" gives the form field "${id}" the type ${JSON.stringify(f?.type)}, `
|
|
216
|
-
+ `${formFieldTypeWhy(f?.type)}. Valid: ${
|
|
218
|
+
+ `${formFieldTypeWhy(f?.type)}. Valid: ${validFormFieldTypesText()}.`, formFieldTypeHint(f?.type));
|
|
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' }]`);
|
|
217
223
|
}
|
|
218
224
|
if (isAnswerField(f))
|
|
219
225
|
answers++; // an `output`, or an `inOut` whose reviewed value comes back
|
|
@@ -13,11 +13,10 @@
|
|
|
13
13
|
* every edge out of an outcome-handle node to.
|
|
14
14
|
*/
|
|
15
15
|
import { Expr, toExpr } from '../../../core/expr.js';
|
|
16
|
-
import {
|
|
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';
|
|
20
|
-
import { ownEntry } from '../../../core/own-entry.js';
|
|
21
20
|
import { schemaId } from '../../../core/stable-id.js';
|
|
22
21
|
import { wireExprBody } from '../../../core/wire-expr.js';
|
|
23
22
|
import { checkHitl, checkHitlRead } from './check.js';
|
|
@@ -87,6 +86,11 @@ function hitlInputs(inputs, nodeType, ctx) {
|
|
|
87
86
|
if (f.required)
|
|
88
87
|
base.required = true;
|
|
89
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;
|
|
90
94
|
return base;
|
|
91
95
|
});
|
|
92
96
|
const outcomes = (inputs?.outcomes ?? []).map((o, i) => {
|
|
@@ -99,7 +103,7 @@ function hitlInputs(inputs, nodeType, ctx) {
|
|
|
99
103
|
// inOut fields land in the answers too — their reviewed value flows back.
|
|
100
104
|
if (!isAnswerField(f))
|
|
101
105
|
continue;
|
|
102
|
-
properties[f.id] = { ...
|
|
106
|
+
properties[f.id] = { ...formFieldJsonSchema(f.type) };
|
|
103
107
|
}
|
|
104
108
|
const names = outcomes.map((o) => o.name).filter((n) => typeof n === 'string');
|
|
105
109
|
if (names.length > 0) {
|
|
@@ -327,15 +331,18 @@ function liftHitl(node, typeName, ctx) {
|
|
|
327
331
|
const id = String(f.id ?? '');
|
|
328
332
|
const direction = String(f.direction ?? 'output');
|
|
329
333
|
const value = direction === 'input' || direction === 'inOut' ? bindingExpr(f.binding) : undefined;
|
|
334
|
+
const options = liftFormFieldOptions(f.options);
|
|
330
335
|
return {
|
|
331
336
|
id,
|
|
332
337
|
// serialize defaults a row's label to its id.
|
|
333
338
|
...(typeof f.label === 'string' && f.label !== id ? { label: f.label } : {}),
|
|
334
|
-
//
|
|
335
|
-
|
|
339
|
+
// A type the SDK accepts stays as written, so the form compiles back to
|
|
340
|
+
// the same bytes; a .NET alias becomes its canonical type (#1143, #1176).
|
|
341
|
+
type: sourceFormFieldType(f.type ?? 'string'),
|
|
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 {
|
|
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';
|
|
@@ -1362,7 +1362,7 @@ function escalationResourceJson(esc, spec) {
|
|
|
1362
1362
|
const fields = esc.fields ?? [];
|
|
1363
1363
|
const props = (dirs) => Object.fromEntries(fields
|
|
1364
1364
|
.filter((f) => dirs.includes(f.direction))
|
|
1365
|
-
.map((f) => [f.id,
|
|
1365
|
+
.map((f) => [f.id, formFieldJsonSchema(f.type) ?? { type: 'string' }]));
|
|
1366
1366
|
channel = {
|
|
1367
1367
|
...common,
|
|
1368
1368
|
type: 'actionCenterQuickForm',
|
|
@@ -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
|
}
|