snow-flow 10.0.1-dev.465 → 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
|
@@ -1210,94 +1210,76 @@ function parseEncodedQuery(query: string): { prefix: string; field: string; oper
|
|
|
1210
1210
|
}
|
|
1211
1211
|
|
|
1212
1212
|
/**
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
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
1215
|
*
|
|
1216
|
-
*
|
|
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.
|
|
1241
|
+
*
|
|
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.
|
|
1217
1247
|
*/
|
|
1218
1248
|
function transformConditionToDataPills(conditionValue: string, dataPillBase: string): string {
|
|
1219
1249
|
if (!conditionValue || !dataPillBase) return conditionValue;
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
if (clauses.length === 0) return conditionValue;
|
|
1223
|
-
|
|
1224
|
-
var result = '';
|
|
1225
|
-
for (var i = 0; i < clauses.length; i++) {
|
|
1226
|
-
var clause = clauses[i];
|
|
1227
|
-
result += clause.prefix;
|
|
1228
|
-
result += '{{' + dataPillBase + '.' + clause.field + '}}';
|
|
1229
|
-
result += clause.operator;
|
|
1230
|
-
result += clause.value;
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
return result;
|
|
1250
|
+
// Prepend the record-level data pill to the encoded query
|
|
1251
|
+
return '{{' + dataPillBase + '}}' + conditionValue;
|
|
1234
1252
|
}
|
|
1235
1253
|
|
|
1236
1254
|
/**
|
|
1237
|
-
* Build labelCache
|
|
1238
|
-
*
|
|
1239
|
-
* 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:
|
|
1240
1257
|
*
|
|
1241
|
-
*
|
|
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" }] }
|
|
1242
1262
|
*/
|
|
1243
1263
|
function buildConditionLabelCache(
|
|
1244
|
-
conditionValue: string,
|
|
1245
1264
|
dataPillBase: string,
|
|
1246
1265
|
triggerName: string,
|
|
1247
1266
|
table: string,
|
|
1248
1267
|
tableLabel: string,
|
|
1249
1268
|
logicUiId: string
|
|
1250
1269
|
): any[] {
|
|
1251
|
-
if (!
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
entries.push({
|
|
1265
|
-
name: dataPillBase,
|
|
1266
|
-
label: 'Trigger - Record ' + triggerName + '\u27a1' + tableLabel + ' Record',
|
|
1267
|
-
reference: table,
|
|
1268
|
-
reference_display: tableLabel,
|
|
1269
|
-
type: 'reference',
|
|
1270
|
-
base_type: 'reference',
|
|
1271
|
-
attributes: '',
|
|
1272
|
-
usedInstances: [{ uiUniqueIdentifier: logicUiId, inputName: 'condition' }],
|
|
1273
|
-
choices: {}
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
for (var i = 0; i < clauses.length; i++) {
|
|
1278
|
-
var field = clauses[i].field;
|
|
1279
|
-
if (!field) continue;
|
|
1280
|
-
var pillName = dataPillBase + '.' + field;
|
|
1281
|
-
if (seen[pillName]) continue;
|
|
1282
|
-
seen[pillName] = true;
|
|
1283
|
-
|
|
1284
|
-
// Capitalize field name for label
|
|
1285
|
-
var fieldLabel = field.replace(/_/g, ' ').replace(/\b\w/g, function (c: string) { return c.toUpperCase(); });
|
|
1286
|
-
|
|
1287
|
-
entries.push({
|
|
1288
|
-
name: pillName,
|
|
1289
|
-
label: 'Trigger - Record ' + triggerName + '\u27a1' + tableLabel + ' Record\u27a1' + fieldLabel,
|
|
1290
|
-
reference: '',
|
|
1291
|
-
reference_display: '',
|
|
1292
|
-
type: 'string',
|
|
1293
|
-
base_type: 'string',
|
|
1294
|
-
attributes: '',
|
|
1295
|
-
usedInstances: [{ uiUniqueIdentifier: logicUiId, inputName: 'condition' }],
|
|
1296
|
-
choices: {}
|
|
1297
|
-
});
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
return entries;
|
|
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
|
+
}];
|
|
1301
1283
|
}
|
|
1302
1284
|
|
|
1303
1285
|
// ── DATA PILL SUPPORT FOR RECORD ACTIONS (Update/Create Record) ──────
|
|
@@ -1547,31 +1529,32 @@ async function addFlowLogicViaGraphQL(
|
|
|
1547
1529
|
steps.resolved_inputs = inputResult.resolvedInputs;
|
|
1548
1530
|
steps.input_query_stats = { defParamsFound: inputResult.defParamsCount, inputsBuilt: inputResult.inputs.length, error: inputResult.inputQueryError };
|
|
1549
1531
|
|
|
1550
|
-
// ──
|
|
1551
|
-
// Flow Designer conditions
|
|
1552
|
-
//
|
|
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.
|
|
1553
1536
|
const uuid = generateUUID();
|
|
1554
|
-
var labelCacheEntries: any[] = [];
|
|
1555
|
-
|
|
1556
1537
|
var conditionInput = inputResult.inputs.find(function (inp: any) { return inp.name === 'condition'; });
|
|
1557
1538
|
var rawCondition = conditionInput?.value?.value || '';
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
);
|
|
1573
|
-
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';
|
|
1574
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;
|
|
1575
1558
|
}
|
|
1576
1559
|
|
|
1577
1560
|
// Calculate insertion order
|
|
@@ -1608,23 +1591,55 @@ async function addFlowLogicViaGraphQL(
|
|
|
1608
1591
|
}
|
|
1609
1592
|
};
|
|
1610
1593
|
|
|
1611
|
-
// Add labelCache entries for data pill references in conditions
|
|
1612
|
-
if (labelCacheEntries.length > 0) {
|
|
1613
|
-
flowPatch.labelCache = { insert: labelCacheEntries };
|
|
1614
|
-
}
|
|
1615
|
-
|
|
1616
1594
|
// Add parent flow logic update signal (tells GraphQL the parent was modified)
|
|
1617
1595
|
if (parentUiId) {
|
|
1618
1596
|
flowPatch.flowLogics.update = [{ uiUniqueIdentifier: parentUiId, type: 'flowlogic' }];
|
|
1619
1597
|
}
|
|
1620
1598
|
|
|
1621
1599
|
try {
|
|
1600
|
+
// Step 1: INSERT the flow logic element (with empty condition if data pill transform is needed)
|
|
1622
1601
|
const result = await executeFlowPatchMutation(client, flowPatch, logicResponseFields);
|
|
1623
1602
|
const logicId = result?.flowLogics?.inserts?.[0]?.sysId;
|
|
1624
1603
|
const returnedUuid = result?.flowLogics?.inserts?.[0]?.uiUniqueIdentifier || uuid;
|
|
1625
1604
|
steps.insert = { success: !!logicId, logicId, uuid: returnedUuid };
|
|
1626
1605
|
if (!logicId) return { success: false, steps, error: 'GraphQL flow logic INSERT returned no ID' };
|
|
1627
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
|
+
|
|
1628
1643
|
return { success: true, logicId, uiUniqueIdentifier: returnedUuid, steps };
|
|
1629
1644
|
} catch (e: any) {
|
|
1630
1645
|
steps.insert = { success: false, error: e.message };
|