@uipath/maestro-builder-sdk 6.55.0 → 6.56.0
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 +97 -80
- package/dist/api-members.md +372 -345
- package/dist/bpmn/bpmn-sdk.d.ts +110 -27
- package/dist/bpmn/bpmn-sdk.js +84 -6
- package/dist/bpmn/declared-vars.js +3 -2
- package/dist/bpmn/decompile.js +66 -0
- package/dist/bpmn/human-task-form.d.ts +170 -0
- package/dist/bpmn/human-task-form.js +321 -0
- package/dist/bpmn/serialize.js +8 -0
- package/dist/bpmn/typed-node.d.ts +6 -0
- package/dist/bpmn/typed-node.js +6 -0
- package/package.json +2 -2
package/dist/bpmn/bpmn-sdk.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ import type { TypeDesc } from '../core/expr.js';
|
|
|
23
23
|
import { type ConnectorOpts, type EventFilter } from '../core/actions.js';
|
|
24
24
|
import type { ConnectorDescriptor } from '../core/connectors.js';
|
|
25
25
|
import type { RegistryTypeSpec, TypedContextRow, TypedInputRow, TypedOutputRow } from './typed-node.js';
|
|
26
|
+
import { type HumanTaskForm } from './human-task-form.js';
|
|
27
|
+
export type { HumanTaskForm, HumanTaskFormField, HumanTaskShownField, HumanTaskAskedField, HumanTaskInOutField, HumanTaskOutcome, } from './human-task-form.js';
|
|
26
28
|
import { type DataServiceOperation } from './data-service.js';
|
|
27
29
|
export type { DataServiceOperation } from './data-service.js';
|
|
28
30
|
export { BpmnBuildError } from './bpmn-expr-check.js';
|
|
@@ -191,6 +193,12 @@ export type BpmnNode = {
|
|
|
191
193
|
outputs?: Record<string, string>;
|
|
192
194
|
/** Output rows spelled out, replacing the derived ones — see `TypedOutputRow`. */
|
|
193
195
|
outputRows?: TypedOutputRow[];
|
|
196
|
+
/**
|
|
197
|
+
* Rows written AFTER `outputRows`, each typed from the AUTHOR-declared variable it
|
|
198
|
+
* writes when there is one, its own `type` otherwise — `.humanTask({ form })`'s
|
|
199
|
+
* `outputs`, which have to be typed like the app variant's.
|
|
200
|
+
*/
|
|
201
|
+
mappedOutputRows?: TypedOutputRow[];
|
|
194
202
|
/** The `uipath:type` `version` attribute — see `ActivityNodeOpts.typeVersion`. */
|
|
195
203
|
typeVersion?: string;
|
|
196
204
|
/** The `uipath:inputSchema` body — see `ActivityNodeOpts.inputSchema`. */
|
|
@@ -1355,19 +1363,41 @@ export interface QueueItemOpts extends ActivityOpts {
|
|
|
1355
1363
|
/** `=`-expression that skips the enqueue when truthy. */
|
|
1356
1364
|
skipCondition?: string;
|
|
1357
1365
|
}
|
|
1366
|
+
/** What both variants of `.humanTask()` take. */
|
|
1367
|
+
export interface HumanTaskCommonOpts extends ActivityOpts {
|
|
1368
|
+
/** Display name the designer shows on the task. */
|
|
1369
|
+
name?: string;
|
|
1370
|
+
/** The task title a human sees (`taskTitle`). */
|
|
1371
|
+
title?: string;
|
|
1372
|
+
/**
|
|
1373
|
+
* Fields to pull out of the human's response into variables, e.g.
|
|
1374
|
+
* `{ decision: '=Action' }`.
|
|
1375
|
+
*
|
|
1376
|
+
* Worth setting whenever a gateway branches on the outcome. The type's own
|
|
1377
|
+
* output row is typed (`type="Actions.HITL"`, no `source`), which the designer
|
|
1378
|
+
* resolves but the local runtime leaves `undefined` — so without a mapped field
|
|
1379
|
+
* here, a local run cannot branch on the decision at all. `=Action` is the field
|
|
1380
|
+
* the runtime's own outcome routing reads.
|
|
1381
|
+
*/
|
|
1382
|
+
outputs?: Record<string, string>;
|
|
1383
|
+
/** Variable the whole typed response lands in. Defaults to `<id>_processResponse`. */
|
|
1384
|
+
outputVar?: string;
|
|
1385
|
+
/** `=`-expression that skips the task when truthy. */
|
|
1386
|
+
skipCondition?: string;
|
|
1387
|
+
}
|
|
1358
1388
|
/**
|
|
1359
|
-
* Options for `.humanTask()` — an `Actions.HITL` action-app task.
|
|
1389
|
+
* Options for `.humanTask()` backed by an Action App — an `Actions.HITL` action-app task.
|
|
1360
1390
|
*
|
|
1361
1391
|
* `app` is the Action App's id and the registry marks it the type's primary key,
|
|
1362
1392
|
* so it comes from the tenant (`RequiresDiscovery: Yes`). Nothing offline can
|
|
1363
1393
|
* resolve it: pass the id, or a `=bindings.<id>` reference so it is configurable
|
|
1364
|
-
* per environment.
|
|
1394
|
+
* per environment. With no app on the tenant, use {@link HumanTaskFormOpts} instead.
|
|
1365
1395
|
*/
|
|
1366
|
-
export interface
|
|
1367
|
-
/** Display name the designer shows on the task. */
|
|
1368
|
-
name?: string;
|
|
1396
|
+
export interface HumanTaskAppOpts extends HumanTaskCommonOpts {
|
|
1369
1397
|
/** The Action App's id (`appId`). Tenant-specific — see the remarks above. */
|
|
1370
1398
|
app: string;
|
|
1399
|
+
/** Not on this variant — see {@link HumanTaskFormOpts}. */
|
|
1400
|
+
form?: never;
|
|
1371
1401
|
/** The app version (`appVersion`). */
|
|
1372
1402
|
appVersion?: number;
|
|
1373
1403
|
/**
|
|
@@ -1380,28 +1410,41 @@ export interface HumanTaskOpts extends ActivityOpts {
|
|
|
1380
1410
|
* outcomes, this is the first thing to compare against a Studio Web export.
|
|
1381
1411
|
*/
|
|
1382
1412
|
actions?: string[];
|
|
1383
|
-
/** The task title a human sees (`taskTitle`). */
|
|
1384
|
-
title?: string;
|
|
1385
1413
|
/** An existing task key, when resuming rather than creating (`key`). */
|
|
1386
1414
|
key?: string;
|
|
1387
1415
|
/** Data the task shows the human — the node's `HitlTaskArguments`. */
|
|
1388
1416
|
input?: Record<string, unknown>;
|
|
1389
|
-
/**
|
|
1390
|
-
* Fields to pull out of the human's response into variables, e.g.
|
|
1391
|
-
* `{ decision: '=Action' }`.
|
|
1392
|
-
*
|
|
1393
|
-
* Worth setting whenever a gateway branches on the outcome. The type's own
|
|
1394
|
-
* output row is typed (`type="Actions.HITL"`, no `source`), which the designer
|
|
1395
|
-
* resolves but the local runtime leaves `undefined` — so without a mapped field
|
|
1396
|
-
* here, a local run cannot branch on the decision at all. `=Action` is the field
|
|
1397
|
-
* the runtime's own outcome routing reads.
|
|
1398
|
-
*/
|
|
1399
|
-
outputs?: Record<string, string>;
|
|
1400
|
-
/** Variable the whole typed response lands in. Defaults to `<id>_processResponse`. */
|
|
1401
|
-
outputVar?: string;
|
|
1402
|
-
/** `=`-expression that skips the task when truthy. */
|
|
1403
|
-
skipCondition?: string;
|
|
1404
1417
|
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Options for `.humanTask()` with an INLINE form — the quick-form `Actions.HITL` task,
|
|
1420
|
+
* which needs no Action App.
|
|
1421
|
+
*
|
|
1422
|
+
* The default for a "a human reviews this" step whenever no deployed app is named: the
|
|
1423
|
+
* form's fields and outcomes travel in the `.bpmn` itself (`hitlType=quick`, the
|
|
1424
|
+
* `__hitlFormSchema` context row and its `hitlSchemaId`), the way the product's own
|
|
1425
|
+
* Flow-to-BPMN converter writes a quick form. Each asked field's answer lands in its
|
|
1426
|
+
* `variable` (default: its id); the outcome picked is `=Action`. See
|
|
1427
|
+
* `human-task-form.ts` for why the form is inline rather than a `.hitl.json` sidecar.
|
|
1428
|
+
*
|
|
1429
|
+
* The engine takes this path only when the tenant has the `ShouldUseHitlQuickFormSchema`
|
|
1430
|
+
* flag on; otherwise it falls back to the Action-App path, which has no app to open.
|
|
1431
|
+
*/
|
|
1432
|
+
export interface HumanTaskFormOpts extends HumanTaskCommonOpts {
|
|
1433
|
+
/** The inline form: its fields and its outcomes. */
|
|
1434
|
+
form: HumanTaskForm;
|
|
1435
|
+
/** Not on this variant — the form replaces the app. */
|
|
1436
|
+
app?: never;
|
|
1437
|
+
/** Action Center priority, e.g. `'Medium'` (`priority`). */
|
|
1438
|
+
priority?: string;
|
|
1439
|
+
/** Action Center labels, comma-separated (`labels`). */
|
|
1440
|
+
labels?: string;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Options for `.humanTask()` — an `Actions.HITL` task, backed by an Action App
|
|
1444
|
+
* ({@link HumanTaskAppOpts}) or by an inline form ({@link HumanTaskFormOpts}).
|
|
1445
|
+
* Exactly one of `app` and `form`.
|
|
1446
|
+
*/
|
|
1447
|
+
export type HumanTaskOpts = HumanTaskAppOpts | HumanTaskFormOpts;
|
|
1405
1448
|
/**
|
|
1406
1449
|
* Options for `.receiveMessage()` — `Maestro.ReceiveMessageEvent`.
|
|
1407
1450
|
*
|
|
@@ -2007,6 +2050,14 @@ declare class SugarRegistry {
|
|
|
2007
2050
|
vars: BpmnVarDecl[];
|
|
2008
2051
|
elementId: string;
|
|
2009
2052
|
}>;
|
|
2053
|
+
/**
|
|
2054
|
+
* The `bpmn(…)` id, which every scope can derive stable ids from — a quick human
|
|
2055
|
+
* task's default `hitlSchemaId`. An explicit field rather than a parameter property,
|
|
2056
|
+
* whose comment would not reach the emitted `.d.ts`.
|
|
2057
|
+
*/
|
|
2058
|
+
readonly processId: string;
|
|
2059
|
+
/** @param processId - The `bpmn(…)` id. */
|
|
2060
|
+
constructor(processId?: string);
|
|
2010
2061
|
}
|
|
2011
2062
|
/**
|
|
2012
2063
|
* Whether the node serializes to a start event — nothing may flow INTO it.
|
|
@@ -2666,10 +2717,16 @@ declare abstract class ScopeBuilder {
|
|
|
2666
2717
|
*/
|
|
2667
2718
|
queueItem(id: string, opts: QueueItemOpts, body?: ActivityBodyFn): this;
|
|
2668
2719
|
/**
|
|
2669
|
-
* A **human task** —
|
|
2670
|
-
* `uipath:activity` / `Actions.HITL`).
|
|
2720
|
+
* A **human task** — a task a person completes in Action Center (`bpmn:userTask` +
|
|
2721
|
+
* `uipath:activity` / `Actions.HITL`), shown either as an inline form or by an Action App.
|
|
2671
2722
|
*
|
|
2672
2723
|
* @remarks
|
|
2724
|
+
* **Pick the variant by whether an app is named.** With no deployed Action App named,
|
|
2725
|
+
* use `form: { fields, outcomes }` ({@link HumanTaskFormOpts}): the form travels in the
|
|
2726
|
+
* `.bpmn` and nothing on the tenant has to exist. Use `app` ({@link HumanTaskAppOpts})
|
|
2727
|
+
* only when the request names a deployed app — an app id that is not on the tenant fails
|
|
2728
|
+
* `uip maestro bpmn validate` with `MISSING_BINDING` / `MISSING_RESOURCE`.
|
|
2729
|
+
*
|
|
2673
2730
|
* The offline runtime can stand in for the human — `--hitl-response` injects an
|
|
2674
2731
|
* outcome — so an approval gate's branches are testable with no tenant and no
|
|
2675
2732
|
* waiting. That is why this is the one discovery-requiring type worth authoring
|
|
@@ -2680,7 +2737,7 @@ declare abstract class ScopeBuilder {
|
|
|
2680
2737
|
* ```
|
|
2681
2738
|
*
|
|
2682
2739
|
* Map the decision into a variable with `outputs` if anything branches on it —
|
|
2683
|
-
* see {@link
|
|
2740
|
+
* see {@link HumanTaskCommonOpts.outputs} for why the type's own output is not enough.
|
|
2684
2741
|
*
|
|
2685
2742
|
* @example
|
|
2686
2743
|
* **An approval gate whose branches can be exercised offline**
|
|
@@ -2710,9 +2767,35 @@ declare abstract class ScopeBuilder {
|
|
|
2710
2767
|
* .build();
|
|
2711
2768
|
* ```
|
|
2712
2769
|
*
|
|
2770
|
+
* @example
|
|
2771
|
+
* **A review fallback with an inline form — no Action App**
|
|
2772
|
+
* ```ts
|
|
2773
|
+
* bpmn('triage')
|
|
2774
|
+
* .var('category', 'string', { default: 'billing' })
|
|
2775
|
+
* .var('decision', 'string')
|
|
2776
|
+
* .startEvent('start')
|
|
2777
|
+
* .humanTask('review', {
|
|
2778
|
+
* name: 'Review the category',
|
|
2779
|
+
* form: {
|
|
2780
|
+
* fields: [
|
|
2781
|
+
* // Shown and correctable: pre-filled from vars.category, written back to it.
|
|
2782
|
+
* { id: 'category', type: 'string', direction: 'inOut', value: '=vars.category' },
|
|
2783
|
+
* // Asked: the answer lands in vars.reviewNote.
|
|
2784
|
+
* { id: 'note', type: 'string', direction: 'output', variable: 'reviewNote' },
|
|
2785
|
+
* ],
|
|
2786
|
+
* outcomes: ['Accept', 'Escalate'],
|
|
2787
|
+
* },
|
|
2788
|
+
* outputs: { decision: '=Action' },
|
|
2789
|
+
* })
|
|
2790
|
+
* .endEvent('done')
|
|
2791
|
+
* .sequenceFlow('start', 'review')
|
|
2792
|
+
* .sequenceFlow('review', 'done')
|
|
2793
|
+
* .build();
|
|
2794
|
+
* ```
|
|
2795
|
+
*
|
|
2713
2796
|
* @param id - The element id, unique in the process and used by `sequenceFlow`.
|
|
2714
|
-
* @param opts - The
|
|
2715
|
-
*
|
|
2797
|
+
* @param opts - The inline form or the app, what the human sees, and which response
|
|
2798
|
+
* fields to keep.
|
|
2716
2799
|
* @param body - Boundary events attached to this activity, declared on the {@link ActivityBuilder} it receives.
|
|
2717
2800
|
* @returns This builder, so calls chain.
|
|
2718
2801
|
*/
|
package/dist/bpmn/bpmn-sdk.js
CHANGED
|
@@ -4,6 +4,7 @@ import { BPMN_SCHEMA_VERSIONS } from './format-profile.js';
|
|
|
4
4
|
import { schemaVersionRefusal } from '../schema-version.js';
|
|
5
5
|
import { bindingRequiredFields, REGISTRY_GAPS, registryType } from './typed-node.js';
|
|
6
6
|
import { resolveResourceKeyPattern } from './resource-key-pattern.js';
|
|
7
|
+
import { quickHumanTaskRows } from './human-task-form.js';
|
|
7
8
|
import { DATA_SERVICE_ACTIVITY_TYPE, DATA_SERVICE_CONNECTOR_KEY, dataServiceWire } from './data-service.js';
|
|
8
9
|
import { MANAGED_HTTP_CONNECTION_NAME, MANAGED_HTTP_CONNECTOR_KEY, MANAGED_HTTP_FOLDER_NAME, MANAGED_HTTP_TYPE, managedHttpContext, managedHttpInputs, managedHttpOutputs, } from './managed-http.js';
|
|
9
10
|
import { ownEntry } from '../core/own-entry.js';
|
|
@@ -27,6 +28,16 @@ class SugarRegistry {
|
|
|
27
28
|
pinnedFlowIds = new Map();
|
|
28
29
|
/** Variables an `errorVar` asked for — declared at build unless the author declared the id. */
|
|
29
30
|
autoVars = [];
|
|
31
|
+
/**
|
|
32
|
+
* The `bpmn(…)` id, which every scope can derive stable ids from — a quick human
|
|
33
|
+
* task's default `hitlSchemaId`. An explicit field rather than a parameter property,
|
|
34
|
+
* whose comment would not reach the emitted `.d.ts`.
|
|
35
|
+
*/
|
|
36
|
+
processId;
|
|
37
|
+
/** @param processId - The `bpmn(…)` id. */
|
|
38
|
+
constructor(processId = '') {
|
|
39
|
+
this.processId = processId;
|
|
40
|
+
}
|
|
30
41
|
}
|
|
31
42
|
const GATEWAY_NODE_KINDS = new Set(['exclusiveGateway', 'parallelGateway', 'inclusiveGateway', 'eventBasedGateway']);
|
|
32
43
|
/**
|
|
@@ -1511,10 +1522,16 @@ class ScopeBuilder {
|
|
|
1511
1522
|
}, body);
|
|
1512
1523
|
}
|
|
1513
1524
|
/**
|
|
1514
|
-
* A **human task** —
|
|
1515
|
-
* `uipath:activity` / `Actions.HITL`).
|
|
1525
|
+
* A **human task** — a task a person completes in Action Center (`bpmn:userTask` +
|
|
1526
|
+
* `uipath:activity` / `Actions.HITL`), shown either as an inline form or by an Action App.
|
|
1516
1527
|
*
|
|
1517
1528
|
* @remarks
|
|
1529
|
+
* **Pick the variant by whether an app is named.** With no deployed Action App named,
|
|
1530
|
+
* use `form: { fields, outcomes }` ({@link HumanTaskFormOpts}): the form travels in the
|
|
1531
|
+
* `.bpmn` and nothing on the tenant has to exist. Use `app` ({@link HumanTaskAppOpts})
|
|
1532
|
+
* only when the request names a deployed app — an app id that is not on the tenant fails
|
|
1533
|
+
* `uip maestro bpmn validate` with `MISSING_BINDING` / `MISSING_RESOURCE`.
|
|
1534
|
+
*
|
|
1518
1535
|
* The offline runtime can stand in for the human — `--hitl-response` injects an
|
|
1519
1536
|
* outcome — so an approval gate's branches are testable with no tenant and no
|
|
1520
1537
|
* waiting. That is why this is the one discovery-requiring type worth authoring
|
|
@@ -1525,7 +1542,7 @@ class ScopeBuilder {
|
|
|
1525
1542
|
* ```
|
|
1526
1543
|
*
|
|
1527
1544
|
* Map the decision into a variable with `outputs` if anything branches on it —
|
|
1528
|
-
* see {@link
|
|
1545
|
+
* see {@link HumanTaskCommonOpts.outputs} for why the type's own output is not enough.
|
|
1529
1546
|
*
|
|
1530
1547
|
* @example
|
|
1531
1548
|
* **An approval gate whose branches can be exercised offline**
|
|
@@ -1555,13 +1572,74 @@ class ScopeBuilder {
|
|
|
1555
1572
|
* .build();
|
|
1556
1573
|
* ```
|
|
1557
1574
|
*
|
|
1575
|
+
* @example
|
|
1576
|
+
* **A review fallback with an inline form — no Action App**
|
|
1577
|
+
* ```ts
|
|
1578
|
+
* bpmn('triage')
|
|
1579
|
+
* .var('category', 'string', { default: 'billing' })
|
|
1580
|
+
* .var('decision', 'string')
|
|
1581
|
+
* .startEvent('start')
|
|
1582
|
+
* .humanTask('review', {
|
|
1583
|
+
* name: 'Review the category',
|
|
1584
|
+
* form: {
|
|
1585
|
+
* fields: [
|
|
1586
|
+
* // Shown and correctable: pre-filled from vars.category, written back to it.
|
|
1587
|
+
* { id: 'category', type: 'string', direction: 'inOut', value: '=vars.category' },
|
|
1588
|
+
* // Asked: the answer lands in vars.reviewNote.
|
|
1589
|
+
* { id: 'note', type: 'string', direction: 'output', variable: 'reviewNote' },
|
|
1590
|
+
* ],
|
|
1591
|
+
* outcomes: ['Accept', 'Escalate'],
|
|
1592
|
+
* },
|
|
1593
|
+
* outputs: { decision: '=Action' },
|
|
1594
|
+
* })
|
|
1595
|
+
* .endEvent('done')
|
|
1596
|
+
* .sequenceFlow('start', 'review')
|
|
1597
|
+
* .sequenceFlow('review', 'done')
|
|
1598
|
+
* .build();
|
|
1599
|
+
* ```
|
|
1600
|
+
*
|
|
1558
1601
|
* @param id - The element id, unique in the process and used by `sequenceFlow`.
|
|
1559
|
-
* @param opts - The
|
|
1560
|
-
*
|
|
1602
|
+
* @param opts - The inline form or the app, what the human sees, and which response
|
|
1603
|
+
* fields to keep.
|
|
1561
1604
|
* @param body - Boundary events attached to this activity, declared on the {@link ActivityBuilder} it receives.
|
|
1562
1605
|
* @returns This builder, so calls chain.
|
|
1563
1606
|
*/
|
|
1564
1607
|
humanTask(id, opts, body) {
|
|
1608
|
+
const hasApp = opts.app !== undefined;
|
|
1609
|
+
const hasForm = opts.form !== undefined;
|
|
1610
|
+
if (hasApp === hasForm) {
|
|
1611
|
+
throw new Error(`humanTask "${id}": pass exactly one of app (a deployed Action App) or form ({ fields, outcomes }, an inline form that needs no app).`);
|
|
1612
|
+
}
|
|
1613
|
+
if (hasForm) {
|
|
1614
|
+
const o = opts;
|
|
1615
|
+
// The app variant's fields have no meaning on an inline form: the form IS the
|
|
1616
|
+
// outcomes (`actions`) and what the human sees (`input`).
|
|
1617
|
+
const appOnly = ['appVersion', 'actions', 'key', 'input'].filter((k) => opts[k] !== undefined);
|
|
1618
|
+
if (appOnly.length) {
|
|
1619
|
+
throw new Error(`humanTask "${id}": ${appOnly.join(', ')} belong to an app-backed task. On an inline form, put the outcomes in form.outcomes and what the human sees in form.fields.`);
|
|
1620
|
+
}
|
|
1621
|
+
const rows = quickHumanTaskRows(id, this._sugar.processId, o);
|
|
1622
|
+
return this.pushActivity({
|
|
1623
|
+
kind: 'typed',
|
|
1624
|
+
id,
|
|
1625
|
+
name: o.name,
|
|
1626
|
+
type: 'Actions.HITL',
|
|
1627
|
+
typeVersion: rows.typeVersion,
|
|
1628
|
+
context: {},
|
|
1629
|
+
contextRows: rows.contextRows,
|
|
1630
|
+
inputSchema: rows.inputSchema,
|
|
1631
|
+
inputs: {},
|
|
1632
|
+
inputRows: rows.inputRows,
|
|
1633
|
+
outputRows: rows.outputRows,
|
|
1634
|
+
mappedOutputRows: rows.mappedOutputRows,
|
|
1635
|
+
skipCondition: o.skipCondition,
|
|
1636
|
+
tags: o.tags,
|
|
1637
|
+
retry: o.retry,
|
|
1638
|
+
errorMapping: o.errorMapping,
|
|
1639
|
+
loop: o.loop,
|
|
1640
|
+
}, body);
|
|
1641
|
+
}
|
|
1642
|
+
opts = opts;
|
|
1565
1643
|
return this.pushActivity({
|
|
1566
1644
|
kind: 'typed',
|
|
1567
1645
|
id,
|
|
@@ -2612,7 +2690,7 @@ export class BpmnBuilder extends ScopeBuilder {
|
|
|
2612
2690
|
* @returns The top-level builder.
|
|
2613
2691
|
*/
|
|
2614
2692
|
constructor(_id) {
|
|
2615
|
-
super(new DefinitionsRegistry(), new BindingsRegistry());
|
|
2693
|
+
super(new DefinitionsRegistry(), new BindingsRegistry(), undefined, 'explicit', new SugarRegistry(_id));
|
|
2616
2694
|
this._id = _id;
|
|
2617
2695
|
}
|
|
2618
2696
|
/**
|
|
@@ -35,10 +35,11 @@ export function connectorOutputVars(n) {
|
|
|
35
35
|
*/
|
|
36
36
|
export function typedNodeDeclaredVars(n) {
|
|
37
37
|
// Spelled-out rows REPLACE the derived pair, so they are the whole answer.
|
|
38
|
+
const mapped = (n.mappedOutputRows ?? []).map((r) => r.var).filter((v) => v !== undefined);
|
|
38
39
|
if (n.outputRows)
|
|
39
|
-
return n.outputRows.map((r) => r.var).filter((v) => v !== undefined);
|
|
40
|
+
return [...n.outputRows.map((r) => r.var).filter((v) => v !== undefined), ...mapped];
|
|
40
41
|
const v = typedNodeOutputVar(n.id, n.type, n.outputVar, n.spec);
|
|
41
|
-
return [...(v ? [v] : []), ...typedNodeAdditionalOutputVars(n.id, n.type, n.spec), ...Object.keys(n.outputs ?? {})];
|
|
42
|
+
return [...(v ? [v] : []), ...typedNodeAdditionalOutputVars(n.id, n.type, n.spec), ...Object.keys(n.outputs ?? {}), ...mapped];
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
44
45
|
* Every variable name a node DECLARES by writing to it — the platform counts a
|
package/dist/bpmn/decompile.js
CHANGED
|
@@ -62,6 +62,7 @@ import { preserveSchemaVersion } from '../schema-version.js';
|
|
|
62
62
|
import { commentText } from '../core/comment-text.js';
|
|
63
63
|
import { tsLiteral, tsText } from '../core/ts-literal.js';
|
|
64
64
|
import { defaultEntryPointId } from './entry-point-id.js';
|
|
65
|
+
import { liftQuickHumanTask } from './human-task-form.js';
|
|
65
66
|
const require = createRequire(import.meta.url);
|
|
66
67
|
const uipathDescriptor = require('./uipath-moddle.v1.json');
|
|
67
68
|
/**
|
|
@@ -79,6 +80,12 @@ let pinExplicitInBodies = false;
|
|
|
79
80
|
* business carrying a document-wide table.
|
|
80
81
|
*/
|
|
81
82
|
let foldedVarSchemas;
|
|
83
|
+
/**
|
|
84
|
+
* The wire type of each ROOT variable the source writes as a `.var()` — every declared one
|
|
85
|
+
* the derivation does not fold away. What `serialize` types a quick human task's mapped
|
|
86
|
+
* `outputs` rows from on the way back, so the lift compares against the same thing.
|
|
87
|
+
*/
|
|
88
|
+
let authoredVarTypes;
|
|
82
89
|
// ─── Source emitters ──────────────────────────────────────────────────────────
|
|
83
90
|
/**
|
|
84
91
|
* Schema bodies that need no declaration, because the platform defines them.
|
|
@@ -759,6 +766,59 @@ function entryPointText(startId, value) {
|
|
|
759
766
|
return 'false';
|
|
760
767
|
return value === defaultEntryPointId(runEntryPoints.builderProcessId, startId) ? undefined : tsText(value);
|
|
761
768
|
}
|
|
769
|
+
/**
|
|
770
|
+
* A quick (inline-form) human task, written back as `.humanTask({ form })` — when the
|
|
771
|
+
* form options reproduce the node's rows exactly, which `liftQuickHumanTask` checks by
|
|
772
|
+
* compiling them. Anything else (a Studio Web task with a `.hitl.json` sidecar, an
|
|
773
|
+
* app-backed task) returns `false` and stays the verbatim `.activity()` below.
|
|
774
|
+
*
|
|
775
|
+
* So does a task whose output variable had its declaration folded onto the row with a
|
|
776
|
+
* schema body (`foldedVarSchemas`): the row carries that schema as `varSchema`, which
|
|
777
|
+
* `.humanTask()` has no option for, and the lift would drop it.
|
|
778
|
+
*
|
|
779
|
+
* @returns Whether the node was written.
|
|
780
|
+
*/
|
|
781
|
+
function emitQuickHumanTask(chain, el, payload) {
|
|
782
|
+
if ((payload.output ?? []).some((r) => r.var !== undefined && foldedVarSchemas?.has(r.var)))
|
|
783
|
+
return false;
|
|
784
|
+
const defined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined));
|
|
785
|
+
const lifted = liftQuickHumanTask({
|
|
786
|
+
id: el.id,
|
|
787
|
+
name: el.name,
|
|
788
|
+
typeVersion: payload.type?.version,
|
|
789
|
+
contextRows: (payload.context?.input ?? []).map((r) => defined({ name: r.name, type: r.type, value: r.value, body: r.body, target: r.target, required: r.required })),
|
|
790
|
+
inputSchema: payload.context?.inputSchema?.body,
|
|
791
|
+
inputRows: (payload.input ?? []).map((r) => defined({ name: r.name, type: r.type, target: r.target, value: r.value, body: r.body })),
|
|
792
|
+
outputRows: (payload.output ?? []).map((r) => defined({
|
|
793
|
+
name: r.name,
|
|
794
|
+
type: r.type,
|
|
795
|
+
var: r.var,
|
|
796
|
+
source: r.source,
|
|
797
|
+
custom: r.custom === true || r.custom === 'true' ? true : undefined,
|
|
798
|
+
description: r.description,
|
|
799
|
+
target: r.target,
|
|
800
|
+
schema: r.body,
|
|
801
|
+
})),
|
|
802
|
+
}, runEntryPoints.builderProcessId, (varId) => authoredVarTypes?.get(varId));
|
|
803
|
+
if (!lifted)
|
|
804
|
+
return false;
|
|
805
|
+
const { form, ...rest } = lifted;
|
|
806
|
+
chain.add(`.humanTask(${tsText(el.id)}, ${opts([
|
|
807
|
+
['name', rest.name !== undefined ? tsText(rest.name) : undefined],
|
|
808
|
+
['title', rest.title !== undefined ? tsText(rest.title) : undefined],
|
|
809
|
+
['form', tsLiteral(form)],
|
|
810
|
+
['priority', rest.priority !== undefined ? tsText(rest.priority) : undefined],
|
|
811
|
+
['labels', rest.labels !== undefined ? tsText(rest.labels) : undefined],
|
|
812
|
+
['outputs', record(rest.outputs)],
|
|
813
|
+
['outputVar', rest.outputVar !== undefined ? tsText(rest.outputVar) : undefined],
|
|
814
|
+
['skipCondition', payload.skipCondition !== undefined ? tsText(payload.skipCondition) : undefined],
|
|
815
|
+
['tags', tagsOf(el)],
|
|
816
|
+
['retry', emitRetry(retryOf(el))],
|
|
817
|
+
['errorMapping', emitErrorMapping(errorMappingOf(el))],
|
|
818
|
+
['loop', emitLoop(el)],
|
|
819
|
+
])})`);
|
|
820
|
+
return true;
|
|
821
|
+
}
|
|
762
822
|
/**
|
|
763
823
|
* A registry-typed node.
|
|
764
824
|
*
|
|
@@ -771,6 +831,8 @@ function entryPointText(startId, value) {
|
|
|
771
831
|
function emitTypedNode(chain, el, payload, type) {
|
|
772
832
|
const spec = registryType(type);
|
|
773
833
|
const id = el.id;
|
|
834
|
+
if (type === 'Actions.HITL' && emitQuickHumanTask(chain, el, payload))
|
|
835
|
+
return;
|
|
774
836
|
// Verbatim: reproduce every context field, in document order, and let the
|
|
775
837
|
// emitter inject nothing. Stripping the ones that match a registry default
|
|
776
838
|
// would be smaller source but a lossy round-trip — the artifact's own emitter
|
|
@@ -2241,6 +2303,9 @@ export async function decompile(xml, options = {}) {
|
|
|
2241
2303
|
// `.schema()` plan when the document repeats it, inline when it does not — so
|
|
2242
2304
|
// folding a declaration onto its row does not un-share a schema 27 nodes use.
|
|
2243
2305
|
foldedVarSchemas = new Map([...folds].map(([id, body]) => [id, schemaPlan.ref.get(String(body)) ?? jsonLiteral(body)]));
|
|
2306
|
+
authoredVarTypes = new Map([...(varsExt?.input ?? []), ...(varsExt?.inputOutput ?? []), ...(varsExt?.output ?? [])]
|
|
2307
|
+
.filter((v) => !derived.has(v.id))
|
|
2308
|
+
.map((v) => [String(v.id), String(v.type)]));
|
|
2244
2309
|
// A folded declaration is not written as a `.var()`, so its POSITION in the block
|
|
2245
2310
|
// would be lost — derived declarations are appended after the declared ones, and the
|
|
2246
2311
|
// designer's order is not recoverable from anything else (it follows the owning
|
|
@@ -2275,6 +2340,7 @@ export async function decompile(xml, options = {}) {
|
|
|
2275
2340
|
}
|
|
2276
2341
|
finally {
|
|
2277
2342
|
foldedVarSchemas = undefined;
|
|
2343
|
+
authoredVarTypes = undefined;
|
|
2278
2344
|
runLibrary = undefined;
|
|
2279
2345
|
}
|
|
2280
2346
|
const importFrom = options.importSpecifier ?? './bpmn-sdk.js';
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* human-task-form — the inline-form ("quick") `Actions.HITL` task, as rows.
|
|
3
|
+
*
|
|
4
|
+
* `.humanTask({ form })` and decompile's lift of a quick task both go through
|
|
5
|
+
* {@link quickHumanTaskRows}, so the rows an author's call compiles to and the rows a
|
|
6
|
+
* lift is checked against cannot drift apart: decompile writes `.humanTask({ form })`
|
|
7
|
+
* only when this function, fed the lifted options, reproduces the file's rows exactly.
|
|
8
|
+
*
|
|
9
|
+
* **The wire shape is the product's own Flow-to-BPMN converter's** (`applyHitlExtension`
|
|
10
|
+
* in `PO.Frontend`, vendored as `local-engine/vendor/flow-to-bpmn.mjs`), not Studio Web's
|
|
11
|
+
* BPMN designer's. Both reach the same engine path, and the difference is where the form
|
|
12
|
+
* lives:
|
|
13
|
+
*
|
|
14
|
+
* - The converter puts it INLINE, in a `__hitlFormSchema` context row. The engine's
|
|
15
|
+
* `TemporalBpmnExecutor.TryResolveInlineSchema` reads that first, in every mode.
|
|
16
|
+
* - Studio Web writes a `<Label>.hitl.json` beside the process plus a `_schemaFileId`
|
|
17
|
+
* context row. The engine finds the file in the package by its `schemaId`, and
|
|
18
|
+
* `_schemaFileId` is a server-assigned designer pointer the engine never reads — so an
|
|
19
|
+
* offline author can only ever write a placeholder there.
|
|
20
|
+
*
|
|
21
|
+
* Inline keeps the whole task in the `.bpmn`, needs no second output file, and is the
|
|
22
|
+
* shape the local engine already runs (`local-engine/src/hitl.ts`). What it gives up is
|
|
23
|
+
* Studio Web's "Edit Schema" canvas, which looks for the sidecar.
|
|
24
|
+
*
|
|
25
|
+
* Either way, the engine takes the quick path only when its `ShouldUseHitlQuickFormSchema`
|
|
26
|
+
* flag is on for the tenant (`HumanInTheLoopActivities`); otherwise it falls back to the
|
|
27
|
+
* Action-App path, which has no app to open.
|
|
28
|
+
*/
|
|
29
|
+
import type { FormFieldSettings, FormFieldType } from '../core/actions.js';
|
|
30
|
+
import type { TypedContextRow, TypedInputRow, TypedOutputRow } from './typed-node.js';
|
|
31
|
+
/** A value the reviewer READS: shown on the form, filled in from the process. */
|
|
32
|
+
export interface HumanTaskShownField extends FormFieldSettings {
|
|
33
|
+
/** Field id — the key the form and its answers use. Must be unique on the form. */
|
|
34
|
+
id: string;
|
|
35
|
+
/** Label the reviewer sees. Defaults to `id`. */
|
|
36
|
+
label?: string;
|
|
37
|
+
/** The field's data type, e.g. `'string'` or `'number'` — the quick-form vocabulary Flow's forms use. */
|
|
38
|
+
type: FormFieldType;
|
|
39
|
+
direction: 'input';
|
|
40
|
+
/**
|
|
41
|
+
* What to show — a `=`-expression, e.g. `'=vars.amount'` or `'=js:vars.total * 1.2'`.
|
|
42
|
+
* Required: a shown field with nothing bound renders empty.
|
|
43
|
+
*/
|
|
44
|
+
value: string;
|
|
45
|
+
}
|
|
46
|
+
/** A value the reviewer FILLS IN, landing in a process variable. */
|
|
47
|
+
export interface HumanTaskAskedField extends FormFieldSettings {
|
|
48
|
+
/** Field id — the key the form and its answers use. Must be unique on the form. */
|
|
49
|
+
id: string;
|
|
50
|
+
/** Label the reviewer sees. Defaults to `id`. */
|
|
51
|
+
label?: string;
|
|
52
|
+
/** The field's data type, e.g. `'string'` or `'number'` — the quick-form vocabulary Flow's forms use. */
|
|
53
|
+
type: FormFieldType;
|
|
54
|
+
direction: 'output';
|
|
55
|
+
/** Reviewer must fill it in before the task can be completed. */
|
|
56
|
+
required?: boolean;
|
|
57
|
+
/** The process variable the answer lands in. Defaults to the field id. */
|
|
58
|
+
variable?: string;
|
|
59
|
+
}
|
|
60
|
+
/** A value the reviewer READS AND CAN CORRECT: pre-filled, editable, and written back. */
|
|
61
|
+
export interface HumanTaskInOutField extends FormFieldSettings {
|
|
62
|
+
/** Field id — the key the form and its answers use. Must be unique on the form. */
|
|
63
|
+
id: string;
|
|
64
|
+
/** Label the reviewer sees. Defaults to `id`. */
|
|
65
|
+
label?: string;
|
|
66
|
+
/** The field's data type, e.g. `'string'` or `'number'` — the quick-form vocabulary Flow's forms use. */
|
|
67
|
+
type: FormFieldType;
|
|
68
|
+
direction: 'inOut';
|
|
69
|
+
/** What to pre-fill — a `=`-expression, e.g. `'=vars.category'`. */
|
|
70
|
+
value: string;
|
|
71
|
+
/** Reviewer must confirm or fill it before the task can be completed. */
|
|
72
|
+
required?: boolean;
|
|
73
|
+
/** The process variable the (possibly corrected) value lands in. Defaults to the field id. */
|
|
74
|
+
variable?: string;
|
|
75
|
+
}
|
|
76
|
+
/** One field of an inline human-task form. */
|
|
77
|
+
export type HumanTaskFormField = HumanTaskShownField | HumanTaskAskedField | HumanTaskInOutField;
|
|
78
|
+
/** One button the reviewer can finish the task with. */
|
|
79
|
+
export type HumanTaskOutcome = string | {
|
|
80
|
+
name: string;
|
|
81
|
+
id?: string;
|
|
82
|
+
};
|
|
83
|
+
/** An inline form — the quick-form variant of `.humanTask()`, which needs no Action App. */
|
|
84
|
+
export interface HumanTaskForm {
|
|
85
|
+
/** The fields, in the order the form shows them. */
|
|
86
|
+
fields: HumanTaskFormField[];
|
|
87
|
+
/**
|
|
88
|
+
* The buttons that finish the task, e.g. `['Approve', 'Reject']`. The one picked is
|
|
89
|
+
* the response's `Action` — map it with `outputs: { decision: '=Action' }`.
|
|
90
|
+
*/
|
|
91
|
+
outcomes: HumanTaskOutcome[];
|
|
92
|
+
/**
|
|
93
|
+
* The form's `hitlSchemaId`, which Action Center caches the form under.
|
|
94
|
+
*
|
|
95
|
+
* Defaults to a v5 UUID derived from the process and task ids, so a rebuild is the
|
|
96
|
+
* same form and the same bytes. Set it only to keep an imported task's id.
|
|
97
|
+
*/
|
|
98
|
+
schemaId?: string;
|
|
99
|
+
}
|
|
100
|
+
/** What `.humanTask({ form })` takes besides the form — the fields it shares with the app variant. */
|
|
101
|
+
export interface QuickHumanTaskInput {
|
|
102
|
+
form: HumanTaskForm;
|
|
103
|
+
/** The task title (`taskTitle`). Defaults to the task's `name`, else its id. */
|
|
104
|
+
title?: string;
|
|
105
|
+
/** Display name of the task. */
|
|
106
|
+
name?: string;
|
|
107
|
+
/** Action Center priority, e.g. `'Medium'`. */
|
|
108
|
+
priority?: string;
|
|
109
|
+
/** Action Center labels, comma-separated. */
|
|
110
|
+
labels?: string;
|
|
111
|
+
/** Extra output rows: variable id → `=`-expression against the response, e.g. `{ decision: '=Action' }`. */
|
|
112
|
+
outputs?: Record<string, string>;
|
|
113
|
+
/** Variable the whole typed response lands in. Defaults to `<id>_processResponse`. */
|
|
114
|
+
outputVar?: string;
|
|
115
|
+
}
|
|
116
|
+
/** The rows a quick human task is written as. */
|
|
117
|
+
export interface QuickHumanTaskRows {
|
|
118
|
+
typeVersion: string;
|
|
119
|
+
contextRows: TypedContextRow[];
|
|
120
|
+
inputSchema: Record<string, unknown>;
|
|
121
|
+
inputRows: TypedInputRow[];
|
|
122
|
+
outputRows: TypedOutputRow[];
|
|
123
|
+
/**
|
|
124
|
+
* The author's `outputs` mappings, written after `outputRows`. Each row's `type` is
|
|
125
|
+
* only the FALLBACK: the serializer types the row from the variable it writes when the
|
|
126
|
+
* author declared that variable (`.var('approved', 'boolean')`), as the app variant's
|
|
127
|
+
* `outputs` are typed — and from the answer field it reads, or `string`, otherwise.
|
|
128
|
+
*/
|
|
129
|
+
mappedOutputRows: TypedOutputRow[];
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The rows a quick human task is written as.
|
|
133
|
+
*
|
|
134
|
+
* @param id - The task's element id.
|
|
135
|
+
* @param processId - The process id, which the default `hitlSchemaId` is derived from.
|
|
136
|
+
* @param input - The form and the task options.
|
|
137
|
+
* @returns The context, payload and output rows, the input schema and the type version.
|
|
138
|
+
* @throws Error when the form is malformed — see {@link validate}.
|
|
139
|
+
*/
|
|
140
|
+
export declare function quickHumanTaskRows(id: string, processId: string, input: QuickHumanTaskInput): QuickHumanTaskRows;
|
|
141
|
+
/** The parts of a typed `Actions.HITL` node decompile reads a quick task back from. */
|
|
142
|
+
export interface QuickHumanTaskSource {
|
|
143
|
+
id: string;
|
|
144
|
+
name?: string;
|
|
145
|
+
typeVersion?: string;
|
|
146
|
+
contextRows: TypedContextRow[];
|
|
147
|
+
inputSchema?: unknown;
|
|
148
|
+
inputRows: TypedInputRow[];
|
|
149
|
+
outputRows: TypedOutputRow[];
|
|
150
|
+
}
|
|
151
|
+
/** A lifted quick task: the `.humanTask()` options that reproduce it. */
|
|
152
|
+
export type LiftedQuickHumanTask = QuickHumanTaskInput;
|
|
153
|
+
/**
|
|
154
|
+
* Read a quick task back as `.humanTask({ form })` options — or `undefined` when its
|
|
155
|
+
* rows are anything but what those options compile to.
|
|
156
|
+
*
|
|
157
|
+
* Best effort by construction, and safe because of the last step: the lifted options
|
|
158
|
+
* are run through {@link quickHumanTaskRows} and the result must equal the node's rows,
|
|
159
|
+
* order and all. A Studio Web task (sidecar schema, `_schemaFileId`, no response row)
|
|
160
|
+
* fails that and stays the verbatim `.activity()` it was.
|
|
161
|
+
*
|
|
162
|
+
* @param node - The node's rows, as decompile read them.
|
|
163
|
+
* @param processId - The id the decompiled `bpmn(…)` call will carry.
|
|
164
|
+
* @param authoredVarType - The wire type of each variable the decompiled source will
|
|
165
|
+
* DECLARE with `.var()` — what the serializer types a mapped `outputs` row from on the
|
|
166
|
+
* way back. A variable decompile folds away is not one: its row is re-typed from the
|
|
167
|
+
* fallback, so it has to already carry that type to match.
|
|
168
|
+
* @returns The options, or `undefined` to keep the node verbatim.
|
|
169
|
+
*/
|
|
170
|
+
export declare function liftQuickHumanTask(node: QuickHumanTaskSource, processId: string, authoredVarType?: (varId: string) => string | undefined): LiftedQuickHumanTask | undefined;
|