snow-flow 10.0.1-dev.464 → 10.0.1-dev.466
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/package.json
CHANGED
|
@@ -141,7 +141,7 @@ async function buildActionInputsForInsert(
|
|
|
141
141
|
}
|
|
142
142
|
var match = actionParams.find(function (p: any) {
|
|
143
143
|
var el = str(p.element);
|
|
144
|
-
return el.endsWith('_' + key) || el === key || str(p.label).toLowerCase() === key.toLowerCase();
|
|
144
|
+
return el.endsWith('_' + key) || el.startsWith(key + '_') || el === key || str(p.label).toLowerCase() === key.toLowerCase();
|
|
145
145
|
});
|
|
146
146
|
if (match) resolvedInputs[str(match.element)] = value;
|
|
147
147
|
else resolvedInputs[key] = value;
|
|
@@ -1001,6 +1001,15 @@ async function addActionViaGraphQL(
|
|
|
1001
1001
|
steps.insert_order = resolvedOrder;
|
|
1002
1002
|
|
|
1003
1003
|
const uuid = generateUUID();
|
|
1004
|
+
|
|
1005
|
+
// ── Data pill transformation for record actions (Update/Create Record) ──
|
|
1006
|
+
// These actions need: record → data pill, table_name → displayValue, field values → packed into values string
|
|
1007
|
+
var recordActionResult = await transformActionInputsForRecordAction(
|
|
1008
|
+
client, flowId, inputResult.inputs, inputResult.resolvedInputs,
|
|
1009
|
+
inputResult.actionParams, uuid
|
|
1010
|
+
);
|
|
1011
|
+
steps.record_action = recordActionResult.steps;
|
|
1012
|
+
|
|
1004
1013
|
const actionResponseFields = 'actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
1005
1014
|
' flowLogics { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
1006
1015
|
' subflows { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
|
|
@@ -1019,11 +1028,16 @@ async function addActionViaGraphQL(
|
|
|
1019
1028
|
uiUniqueIdentifier: uuid,
|
|
1020
1029
|
type: 'action',
|
|
1021
1030
|
parentUiId: parentUiId || '',
|
|
1022
|
-
inputs:
|
|
1031
|
+
inputs: recordActionResult.inputs
|
|
1023
1032
|
}]
|
|
1024
1033
|
}
|
|
1025
1034
|
};
|
|
1026
1035
|
|
|
1036
|
+
// Add labelCache entries for data pill references in record actions
|
|
1037
|
+
if (recordActionResult.labelCacheEntries.length > 0) {
|
|
1038
|
+
flowPatch.labelCache = { insert: recordActionResult.labelCacheEntries };
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1027
1041
|
// Add parent flow logic update signal (tells GraphQL the parent was modified)
|
|
1028
1042
|
if (parentUiId) {
|
|
1029
1043
|
flowPatch.flowLogics = { update: [{ uiUniqueIdentifier: parentUiId, type: 'flowlogic' }] };
|
|
@@ -1196,94 +1210,251 @@ function parseEncodedQuery(query: string): { prefix: string; field: string; oper
|
|
|
1196
1210
|
}
|
|
1197
1211
|
|
|
1198
1212
|
/**
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1213
|
+
* Check if a condition value looks like a standard ServiceNow encoded query.
|
|
1214
|
+
* Standard encoded queries use: field_name=value^field_name2!=value2
|
|
1215
|
+
*
|
|
1216
|
+
* Returns false for JavaScript expressions, scripts, fd_data references, etc.
|
|
1217
|
+
* which should be passed through as-is without data pill transformation.
|
|
1218
|
+
*/
|
|
1219
|
+
function isStandardEncodedQuery(condition: string): boolean {
|
|
1220
|
+
if (!condition) return false;
|
|
1221
|
+
// Parentheses indicate function calls or grouping expressions
|
|
1222
|
+
if (/[()]/.test(condition)) return false;
|
|
1223
|
+
// Method calls like .toString(, .replace(, .match(
|
|
1224
|
+
if (/\.\w+\(/.test(condition)) return false;
|
|
1225
|
+
// Regex patterns like /[
|
|
1226
|
+
if (/\/\[/.test(condition)) return false;
|
|
1227
|
+
// JS equality operators == or ===
|
|
1228
|
+
if (/===?/.test(condition)) return false;
|
|
1229
|
+
// JS modulo, logical AND/OR
|
|
1230
|
+
if (/%/.test(condition)) return false;
|
|
1231
|
+
if (/&&|\|\|/.test(condition)) return false;
|
|
1232
|
+
// Flow Designer internal variable references
|
|
1233
|
+
if (condition.startsWith('fd_data.')) return false;
|
|
1234
|
+
// Already contains data pill references (already transformed)
|
|
1235
|
+
if (condition.includes('{{')) return false;
|
|
1236
|
+
return true;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
/**
|
|
1240
|
+
* Transform an encoded query condition into Flow Designer data pill format.
|
|
1201
1241
|
*
|
|
1202
|
-
*
|
|
1242
|
+
* The UI format uses a record-level data pill prepended to the encoded query:
|
|
1243
|
+
* "category=inquiry" → "{{Created or Updated_1.current}}category=inquiry"
|
|
1244
|
+
*
|
|
1245
|
+
* The record pill tells Flow Designer which record/table the condition applies to.
|
|
1246
|
+
* The encoded query after the pill is the actual filter.
|
|
1203
1247
|
*/
|
|
1204
1248
|
function transformConditionToDataPills(conditionValue: string, dataPillBase: string): string {
|
|
1205
1249
|
if (!conditionValue || !dataPillBase) return conditionValue;
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
if (clauses.length === 0) return conditionValue;
|
|
1209
|
-
|
|
1210
|
-
var result = '';
|
|
1211
|
-
for (var i = 0; i < clauses.length; i++) {
|
|
1212
|
-
var clause = clauses[i];
|
|
1213
|
-
result += clause.prefix;
|
|
1214
|
-
result += '{{' + dataPillBase + '.' + clause.field + '}}';
|
|
1215
|
-
result += clause.operator;
|
|
1216
|
-
result += clause.value;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
return result;
|
|
1250
|
+
// Prepend the record-level data pill to the encoded query
|
|
1251
|
+
return '{{' + dataPillBase + '}}' + conditionValue;
|
|
1220
1252
|
}
|
|
1221
1253
|
|
|
1222
1254
|
/**
|
|
1223
|
-
* Build labelCache
|
|
1224
|
-
*
|
|
1225
|
-
* can display the data pill label correctly.
|
|
1255
|
+
* Build a single record-level labelCache entry for the data pill used in a condition.
|
|
1256
|
+
* The UI registers the record pill with the condition input, matching the captured format:
|
|
1226
1257
|
*
|
|
1227
|
-
*
|
|
1258
|
+
* { name: "Created or Updated_1.current",
|
|
1259
|
+
* label: "Trigger - Record Created or Updated➛Incident Record",
|
|
1260
|
+
* reference: "incident", type: "reference", base_type: "reference",
|
|
1261
|
+
* usedInstances: [{ uiUniqueIdentifier, inputName: "condition" }] }
|
|
1228
1262
|
*/
|
|
1229
1263
|
function buildConditionLabelCache(
|
|
1230
|
-
conditionValue: string,
|
|
1231
1264
|
dataPillBase: string,
|
|
1232
1265
|
triggerName: string,
|
|
1233
1266
|
table: string,
|
|
1234
1267
|
tableLabel: string,
|
|
1235
1268
|
logicUiId: string
|
|
1236
1269
|
): any[] {
|
|
1237
|
-
if (!
|
|
1270
|
+
if (!dataPillBase) return [];
|
|
1271
|
+
|
|
1272
|
+
return [{
|
|
1273
|
+
name: dataPillBase,
|
|
1274
|
+
label: 'Trigger - Record ' + triggerName + '\u27a1' + tableLabel + ' Record',
|
|
1275
|
+
reference: table,
|
|
1276
|
+
reference_display: tableLabel,
|
|
1277
|
+
type: 'reference',
|
|
1278
|
+
base_type: 'reference',
|
|
1279
|
+
attributes: '',
|
|
1280
|
+
usedInstances: [{ uiUniqueIdentifier: logicUiId, inputName: 'condition' }],
|
|
1281
|
+
choices: {}
|
|
1282
|
+
}];
|
|
1283
|
+
}
|
|
1238
1284
|
|
|
1239
|
-
|
|
1240
|
-
if (clauses.length === 0) return [];
|
|
1285
|
+
// ── DATA PILL SUPPORT FOR RECORD ACTIONS (Update/Create Record) ──────
|
|
1241
1286
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
var entries: any[] = [];
|
|
1287
|
+
/** Shorthands that users can pass for `record` to mean "the trigger's current record". */
|
|
1288
|
+
const RECORD_PILL_SHORTHANDS = ['current', 'trigger.current', 'trigger_record', 'trigger record'];
|
|
1245
1289
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1290
|
+
/**
|
|
1291
|
+
* Post-process action inputs for record-modifying actions (Update Record, Create Record).
|
|
1292
|
+
*
|
|
1293
|
+
* These actions have 3 key inputs:
|
|
1294
|
+
* - `record`: reference to the record → needs data pill format {{TriggerName_1.current}}
|
|
1295
|
+
* - `table_name`: target table → needs displayValue (e.g. "Incident")
|
|
1296
|
+
* - `values`: packed field=value pairs → e.g. "priority=2^state=3"
|
|
1297
|
+
*
|
|
1298
|
+
* User-provided field-value pairs that don't match defined action parameters are
|
|
1299
|
+
* automatically packed into the `values` string.
|
|
1300
|
+
*
|
|
1301
|
+
* Returns the transformed inputs and labelCache entries.
|
|
1302
|
+
*/
|
|
1303
|
+
async function transformActionInputsForRecordAction(
|
|
1304
|
+
client: any,
|
|
1305
|
+
flowId: string,
|
|
1306
|
+
actionInputs: any[],
|
|
1307
|
+
resolvedInputs: Record<string, string>,
|
|
1308
|
+
actionParams: any[],
|
|
1309
|
+
uuid: string
|
|
1310
|
+
): Promise<{ inputs: any[]; labelCacheEntries: any[]; steps: any }> {
|
|
1311
|
+
var steps: any = {};
|
|
1312
|
+
|
|
1313
|
+
// Detect if this is a record action: must have both `record` and `table_name` parameters
|
|
1314
|
+
var definedParamNames = actionParams.map(function (p: any) { return str(p.element); });
|
|
1315
|
+
var hasRecord = definedParamNames.includes('record');
|
|
1316
|
+
var hasTableName = definedParamNames.includes('table_name');
|
|
1317
|
+
var hasValues = definedParamNames.includes('values');
|
|
1318
|
+
|
|
1319
|
+
if (!hasRecord || !hasTableName) {
|
|
1320
|
+
steps.record_action = false;
|
|
1321
|
+
return { inputs: actionInputs, labelCacheEntries: [], steps };
|
|
1322
|
+
}
|
|
1323
|
+
steps.record_action = true;
|
|
1324
|
+
|
|
1325
|
+
// Get trigger info for data pill construction
|
|
1326
|
+
var triggerInfo = await getFlowTriggerInfo(client, flowId);
|
|
1327
|
+
steps.trigger_info = {
|
|
1328
|
+
dataPillBase: triggerInfo.dataPillBase,
|
|
1329
|
+
triggerName: triggerInfo.triggerName,
|
|
1330
|
+
table: triggerInfo.table,
|
|
1331
|
+
tableLabel: triggerInfo.tableLabel,
|
|
1332
|
+
error: triggerInfo.error
|
|
1333
|
+
};
|
|
1334
|
+
|
|
1335
|
+
var dataPillBase = triggerInfo.dataPillBase; // e.g. "Created or Updated_1.current"
|
|
1336
|
+
var labelCacheEntries: any[] = [];
|
|
1337
|
+
var usedInstances: { uiUniqueIdentifier: string; inputName: string }[] = [];
|
|
1338
|
+
|
|
1339
|
+
// ── 1. Transform `record` input to data pill ──────────────────────
|
|
1340
|
+
var recordInput = actionInputs.find(function (inp: any) { return inp.name === 'record'; });
|
|
1341
|
+
if (recordInput && dataPillBase) {
|
|
1342
|
+
var recordVal = recordInput.value?.value || '';
|
|
1343
|
+
var isShorthand = RECORD_PILL_SHORTHANDS.includes(recordVal.toLowerCase());
|
|
1344
|
+
var isAlreadyPill = recordVal.startsWith('{{');
|
|
1345
|
+
|
|
1346
|
+
if (isShorthand || !recordVal) {
|
|
1347
|
+
// Auto-fill with trigger's current record data pill
|
|
1348
|
+
recordInput.value = { schemaless: false, schemalessValue: '', value: '{{' + dataPillBase + '}}' };
|
|
1349
|
+
usedInstances.push({ uiUniqueIdentifier: uuid, inputName: 'record' });
|
|
1350
|
+
steps.record_transform = { original: recordVal, pill: '{{' + dataPillBase + '}}' };
|
|
1351
|
+
} else if (isAlreadyPill) {
|
|
1352
|
+
usedInstances.push({ uiUniqueIdentifier: uuid, inputName: 'record' });
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
// ── 2. Transform `table_name` input with displayValue ─────────────
|
|
1357
|
+
var tableNameInput = actionInputs.find(function (inp: any) { return inp.name === 'table_name'; });
|
|
1358
|
+
if (tableNameInput) {
|
|
1359
|
+
var tableVal = tableNameInput.value?.value || '';
|
|
1360
|
+
// Also accept `table` as user key (maps to table_name)
|
|
1361
|
+
if (!tableVal && resolvedInputs['table']) {
|
|
1362
|
+
tableVal = resolvedInputs['table'];
|
|
1363
|
+
}
|
|
1364
|
+
// If still empty, use trigger's table
|
|
1365
|
+
if (!tableVal && triggerInfo.table) {
|
|
1366
|
+
tableVal = triggerInfo.table;
|
|
1367
|
+
}
|
|
1368
|
+
if (tableVal) {
|
|
1369
|
+
// Look up display name for the table
|
|
1370
|
+
var tableDisplayName = triggerInfo.tableLabel || '';
|
|
1371
|
+
if (tableVal !== triggerInfo.table || !tableDisplayName) {
|
|
1372
|
+
// Different table than trigger — look up its label
|
|
1373
|
+
try {
|
|
1374
|
+
var tblResp = await client.get('/api/now/table/sys_db_object', {
|
|
1375
|
+
params: { sysparm_query: 'name=' + tableVal, sysparm_fields: 'label', sysparm_display_value: 'true', sysparm_limit: 1 }
|
|
1376
|
+
});
|
|
1377
|
+
tableDisplayName = str(tblResp.data.result?.[0]?.label) || tableVal.charAt(0).toUpperCase() + tableVal.slice(1).replace(/_/g, ' ');
|
|
1378
|
+
} catch (_) {
|
|
1379
|
+
tableDisplayName = tableVal.charAt(0).toUpperCase() + tableVal.slice(1).replace(/_/g, ' ');
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
tableNameInput.value = { schemaless: false, schemalessValue: '', value: tableVal };
|
|
1383
|
+
tableNameInput.displayValue = { schemaless: false, schemalessValue: '', value: tableDisplayName };
|
|
1384
|
+
steps.table_name_transform = { value: tableVal, displayValue: tableDisplayName };
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
// ── 3. Pack non-parameter field values into `values` string ───────
|
|
1389
|
+
// Any user-provided key that is NOT a defined action parameter goes into the values string
|
|
1390
|
+
var valuesInput = actionInputs.find(function (inp: any) { return inp.name === 'values'; });
|
|
1391
|
+
if (valuesInput) {
|
|
1392
|
+
var fieldPairs: string[] = [];
|
|
1393
|
+
var existingValues = valuesInput.value?.value || '';
|
|
1394
|
+
|
|
1395
|
+
// If user already passed a pre-built values string, use it
|
|
1396
|
+
if (existingValues && existingValues.includes('=')) {
|
|
1397
|
+
fieldPairs.push(existingValues);
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// Find user-provided keys that are not defined action parameters
|
|
1401
|
+
for (var key of Object.keys(resolvedInputs)) {
|
|
1402
|
+
if (definedParamNames.includes(key)) continue;
|
|
1403
|
+
// Also skip table (alias for table_name) and record
|
|
1404
|
+
if (key === 'table' || key === 'record') continue;
|
|
1405
|
+
|
|
1406
|
+
var val = resolvedInputs[key];
|
|
1407
|
+
|
|
1408
|
+
// Check if value should be a data pill reference
|
|
1409
|
+
if (val && dataPillBase) {
|
|
1410
|
+
var valLower = val.toLowerCase();
|
|
1411
|
+
if (RECORD_PILL_SHORTHANDS.includes(valLower)) {
|
|
1412
|
+
// Shorthand → record-level data pill
|
|
1413
|
+
val = '{{' + dataPillBase + '}}';
|
|
1414
|
+
usedInstances.push({ uiUniqueIdentifier: uuid, inputName: key });
|
|
1415
|
+
} else if (valLower.startsWith('trigger.current.') || valLower.startsWith('current.')) {
|
|
1416
|
+
// Field-level data pill: "trigger.current.assigned_to" → {{dataPillBase.assigned_to}}
|
|
1417
|
+
var fieldName = valLower.startsWith('trigger.current.') ? val.substring(16) : val.substring(8);
|
|
1418
|
+
val = '{{' + dataPillBase + '.' + fieldName + '}}';
|
|
1419
|
+
usedInstances.push({ uiUniqueIdentifier: uuid, inputName: key });
|
|
1420
|
+
} else if (val.startsWith('{{')) {
|
|
1421
|
+
// Already a data pill
|
|
1422
|
+
usedInstances.push({ uiUniqueIdentifier: uuid, inputName: key });
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
fieldPairs.push(key + '=' + val);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
if (fieldPairs.length > 0) {
|
|
1430
|
+
var packedValues = fieldPairs.join('^');
|
|
1431
|
+
valuesInput.value = { schemaless: false, schemalessValue: '', value: packedValues };
|
|
1432
|
+
steps.values_transform = { packed: packedValues, fieldCount: fieldPairs.length };
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// ── 4. Build labelCache entries for data pills ────────────────────
|
|
1437
|
+
if (dataPillBase && usedInstances.length > 0) {
|
|
1438
|
+
var tableRef = triggerInfo.tableRef || triggerInfo.table || '';
|
|
1439
|
+
var tableLabel = triggerInfo.tableLabel || '';
|
|
1440
|
+
|
|
1441
|
+
// Record-level data pill entry
|
|
1442
|
+
labelCacheEntries.push({
|
|
1251
1443
|
name: dataPillBase,
|
|
1252
|
-
label: 'Trigger - Record ' + triggerName + '\u27a1' + tableLabel + ' Record',
|
|
1253
|
-
reference:
|
|
1444
|
+
label: 'Trigger - Record ' + triggerInfo.triggerName + '\u27a1' + tableLabel + ' Record',
|
|
1445
|
+
reference: tableRef,
|
|
1254
1446
|
reference_display: tableLabel,
|
|
1255
1447
|
type: 'reference',
|
|
1256
1448
|
base_type: 'reference',
|
|
1257
1449
|
attributes: '',
|
|
1258
|
-
usedInstances:
|
|
1450
|
+
usedInstances: usedInstances,
|
|
1259
1451
|
choices: {}
|
|
1260
1452
|
});
|
|
1261
|
-
}
|
|
1262
1453
|
|
|
1263
|
-
|
|
1264
|
-
var field = clauses[i].field;
|
|
1265
|
-
if (!field) continue;
|
|
1266
|
-
var pillName = dataPillBase + '.' + field;
|
|
1267
|
-
if (seen[pillName]) continue;
|
|
1268
|
-
seen[pillName] = true;
|
|
1269
|
-
|
|
1270
|
-
// Capitalize field name for label
|
|
1271
|
-
var fieldLabel = field.replace(/_/g, ' ').replace(/\b\w/g, function (c: string) { return c.toUpperCase(); });
|
|
1272
|
-
|
|
1273
|
-
entries.push({
|
|
1274
|
-
name: pillName,
|
|
1275
|
-
label: 'Trigger - Record ' + triggerName + '\u27a1' + tableLabel + ' Record\u27a1' + fieldLabel,
|
|
1276
|
-
reference: '',
|
|
1277
|
-
reference_display: '',
|
|
1278
|
-
type: 'string',
|
|
1279
|
-
base_type: 'string',
|
|
1280
|
-
attributes: '',
|
|
1281
|
-
usedInstances: [{ uiUniqueIdentifier: logicUiId, inputName: 'condition' }],
|
|
1282
|
-
choices: {}
|
|
1283
|
-
});
|
|
1454
|
+
steps.label_cache = { count: labelCacheEntries.length, pills: [dataPillBase], usedInstances: usedInstances.length };
|
|
1284
1455
|
}
|
|
1285
1456
|
|
|
1286
|
-
return
|
|
1457
|
+
return { inputs: actionInputs, labelCacheEntries, steps };
|
|
1287
1458
|
}
|
|
1288
1459
|
|
|
1289
1460
|
// ── FLOW LOGIC (If/Else, For Each, etc.) ─────────────────────────────
|
|
@@ -1358,31 +1529,32 @@ async function addFlowLogicViaGraphQL(
|
|
|
1358
1529
|
steps.resolved_inputs = inputResult.resolvedInputs;
|
|
1359
1530
|
steps.input_query_stats = { defParamsFound: inputResult.defParamsCount, inputsBuilt: inputResult.inputs.length, error: inputResult.inputQueryError };
|
|
1360
1531
|
|
|
1361
|
-
// ──
|
|
1362
|
-
// Flow Designer conditions
|
|
1363
|
-
//
|
|
1532
|
+
// ── Detect condition that needs data pill transformation ────────────
|
|
1533
|
+
// Flow Designer sets conditions via a SEPARATE UPDATE after the element is created.
|
|
1534
|
+
// The condition format uses record-level data pill: {{TriggerName_1.current}}encodedQuery
|
|
1535
|
+
// Non-standard conditions (JS expressions, fd_data refs) are passed through as-is.
|
|
1364
1536
|
const uuid = generateUUID();
|
|
1365
|
-
var labelCacheEntries: any[] = [];
|
|
1366
|
-
|
|
1367
1537
|
var conditionInput = inputResult.inputs.find(function (inp: any) { return inp.name === 'condition'; });
|
|
1368
1538
|
var rawCondition = conditionInput?.value?.value || '';
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
);
|
|
1384
|
-
steps.label_cache = { count: labelCacheEntries.length, pills: labelCacheEntries.map(function (e: any) { return e.name; }) };
|
|
1539
|
+
var needsConditionUpdate = false;
|
|
1540
|
+
var conditionTriggerInfo: any = null;
|
|
1541
|
+
|
|
1542
|
+
if (rawCondition && rawCondition !== '^EQ' && isStandardEncodedQuery(rawCondition)) {
|
|
1543
|
+
conditionTriggerInfo = await getFlowTriggerInfo(client, flowId);
|
|
1544
|
+
steps.trigger_info = {
|
|
1545
|
+
dataPillBase: conditionTriggerInfo.dataPillBase, triggerName: conditionTriggerInfo.triggerName,
|
|
1546
|
+
table: conditionTriggerInfo.table, tableLabel: conditionTriggerInfo.tableLabel, error: conditionTriggerInfo.error
|
|
1547
|
+
};
|
|
1548
|
+
if (conditionTriggerInfo.dataPillBase) {
|
|
1549
|
+
needsConditionUpdate = true;
|
|
1550
|
+
// Clear condition in INSERT — it will be set via separate UPDATE with labelCache
|
|
1551
|
+
conditionInput.value = { schemaless: false, schemalessValue: '', value: '' };
|
|
1552
|
+
steps.condition_strategy = 'two_step';
|
|
1385
1553
|
}
|
|
1554
|
+
} else if (rawCondition && rawCondition !== '^EQ') {
|
|
1555
|
+
// Non-standard condition (JS expression, fd_data ref, etc.) — pass through as-is
|
|
1556
|
+
steps.condition_strategy = 'passthrough';
|
|
1557
|
+
steps.condition_not_encoded_query = true;
|
|
1386
1558
|
}
|
|
1387
1559
|
|
|
1388
1560
|
// Calculate insertion order
|
|
@@ -1419,23 +1591,55 @@ async function addFlowLogicViaGraphQL(
|
|
|
1419
1591
|
}
|
|
1420
1592
|
};
|
|
1421
1593
|
|
|
1422
|
-
// Add labelCache entries for data pill references in conditions
|
|
1423
|
-
if (labelCacheEntries.length > 0) {
|
|
1424
|
-
flowPatch.labelCache = { insert: labelCacheEntries };
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
1594
|
// Add parent flow logic update signal (tells GraphQL the parent was modified)
|
|
1428
1595
|
if (parentUiId) {
|
|
1429
1596
|
flowPatch.flowLogics.update = [{ uiUniqueIdentifier: parentUiId, type: 'flowlogic' }];
|
|
1430
1597
|
}
|
|
1431
1598
|
|
|
1432
1599
|
try {
|
|
1600
|
+
// Step 1: INSERT the flow logic element (with empty condition if data pill transform is needed)
|
|
1433
1601
|
const result = await executeFlowPatchMutation(client, flowPatch, logicResponseFields);
|
|
1434
1602
|
const logicId = result?.flowLogics?.inserts?.[0]?.sysId;
|
|
1435
1603
|
const returnedUuid = result?.flowLogics?.inserts?.[0]?.uiUniqueIdentifier || uuid;
|
|
1436
1604
|
steps.insert = { success: !!logicId, logicId, uuid: returnedUuid };
|
|
1437
1605
|
if (!logicId) return { success: false, steps, error: 'GraphQL flow logic INSERT returned no ID' };
|
|
1438
1606
|
|
|
1607
|
+
// Step 2: UPDATE condition with data pill + labelCache (separate mutation, matching UI behavior)
|
|
1608
|
+
// The Flow Designer UI always sets conditions in a separate UPDATE after creating the element.
|
|
1609
|
+
if (needsConditionUpdate && conditionTriggerInfo) {
|
|
1610
|
+
var dataPillBase = conditionTriggerInfo.dataPillBase;
|
|
1611
|
+
var transformedCondition = transformConditionToDataPills(rawCondition, dataPillBase);
|
|
1612
|
+
var labelCacheEntries = buildConditionLabelCache(
|
|
1613
|
+
dataPillBase, conditionTriggerInfo.triggerName,
|
|
1614
|
+
conditionTriggerInfo.tableRef, conditionTriggerInfo.tableLabel, returnedUuid
|
|
1615
|
+
);
|
|
1616
|
+
|
|
1617
|
+
steps.condition_transform = { original: rawCondition, transformed: transformedCondition };
|
|
1618
|
+
steps.label_cache = { count: labelCacheEntries.length, pills: labelCacheEntries.map(function (e: any) { return e.name; }) };
|
|
1619
|
+
|
|
1620
|
+
try {
|
|
1621
|
+
var updatePatch: any = {
|
|
1622
|
+
flowId: flowId,
|
|
1623
|
+
labelCache: { insert: labelCacheEntries },
|
|
1624
|
+
flowLogics: {
|
|
1625
|
+
update: [{
|
|
1626
|
+
uiUniqueIdentifier: returnedUuid,
|
|
1627
|
+
type: 'flowlogic',
|
|
1628
|
+
inputs: [{
|
|
1629
|
+
name: 'condition',
|
|
1630
|
+
value: { schemaless: false, schemalessValue: '', value: transformedCondition }
|
|
1631
|
+
}]
|
|
1632
|
+
}]
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
await executeFlowPatchMutation(client, updatePatch, logicResponseFields);
|
|
1636
|
+
steps.condition_update = { success: true };
|
|
1637
|
+
} catch (ue: any) {
|
|
1638
|
+
steps.condition_update = { success: false, error: ue.message };
|
|
1639
|
+
// Element was created successfully — condition update failure is non-fatal
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1439
1643
|
return { success: true, logicId, uiUniqueIdentifier: returnedUuid, steps };
|
|
1440
1644
|
} catch (e: any) {
|
|
1441
1645
|
steps.insert = { success: false, error: e.message };
|