@servicenow/sdk-build-plugins 4.6.0 → 4.7.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/acl-plugin.js +3 -4
- package/dist/acl-plugin.js.map +1 -1
- package/dist/applicability-plugin.js +0 -2
- package/dist/applicability-plugin.js.map +1 -1
- package/dist/application-menu-plugin.js +0 -2
- package/dist/application-menu-plugin.js.map +1 -1
- package/dist/arrow-function-plugin.js +0 -1
- package/dist/arrow-function-plugin.js.map +1 -1
- package/dist/atf/test-plugin.js +6 -10
- package/dist/atf/test-plugin.js.map +1 -1
- package/dist/basic-syntax-plugin.js +10 -4
- package/dist/basic-syntax-plugin.js.map +1 -1
- package/dist/business-rule-plugin.js +0 -1
- package/dist/business-rule-plugin.js.map +1 -1
- package/dist/call-expression-plugin.js +0 -1
- package/dist/call-expression-plugin.js.map +1 -1
- package/dist/claims-plugin.js +0 -1
- package/dist/claims-plugin.js.map +1 -1
- package/dist/client-script-plugin.js +0 -1
- package/dist/client-script-plugin.js.map +1 -1
- package/dist/column-plugin.js +120 -49
- package/dist/column-plugin.js.map +1 -1
- package/dist/cross-scope-privilege-plugin.js +0 -1
- package/dist/cross-scope-privilege-plugin.js.map +1 -1
- package/dist/dashboard/dashboard-plugin.js +0 -2
- package/dist/dashboard/dashboard-plugin.js.map +1 -1
- package/dist/data-plugin.js +0 -1
- package/dist/data-plugin.js.map +1 -1
- package/dist/data-policy-plugin.d.ts +2 -0
- package/dist/data-policy-plugin.js +276 -0
- package/dist/data-policy-plugin.js.map +1 -0
- package/dist/email-notification-plugin.js +2 -3
- package/dist/email-notification-plugin.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-constants.d.ts +2 -0
- package/dist/flow/flow-logic/flow-logic-constants.js +6 -1
- package/dist/flow/flow-logic/flow-logic-constants.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-diagnostics.js +192 -56
- package/dist/flow/flow-logic/flow-logic-diagnostics.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.d.ts +2 -1
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.js +44 -5
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-plugin.js +279 -29
- package/dist/flow/flow-logic/flow-logic-plugin.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-shapes.d.ts +15 -0
- package/dist/flow/flow-logic/flow-logic-shapes.js +25 -1
- package/dist/flow/flow-logic/flow-logic-shapes.js.map +1 -1
- package/dist/flow/plugins/approval-rules-plugin.js +0 -1
- package/dist/flow/plugins/approval-rules-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-action-definition-plugin.js +804 -205
- package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-data-pill-plugin.js +3 -5
- package/dist/flow/plugins/flow-data-pill-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-definition-plugin.js +84 -17
- package/dist/flow/plugins/flow-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-diagnostics-plugin.js +65 -3
- package/dist/flow/plugins/flow-diagnostics-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-instance-plugin.js +13 -5
- package/dist/flow/plugins/flow-instance-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-trigger-instance-plugin.js +0 -1
- package/dist/flow/plugins/flow-trigger-instance-plugin.js.map +1 -1
- package/dist/flow/plugins/inline-script-plugin.js +0 -1
- package/dist/flow/plugins/inline-script-plugin.js.map +1 -1
- package/dist/flow/plugins/step-definition-plugin.js +0 -2
- package/dist/flow/plugins/step-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/step-instance-plugin.js +216 -77
- package/dist/flow/plugins/step-instance-plugin.js.map +1 -1
- package/dist/flow/plugins/trigger-plugin.js +0 -2
- package/dist/flow/plugins/trigger-plugin.js.map +1 -1
- package/dist/flow/plugins/wfa-datapill-plugin.js +0 -1
- package/dist/flow/plugins/wfa-datapill-plugin.js.map +1 -1
- package/dist/flow/utils/datapill-transformer.js +9 -5
- package/dist/flow/utils/datapill-transformer.js.map +1 -1
- package/dist/flow/utils/flow-constants.d.ts +12 -0
- package/dist/flow/utils/flow-constants.js +17 -3
- package/dist/flow/utils/flow-constants.js.map +1 -1
- package/dist/flow/utils/flow-io-to-record.d.ts +1 -1
- package/dist/flow/utils/flow-io-to-record.js +21 -13
- package/dist/flow/utils/flow-io-to-record.js.map +1 -1
- package/dist/flow/utils/flow-pill-utils.d.ts +26 -0
- package/dist/flow/utils/flow-pill-utils.js +50 -0
- package/dist/flow/utils/flow-pill-utils.js.map +1 -0
- package/dist/flow/utils/flow-stage-processor.d.ts +138 -0
- package/dist/flow/utils/flow-stage-processor.js +665 -0
- package/dist/flow/utils/flow-stage-processor.js.map +1 -0
- package/dist/flow/utils/pill-string-parser.js +28 -43
- package/dist/flow/utils/pill-string-parser.js.map +1 -1
- package/dist/flow/utils/utils.d.ts +11 -6
- package/dist/flow/utils/utils.js +37 -28
- package/dist/flow/utils/utils.js.map +1 -1
- package/dist/form-plugin.js +4 -14
- package/dist/form-plugin.js.map +1 -1
- package/dist/html-import-plugin.js +0 -1
- package/dist/html-import-plugin.js.map +1 -1
- package/dist/import-sets-plugin.js +0 -2
- package/dist/import-sets-plugin.js.map +1 -1
- package/dist/inbound-email-action-plugin.js +0 -1
- package/dist/inbound-email-action-plugin.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/instance-scan-plugin.js +0 -7
- package/dist/instance-scan-plugin.js.map +1 -1
- package/dist/json-plugin.js +0 -1
- package/dist/json-plugin.js.map +1 -1
- package/dist/list-plugin.js +4 -1
- package/dist/list-plugin.js.map +1 -1
- package/dist/now-attach-plugin.js +0 -1
- package/dist/now-attach-plugin.js.map +1 -1
- package/dist/now-config-plugin.js +1 -1
- package/dist/now-config-plugin.js.map +1 -1
- package/dist/now-id-plugin.js +0 -1
- package/dist/now-id-plugin.js.map +1 -1
- package/dist/now-include-plugin.js +0 -1
- package/dist/now-include-plugin.js.map +1 -1
- package/dist/now-ref-plugin.js +0 -1
- package/dist/now-ref-plugin.js.map +1 -1
- package/dist/now-unresolved-plugin.js +0 -1
- package/dist/now-unresolved-plugin.js.map +1 -1
- package/dist/package-json-plugin.js +3 -2
- package/dist/package-json-plugin.js.map +1 -1
- package/dist/property-plugin.js +0 -2
- package/dist/property-plugin.js.map +1 -1
- package/dist/record-plugin.d.ts +2 -0
- package/dist/record-plugin.js +5 -4
- package/dist/record-plugin.js.map +1 -1
- package/dist/repack/lint/Rules.d.ts +1 -2
- package/dist/rest-api-plugin.js +6 -5
- package/dist/rest-api-plugin.js.map +1 -1
- package/dist/role-plugin.js +0 -1
- package/dist/role-plugin.js.map +1 -1
- package/dist/schedule-script/scheduled-script-plugin.js +5 -4
- package/dist/schedule-script/scheduled-script-plugin.js.map +1 -1
- package/dist/script-action-plugin.js +0 -2
- package/dist/script-action-plugin.js.map +1 -1
- package/dist/script-include-plugin.js +4 -4
- package/dist/script-include-plugin.js.map +1 -1
- package/dist/server-module-plugin/index.js +2 -3
- package/dist/server-module-plugin/index.js.map +1 -1
- package/dist/service-catalog/catalog-clientscript-plugin.js +2 -4
- package/dist/service-catalog/catalog-clientscript-plugin.js.map +1 -1
- package/dist/service-catalog/catalog-item-plugin.js +0 -2
- package/dist/service-catalog/catalog-item-plugin.js.map +1 -1
- package/dist/service-catalog/catalog-ui-policy-plugin.js +2 -4
- package/dist/service-catalog/catalog-ui-policy-plugin.js.map +1 -1
- package/dist/service-catalog/sc-record-producer-plugin.js +0 -2
- package/dist/service-catalog/sc-record-producer-plugin.js.map +1 -1
- package/dist/service-catalog/service-catalog-base.d.ts +2 -2
- package/dist/service-catalog/service-catalog-base.js +2 -2
- package/dist/service-catalog/service-catalog-base.js.map +1 -1
- package/dist/service-catalog/utils.js +1 -1
- package/dist/service-catalog/utils.js.map +1 -1
- package/dist/service-catalog/variable-set-plugin.js +0 -2
- package/dist/service-catalog/variable-set-plugin.js.map +1 -1
- package/dist/service-portal/angular-provider-plugin.js +0 -2
- package/dist/service-portal/angular-provider-plugin.js.map +1 -1
- package/dist/service-portal/dependency-plugin.js +3 -5
- package/dist/service-portal/dependency-plugin.js.map +1 -1
- package/dist/service-portal/header-footer-plugin.js +3 -5
- package/dist/service-portal/header-footer-plugin.js.map +1 -1
- package/dist/service-portal/menu-plugin.js +0 -1
- package/dist/service-portal/menu-plugin.js.map +1 -1
- package/dist/service-portal/page-plugin.js +0 -1
- package/dist/service-portal/page-plugin.js.map +1 -1
- package/dist/service-portal/page-route-map-plugin.js +0 -1
- package/dist/service-portal/page-route-map-plugin.js.map +1 -1
- package/dist/service-portal/portal-plugin.js +0 -2
- package/dist/service-portal/portal-plugin.js.map +1 -1
- package/dist/service-portal/theme-plugin.js +0 -2
- package/dist/service-portal/theme-plugin.js.map +1 -1
- package/dist/service-portal/widget-plugin.js +3 -5
- package/dist/service-portal/widget-plugin.js.map +1 -1
- package/dist/sla-plugin.js +0 -2
- package/dist/sla-plugin.js.map +1 -1
- package/dist/static-content-plugin.js +32 -3
- package/dist/static-content-plugin.js.map +1 -1
- package/dist/table-plugin.js +303 -66
- package/dist/table-plugin.js.map +1 -1
- package/dist/ui-action-plugin.js +26 -17
- package/dist/ui-action-plugin.js.map +1 -1
- package/dist/ui-page-plugin.js +159 -17
- package/dist/ui-page-plugin.js.map +1 -1
- package/dist/ui-policy-plugin.js +28 -97
- package/dist/ui-policy-plugin.js.map +1 -1
- package/dist/user-preference-plugin.js +0 -2
- package/dist/user-preference-plugin.js.map +1 -1
- package/dist/utils.d.ts +5 -9
- package/dist/utils.js +38 -11
- package/dist/utils.js.map +1 -1
- package/dist/ux-list-menu-config-plugin.js +0 -2
- package/dist/ux-list-menu-config-plugin.js.map +1 -1
- package/dist/view-plugin.js +0 -1
- package/dist/view-plugin.js.map +1 -1
- package/dist/workspace-plugin.js +0 -2
- package/dist/workspace-plugin.js.map +1 -1
- package/package.json +6 -6
- package/src/acl-plugin.ts +4 -5
- package/src/applicability-plugin.ts +0 -2
- package/src/application-menu-plugin.ts +0 -2
- package/src/arrow-function-plugin.ts +0 -1
- package/src/atf/test-plugin.ts +6 -11
- package/src/basic-syntax-plugin.ts +11 -4
- package/src/business-rule-plugin.ts +1 -2
- package/src/call-expression-plugin.ts +0 -1
- package/src/claims-plugin.ts +0 -1
- package/src/client-script-plugin.ts +1 -2
- package/src/column-plugin.ts +163 -76
- package/src/cross-scope-privilege-plugin.ts +1 -2
- package/src/dashboard/dashboard-plugin.ts +0 -2
- package/src/data-plugin.ts +0 -1
- package/src/data-policy-plugin.ts +333 -0
- package/src/email-notification-plugin.ts +8 -4
- package/src/flow/flow-logic/flow-logic-constants.ts +6 -0
- package/src/flow/flow-logic/flow-logic-diagnostics.ts +236 -58
- package/src/flow/flow-logic/flow-logic-plugin-helpers.ts +59 -6
- package/src/flow/flow-logic/flow-logic-plugin.ts +368 -38
- package/src/flow/flow-logic/flow-logic-shapes.ts +25 -0
- package/src/flow/plugins/approval-rules-plugin.ts +0 -1
- package/src/flow/plugins/flow-action-definition-plugin.ts +940 -208
- package/src/flow/plugins/flow-data-pill-plugin.ts +3 -5
- package/src/flow/plugins/flow-definition-plugin.ts +159 -26
- package/src/flow/plugins/flow-diagnostics-plugin.ts +89 -3
- package/src/flow/plugins/flow-instance-plugin.ts +26 -12
- package/src/flow/plugins/flow-trigger-instance-plugin.ts +0 -1
- package/src/flow/plugins/inline-script-plugin.ts +0 -1
- package/src/flow/plugins/step-definition-plugin.ts +0 -2
- package/src/flow/plugins/step-instance-plugin.ts +259 -65
- package/src/flow/plugins/trigger-plugin.ts +0 -2
- package/src/flow/plugins/wfa-datapill-plugin.ts +0 -1
- package/src/flow/utils/datapill-transformer.ts +13 -5
- package/src/flow/utils/flow-constants.ts +19 -1
- package/src/flow/utils/flow-io-to-record.ts +29 -19
- package/src/flow/utils/flow-pill-utils.ts +48 -0
- package/src/flow/utils/flow-stage-processor.ts +831 -0
- package/src/flow/utils/pill-string-parser.ts +29 -47
- package/src/flow/utils/utils.ts +39 -35
- package/src/form-plugin.ts +5 -15
- package/src/html-import-plugin.ts +0 -1
- package/src/import-sets-plugin.ts +0 -2
- package/src/inbound-email-action-plugin.ts +1 -2
- package/src/index.ts +7 -1
- package/src/instance-scan-plugin.ts +0 -7
- package/src/json-plugin.ts +0 -1
- package/src/list-plugin.ts +6 -2
- package/src/now-attach-plugin.ts +0 -1
- package/src/now-config-plugin.ts +1 -1
- package/src/now-id-plugin.ts +0 -1
- package/src/now-include-plugin.ts +0 -1
- package/src/now-ref-plugin.ts +0 -1
- package/src/now-unresolved-plugin.ts +0 -1
- package/src/package-json-plugin.ts +8 -3
- package/src/property-plugin.ts +0 -2
- package/src/record-plugin.ts +14 -6
- package/src/repack/lint/Rules.ts +1 -1
- package/src/rest-api-plugin.ts +7 -6
- package/src/role-plugin.ts +1 -2
- package/src/schedule-script/scheduled-script-plugin.ts +11 -5
- package/src/script-action-plugin.ts +0 -2
- package/src/script-include-plugin.ts +8 -4
- package/src/server-module-plugin/index.ts +2 -3
- package/src/service-catalog/catalog-clientscript-plugin.ts +2 -4
- package/src/service-catalog/catalog-item-plugin.ts +0 -2
- package/src/service-catalog/catalog-ui-policy-plugin.ts +2 -4
- package/src/service-catalog/sc-record-producer-plugin.ts +0 -2
- package/src/service-catalog/service-catalog-base.ts +2 -2
- package/src/service-catalog/utils.ts +1 -1
- package/src/service-catalog/variable-set-plugin.ts +0 -2
- package/src/service-portal/angular-provider-plugin.ts +0 -2
- package/src/service-portal/dependency-plugin.ts +0 -2
- package/src/service-portal/header-footer-plugin.ts +0 -2
- package/src/service-portal/menu-plugin.ts +1 -2
- package/src/service-portal/page-plugin.ts +1 -2
- package/src/service-portal/page-route-map-plugin.ts +1 -2
- package/src/service-portal/portal-plugin.ts +0 -2
- package/src/service-portal/theme-plugin.ts +0 -2
- package/src/service-portal/widget-plugin.ts +0 -2
- package/src/sla-plugin.ts +0 -2
- package/src/static-content-plugin.ts +37 -4
- package/src/table-plugin.ts +371 -92
- package/src/ui-action-plugin.ts +30 -17
- package/src/ui-page-plugin.ts +188 -20
- package/src/ui-policy-plugin.ts +33 -130
- package/src/user-preference-plugin.ts +0 -2
- package/src/utils.ts +48 -11
- package/src/ux-list-menu-config-plugin.ts +0 -2
- package/src/view-plugin.ts +0 -1
- package/src/workspace-plugin.ts +0 -2
|
@@ -17,27 +17,34 @@ import {
|
|
|
17
17
|
type Shape,
|
|
18
18
|
} from '@servicenow/sdk-build-core'
|
|
19
19
|
import { buildVariableRecords, buildVariableShapes, complexObjectMatchesIoRecord } from '../utils/flow-io-to-record'
|
|
20
|
+
import { builtInComplexObjects } from '../utils/built-in-complex-objects'
|
|
20
21
|
import { generateXML } from '../utils/flow-to-xml'
|
|
21
22
|
import {
|
|
22
23
|
slugifyString,
|
|
23
24
|
BUILT_IN_STEP_DEFINITIONS,
|
|
24
25
|
BUILT_IN_STEP_SYS_ID_NAME_MAP,
|
|
25
|
-
CORE_ACTIONS_SYS_ID_NAME_MAP,
|
|
26
26
|
ELEMENT_MAPPING_FIELD_ALIASES,
|
|
27
|
+
ASSIGN_ACTION_OUTPUTS_CALLEE,
|
|
28
|
+
ERROR_EVALUATION_CALLEE,
|
|
29
|
+
STEP_DEF_INPUT_TABLE_PREFIX,
|
|
30
|
+
EXT_INPUT_TABLE_PREFIX,
|
|
31
|
+
ACTION_OUTPUT_TABLE_PREFIX,
|
|
27
32
|
getVarEntryName,
|
|
28
33
|
getVarEntryType,
|
|
29
34
|
} from '../utils/flow-constants'
|
|
35
|
+
import { STEP_PILL_TYPE_REGEX, stripPillType, collectPillTypes } from '../utils/flow-pill-utils'
|
|
30
36
|
import { COLUMN_TYPE_TO_API } from '../../column/column-helper'
|
|
31
37
|
import { getAttributeValue } from '../utils/schema-to-flow-object'
|
|
32
38
|
import { normalizeInputValue } from './flow-instance-plugin'
|
|
39
|
+
import { ApprovalRulesShape, ApprovalDueDateShape } from '../utils/flow-shapes'
|
|
33
40
|
import { ArrowFunctionShape } from '../../arrow-function-plugin'
|
|
34
|
-
import { createSdkDocEntry } from '../../utils'
|
|
35
41
|
import { FDInlineScriptCallShape } from './inline-script-plugin'
|
|
36
42
|
import { StepInstanceShape, StepInstancePlugin } from './step-instance-plugin'
|
|
37
43
|
import { NowIdShape } from '../../now-id-plugin'
|
|
38
44
|
import { NowIncludeShape } from '../../now-include-plugin'
|
|
39
45
|
import { getBuiltInStepIdentifier, getIdentifierFromRecord } from '../utils/utils'
|
|
40
46
|
import { convertPillStringToShape, detectPillPattern } from '../utils/pill-string-parser'
|
|
47
|
+
import { PillShape } from '../utils/data-pill-shapes'
|
|
41
48
|
import { createLableCacheNameToTypeMap } from '../utils/label-cache-parser'
|
|
42
49
|
import { COLUMN_API_TO_TYPE } from '../../column/column-helper'
|
|
43
50
|
import { wrapWithDataPillCall, extractDataPillNames } from '../utils/pill-shape-helpers'
|
|
@@ -187,27 +194,7 @@ function resolveAnyPillFromShape(
|
|
|
187
194
|
return { pill: `{{step[${stepCid}].${pathParts.join('.')}${typeSuffix}}}`, isStep: true }
|
|
188
195
|
}
|
|
189
196
|
|
|
190
|
-
|
|
191
|
-
* Strips the |type suffix from a pill string.
|
|
192
|
-
* e.g., "{{step[CID].record.number|string}}" → "{{step[CID].record.number}}"
|
|
193
|
-
* Note: Mirrors stripPillType in step-instance-plugin.ts (kept separate to avoid exporting private functions).
|
|
194
|
-
*/
|
|
195
|
-
function stripPillTypeSuffix(pill: string): string {
|
|
196
|
-
return pill.replace(/\|[^}]+/, '')
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/** Regex for extracting step pill type annotations — same pattern as STEP_PILL_TYPE_REGEX in step-instance-plugin.ts */
|
|
200
|
-
const STEP_PILL_WITH_TYPE_REGEX = /\{\{step\[([^\]]+)\]\.([^|}]+)(?:\|([^}]+))?\}\}/g
|
|
201
|
-
|
|
202
|
-
/** Extracts the step pill type annotation from a pill string and stores it in pillTypeMap for label_cache. */
|
|
203
|
-
function collectStepPillType(pill: string, pillTypeMap: Map<string, string>): void {
|
|
204
|
-
for (const match of pill.matchAll(STEP_PILL_WITH_TYPE_REGEX)) {
|
|
205
|
-
const [, cid, pillPath, dataType] = match
|
|
206
|
-
if (cid && pillPath && dataType) {
|
|
207
|
-
pillTypeMap.set(`${cid}::${pillPath}`, dataType)
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
197
|
+
// stripPillType, collectPillTypes, and STEP_PILL_TYPE_REGEX are imported from ../utils/flow-pill-utils
|
|
211
198
|
|
|
212
199
|
/** Creates a sys_element_mapping record — shared by all cases in resolveUnresolvedStepPills. */
|
|
213
200
|
function createElementMapping(
|
|
@@ -221,7 +208,7 @@ function createElementMapping(
|
|
|
221
208
|
source: Shape,
|
|
222
209
|
field: string,
|
|
223
210
|
id: string,
|
|
224
|
-
|
|
211
|
+
mappingTable: string,
|
|
225
212
|
value: string
|
|
226
213
|
): Promise<Record> {
|
|
227
214
|
return factory.createRecord({
|
|
@@ -230,47 +217,46 @@ function createElementMapping(
|
|
|
230
217
|
properties: {
|
|
231
218
|
field,
|
|
232
219
|
id,
|
|
233
|
-
table:
|
|
220
|
+
table: mappingTable,
|
|
234
221
|
value,
|
|
235
222
|
},
|
|
236
223
|
})
|
|
237
224
|
}
|
|
238
225
|
|
|
239
226
|
/**
|
|
240
|
-
* Resolves a TemplateExpressionShape
|
|
241
|
-
*
|
|
242
|
-
*
|
|
227
|
+
* Resolves ALL pills in a TemplateExpressionShape — both action pills (PillShape) and
|
|
228
|
+
* step pills (wfa.dataPill CallExpressionShape). Returns the full resolved pill string
|
|
229
|
+
* with type suffixes stripped. Plain text spans are preserved verbatim.
|
|
243
230
|
*/
|
|
244
|
-
function
|
|
231
|
+
function resolveAllPillsInTemplate(
|
|
245
232
|
templateShape: TemplateExpressionShape,
|
|
246
233
|
cidMap: Map<string, string>,
|
|
247
234
|
pillTypeMap?: Map<string, string>
|
|
248
|
-
):
|
|
235
|
+
): string {
|
|
249
236
|
let result = templateShape.getLiteralText()
|
|
250
|
-
let hasStepPills = false
|
|
251
237
|
for (const span of templateShape.getSpans()) {
|
|
252
238
|
const expr = span.getExpression()
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if (
|
|
256
|
-
|
|
257
|
-
collectStepPillType(resolved.pill, pillTypeMap)
|
|
258
|
-
}
|
|
259
|
-
hasStepPills = true
|
|
239
|
+
if (expr instanceof PillShape) {
|
|
240
|
+
const raw = expr.getValue()
|
|
241
|
+
if (pillTypeMap) {
|
|
242
|
+
collectPillTypes(raw, pillTypeMap)
|
|
260
243
|
}
|
|
261
|
-
result +=
|
|
244
|
+
result += stripPillType(raw)
|
|
262
245
|
} else {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
246
|
+
const resolved = resolveAnyPillFromShape(expr as Shape, cidMap)
|
|
247
|
+
if (resolved) {
|
|
248
|
+
if (resolved.isStep && pillTypeMap) {
|
|
249
|
+
collectPillTypes(resolved.pill, pillTypeMap)
|
|
250
|
+
}
|
|
251
|
+
result += stripPillType(resolved.pill)
|
|
252
|
+
} else {
|
|
253
|
+
const val = String(expr.getValue?.() ?? '')
|
|
254
|
+
result += val.startsWith('{{') ? stripPillType(val) : val
|
|
255
|
+
}
|
|
267
256
|
}
|
|
268
257
|
result += span.getLiteralText()
|
|
269
258
|
}
|
|
270
|
-
|
|
271
|
-
return undefined
|
|
272
|
-
}
|
|
273
|
-
return { result, hasStepPills }
|
|
259
|
+
return result
|
|
274
260
|
}
|
|
275
261
|
|
|
276
262
|
/**
|
|
@@ -311,6 +297,58 @@ async function resolveUnresolvedStepPills(
|
|
|
311
297
|
|
|
312
298
|
const valuesProperties = inputs.properties({ resolve: false })
|
|
313
299
|
|
|
300
|
+
// Handle inputVariables — nested object where each entry's `value` may contain step pills.
|
|
301
|
+
// Ext inputs use a different element_mapping table than regular step definition inputs.
|
|
302
|
+
const inputVariablesShape = valuesProperties['inputVariables']
|
|
303
|
+
if (inputVariablesShape) {
|
|
304
|
+
const inputVarObj = inputVariablesShape.asObject()
|
|
305
|
+
const inputVarProps = inputVarObj.properties({ resolve: false })
|
|
306
|
+
const extInputTableName = `${EXT_INPUT_TABLE_PREFIX}${stepInstanceSysId}`
|
|
307
|
+
|
|
308
|
+
for (const [varName, configShapeRaw] of Object.entries(inputVarProps)) {
|
|
309
|
+
const configObj = configShapeRaw.asObject()
|
|
310
|
+
const varValueShape = configObj.properties({ resolve: false })['value']
|
|
311
|
+
if (!varValueShape) {
|
|
312
|
+
continue
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const resolved = resolveAnyPillFromShape(varValueShape, cidMap)
|
|
316
|
+
if (resolved?.isStep) {
|
|
317
|
+
collectPillTypes(resolved.pill, pillTypeMap)
|
|
318
|
+
newRecords.push(
|
|
319
|
+
await createElementMapping(
|
|
320
|
+
factory,
|
|
321
|
+
stepShape,
|
|
322
|
+
varName,
|
|
323
|
+
stepInstanceSysId,
|
|
324
|
+
extInputTableName,
|
|
325
|
+
stripPillType(resolved.pill)
|
|
326
|
+
)
|
|
327
|
+
)
|
|
328
|
+
} else if (varValueShape.is(TemplateExpressionShape)) {
|
|
329
|
+
const resolvedText = resolveAllPillsInTemplate(
|
|
330
|
+
varValueShape as TemplateExpressionShape,
|
|
331
|
+
cidMap,
|
|
332
|
+
pillTypeMap
|
|
333
|
+
)
|
|
334
|
+
if (resolvedText.includes('{{step[')) {
|
|
335
|
+
newRecords.push(
|
|
336
|
+
await createElementMapping(
|
|
337
|
+
factory,
|
|
338
|
+
stepShape,
|
|
339
|
+
varName,
|
|
340
|
+
stepInstanceSysId,
|
|
341
|
+
extInputTableName,
|
|
342
|
+
resolvedText
|
|
343
|
+
)
|
|
344
|
+
)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const stepDefTableName = `${STEP_DEF_INPUT_TABLE_PREFIX}${stepDefinitionSysId}`
|
|
351
|
+
|
|
314
352
|
for (const [key, valueShape] of Object.entries(valuesProperties)) {
|
|
315
353
|
if (key === 'inputVariables' || key === 'outputVariables' || key === 'errorHandlingType') {
|
|
316
354
|
continue
|
|
@@ -319,15 +357,15 @@ async function resolveUnresolvedStepPills(
|
|
|
319
357
|
// Case 1: Simple step pill — wfa.dataPill(stepVar.prop, 'type')
|
|
320
358
|
const resolved = resolveAnyPillFromShape(valueShape, cidMap)
|
|
321
359
|
if (resolved?.isStep) {
|
|
322
|
-
|
|
360
|
+
collectPillTypes(resolved.pill, pillTypeMap)
|
|
323
361
|
newRecords.push(
|
|
324
362
|
await createElementMapping(
|
|
325
363
|
factory,
|
|
326
364
|
stepShape,
|
|
327
365
|
key,
|
|
328
366
|
stepInstanceSysId,
|
|
329
|
-
|
|
330
|
-
|
|
367
|
+
stepDefTableName,
|
|
368
|
+
stripPillType(resolved.pill)
|
|
331
369
|
)
|
|
332
370
|
)
|
|
333
371
|
continue
|
|
@@ -335,20 +373,22 @@ async function resolveUnresolvedStepPills(
|
|
|
335
373
|
|
|
336
374
|
// Case 2: TemplateExpressionShape with step pills
|
|
337
375
|
if (valueShape.is(TemplateExpressionShape)) {
|
|
338
|
-
const
|
|
376
|
+
const resolvedText = resolveAllPillsInTemplate(
|
|
339
377
|
valueShape as TemplateExpressionShape,
|
|
340
378
|
cidMap,
|
|
341
379
|
pillTypeMap
|
|
342
380
|
)
|
|
343
|
-
if
|
|
381
|
+
// Only emit if step pills were resolved — action-only pills are already
|
|
382
|
+
// handled by SDK auto-processing.
|
|
383
|
+
if (resolvedText.includes('{{step[')) {
|
|
344
384
|
newRecords.push(
|
|
345
385
|
await createElementMapping(
|
|
346
386
|
factory,
|
|
347
387
|
stepShape,
|
|
348
388
|
key,
|
|
349
389
|
stepInstanceSysId,
|
|
350
|
-
|
|
351
|
-
|
|
390
|
+
stepDefTableName,
|
|
391
|
+
resolvedText
|
|
352
392
|
)
|
|
353
393
|
)
|
|
354
394
|
}
|
|
@@ -364,25 +404,22 @@ async function resolveUnresolvedStepPills(
|
|
|
364
404
|
for (const [field, fieldShape] of templateObj.entries({ resolve: false })) {
|
|
365
405
|
const fieldResolved = resolveAnyPillFromShape(fieldShape, cidMap)
|
|
366
406
|
if (fieldResolved?.isStep) {
|
|
367
|
-
|
|
368
|
-
entries.push(`${field}=${
|
|
407
|
+
collectPillTypes(fieldResolved.pill, pillTypeMap)
|
|
408
|
+
entries.push(`${field}=${stripPillType(fieldResolved.pill)}`)
|
|
369
409
|
hasStepPills = true
|
|
370
410
|
} else if (fieldShape.is(TemplateExpressionShape)) {
|
|
371
|
-
const
|
|
411
|
+
const resolvedText = resolveAllPillsInTemplate(
|
|
372
412
|
fieldShape as TemplateExpressionShape,
|
|
373
413
|
cidMap,
|
|
374
414
|
pillTypeMap
|
|
375
415
|
)
|
|
376
|
-
|
|
377
|
-
|
|
416
|
+
entries.push(`${field}=${resolvedText}`)
|
|
417
|
+
if (resolvedText.includes('{{step[')) {
|
|
378
418
|
hasStepPills = true
|
|
379
|
-
} else {
|
|
380
|
-
const val = fieldShape.getValue?.()
|
|
381
|
-
entries.push(`${field}=${String(val ?? '')}`)
|
|
382
419
|
}
|
|
383
420
|
} else {
|
|
384
421
|
const val = String(fieldShape.getValue?.() ?? '')
|
|
385
|
-
entries.push(`${field}=${val.startsWith('{{') ?
|
|
422
|
+
entries.push(`${field}=${val.startsWith('{{') ? stripPillType(val) : val}`)
|
|
386
423
|
}
|
|
387
424
|
}
|
|
388
425
|
|
|
@@ -393,11 +430,120 @@ async function resolveUnresolvedStepPills(
|
|
|
393
430
|
stepShape,
|
|
394
431
|
key,
|
|
395
432
|
stepInstanceSysId,
|
|
396
|
-
|
|
433
|
+
stepDefTableName,
|
|
397
434
|
entries.join('^')
|
|
398
435
|
)
|
|
399
436
|
)
|
|
400
437
|
}
|
|
438
|
+
continue
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Case 4: ApprovalDueDateShape — resolve step pill in 'date' field
|
|
442
|
+
// During initial auto-processing, cidMap was empty so the step pill in 'date'
|
|
443
|
+
// couldn't be resolved. Now cidMap is populated, so resolve and create element_mapping.
|
|
444
|
+
if (valueShape.is(ApprovalDueDateShape)) {
|
|
445
|
+
const dueDateShape = valueShape as ApprovalDueDateShape
|
|
446
|
+
const dateFieldShape = dueDateShape.get('date', false)
|
|
447
|
+
const dateResolved = resolveAnyPillFromShape(dateFieldShape, cidMap)
|
|
448
|
+
if (dateResolved?.isStep) {
|
|
449
|
+
collectPillTypes(dateResolved.pill, pillTypeMap)
|
|
450
|
+
// Build the full JSON with the resolved step pill in the date field.
|
|
451
|
+
// getApprovalDueDate() resolves all properties (turning the unresolvable
|
|
452
|
+
// CallExpressionShape into a Symbol that JSON.stringify drops).
|
|
453
|
+
// Override the date field with the resolved pill string.
|
|
454
|
+
const dueDate = dueDateShape.getApprovalDueDate()
|
|
455
|
+
const correctedShape = new ApprovalDueDateShape({
|
|
456
|
+
source: dueDateShape.getSource(),
|
|
457
|
+
value: { ...dueDate, date: stripPillType(dateResolved.pill) },
|
|
458
|
+
})
|
|
459
|
+
const jsonValue = correctedShape.toString().getValue()
|
|
460
|
+
newRecords.push(
|
|
461
|
+
await createElementMapping(
|
|
462
|
+
factory,
|
|
463
|
+
stepShape,
|
|
464
|
+
key,
|
|
465
|
+
stepInstanceSysId,
|
|
466
|
+
stepDefTableName,
|
|
467
|
+
jsonValue
|
|
468
|
+
)
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
continue
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Case 5: ApprovalRulesShape — resolve step pills in users/groups arrays.
|
|
475
|
+
// Uses the same structural walk as resolveApprovalRulesPills in step-instance-plugin
|
|
476
|
+
// but with resolveAnyPillFromShape (which has access to cidMap).
|
|
477
|
+
if (valueShape.is(ApprovalRulesShape)) {
|
|
478
|
+
const rulesShape = valueShape as ApprovalRulesShape
|
|
479
|
+
const rules = rulesShape.getApprovalRules()
|
|
480
|
+
let hasStepPills = false
|
|
481
|
+
|
|
482
|
+
const ruleSetsShape = rulesShape.get('ruleSets', false).ifArray()
|
|
483
|
+
ruleSetsShape?.getElements(false).forEach((ruleSetShape, rsIdx) => {
|
|
484
|
+
const rulesArrayShape = ruleSetShape.ifObject()?.get('rules', false).ifArray()
|
|
485
|
+
rulesArrayShape?.getElements(false).forEach((ruleShape, rIdx) => {
|
|
486
|
+
ruleShape
|
|
487
|
+
.ifArray()
|
|
488
|
+
?.getElements(false)
|
|
489
|
+
.forEach((conditionShape, cIdx) => {
|
|
490
|
+
const conditionObj = conditionShape.ifObject()
|
|
491
|
+
if (!conditionObj) {
|
|
492
|
+
return
|
|
493
|
+
}
|
|
494
|
+
const condition = rules.ruleSets?.[rsIdx]?.rules?.[rIdx]?.[cIdx]
|
|
495
|
+
if (!condition) {
|
|
496
|
+
return
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Resolve step pills in users array
|
|
500
|
+
conditionObj
|
|
501
|
+
.get('users', false)
|
|
502
|
+
.ifArray()
|
|
503
|
+
?.getElements(false)
|
|
504
|
+
.forEach((userShape, uIdx) => {
|
|
505
|
+
const resolved = resolveAnyPillFromShape(userShape, cidMap)
|
|
506
|
+
if (resolved?.isStep && condition.users) {
|
|
507
|
+
collectPillTypes(resolved.pill, pillTypeMap)
|
|
508
|
+
condition.users[uIdx] = stripPillType(resolved.pill)
|
|
509
|
+
hasStepPills = true
|
|
510
|
+
}
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
// Resolve step pills in groups array
|
|
514
|
+
conditionObj
|
|
515
|
+
.get('groups', false)
|
|
516
|
+
.ifArray()
|
|
517
|
+
?.getElements(false)
|
|
518
|
+
.forEach((groupShape, gIdx) => {
|
|
519
|
+
const resolved = resolveAnyPillFromShape(groupShape, cidMap)
|
|
520
|
+
if (resolved?.isStep && condition.groups) {
|
|
521
|
+
collectPillTypes(resolved.pill, pillTypeMap)
|
|
522
|
+
condition.groups[gIdx] = stripPillType(resolved.pill)
|
|
523
|
+
hasStepPills = true
|
|
524
|
+
}
|
|
525
|
+
})
|
|
526
|
+
})
|
|
527
|
+
})
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
if (hasStepPills) {
|
|
531
|
+
const correctedShape = new ApprovalRulesShape({
|
|
532
|
+
source: rulesShape.getSource(),
|
|
533
|
+
value: rules,
|
|
534
|
+
})
|
|
535
|
+
const jsonValue = correctedShape.toString().getValue()
|
|
536
|
+
newRecords.push(
|
|
537
|
+
await createElementMapping(
|
|
538
|
+
factory,
|
|
539
|
+
stepShape,
|
|
540
|
+
key,
|
|
541
|
+
stepInstanceSysId,
|
|
542
|
+
stepDefTableName,
|
|
543
|
+
jsonValue
|
|
544
|
+
)
|
|
545
|
+
)
|
|
546
|
+
}
|
|
401
547
|
}
|
|
402
548
|
}
|
|
403
549
|
}
|
|
@@ -405,13 +551,34 @@ async function resolveUnresolvedStepPills(
|
|
|
405
551
|
}
|
|
406
552
|
|
|
407
553
|
/**
|
|
408
|
-
*
|
|
409
|
-
* Scans
|
|
410
|
-
* and deduplicates by (cid, pillPath).
|
|
411
|
-
*
|
|
412
|
-
* This follows the same post-processing pattern as flow-definition-plugin which extracts
|
|
413
|
-
* pills from already-created records rather than during shape transformation.
|
|
554
|
+
* Collects all pill-bearing text strings from records.
|
|
555
|
+
* Scans sys_element_mapping.value, sys_hub_status_condition.condition and .status fields.
|
|
414
556
|
*/
|
|
557
|
+
function collectPillTextsFromRecords(records: Record[]): string[] {
|
|
558
|
+
const texts: string[] = []
|
|
559
|
+
for (const topRec of records) {
|
|
560
|
+
for (const rec of topRec.flat()) {
|
|
561
|
+
const table = rec.getTable()
|
|
562
|
+
if (table === 'sys_element_mapping') {
|
|
563
|
+
const value = rec.get('value')?.asString()?.getValue() ?? ''
|
|
564
|
+
if (value) {
|
|
565
|
+
texts.push(value)
|
|
566
|
+
}
|
|
567
|
+
} else if (table === 'sys_hub_status_condition') {
|
|
568
|
+
const condition = rec.get('condition')?.asString()?.getValue() ?? ''
|
|
569
|
+
if (condition) {
|
|
570
|
+
texts.push(condition)
|
|
571
|
+
}
|
|
572
|
+
const status = rec.get('status')?.asString()?.getValue() ?? ''
|
|
573
|
+
if (status) {
|
|
574
|
+
texts.push(status)
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return texts
|
|
580
|
+
}
|
|
581
|
+
|
|
415
582
|
function extractStepPillsFromRecords(
|
|
416
583
|
records: Record[],
|
|
417
584
|
cidToLabelMap: Map<string, string>,
|
|
@@ -420,42 +587,38 @@ function extractStepPillsFromRecords(
|
|
|
420
587
|
const pills: StepPillInfo[] = []
|
|
421
588
|
const seen = new Set<string>()
|
|
422
589
|
|
|
423
|
-
for (const
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if (
|
|
590
|
+
for (const text of collectPillTextsFromRecords(records)) {
|
|
591
|
+
const matches = text.matchAll(STEP_PILL_TYPE_REGEX)
|
|
592
|
+
for (const match of matches) {
|
|
593
|
+
const [, cid, pillPath, dataType] = match
|
|
594
|
+
if (!cid || !pillPath) {
|
|
428
595
|
continue
|
|
429
596
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
const key = `${cid}::${pillPath}`
|
|
438
|
-
if (seen.has(key)) {
|
|
439
|
-
continue
|
|
440
|
-
}
|
|
441
|
-
seen.add(key)
|
|
442
|
-
// Prefer type from pillTypeMap (collected from wfa.dataPill() args before stripping),
|
|
443
|
-
// fall back to regex capture from element_mapping, then default to 'string'
|
|
444
|
-
const resolvedType = pillTypeMap?.get(key) ?? dataType ?? 'string'
|
|
445
|
-
pills.push({
|
|
446
|
-
cid,
|
|
447
|
-
stepLabel: cidToLabelMap.get(cid) ?? '',
|
|
448
|
-
pillPath,
|
|
449
|
-
dataType: resolvedType,
|
|
450
|
-
})
|
|
597
|
+
// Skip base __step_status__ — already handled in buildActionLabelCache via cidToLabelMap
|
|
598
|
+
if (pillPath === '__step_status__') {
|
|
599
|
+
continue
|
|
600
|
+
}
|
|
601
|
+
const key = `${cid}::${pillPath}`
|
|
602
|
+
if (seen.has(key)) {
|
|
603
|
+
continue
|
|
451
604
|
}
|
|
605
|
+
seen.add(key)
|
|
606
|
+
// Prefer type from pillTypeMap (collected from wfa.dataPill() args before stripping),
|
|
607
|
+
// fall back to regex capture from element_mapping, then default to 'string'
|
|
608
|
+
const resolvedType = pillTypeMap?.get(key) ?? dataType ?? 'string'
|
|
609
|
+
pills.push({
|
|
610
|
+
cid,
|
|
611
|
+
stepLabel: cidToLabelMap.get(cid) ?? '',
|
|
612
|
+
pillPath,
|
|
613
|
+
dataType: resolvedType,
|
|
614
|
+
})
|
|
452
615
|
}
|
|
453
616
|
}
|
|
454
617
|
return pills
|
|
455
618
|
}
|
|
456
619
|
|
|
457
620
|
/**
|
|
458
|
-
* Extracts action dot-walk pill info from
|
|
621
|
+
* Extracts action dot-walk pill info from records.
|
|
459
622
|
* Scans for {{action.X.Y...}} patterns where the path has 2+ segments (i.e., deeper than top-level input).
|
|
460
623
|
* Deduplicates by full path. Uses pillTypeMap for type resolution.
|
|
461
624
|
*/
|
|
@@ -464,34 +627,28 @@ function extractActionDotWalkPills(records: Record[], pillTypeMap?: Map<string,
|
|
|
464
627
|
const seen = new Set<string>()
|
|
465
628
|
const regex = /\{\{action\.([^|}]+)(?:\|([^}]+))?\}\}/g
|
|
466
629
|
|
|
467
|
-
for (const
|
|
468
|
-
for (const
|
|
469
|
-
|
|
630
|
+
for (const text of collectPillTextsFromRecords(records)) {
|
|
631
|
+
for (const match of text.matchAll(regex)) {
|
|
632
|
+
const [, path, dataType] = match
|
|
633
|
+
if (!path) {
|
|
470
634
|
continue
|
|
471
635
|
}
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
// Only dot-walk pills (2+ segments) — top-level ones are already in inputsConfig
|
|
480
|
-
if (segments.length < 2) {
|
|
481
|
-
continue
|
|
482
|
-
}
|
|
483
|
-
if (seen.has(path)) {
|
|
484
|
-
continue
|
|
485
|
-
}
|
|
486
|
-
seen.add(path)
|
|
487
|
-
const resolvedType = pillTypeMap?.get(`action::${path}`) ?? dataType ?? 'string'
|
|
488
|
-
pills.push({
|
|
489
|
-
fullPath: path,
|
|
490
|
-
parentField: segments[0] ?? '',
|
|
491
|
-
columnName: segments[segments.length - 1] ?? '',
|
|
492
|
-
dataType: resolvedType,
|
|
493
|
-
})
|
|
636
|
+
const segments = path.split('.')
|
|
637
|
+
// Only dot-walk pills (2+ segments) — top-level ones are already in inputsConfig
|
|
638
|
+
if (segments.length < 2) {
|
|
639
|
+
continue
|
|
640
|
+
}
|
|
641
|
+
if (seen.has(path)) {
|
|
642
|
+
continue
|
|
494
643
|
}
|
|
644
|
+
seen.add(path)
|
|
645
|
+
const resolvedType = pillTypeMap?.get(`action::${path}`) ?? dataType ?? 'string'
|
|
646
|
+
pills.push({
|
|
647
|
+
fullPath: path,
|
|
648
|
+
parentField: segments[0] ?? '',
|
|
649
|
+
columnName: segments[segments.length - 1] ?? '',
|
|
650
|
+
dataType: resolvedType,
|
|
651
|
+
})
|
|
495
652
|
}
|
|
496
653
|
}
|
|
497
654
|
return pills
|
|
@@ -778,6 +935,73 @@ function convertActionPillsInInputs(
|
|
|
778
935
|
}
|
|
779
936
|
}
|
|
780
937
|
|
|
938
|
+
/**
|
|
939
|
+
* Converts pill strings buried inside ApprovalRulesShape and ApprovalDueDateShape values
|
|
940
|
+
* to wfa.dataPill() shapes. These structured shapes are created by normalizeInputValue()
|
|
941
|
+
* before convertActionPillsInInputs runs, so their nested pill strings are unreachable
|
|
942
|
+
* by the normal string-based pill conversion.
|
|
943
|
+
*/
|
|
944
|
+
function convertPillsInStructuredShapes(
|
|
945
|
+
inputsObj: Props,
|
|
946
|
+
source: Source,
|
|
947
|
+
diagnostics: Diagnostics,
|
|
948
|
+
labelCacheMap?: Map<string, string>
|
|
949
|
+
): void {
|
|
950
|
+
for (const [key, val] of Object.entries(inputsObj)) {
|
|
951
|
+
if (val instanceof ApprovalRulesShape) {
|
|
952
|
+
const rules = val.getApprovalRules()
|
|
953
|
+
let changed = false
|
|
954
|
+
const newRuleSets = rules.ruleSets?.map((ruleSet) => ({
|
|
955
|
+
...ruleSet,
|
|
956
|
+
rules: ruleSet.rules?.map((rule) =>
|
|
957
|
+
rule.map((condition) => ({
|
|
958
|
+
...condition,
|
|
959
|
+
users: condition.users?.map((user) => {
|
|
960
|
+
const s = String(user)
|
|
961
|
+
if (detectPillPattern(s) !== 'none') {
|
|
962
|
+
const shape = convertActionPillToShape(s, source, diagnostics, labelCacheMap)
|
|
963
|
+
if (shape) {
|
|
964
|
+
changed = true
|
|
965
|
+
return shape
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return user
|
|
969
|
+
}),
|
|
970
|
+
groups: condition.groups?.map((group) => {
|
|
971
|
+
const s = String(group)
|
|
972
|
+
if (detectPillPattern(s) !== 'none') {
|
|
973
|
+
const shape = convertActionPillToShape(s, source, diagnostics, labelCacheMap)
|
|
974
|
+
if (shape) {
|
|
975
|
+
changed = true
|
|
976
|
+
return shape
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return group
|
|
980
|
+
}),
|
|
981
|
+
}))
|
|
982
|
+
),
|
|
983
|
+
}))
|
|
984
|
+
if (changed && newRuleSets) {
|
|
985
|
+
inputsObj[key] = new ApprovalRulesShape({
|
|
986
|
+
source,
|
|
987
|
+
value: { ...rules, ruleSets: newRuleSets },
|
|
988
|
+
})
|
|
989
|
+
}
|
|
990
|
+
} else if (val instanceof ApprovalDueDateShape) {
|
|
991
|
+
const dueDate = val.getApprovalDueDate()
|
|
992
|
+
if (dueDate.date && detectPillPattern(dueDate.date) !== 'none') {
|
|
993
|
+
const shape = convertActionPillToShape(dueDate.date, source, diagnostics, labelCacheMap)
|
|
994
|
+
if (shape) {
|
|
995
|
+
inputsObj[key] = new ApprovalDueDateShape({
|
|
996
|
+
source,
|
|
997
|
+
value: { ...dueDate, date: shape as unknown as string },
|
|
998
|
+
})
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
781
1005
|
/** Regex to find step[UUID] pills */
|
|
782
1006
|
const STEP_PILL_REGEX =
|
|
783
1007
|
/\{\{step\[([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\]\.([^|}]+)(?:\|[^}]*)?\}\}/g
|
|
@@ -832,6 +1056,89 @@ function convertStepPillsInInputs(
|
|
|
832
1056
|
if (hasChanges) {
|
|
833
1057
|
inputsObj[key] = new TemplateValueShape({ source, value: newTemplateValue })
|
|
834
1058
|
}
|
|
1059
|
+
} else if (val instanceof ApprovalDueDateShape) {
|
|
1060
|
+
const dueDate = val.getApprovalDueDate()
|
|
1061
|
+
if (dueDate.date && typeof dueDate.date === 'string' && detectPillPattern(dueDate.date) !== 'none') {
|
|
1062
|
+
const shape = convertStepPillString(dueDate.date, source, cidToIdentifierMap, labelCacheMap)
|
|
1063
|
+
if (shape) {
|
|
1064
|
+
inputsObj[key] = new ApprovalDueDateShape({
|
|
1065
|
+
source,
|
|
1066
|
+
value: { ...dueDate, date: shape as unknown as string },
|
|
1067
|
+
})
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
} else if (val instanceof ApprovalRulesShape) {
|
|
1071
|
+
const rules = val.getApprovalRules()
|
|
1072
|
+
let changed = false
|
|
1073
|
+
const newRuleSets = rules.ruleSets?.map((ruleSet) => ({
|
|
1074
|
+
...ruleSet,
|
|
1075
|
+
rules: ruleSet.rules?.map((rule) =>
|
|
1076
|
+
rule.map((condition) => ({
|
|
1077
|
+
...condition,
|
|
1078
|
+
users: condition.users?.map((user) => {
|
|
1079
|
+
const s = String(user)
|
|
1080
|
+
if (detectPillPattern(s) !== 'none') {
|
|
1081
|
+
const shape = convertStepPillString(s, source, cidToIdentifierMap, labelCacheMap)
|
|
1082
|
+
if (shape) {
|
|
1083
|
+
changed = true
|
|
1084
|
+
return shape
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
return user
|
|
1088
|
+
}),
|
|
1089
|
+
groups: condition.groups?.map((group) => {
|
|
1090
|
+
const s = String(group)
|
|
1091
|
+
if (detectPillPattern(s) !== 'none') {
|
|
1092
|
+
const shape = convertStepPillString(s, source, cidToIdentifierMap, labelCacheMap)
|
|
1093
|
+
if (shape) {
|
|
1094
|
+
changed = true
|
|
1095
|
+
return shape
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
return group
|
|
1099
|
+
}),
|
|
1100
|
+
}))
|
|
1101
|
+
),
|
|
1102
|
+
}))
|
|
1103
|
+
if (changed && newRuleSets) {
|
|
1104
|
+
inputsObj[key] = new ApprovalRulesShape({
|
|
1105
|
+
source,
|
|
1106
|
+
value: { ...rules, ruleSets: newRuleSets },
|
|
1107
|
+
})
|
|
1108
|
+
}
|
|
1109
|
+
} else if (val && typeof val === 'object' && !Array.isArray(val) && !isShapeInstance(val)) {
|
|
1110
|
+
// Recursively process nested plain objects (e.g., inputVariables)
|
|
1111
|
+
// This handles script step input variables which have 'value' fields with step pills
|
|
1112
|
+
const nestedObj = val as Props
|
|
1113
|
+
for (const nestedVal of Object.values(nestedObj)) {
|
|
1114
|
+
if (
|
|
1115
|
+
nestedVal &&
|
|
1116
|
+
typeof nestedVal === 'object' &&
|
|
1117
|
+
!Array.isArray(nestedVal) &&
|
|
1118
|
+
!isShapeInstance(nestedVal)
|
|
1119
|
+
) {
|
|
1120
|
+
const innerObj = nestedVal as Props
|
|
1121
|
+
const innerValue = innerObj['value']
|
|
1122
|
+
if (typeof innerValue === 'string') {
|
|
1123
|
+
const converted = convertStepPillString(innerValue, source, cidToIdentifierMap, labelCacheMap)
|
|
1124
|
+
if (converted) {
|
|
1125
|
+
innerObj['value'] = converted
|
|
1126
|
+
}
|
|
1127
|
+
} else if (innerValue instanceof TemplateExpressionShape) {
|
|
1128
|
+
// Handle case where convertActionPillsInInputs already converted action pills,
|
|
1129
|
+
// leaving step pills in the template literal text segments
|
|
1130
|
+
const resolved = resolveStepPillsInTemplateExpression(
|
|
1131
|
+
innerValue,
|
|
1132
|
+
source,
|
|
1133
|
+
cidToIdentifierMap,
|
|
1134
|
+
labelCacheMap
|
|
1135
|
+
)
|
|
1136
|
+
if (resolved) {
|
|
1137
|
+
innerObj['value'] = resolved
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
835
1142
|
}
|
|
836
1143
|
}
|
|
837
1144
|
}
|
|
@@ -851,9 +1158,12 @@ function resolveStepPillMatch(
|
|
|
851
1158
|
return undefined
|
|
852
1159
|
}
|
|
853
1160
|
|
|
1161
|
+
// Split dot-walk property path into individual segments (e.g., "record.manager.email" → ["record", "manager", "email"])
|
|
1162
|
+
// PropertyAccessShape needs each path segment as a separate element for correct code generation
|
|
1163
|
+
const pathParts = property.split('.')
|
|
854
1164
|
const expression = new PropertyAccessShape({
|
|
855
1165
|
source,
|
|
856
|
-
elements: [identifier,
|
|
1166
|
+
elements: [identifier, ...pathParts] as unknown as readonly [unknown, unknown, ...unknown[]],
|
|
857
1167
|
})
|
|
858
1168
|
|
|
859
1169
|
const pillName = `step[${uuid}].${property}`
|
|
@@ -1151,9 +1461,131 @@ const actionDefRelationships = {
|
|
|
1151
1461
|
},
|
|
1152
1462
|
}
|
|
1153
1463
|
|
|
1464
|
+
/**
|
|
1465
|
+
* Resolves any shape (string literal, number, template expression, dataPill call)
|
|
1466
|
+
* to its final string representation with pill references resolved.
|
|
1467
|
+
*/
|
|
1468
|
+
function resolveToString(shape: Shape, cidMap: Map<string, string>, pillTypeMap: Map<string, string>): string {
|
|
1469
|
+
if (shape instanceof TemplateExpressionShape) {
|
|
1470
|
+
return resolveAllPillsInTemplate(shape, cidMap, pillTypeMap)
|
|
1471
|
+
}
|
|
1472
|
+
if (shape instanceof PillShape) {
|
|
1473
|
+
const raw = shape.getValue()
|
|
1474
|
+
collectPillTypes(raw, pillTypeMap)
|
|
1475
|
+
return stripPillType(raw)
|
|
1476
|
+
}
|
|
1477
|
+
const resolved = resolveAnyPillFromShape(shape, cidMap)
|
|
1478
|
+
if (resolved) {
|
|
1479
|
+
if (resolved.isStep) {
|
|
1480
|
+
collectPillTypes(resolved.pill, pillTypeMap)
|
|
1481
|
+
}
|
|
1482
|
+
return stripPillType(resolved.pill)
|
|
1483
|
+
}
|
|
1484
|
+
return String(shape.getValue?.() ?? '')
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* Builds the complex JSON `status` field for a sys_hub_status_condition record.
|
|
1489
|
+
* The status contains complexObject (runtime values), complexObjectSchema
|
|
1490
|
+
* (FlowDesigner:FDACTIONSTATUS with SimpleMapFacet field descriptors), and type facets.
|
|
1491
|
+
*
|
|
1492
|
+
* When a field value contains datapill references ({{...}}), it goes into the
|
|
1493
|
+
* `mapped` field of the SimpleMapFacet; otherwise static values go into
|
|
1494
|
+
* complexObject.$cv.$v and mapped is "{}".
|
|
1495
|
+
*/
|
|
1496
|
+
function buildStatusConditionJson(codeValue: string, messageValue: string): string {
|
|
1497
|
+
const hasPillInCode = codeValue.includes('{{')
|
|
1498
|
+
const hasPillInMessage = messageValue.includes('{{')
|
|
1499
|
+
|
|
1500
|
+
const codeMapped = hasPillInCode ? JSON.stringify({ code: codeValue }) : '{}'
|
|
1501
|
+
const messageMapped = hasPillInMessage ? JSON.stringify({ message: messageValue }) : '{}'
|
|
1502
|
+
|
|
1503
|
+
const codeCV = hasPillInCode ? '' : codeValue
|
|
1504
|
+
const messageCV = hasPillInMessage ? '' : messageValue
|
|
1505
|
+
|
|
1506
|
+
// Derive the complexObjectSchema from the built-in FDACTIONSTATUS definition
|
|
1507
|
+
// rather than hardcoding it, so it stays in sync with the canonical schema.
|
|
1508
|
+
const fdActionStatus = builtInComplexObjects['FDACTIONSTATUS']
|
|
1509
|
+
if (!fdActionStatus) {
|
|
1510
|
+
throw new Error('FDACTIONSTATUS not found in builtInComplexObjects')
|
|
1511
|
+
}
|
|
1512
|
+
const baseSchema = JSON.parse(fdActionStatus.data.serialized_content)
|
|
1513
|
+
const fdSchema = baseSchema['FlowDesigner:FDACTIONSTATUS']
|
|
1514
|
+
|
|
1515
|
+
// Inject `mapped` into the field facets for code and message
|
|
1516
|
+
for (const [fieldName, mapped] of [
|
|
1517
|
+
['code', codeMapped],
|
|
1518
|
+
['message', messageMapped],
|
|
1519
|
+
] as const) {
|
|
1520
|
+
const facetKey = `${fieldName}.$field_facets`
|
|
1521
|
+
const facets = JSON.parse(fdSchema[facetKey].SimpleMapFacet)
|
|
1522
|
+
facets.mapped = mapped
|
|
1523
|
+
fdSchema[facetKey].SimpleMapFacet = JSON.stringify(facets)
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
return JSON.stringify({
|
|
1527
|
+
version: '1.0',
|
|
1528
|
+
complexObject: {
|
|
1529
|
+
code: { $cv: { $c: 'java.lang.String', $v: codeCV } },
|
|
1530
|
+
message: { $cv: { $c: 'java.lang.String', $v: messageCV } },
|
|
1531
|
+
},
|
|
1532
|
+
complexObjectSchema: baseSchema,
|
|
1533
|
+
serializationFormat: 'JSON',
|
|
1534
|
+
})
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
/**
|
|
1538
|
+
* Parses a status JSON blob from a sys_hub_status_condition record and extracts
|
|
1539
|
+
* the code and message values. Datapill references live in the `mapped` field
|
|
1540
|
+
* of the SimpleMapFacet; static values live in complexObject.$cv.$v.
|
|
1541
|
+
*/
|
|
1542
|
+
function parseStatusConditionJson(
|
|
1543
|
+
statusJson: string,
|
|
1544
|
+
logger?: { warn: (msg: string) => void }
|
|
1545
|
+
): { code: string; message: string } {
|
|
1546
|
+
try {
|
|
1547
|
+
const parsed = JSON.parse(statusJson)
|
|
1548
|
+
const co = parsed?.complexObject ?? {}
|
|
1549
|
+
const schema = parsed?.complexObjectSchema ?? {}
|
|
1550
|
+
const fdSchema = schema['FlowDesigner:FDACTIONSTATUS'] ?? {}
|
|
1551
|
+
|
|
1552
|
+
// Extract code
|
|
1553
|
+
let code = co?.code?.$cv?.$v ?? ''
|
|
1554
|
+
const codeFacetsRaw = fdSchema['code.$field_facets']?.SimpleMapFacet
|
|
1555
|
+
if (codeFacetsRaw) {
|
|
1556
|
+
const codeFacets = typeof codeFacetsRaw === 'string' ? JSON.parse(codeFacetsRaw) : codeFacetsRaw
|
|
1557
|
+
const codeMapped = codeFacets?.mapped
|
|
1558
|
+
if (codeMapped && codeMapped !== '{}') {
|
|
1559
|
+
const mappedObj = typeof codeMapped === 'string' ? JSON.parse(codeMapped) : codeMapped
|
|
1560
|
+
if (mappedObj?.code) {
|
|
1561
|
+
code = mappedObj.code
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
// Extract message
|
|
1567
|
+
let message = co?.message?.$cv?.$v ?? ''
|
|
1568
|
+
const msgFacetsRaw = fdSchema['message.$field_facets']?.SimpleMapFacet
|
|
1569
|
+
if (msgFacetsRaw) {
|
|
1570
|
+
const msgFacets = typeof msgFacetsRaw === 'string' ? JSON.parse(msgFacetsRaw) : msgFacetsRaw
|
|
1571
|
+
const msgMapped = msgFacets?.mapped
|
|
1572
|
+
if (msgMapped && msgMapped !== '{}') {
|
|
1573
|
+
const mappedObj = typeof msgMapped === 'string' ? JSON.parse(msgMapped) : msgMapped
|
|
1574
|
+
if (mappedObj?.message) {
|
|
1575
|
+
message = mappedObj.message
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
return { code, message }
|
|
1581
|
+
} catch (e) {
|
|
1582
|
+
logger?.warn(`parseStatusConditionJson: failed to parse status JSON — ${e}`)
|
|
1583
|
+
return { code: '', message: '' }
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1154
1587
|
export const ActionDefinitionPlugin = Plugin.create({
|
|
1155
1588
|
name: 'ActionDefinitionPlugin',
|
|
1156
|
-
docs: [createSdkDocEntry('Action', ['sys_hub_action_type_definition'])],
|
|
1157
1589
|
records: {
|
|
1158
1590
|
sys_hub_action_type_definition: {
|
|
1159
1591
|
relationships: {
|
|
@@ -1163,6 +1595,10 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1163
1595
|
descendant: true,
|
|
1164
1596
|
relationships: {
|
|
1165
1597
|
...actionDefRelationships,
|
|
1598
|
+
sys_variable_value: {
|
|
1599
|
+
via: 'document_key',
|
|
1600
|
+
descendant: true,
|
|
1601
|
+
},
|
|
1166
1602
|
sys_element_mapping: {
|
|
1167
1603
|
via: 'id',
|
|
1168
1604
|
descendant: true,
|
|
@@ -1197,95 +1633,38 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1197
1633
|
async toShape(record, { descendants, diagnostics, logger }) {
|
|
1198
1634
|
const actionSysId = record.getId().getValue()
|
|
1199
1635
|
|
|
1200
|
-
//
|
|
1201
|
-
//
|
|
1202
|
-
//
|
|
1203
|
-
const
|
|
1636
|
+
// Query error evaluation descendants for this action.
|
|
1637
|
+
// sys_hub_action_status_metadata is the parent container;
|
|
1638
|
+
// sys_hub_status_condition holds the individual conditions.
|
|
1639
|
+
const actionStatusMetadata = descendants
|
|
1204
1640
|
.query('sys_hub_action_status_metadata')
|
|
1205
1641
|
.filter((r) => r.get('action_type_id')?.asString()?.getValue() === actionSysId)
|
|
1206
|
-
|
|
1207
|
-
const
|
|
1642
|
+
const actionStatusMetadataIds = actionStatusMetadata.map((r) => r.getId().getValue())
|
|
1643
|
+
const statusConditions = descendants
|
|
1208
1644
|
.query('sys_hub_status_condition')
|
|
1209
|
-
.
|
|
1645
|
+
.filter((r) =>
|
|
1210
1646
|
actionStatusMetadataIds.includes(
|
|
1211
1647
|
r.get('action_status_metadata_id')?.asString()?.getValue() ?? ''
|
|
1212
1648
|
)
|
|
1213
1649
|
)
|
|
1214
|
-
if (hasErrorEvaluation) {
|
|
1215
|
-
const actionName = record.get('name')?.getValue() ?? actionSysId
|
|
1216
|
-
logger.warn(`Action '${actionName}' has error evaluation — falling back to Record API`)
|
|
1217
|
-
return { success: false }
|
|
1218
|
-
}
|
|
1219
1650
|
|
|
1220
1651
|
// Filter inputs/outputs to only those belonging to this action definition,
|
|
1221
|
-
// excluding snapshot-parented records
|
|
1652
|
+
// excluding snapshot-parented records, and sort by <order> to preserve
|
|
1653
|
+
// the order defined in the XML (instance document order is not guaranteed)
|
|
1654
|
+
const sortByOrder = (a: Record, b: Record) =>
|
|
1655
|
+
Number(a.get('order')?.asString()?.getValue() ?? 0) -
|
|
1656
|
+
Number(b.get('order')?.asString()?.getValue() ?? 0)
|
|
1222
1657
|
const actionInputs = descendants
|
|
1223
1658
|
.query('sys_hub_action_input')
|
|
1224
1659
|
.filter((r) => r.get('model')?.asString()?.getValue() === actionSysId)
|
|
1660
|
+
.sort(sortByOrder)
|
|
1225
1661
|
const actionOutputs = descendants
|
|
1226
1662
|
.query('sys_hub_action_output')
|
|
1227
1663
|
.filter((r) => r.get('model')?.asString()?.getValue() === actionSysId)
|
|
1228
|
-
|
|
1229
|
-
// Fall back to Record API for custom actions with user-defined outputs (not yet fully supported).
|
|
1230
|
-
// Core actions (in CORE_ACTIONS_SYS_ID_NAME_MAP) are fully supported and should not fall back.
|
|
1231
|
-
// System-generated outputs (__action_status__, __dont_treat_as_error__) are excluded —
|
|
1232
|
-
// every action has these automatically, they are not custom outputs.
|
|
1233
|
-
const isCoreAction = actionSysId in CORE_ACTIONS_SYS_ID_NAME_MAP
|
|
1234
|
-
const customOutputs = actionOutputs.filter((r) => {
|
|
1235
|
-
const element = r.get('element')?.asString()?.getValue() ?? ''
|
|
1236
|
-
return element !== '__action_status__' && element !== '__dont_treat_as_error__'
|
|
1237
|
-
})
|
|
1238
|
-
if (!isCoreAction && customOutputs.length > 0) {
|
|
1239
|
-
const actionName = record.get('name')?.getValue() ?? actionSysId
|
|
1240
|
-
logger.warn(`Custom action '${actionName}' has outputs — falling back to Record API`)
|
|
1241
|
-
return { success: false }
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
// Build snapshot output value map: element name → assigned value
|
|
1245
|
-
// Output values are stored in two places on the snapshot:
|
|
1246
|
-
// 1. sys_variable_value records (plain text values)
|
|
1247
|
-
// 2. sys_element_mapping records (datapill/template values)
|
|
1248
|
-
const snapshotOutputValues = new Map<string, string>()
|
|
1249
|
-
const snapshots = descendants.query('sys_hub_action_type_snapshot')
|
|
1250
|
-
if (snapshots.length > 0) {
|
|
1251
|
-
const snapshotId = snapshots[0]?.getId()?.getValue()
|
|
1252
|
-
|
|
1253
|
-
// Check sys_element_mapping for datapill values (field=element name, id=snapshot id)
|
|
1254
|
-
const elementMappings = descendants
|
|
1255
|
-
.query('sys_element_mapping')
|
|
1256
|
-
.filter((r) => r.get('id')?.asString()?.getValue() === snapshotId)
|
|
1257
|
-
for (const mapping of elementMappings) {
|
|
1258
|
-
const fieldName = mapping.get('field')?.asString()?.getValue()
|
|
1259
|
-
const value = mapping.get('value')?.ifString()?.getValue()
|
|
1260
|
-
if (fieldName && value !== undefined && value !== '') {
|
|
1261
|
-
snapshotOutputValues.set(fieldName, value)
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
// Check sys_variable_value for plain text values (on snapshot outputs)
|
|
1266
|
-
const snapshotOutputs = descendants
|
|
1267
|
-
.query('sys_hub_action_output')
|
|
1268
|
-
.filter((r) => r.get('model')?.asString()?.getValue() === snapshotId)
|
|
1269
|
-
for (const snapshotOutput of snapshotOutputs) {
|
|
1270
|
-
const elementName = snapshotOutput.get('element')?.asString()?.getValue()
|
|
1271
|
-
if (!elementName || snapshotOutputValues.has(elementName)) {
|
|
1272
|
-
continue
|
|
1273
|
-
}
|
|
1274
|
-
const snapshotOutputSysId = snapshotOutput.getId().getValue()
|
|
1275
|
-
const varValues = descendants
|
|
1276
|
-
.query('sys_variable_value')
|
|
1277
|
-
.filter((v) => v.get('variable')?.asString()?.getValue() === snapshotOutputSysId)
|
|
1278
|
-
if (varValues.length > 0) {
|
|
1279
|
-
const value = varValues[0]?.get('value')?.ifString()?.getValue()
|
|
1280
|
-
if (value !== undefined && value !== '') {
|
|
1281
|
-
snapshotOutputValues.set(elementName, value)
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1664
|
+
.sort(sortByOrder)
|
|
1286
1665
|
|
|
1287
1666
|
const inputs = buildVariableShapes(actionInputs, descendants)
|
|
1288
|
-
const outputs = buildVariableShapes(actionOutputs, descendants
|
|
1667
|
+
const outputs = buildVariableShapes(actionOutputs, descendants)
|
|
1289
1668
|
|
|
1290
1669
|
// Extract label_cache from action definition for datapill type info
|
|
1291
1670
|
let labelCacheMap: Map<string, string> | undefined
|
|
@@ -1384,7 +1763,7 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1384
1763
|
}
|
|
1385
1764
|
// Ext input element_mappings have table var__m_sys_hub_step_ext_input_*
|
|
1386
1765
|
// Collect their values but don't add to inputsObj (they go under inputVariables)
|
|
1387
|
-
if (table.startsWith(
|
|
1766
|
+
if (table.startsWith(EXT_INPUT_TABLE_PREFIX)) {
|
|
1388
1767
|
extInputMappingValues[rawFieldName] = value
|
|
1389
1768
|
continue
|
|
1390
1769
|
}
|
|
@@ -1461,8 +1840,8 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1461
1840
|
(v) => v.get('variable')?.asString()?.getValue() === extInputSysId
|
|
1462
1841
|
)
|
|
1463
1842
|
const value =
|
|
1464
|
-
extInputMappingValues[elementName]
|
|
1465
|
-
varValueRecord?.get('value')?.asString()?.getValue()
|
|
1843
|
+
extInputMappingValues[elementName] ??
|
|
1844
|
+
varValueRecord?.get('value')?.asString()?.getValue() ??
|
|
1466
1845
|
''
|
|
1467
1846
|
const inputEntry: Props = { label }
|
|
1468
1847
|
if (value) {
|
|
@@ -1489,17 +1868,17 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1489
1868
|
continue
|
|
1490
1869
|
}
|
|
1491
1870
|
const label = extOutput.get('label')?.asString()?.getValue() || elementName
|
|
1492
|
-
const mandatory = extOutput.get('mandatory')?.
|
|
1493
|
-
const internalType = extOutput.get('internal_type')?.
|
|
1871
|
+
const mandatory = extOutput.get('mandatory')?.ifString()?.getValue() === 'true'
|
|
1872
|
+
const internalType = extOutput.get('internal_type')?.ifString()?.getValue() ?? 'string'
|
|
1494
1873
|
// Check attributes for uiType to handle cases where internal_type is generic
|
|
1495
|
-
const attributes = extOutput.get('attributes')?.
|
|
1874
|
+
const attributes = extOutput.get('attributes')?.ifString()?.getValue() ?? ''
|
|
1496
1875
|
const uiType = getAttributeValue(attributes, 'uiType') ?? internalType
|
|
1497
1876
|
const columnApiName = COLUMN_TYPE_TO_API[uiType] ?? 'StringColumn'
|
|
1498
1877
|
const columnProps: Props = { label }
|
|
1499
1878
|
if (mandatory) {
|
|
1500
1879
|
columnProps['mandatory'] = true
|
|
1501
1880
|
}
|
|
1502
|
-
const maxLength = extOutput.get('max_length')?.
|
|
1881
|
+
const maxLength = extOutput.get('max_length')?.ifString()?.getValue()
|
|
1503
1882
|
if (maxLength) {
|
|
1504
1883
|
columnProps['maxLength'] = Number(maxLength)
|
|
1505
1884
|
}
|
|
@@ -1514,14 +1893,14 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1514
1893
|
if (hint) {
|
|
1515
1894
|
columnProps['hint'] = hint
|
|
1516
1895
|
}
|
|
1517
|
-
const referenceTable = extOutput.get('reference')?.
|
|
1896
|
+
const referenceTable = extOutput.get('reference')?.ifString()?.getValue()
|
|
1518
1897
|
if (
|
|
1519
1898
|
referenceTable &&
|
|
1520
1899
|
(columnApiName === 'ReferenceColumn' || columnApiName === 'ListColumn')
|
|
1521
1900
|
) {
|
|
1522
1901
|
columnProps['referenceTable'] = referenceTable
|
|
1523
1902
|
}
|
|
1524
|
-
const defaultValue = extOutput.get('default_value')?.
|
|
1903
|
+
const defaultValue = extOutput.get('default_value')?.ifString()?.getValue()
|
|
1525
1904
|
if (defaultValue) {
|
|
1526
1905
|
columnProps['default'] = defaultValue
|
|
1527
1906
|
}
|
|
@@ -1542,6 +1921,10 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1542
1921
|
// Convert action input pills ({{action.xxx}}) to wfa.dataPill(params.inputs.xxx, 'type')
|
|
1543
1922
|
convertActionPillsInInputs(inputsObj, stepInstance, diagnostics, labelCacheMap)
|
|
1544
1923
|
|
|
1924
|
+
// Convert pills buried inside ApprovalRulesShape/ApprovalDueDateShape
|
|
1925
|
+
// (these were already parsed by normalizeInputValue before pill conversion)
|
|
1926
|
+
convertPillsInStructuredShapes(inputsObj, stepInstance, diagnostics, labelCacheMap)
|
|
1927
|
+
|
|
1545
1928
|
// Convert step output pills ({{step[UUID].xxx}}) to wfa.dataPill(varName.xxx, 'type')
|
|
1546
1929
|
// Earlier steps are already in cidToIdentifierMap since steps are processed in order
|
|
1547
1930
|
convertStepPillsInInputs(inputsObj, stepInstance, cidToIdentifierMap, labelCacheMap)
|
|
@@ -1595,6 +1978,174 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1595
1978
|
}
|
|
1596
1979
|
}
|
|
1597
1980
|
|
|
1981
|
+
// Reconstruct wfa.errorEvaluation([...]) from sys_hub_status_condition records.
|
|
1982
|
+
// This must appear before wfa.assignActionOutputs in the generated Fluent file.
|
|
1983
|
+
if (statusConditions.length > 0) {
|
|
1984
|
+
const sortedConditions = [...statusConditions].sort(sortByOrder)
|
|
1985
|
+
const conditionShapes: Shape[] = []
|
|
1986
|
+
|
|
1987
|
+
for (const cond of sortedConditions) {
|
|
1988
|
+
const label = cond.get('label')?.asString()?.getValue() ?? ''
|
|
1989
|
+
const condition = cond.get('condition')?.asString()?.getValue() ?? ''
|
|
1990
|
+
const dontTreatAsError = cond.get('dont_treat_as_error')?.asString()?.getValue() === 'true'
|
|
1991
|
+
const statusJson = cond.get('status')?.asString()?.getValue() ?? '{}'
|
|
1992
|
+
const { code, message } = parseStatusConditionJson(statusJson, logger)
|
|
1993
|
+
|
|
1994
|
+
// Build status props as plain object, resolve pills, then wrap
|
|
1995
|
+
const statusProps: Props = {}
|
|
1996
|
+
statusProps['code'] = /^\d+$/.test(code) ? Number(code) : code
|
|
1997
|
+
statusProps['message'] = message
|
|
1998
|
+
convertActionPillsInInputs(statusProps, cond, diagnostics, labelCacheMap)
|
|
1999
|
+
convertStepPillsInInputs(statusProps, cond, cidToIdentifierMap, labelCacheMap)
|
|
2000
|
+
|
|
2001
|
+
// Build condition props as plain object, resolve pills on condition only.
|
|
2002
|
+
// label is a display name and must NOT be pill-converted;
|
|
2003
|
+
// status pills are already resolved above via statusProps.
|
|
2004
|
+
const conditionProps: Props = { condition }
|
|
2005
|
+
convertActionPillsInInputs(conditionProps, cond, diagnostics, labelCacheMap)
|
|
2006
|
+
convertStepPillsInInputs(conditionProps, cond, cidToIdentifierMap, labelCacheMap)
|
|
2007
|
+
|
|
2008
|
+
const condProps: Props = {
|
|
2009
|
+
label,
|
|
2010
|
+
condition: conditionProps['condition'],
|
|
2011
|
+
status: new ObjectShape({ source: cond, properties: statusProps }),
|
|
2012
|
+
}
|
|
2013
|
+
if (dontTreatAsError) {
|
|
2014
|
+
condProps['dontTreatAsError'] = true
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
conditionShapes.push(new ObjectShape({ source: cond, properties: condProps }))
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
const statusSource = actionStatusMetadata[0] ?? record
|
|
2021
|
+
stepShapes.push(
|
|
2022
|
+
new CallExpressionShape({
|
|
2023
|
+
source: statusSource,
|
|
2024
|
+
callee: ERROR_EVALUATION_CALLEE,
|
|
2025
|
+
args: [
|
|
2026
|
+
new ArrayShape({
|
|
2027
|
+
source: statusSource,
|
|
2028
|
+
elements: conditionShapes,
|
|
2029
|
+
}),
|
|
2030
|
+
],
|
|
2031
|
+
})
|
|
2032
|
+
)
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
// Reconstruct wfa.assignActionOutputs() from output element_mappings.
|
|
2036
|
+
// Element mappings for output assignments can be keyed to the action def sys_id
|
|
2037
|
+
// (draft actions) or a snapshot sys_id (published actions). Check both.
|
|
2038
|
+
{
|
|
2039
|
+
const candidateIds = new Set<string>([actionSysId])
|
|
2040
|
+
const snapshots = descendants
|
|
2041
|
+
.query('sys_hub_action_type_snapshot')
|
|
2042
|
+
.filter((s) => s.get('parent_action')?.asString()?.getValue() === actionSysId)
|
|
2043
|
+
for (const snap of snapshots) {
|
|
2044
|
+
candidateIds.add(snap.getId().getValue())
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
// Find element_mappings for action outputs keyed to any candidate id
|
|
2048
|
+
const outputElementMappings = descendants
|
|
2049
|
+
.query('sys_element_mapping')
|
|
2050
|
+
.filter(
|
|
2051
|
+
(m) =>
|
|
2052
|
+
candidateIds.has(m.get('id')?.asString()?.getValue() ?? '') &&
|
|
2053
|
+
(m.get('table')?.asString()?.getValue() ?? '').startsWith(ACTION_OUTPUT_TABLE_PREFIX)
|
|
2054
|
+
)
|
|
2055
|
+
|
|
2056
|
+
// Build output element name lookup from all output records
|
|
2057
|
+
// (action-parented and snapshot-parented) for sys_variable_value resolution
|
|
2058
|
+
const varSysIdToElement = new Map<string, string>()
|
|
2059
|
+
const snapshotOutputs = descendants
|
|
2060
|
+
.query('sys_hub_action_output')
|
|
2061
|
+
.filter((r) => candidateIds.has(r.get('model')?.asString()?.getValue() ?? ''))
|
|
2062
|
+
for (const outputRec of [...snapshotOutputs, ...actionOutputs]) {
|
|
2063
|
+
const element = outputRec.get('element')?.asString()?.getValue()
|
|
2064
|
+
if (element) {
|
|
2065
|
+
varSysIdToElement.set(outputRec.getId().getValue(), element)
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// Gather sys_variable_value records for static output values
|
|
2070
|
+
const outputVarValues = descendants.query('sys_variable_value').filter((v) => {
|
|
2071
|
+
const docKey = v.get('document_key')?.asString()?.getValue() ?? ''
|
|
2072
|
+
return candidateIds.has(docKey)
|
|
2073
|
+
})
|
|
2074
|
+
|
|
2075
|
+
if (outputElementMappings.length > 0 || outputVarValues.length > 0) {
|
|
2076
|
+
const valuesObj: Props = {}
|
|
2077
|
+
const sourceRecord = snapshots[0] ?? record
|
|
2078
|
+
|
|
2079
|
+
// Static values from sys_variable_value
|
|
2080
|
+
for (const varValue of outputVarValues) {
|
|
2081
|
+
const variableSysId = varValue.get('variable')?.asString()?.getValue()
|
|
2082
|
+
const value = varValue.get('value')?.asString()?.getValue()
|
|
2083
|
+
const outputName = variableSysId ? varSysIdToElement.get(variableSysId) : undefined
|
|
2084
|
+
// Skip internal platform outputs and missing values (null/undefined)
|
|
2085
|
+
if (!outputName || outputName.startsWith('__') || value == null) {
|
|
2086
|
+
continue
|
|
2087
|
+
}
|
|
2088
|
+
// Skip FlowObject/FlowArray complex object schema serializations.
|
|
2089
|
+
// These sys_variable_value records store the output's type structure
|
|
2090
|
+
// (already declared via FlowObject/FlowArray in Fluent), not user-assigned values.
|
|
2091
|
+
if (value.includes('"complexObjectSchema"') || value.includes('"$COCollectionField"')) {
|
|
2092
|
+
continue
|
|
2093
|
+
}
|
|
2094
|
+
// sys_variable_value can contain pill strings (e.g. {{action.variable|string}})
|
|
2095
|
+
// Strip type suffix (|string, |reference) before pill parsing
|
|
2096
|
+
const pillStripped = value.replace(/\|[a-z_]+\}\}/g, '}}')
|
|
2097
|
+
valuesObj[outputName] = pillStripped
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
// Datapill values from sys_element_mapping (overrides var values when both exist)
|
|
2101
|
+
for (const mapping of outputElementMappings) {
|
|
2102
|
+
const outputName = mapping.get('field')?.asString()?.getValue()
|
|
2103
|
+
const pillValue = mapping.get('value')?.asString()?.getValue()
|
|
2104
|
+
// Skip internal outputs, missing values, and empty pill strings.
|
|
2105
|
+
// An empty pill value means "no datapill assignment" — the static value
|
|
2106
|
+
// from sys_variable_value (if any) should be preserved.
|
|
2107
|
+
if (!outputName || !pillValue || outputName.startsWith('__')) {
|
|
2108
|
+
continue
|
|
2109
|
+
}
|
|
2110
|
+
valuesObj[outputName] = pillValue
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
// Two-pass pill resolution (same approach as step inputs):
|
|
2114
|
+
// Pass 1: Convert action pills ({{action.xxx}}) → dataPill shapes
|
|
2115
|
+
convertActionPillsInInputs(valuesObj, sourceRecord, diagnostics, labelCacheMap)
|
|
2116
|
+
|
|
2117
|
+
// Pass 2: Convert step pills ({{step[UUID].xxx}}) → dataPill shapes
|
|
2118
|
+
convertStepPillsInInputs(valuesObj, sourceRecord, cidToIdentifierMap, labelCacheMap)
|
|
2119
|
+
|
|
2120
|
+
if (Object.keys(valuesObj).length > 0) {
|
|
2121
|
+
// Use params.outputs reference instead of duplicating the full schema
|
|
2122
|
+
const outputsRef = new PropertyAccessShape({
|
|
2123
|
+
source: sourceRecord,
|
|
2124
|
+
elements: [
|
|
2125
|
+
new IdentifierShape({
|
|
2126
|
+
source: sourceRecord,
|
|
2127
|
+
name: ACTION_PILL_PARAM_NAME,
|
|
2128
|
+
}),
|
|
2129
|
+
'outputs',
|
|
2130
|
+
],
|
|
2131
|
+
})
|
|
2132
|
+
stepShapes.push(
|
|
2133
|
+
new CallExpressionShape({
|
|
2134
|
+
source: sourceRecord,
|
|
2135
|
+
callee: ASSIGN_ACTION_OUTPUTS_CALLEE,
|
|
2136
|
+
args: [
|
|
2137
|
+
outputsRef,
|
|
2138
|
+
new ObjectShape({
|
|
2139
|
+
source: sourceRecord,
|
|
2140
|
+
properties: valuesObj,
|
|
2141
|
+
}),
|
|
2142
|
+
],
|
|
2143
|
+
})
|
|
2144
|
+
)
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
|
|
1598
2149
|
// Build args: config + optional body with step instances
|
|
1599
2150
|
const actionConfig = record.transform(({ $ }) => ({
|
|
1600
2151
|
$id: $.val(NowIdShape.from(record)),
|
|
@@ -1603,7 +2154,7 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1603
2154
|
description: $.def(''),
|
|
1604
2155
|
access: $.def('public'),
|
|
1605
2156
|
category: $.def(''),
|
|
1606
|
-
|
|
2157
|
+
protectionPolicy: $.from('sys_policy').def(''),
|
|
1607
2158
|
inputs: $.val(inputs),
|
|
1608
2159
|
outputs: $.val(outputs),
|
|
1609
2160
|
}))
|
|
@@ -1665,6 +2216,9 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1665
2216
|
sys_hub_status_condition: {
|
|
1666
2217
|
coalesce: ['action_status_metadata_id', 'order'],
|
|
1667
2218
|
},
|
|
2219
|
+
sys_element_mapping: {
|
|
2220
|
+
coalesce: ['id', 'table', 'field'],
|
|
2221
|
+
},
|
|
1668
2222
|
},
|
|
1669
2223
|
shapes: [
|
|
1670
2224
|
{
|
|
@@ -1686,12 +2240,11 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1686
2240
|
explicitId: actionConfiguration.get('$id'),
|
|
1687
2241
|
properties: actionConfiguration.transform(({ $ }) => ({
|
|
1688
2242
|
name: $,
|
|
1689
|
-
internal_name: $.from('name').map((n) => slugifyString(n.getValue())),
|
|
1690
2243
|
annotation: $.def(''),
|
|
1691
2244
|
description: $.def(''),
|
|
1692
2245
|
access: $.def('public'),
|
|
1693
2246
|
category: $.def(''),
|
|
1694
|
-
sys_policy: $.from('
|
|
2247
|
+
sys_policy: $.from('protectionPolicy').def(''),
|
|
1695
2248
|
active: $.val(true),
|
|
1696
2249
|
state: $.val('draft'),
|
|
1697
2250
|
system_level: $.val(false),
|
|
@@ -1738,11 +2291,34 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1738
2291
|
const pillTypeMap = new Map<string, string>()
|
|
1739
2292
|
|
|
1740
2293
|
const stepInfos: StepInfo[] = []
|
|
2294
|
+
let assignActionOutputsShape: CallExpressionShape | undefined
|
|
2295
|
+
let errorEvaluationShape: CallExpressionShape | undefined
|
|
1741
2296
|
let order = 1
|
|
1742
2297
|
for (const [, v] of (allInstances ?? []).entries()) {
|
|
1743
2298
|
const isVarStatement = v instanceof VariableStatementShape
|
|
1744
2299
|
const innerShape = isVarStatement ? v.getInitializer() : v
|
|
1745
2300
|
|
|
2301
|
+
if (
|
|
2302
|
+
innerShape instanceof CallExpressionShape &&
|
|
2303
|
+
innerShape.getCallee() === ASSIGN_ACTION_OUTPUTS_CALLEE
|
|
2304
|
+
) {
|
|
2305
|
+
assignActionOutputsShape = innerShape
|
|
2306
|
+
continue
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
if (
|
|
2310
|
+
innerShape instanceof CallExpressionShape &&
|
|
2311
|
+
innerShape.getCallee() === ERROR_EVALUATION_CALLEE
|
|
2312
|
+
) {
|
|
2313
|
+
errorEvaluationShape = innerShape
|
|
2314
|
+
if (assignActionOutputsShape) {
|
|
2315
|
+
diagnostics.error(
|
|
2316
|
+
innerShape,
|
|
2317
|
+
`wfa.errorEvaluation() must appear before wfa.assignActionOutputs() in the action body.`
|
|
2318
|
+
)
|
|
2319
|
+
}
|
|
2320
|
+
continue
|
|
2321
|
+
}
|
|
1746
2322
|
if (innerShape.getSource() instanceof StepInstanceShape) {
|
|
1747
2323
|
const stepShape = innerShape.getSource() as StepInstanceShape
|
|
1748
2324
|
stepShape.setCidMap(cidMap)
|
|
@@ -1793,6 +2369,162 @@ export const ActionDefinitionPlugin = Plugin.create({
|
|
|
1793
2369
|
)
|
|
1794
2370
|
relatedRecords.push(...resolvedStepPillRecords)
|
|
1795
2371
|
|
|
2372
|
+
// Create sys_element_mapping records for assignActionOutputs values.
|
|
2373
|
+
// For draft actions, element_mappings reference the action definition sys_id directly.
|
|
2374
|
+
if (assignActionOutputsShape) {
|
|
2375
|
+
const actionDefId = actionDefinitionRecord.getId().getValue()
|
|
2376
|
+
const valuesArg = assignActionOutputsShape.getArgument(1)?.asObject()
|
|
2377
|
+
|
|
2378
|
+
// Validate that assigned output names match declared outputs
|
|
2379
|
+
if (valuesArg && !outputsConfig) {
|
|
2380
|
+
diagnostics.error(
|
|
2381
|
+
assignActionOutputsShape,
|
|
2382
|
+
'assignActionOutputs is used but no outputs are declared in the action config'
|
|
2383
|
+
)
|
|
2384
|
+
}
|
|
2385
|
+
if (valuesArg && outputsConfig) {
|
|
2386
|
+
const declaredOutputNames = new Set(outputsConfig.keys())
|
|
2387
|
+
const assignedOutputNames = new Set<string>()
|
|
2388
|
+
for (const [outputName] of valuesArg.entries({ resolve: false })) {
|
|
2389
|
+
assignedOutputNames.add(outputName)
|
|
2390
|
+
if (!declaredOutputNames.has(outputName)) {
|
|
2391
|
+
diagnostics.error(
|
|
2392
|
+
valuesArg.get(outputName),
|
|
2393
|
+
`Unknown output '${outputName}'. Available outputs: ${[...declaredOutputNames].join(', ') || '(none)'}`
|
|
2394
|
+
)
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
for (const declaredName of declaredOutputNames) {
|
|
2398
|
+
if (!assignedOutputNames.has(declaredName)) {
|
|
2399
|
+
diagnostics.error(
|
|
2400
|
+
assignActionOutputsShape,
|
|
2401
|
+
`Output '${declaredName}' is declared but not assigned in assignActionOutputs. All declared outputs must be assigned a value.`
|
|
2402
|
+
)
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
if (valuesArg) {
|
|
2408
|
+
const entries = valuesArg.entries({ resolve: false })
|
|
2409
|
+
for (const [outputName, valueShape] of entries) {
|
|
2410
|
+
const shape = valueShape as Shape
|
|
2411
|
+
|
|
2412
|
+
// Validate that the output value is not an empty string
|
|
2413
|
+
if (shape.isString() && shape.getValue() === '') {
|
|
2414
|
+
diagnostics.error(
|
|
2415
|
+
valuesArg.get(outputName),
|
|
2416
|
+
`Output '${outputName}' is assigned an empty string. All action outputs must be assigned a non-empty value.`
|
|
2417
|
+
)
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
const pillValue = resolveToString(shape, cidMap, pillTypeMap)
|
|
2421
|
+
|
|
2422
|
+
const elementMapping = await factory.createRecord({
|
|
2423
|
+
source: assignActionOutputsShape,
|
|
2424
|
+
table: 'sys_element_mapping',
|
|
2425
|
+
properties: {
|
|
2426
|
+
field: outputName,
|
|
2427
|
+
id: actionDefId,
|
|
2428
|
+
table: `${ACTION_OUTPUT_TABLE_PREFIX}${actionDefId}`,
|
|
2429
|
+
value: pillValue,
|
|
2430
|
+
},
|
|
2431
|
+
})
|
|
2432
|
+
relatedRecords.push(elementMapping)
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
// ── Error Evaluation ─────────────────────────────────────────────
|
|
2438
|
+
// wfa.errorEvaluation([...]) → sys_hub_action_status_metadata + sys_hub_status_condition records
|
|
2439
|
+
if (errorEvaluationShape) {
|
|
2440
|
+
const actionDefId = actionDefinitionRecord.getId().getValue()
|
|
2441
|
+
|
|
2442
|
+
// Create the single sys_hub_action_status_metadata record for this action
|
|
2443
|
+
const statusMetadataRecord = await factory.createRecord({
|
|
2444
|
+
source: errorEvaluationShape,
|
|
2445
|
+
table: 'sys_hub_action_status_metadata',
|
|
2446
|
+
properties: {
|
|
2447
|
+
action_type_id: actionDefId,
|
|
2448
|
+
},
|
|
2449
|
+
})
|
|
2450
|
+
relatedRecords.push(statusMetadataRecord)
|
|
2451
|
+
const metadataId = statusMetadataRecord.getId().getValue()
|
|
2452
|
+
|
|
2453
|
+
// Parse the array of conditions (arg 0)
|
|
2454
|
+
const conditionsArg = errorEvaluationShape.getArgument(0)
|
|
2455
|
+
if (conditionsArg?.isArray()) {
|
|
2456
|
+
const elements = conditionsArg.asArray().getElements(false)
|
|
2457
|
+
let condOrder = 1
|
|
2458
|
+
|
|
2459
|
+
for (const condElement of elements) {
|
|
2460
|
+
if (!condElement.isObject()) {
|
|
2461
|
+
continue
|
|
2462
|
+
}
|
|
2463
|
+
const condObj = condElement.asObject()
|
|
2464
|
+
|
|
2465
|
+
// Extract fields from { label, condition, status, dontTreatAsError }
|
|
2466
|
+
const labelShape = condObj.get('label')
|
|
2467
|
+
const conditionShape = condObj.get('condition')
|
|
2468
|
+
const statusShape = condObj.get('status')?.ifObject()?.asObject()
|
|
2469
|
+
const dontTreatShape = condObj.get('dontTreatAsError')
|
|
2470
|
+
|
|
2471
|
+
const label = labelShape?.ifString()?.getValue() ?? ''
|
|
2472
|
+
const condition = conditionShape ? resolveToString(conditionShape, cidMap, pillTypeMap) : ''
|
|
2473
|
+
const dontTreatRaw = dontTreatShape?.getValue?.()
|
|
2474
|
+
const dontTreatAsError = dontTreatRaw === true || dontTreatRaw === 'true'
|
|
2475
|
+
|
|
2476
|
+
// Resolve status code and message (may contain datapills).
|
|
2477
|
+
// Use entries({ resolve: false }) to get raw shapes — without this,
|
|
2478
|
+
// PillShape values get auto-resolved and lose their pill reference.
|
|
2479
|
+
let codeValue = ''
|
|
2480
|
+
let messageValue = ''
|
|
2481
|
+
if (statusShape) {
|
|
2482
|
+
for (const [field, fieldShape] of statusShape.entries({ resolve: false })) {
|
|
2483
|
+
const shape = fieldShape as Shape
|
|
2484
|
+
if (field === 'code') {
|
|
2485
|
+
codeValue = resolveToString(shape, cidMap, pillTypeMap)
|
|
2486
|
+
} else if (field === 'message') {
|
|
2487
|
+
messageValue = resolveToString(shape, cidMap, pillTypeMap)
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
const statusJson = buildStatusConditionJson(codeValue, messageValue)
|
|
2493
|
+
|
|
2494
|
+
const conditionRecord = await factory.createRecord({
|
|
2495
|
+
source: errorEvaluationShape,
|
|
2496
|
+
table: 'sys_hub_status_condition',
|
|
2497
|
+
properties: {
|
|
2498
|
+
action_status_metadata_id: metadataId,
|
|
2499
|
+
condition,
|
|
2500
|
+
dont_treat_as_error: dontTreatAsError,
|
|
2501
|
+
label,
|
|
2502
|
+
order: condOrder,
|
|
2503
|
+
status: statusJson,
|
|
2504
|
+
},
|
|
2505
|
+
})
|
|
2506
|
+
relatedRecords.push(conditionRecord)
|
|
2507
|
+
condOrder++
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
// Create the __action_status__ element_mapping record.
|
|
2512
|
+
// The platform requires this to connect error evaluation status
|
|
2513
|
+
// conditions to the action's output. Its value is the base
|
|
2514
|
+
// FDACTIONSTATUS JSON with empty code/message mapped fields.
|
|
2515
|
+
const actionStatusMapping = await factory.createRecord({
|
|
2516
|
+
source: errorEvaluationShape,
|
|
2517
|
+
table: 'sys_element_mapping',
|
|
2518
|
+
properties: {
|
|
2519
|
+
field: '__action_status__',
|
|
2520
|
+
id: actionDefId,
|
|
2521
|
+
table: `${ACTION_OUTPUT_TABLE_PREFIX}${actionDefId}`,
|
|
2522
|
+
value: buildStatusConditionJson('', ''),
|
|
2523
|
+
},
|
|
2524
|
+
})
|
|
2525
|
+
relatedRecords.push(actionStatusMapping)
|
|
2526
|
+
}
|
|
2527
|
+
|
|
1796
2528
|
const collectedStepPills = extractStepPillsFromRecords(relatedRecords, cidToLabelMap, pillTypeMap)
|
|
1797
2529
|
const dotWalkPills = extractActionDotWalkPills(relatedRecords, pillTypeMap)
|
|
1798
2530
|
|