snow-flow 10.0.1-dev.450 → 10.0.1-dev.451
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
|
@@ -72,6 +72,239 @@ async function executeFlowPatchMutation(
|
|
|
72
72
|
return resp.data?.data?.global?.snFlowDesigner?.flow || resp.data;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
// Type label mapping for parameter definitions
|
|
76
|
+
const TYPE_LABELS: Record<string, string> = {
|
|
77
|
+
string: 'String', integer: 'Integer', boolean: 'True/False', choice: 'Choice',
|
|
78
|
+
reference: 'Reference', object: 'Object', glide_date_time: 'Date/Time',
|
|
79
|
+
glide_date: 'Date', decimal: 'Decimal', conditions: 'Conditions',
|
|
80
|
+
glide_list: 'List', html: 'HTML', script: 'Script', url: 'URL',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Build full action input objects matching the Flow Designer UI format.
|
|
85
|
+
* The UI sends inputs WITH parameter definitions in the INSERT mutation (not empty inputs + separate UPDATE).
|
|
86
|
+
*/
|
|
87
|
+
async function buildActionInputsForInsert(
|
|
88
|
+
client: any,
|
|
89
|
+
actionDefId: string,
|
|
90
|
+
userValues?: Record<string, string>
|
|
91
|
+
): Promise<{ inputs: any[]; resolvedInputs: Record<string, string>; actionParams: any[] }> {
|
|
92
|
+
// Query sys_hub_action_input with full field set
|
|
93
|
+
var actionParams: any[] = [];
|
|
94
|
+
try {
|
|
95
|
+
var resp = await client.get('/api/now/table/sys_hub_action_input', {
|
|
96
|
+
params: {
|
|
97
|
+
sysparm_query: 'model=' + actionDefId,
|
|
98
|
+
sysparm_fields: 'sys_id,element,label,internal_type,mandatory,default_value,order,max_length,hint,read_only,extended,data_structure,reference,reference_display,ref_qual,choice_option,table_name,column_name,use_dependent,dependent_on,show_ref_finder,local,attributes,sys_class_name',
|
|
99
|
+
sysparm_display_value: 'false',
|
|
100
|
+
sysparm_limit: 50
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
actionParams = resp.data.result || [];
|
|
104
|
+
} catch (_) {}
|
|
105
|
+
|
|
106
|
+
// Fuzzy-match user-provided values to actual field names
|
|
107
|
+
var resolvedInputs: Record<string, string> = {};
|
|
108
|
+
if (userValues) {
|
|
109
|
+
var paramElements = actionParams.map(function (p: any) { return p.element; });
|
|
110
|
+
for (var [key, value] of Object.entries(userValues)) {
|
|
111
|
+
if (paramElements.includes(key)) {
|
|
112
|
+
resolvedInputs[key] = value;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
var match = actionParams.find(function (p: any) {
|
|
116
|
+
return p.element.endsWith('_' + key) || p.element === key || (p.label || '').toLowerCase() === key.toLowerCase();
|
|
117
|
+
});
|
|
118
|
+
if (match) resolvedInputs[match.element] = value;
|
|
119
|
+
else resolvedInputs[key] = value;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Build full input objects with parameter definitions (matching UI format)
|
|
124
|
+
var inputs = actionParams.map(function (rec: any) {
|
|
125
|
+
var paramType = rec.internal_type || 'string';
|
|
126
|
+
var userVal = resolvedInputs[rec.element] || '';
|
|
127
|
+
return {
|
|
128
|
+
id: rec.sys_id,
|
|
129
|
+
name: rec.element,
|
|
130
|
+
children: [],
|
|
131
|
+
displayValue: { value: '' },
|
|
132
|
+
value: { schemaless: false, schemalessValue: '', value: userVal },
|
|
133
|
+
parameter: {
|
|
134
|
+
id: rec.sys_id,
|
|
135
|
+
label: rec.label || rec.element,
|
|
136
|
+
name: rec.element,
|
|
137
|
+
type: paramType,
|
|
138
|
+
type_label: TYPE_LABELS[paramType] || paramType.charAt(0).toUpperCase() + paramType.slice(1),
|
|
139
|
+
hint: rec.hint || '',
|
|
140
|
+
order: parseInt(rec.order || '0', 10),
|
|
141
|
+
extended: rec.extended === 'true',
|
|
142
|
+
mandatory: rec.mandatory === 'true',
|
|
143
|
+
readonly: rec.read_only === 'true',
|
|
144
|
+
maxsize: parseInt(rec.max_length || '8000', 10),
|
|
145
|
+
data_structure: rec.data_structure || '',
|
|
146
|
+
reference: rec.reference || '',
|
|
147
|
+
reference_display: rec.reference_display || '',
|
|
148
|
+
ref_qual: rec.ref_qual || '',
|
|
149
|
+
choiceOption: rec.choice_option || '',
|
|
150
|
+
table: rec.table_name || '',
|
|
151
|
+
columnName: rec.column_name || '',
|
|
152
|
+
defaultValue: rec.default_value || '',
|
|
153
|
+
use_dependent: rec.use_dependent === 'true',
|
|
154
|
+
dependent_on: rec.dependent_on || '',
|
|
155
|
+
show_ref_finder: rec.show_ref_finder === 'true',
|
|
156
|
+
local: rec.local === 'true',
|
|
157
|
+
attributes: rec.attributes || '',
|
|
158
|
+
sys_class_name: rec.sys_class_name || '',
|
|
159
|
+
children: []
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return { inputs, resolvedInputs, actionParams };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Find all flow elements at order >= targetOrder and build GraphQL update payloads to bump their order by 1.
|
|
169
|
+
* This is needed when inserting an element inside a flow logic block (e.g. action inside If block).
|
|
170
|
+
* The UI does this to keep the Else block (and other subsequent elements) after the new element.
|
|
171
|
+
*/
|
|
172
|
+
async function findElementsToReorder(
|
|
173
|
+
client: any,
|
|
174
|
+
flowId: string,
|
|
175
|
+
targetOrder: number
|
|
176
|
+
): Promise<{ flowLogicUpdates: any[]; actionUpdates: any[]; subflowUpdates: any[] }> {
|
|
177
|
+
var flowLogicUpdates: any[] = [];
|
|
178
|
+
var actionUpdates: any[] = [];
|
|
179
|
+
var subflowUpdates: any[] = [];
|
|
180
|
+
|
|
181
|
+
// Flow logic blocks
|
|
182
|
+
try {
|
|
183
|
+
var resp = await client.get('/api/now/table/sys_hub_flow_logic', {
|
|
184
|
+
params: {
|
|
185
|
+
sysparm_query: 'flow=' + flowId + '^order>=' + targetOrder,
|
|
186
|
+
sysparm_fields: 'sys_id,order,ui_unique_identifier',
|
|
187
|
+
sysparm_limit: 100
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
for (var rec of (resp.data.result || [])) {
|
|
191
|
+
var uuid = rec.ui_unique_identifier;
|
|
192
|
+
var curOrder = parseInt(rec.order || '0', 10);
|
|
193
|
+
if (uuid && curOrder >= targetOrder) {
|
|
194
|
+
flowLogicUpdates.push({ order: String(curOrder + 1), uiUniqueIdentifier: uuid, type: 'flowlogic' });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} catch (_) {}
|
|
198
|
+
|
|
199
|
+
// Action instances
|
|
200
|
+
try {
|
|
201
|
+
var resp2 = await client.get('/api/now/table/sys_hub_action_instance', {
|
|
202
|
+
params: {
|
|
203
|
+
sysparm_query: 'flow=' + flowId + '^order>=' + targetOrder,
|
|
204
|
+
sysparm_fields: 'sys_id,order,ui_unique_identifier',
|
|
205
|
+
sysparm_limit: 100
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
for (var rec2 of (resp2.data.result || [])) {
|
|
209
|
+
var uuid2 = rec2.ui_unique_identifier;
|
|
210
|
+
var curOrder2 = parseInt(rec2.order || '0', 10);
|
|
211
|
+
if (uuid2 && curOrder2 >= targetOrder) {
|
|
212
|
+
actionUpdates.push({ order: String(curOrder2 + 1), uiUniqueIdentifier: uuid2, type: 'action' });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
} catch (_) {}
|
|
216
|
+
|
|
217
|
+
// Subflow instances
|
|
218
|
+
try {
|
|
219
|
+
var resp3 = await client.get('/api/now/table/sys_hub_sub_flow_instance', {
|
|
220
|
+
params: {
|
|
221
|
+
sysparm_query: 'flow=' + flowId + '^order>=' + targetOrder,
|
|
222
|
+
sysparm_fields: 'sys_id,order,ui_unique_identifier',
|
|
223
|
+
sysparm_limit: 100
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
for (var rec3 of (resp3.data.result || [])) {
|
|
227
|
+
var uuid3 = rec3.ui_unique_identifier;
|
|
228
|
+
var curOrder3 = parseInt(rec3.order || '0', 10);
|
|
229
|
+
if (uuid3 && curOrder3 >= targetOrder) {
|
|
230
|
+
subflowUpdates.push({ order: String(curOrder3 + 1), uiUniqueIdentifier: uuid3, type: 'subflow' });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} catch (_) {}
|
|
234
|
+
|
|
235
|
+
return { flowLogicUpdates, actionUpdates, subflowUpdates };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Calculate the insert order for an element being added inside a parent flow logic block.
|
|
240
|
+
* Returns the order right after the last child of the parent, and reorder info for elements that need bumping.
|
|
241
|
+
*/
|
|
242
|
+
async function calculateInsertOrder(
|
|
243
|
+
client: any,
|
|
244
|
+
flowId: string,
|
|
245
|
+
parentUiId?: string,
|
|
246
|
+
explicitOrder?: number
|
|
247
|
+
): Promise<{ insertOrder: number; reorders: { flowLogicUpdates: any[]; actionUpdates: any[]; subflowUpdates: any[] } }> {
|
|
248
|
+
var noReorders = { flowLogicUpdates: [], actionUpdates: [], subflowUpdates: [] };
|
|
249
|
+
|
|
250
|
+
// Explicit order: bump elements at that position
|
|
251
|
+
if (explicitOrder) {
|
|
252
|
+
var reorders = await findElementsToReorder(client, flowId, explicitOrder);
|
|
253
|
+
return { insertOrder: explicitOrder, reorders };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// No parent: append at end, no bumping needed
|
|
257
|
+
if (!parentUiId) {
|
|
258
|
+
var nextOrder = await getNextOrder(client, flowId);
|
|
259
|
+
return { insertOrder: nextOrder, reorders: noReorders };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Parent specified: find parent's order, then find max child order
|
|
263
|
+
var parentSysId = '';
|
|
264
|
+
var parentOrder = 0;
|
|
265
|
+
try {
|
|
266
|
+
var pResp = await client.get('/api/now/table/sys_hub_flow_logic', {
|
|
267
|
+
params: {
|
|
268
|
+
sysparm_query: 'flow=' + flowId + '^ui_unique_identifier=' + parentUiId,
|
|
269
|
+
sysparm_fields: 'sys_id,order',
|
|
270
|
+
sysparm_limit: 1
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
var found = pResp.data.result?.[0];
|
|
274
|
+
if (found) {
|
|
275
|
+
parentSysId = found.sys_id;
|
|
276
|
+
parentOrder = parseInt(found.order || '0', 10);
|
|
277
|
+
}
|
|
278
|
+
} catch (_) {}
|
|
279
|
+
|
|
280
|
+
if (!parentSysId) {
|
|
281
|
+
// Fallback: append at end
|
|
282
|
+
var fallbackOrder = await getNextOrder(client, flowId);
|
|
283
|
+
return { insertOrder: fallbackOrder, reorders: noReorders };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Find max order of existing children of this parent
|
|
287
|
+
var maxChildOrder = parentOrder;
|
|
288
|
+
for (var table of ['sys_hub_action_instance', 'sys_hub_flow_logic', 'sys_hub_sub_flow_instance']) {
|
|
289
|
+
try {
|
|
290
|
+
var cResp = await client.get('/api/now/table/' + table, {
|
|
291
|
+
params: {
|
|
292
|
+
sysparm_query: 'flow=' + flowId + '^parent=' + parentSysId + '^ORDERBYDESCorder',
|
|
293
|
+
sysparm_fields: 'order',
|
|
294
|
+
sysparm_limit: 1
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
var childOrder = parseInt(cResp.data.result?.[0]?.order || '0', 10);
|
|
298
|
+
if (childOrder > maxChildOrder) maxChildOrder = childOrder;
|
|
299
|
+
} catch (_) {}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Insert after last child; bump everything at that position
|
|
303
|
+
var insertOrder = maxChildOrder + 1;
|
|
304
|
+
var reorderInfo = await findElementsToReorder(client, flowId, insertOrder);
|
|
305
|
+
return { insertOrder: insertOrder, reorders: reorderInfo };
|
|
306
|
+
}
|
|
307
|
+
|
|
75
308
|
async function addTriggerViaGraphQL(
|
|
76
309
|
client: any,
|
|
77
310
|
flowId: string,
|
|
@@ -209,7 +442,6 @@ async function addActionViaGraphQL(
|
|
|
209
442
|
|
|
210
443
|
// Dynamically look up action definition in sys_hub_action_type_snapshot
|
|
211
444
|
let actionDefId: string | null = null;
|
|
212
|
-
// Try exact match on internal_name first, then name
|
|
213
445
|
for (const field of ['internal_name', 'name']) {
|
|
214
446
|
if (actionDefId) break;
|
|
215
447
|
try {
|
|
@@ -223,7 +455,6 @@ async function addActionViaGraphQL(
|
|
|
223
455
|
}
|
|
224
456
|
} catch (_) {}
|
|
225
457
|
}
|
|
226
|
-
// Fallback: LIKE search on both fields
|
|
227
458
|
if (!actionDefId) {
|
|
228
459
|
try {
|
|
229
460
|
const resp = await client.get('/api/now/table/sys_hub_action_type_snapshot', {
|
|
@@ -242,53 +473,29 @@ async function addActionViaGraphQL(
|
|
|
242
473
|
}
|
|
243
474
|
if (!actionDefId) return { success: false, error: 'Action definition not found for: ' + actionType, steps };
|
|
244
475
|
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
default_value: r.default_value || '',
|
|
261
|
-
internal_type: r.internal_type || ''
|
|
262
|
-
}));
|
|
263
|
-
steps.available_inputs = actionParams;
|
|
264
|
-
} catch (_) {}
|
|
265
|
-
|
|
266
|
-
// Match provided inputs to actual field names (fuzzy: "message" → "log_message", "level" → "log_level")
|
|
267
|
-
const resolvedInputs: Record<string, string> = {};
|
|
268
|
-
if (inputs) {
|
|
269
|
-
const paramElements = actionParams.map(p => p.element);
|
|
270
|
-
for (const [key, value] of Object.entries(inputs)) {
|
|
271
|
-
// Exact match first
|
|
272
|
-
if (paramElements.includes(key)) {
|
|
273
|
-
resolvedInputs[key] = value;
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
// Try to find a param whose element ends with the key or contains it
|
|
277
|
-
const match = actionParams.find(p => p.element.endsWith('_' + key) || p.element === key || p.label.toLowerCase() === key.toLowerCase());
|
|
278
|
-
if (match) {
|
|
279
|
-
resolvedInputs[match.element] = value;
|
|
280
|
-
} else {
|
|
281
|
-
resolvedInputs[key] = value;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
steps.resolved_inputs = resolvedInputs;
|
|
476
|
+
// Build full input objects with parameter definitions (matching UI format)
|
|
477
|
+
const inputResult = await buildActionInputsForInsert(client, actionDefId, inputs);
|
|
478
|
+
steps.available_inputs = inputResult.actionParams.map((p: any) => ({ element: p.element, label: p.label }));
|
|
479
|
+
steps.resolved_inputs = inputResult.resolvedInputs;
|
|
480
|
+
|
|
481
|
+
// Calculate insertion order and find elements that need reordering
|
|
482
|
+
const orderCalc = await calculateInsertOrder(client, flowId, parentUiId, order);
|
|
483
|
+
const resolvedOrder = orderCalc.insertOrder;
|
|
484
|
+
steps.insert_order = resolvedOrder;
|
|
485
|
+
if (orderCalc.reorders.flowLogicUpdates.length > 0 || orderCalc.reorders.actionUpdates.length > 0 || orderCalc.reorders.subflowUpdates.length > 0) {
|
|
486
|
+
steps.reordered_elements = {
|
|
487
|
+
flowLogics: orderCalc.reorders.flowLogicUpdates.length,
|
|
488
|
+
actions: orderCalc.reorders.actionUpdates.length,
|
|
489
|
+
subflows: orderCalc.reorders.subflowUpdates.length
|
|
490
|
+
};
|
|
285
491
|
}
|
|
286
492
|
|
|
287
493
|
const uuid = generateUUID();
|
|
288
|
-
const resolvedOrder = order || await getNextOrder(client, flowId);
|
|
289
494
|
const actionResponseFields = 'actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
290
|
-
|
|
291
|
-
|
|
495
|
+
' flowLogics { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
496
|
+
' subflows { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
|
|
497
|
+
|
|
498
|
+
// Build mutation payload — single INSERT with full inputs (matching UI behavior)
|
|
292
499
|
const flowPatch: any = {
|
|
293
500
|
flowId: flowId,
|
|
294
501
|
actions: {
|
|
@@ -302,35 +509,35 @@ async function addActionViaGraphQL(
|
|
|
302
509
|
uiUniqueIdentifier: uuid,
|
|
303
510
|
type: 'action',
|
|
304
511
|
parentUiId: parentUiId || '',
|
|
305
|
-
inputs:
|
|
512
|
+
inputs: inputResult.inputs
|
|
306
513
|
}]
|
|
307
514
|
}
|
|
308
515
|
};
|
|
516
|
+
|
|
517
|
+
// Merge reorder updates + parent flow logic update into the mutation
|
|
518
|
+
var flowLogicUpdates: any[] = orderCalc.reorders.flowLogicUpdates.slice();
|
|
309
519
|
if (parentUiId) {
|
|
310
|
-
|
|
520
|
+
// Add parent update (no order change, just signals the parent was modified)
|
|
521
|
+
// Avoid duplicating if the parent is already in the reorder list
|
|
522
|
+
var parentAlreadyIncluded = flowLogicUpdates.some(function (u: any) { return u.uiUniqueIdentifier === parentUiId; });
|
|
523
|
+
if (!parentAlreadyIncluded) {
|
|
524
|
+
flowLogicUpdates.push({ uiUniqueIdentifier: parentUiId, type: 'flowlogic' });
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (flowLogicUpdates.length > 0) {
|
|
528
|
+
flowPatch.flowLogics = { update: flowLogicUpdates };
|
|
529
|
+
}
|
|
530
|
+
if (orderCalc.reorders.actionUpdates.length > 0) {
|
|
531
|
+
flowPatch.actions.update = orderCalc.reorders.actionUpdates;
|
|
311
532
|
}
|
|
533
|
+
if (orderCalc.reorders.subflowUpdates.length > 0) {
|
|
534
|
+
flowPatch.subflows = { update: orderCalc.reorders.subflowUpdates };
|
|
535
|
+
}
|
|
536
|
+
|
|
312
537
|
try {
|
|
313
538
|
const result = await executeFlowPatchMutation(client, flowPatch, actionResponseFields);
|
|
314
|
-
|
|
315
539
|
const actionId = result?.actions?.inserts?.[0]?.sysId;
|
|
316
540
|
steps.insert = { success: !!actionId, actionId, uuid };
|
|
317
|
-
|
|
318
|
-
if (actionId && Object.keys(resolvedInputs).length > 0) {
|
|
319
|
-
const updateInputs = Object.entries(resolvedInputs).map(([name, value]) => ({
|
|
320
|
-
name,
|
|
321
|
-
value: { schemaless: false, schemalessValue: '', value: String(value) }
|
|
322
|
-
}));
|
|
323
|
-
try {
|
|
324
|
-
await executeFlowPatchMutation(client, {
|
|
325
|
-
flowId: flowId,
|
|
326
|
-
actions: { update: [{ uiUniqueIdentifier: uuid, type: 'action', inputs: updateInputs }] }
|
|
327
|
-
}, actionResponseFields);
|
|
328
|
-
steps.value_update = { success: true, inputs: updateInputs.map(i => i.name) };
|
|
329
|
-
} catch (e: any) {
|
|
330
|
-
steps.value_update = { success: false, error: e.message };
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
541
|
return { success: true, actionId: actionId || undefined, steps };
|
|
335
542
|
} catch (e: any) {
|
|
336
543
|
steps.insert = { success: false, error: e.message };
|
|
@@ -391,49 +598,63 @@ async function addFlowLogicViaGraphQL(
|
|
|
391
598
|
}
|
|
392
599
|
if (!defId) return { success: false, error: 'Flow logic definition not found for: ' + logicType, steps };
|
|
393
600
|
|
|
601
|
+
// Calculate insertion order with reordering
|
|
602
|
+
const orderCalc = await calculateInsertOrder(client, flowId, parentUiId, order);
|
|
603
|
+
const resolvedOrder = orderCalc.insertOrder;
|
|
604
|
+
steps.insert_order = resolvedOrder;
|
|
605
|
+
|
|
394
606
|
const uuid = generateUUID();
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
type: 'flowlogic',
|
|
410
|
-
parentUiId: parentUiId || '',
|
|
411
|
-
inputs: []
|
|
412
|
-
}]
|
|
413
|
-
}
|
|
414
|
-
}, logicResponseFields);
|
|
607
|
+
const logicResponseFields = 'flowLogics { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
608
|
+
' actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
609
|
+
' subflows { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
|
|
610
|
+
|
|
611
|
+
// Build flow logic input objects (for INSERT — matching UI format with id, name, value, parameter)
|
|
612
|
+
var logicInputObjects: any[] = [];
|
|
613
|
+
if (inputs && Object.keys(inputs).length > 0) {
|
|
614
|
+
logicInputObjects = Object.entries(inputs).map(function ([name, value]) {
|
|
615
|
+
return {
|
|
616
|
+
name: name,
|
|
617
|
+
value: { schemaless: false, schemalessValue: '', value: String(value) }
|
|
618
|
+
};
|
|
619
|
+
});
|
|
620
|
+
}
|
|
415
621
|
|
|
622
|
+
var flowPatch: any = {
|
|
623
|
+
flowId: flowId,
|
|
624
|
+
flowLogics: {
|
|
625
|
+
insert: [{
|
|
626
|
+
order: String(resolvedOrder),
|
|
627
|
+
uiUniqueIdentifier: uuid,
|
|
628
|
+
parent: '',
|
|
629
|
+
metadata: '{"predicates":[]}',
|
|
630
|
+
flowSysId: flowId,
|
|
631
|
+
generationSource: '',
|
|
632
|
+
definitionId: defId,
|
|
633
|
+
type: 'flowlogic',
|
|
634
|
+
parentUiId: parentUiId || '',
|
|
635
|
+
inputs: logicInputObjects
|
|
636
|
+
}]
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
// Merge reorder updates into flowLogics.update
|
|
641
|
+
if (orderCalc.reorders.flowLogicUpdates.length > 0) {
|
|
642
|
+
if (!flowPatch.flowLogics.update) flowPatch.flowLogics.update = [];
|
|
643
|
+
flowPatch.flowLogics.update = flowPatch.flowLogics.update.concat(orderCalc.reorders.flowLogicUpdates);
|
|
644
|
+
}
|
|
645
|
+
if (orderCalc.reorders.actionUpdates.length > 0) {
|
|
646
|
+
flowPatch.actions = { update: orderCalc.reorders.actionUpdates };
|
|
647
|
+
}
|
|
648
|
+
if (orderCalc.reorders.subflowUpdates.length > 0) {
|
|
649
|
+
flowPatch.subflows = { update: orderCalc.reorders.subflowUpdates };
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
try {
|
|
653
|
+
const result = await executeFlowPatchMutation(client, flowPatch, logicResponseFields);
|
|
416
654
|
const logicId = result?.flowLogics?.inserts?.[0]?.sysId;
|
|
417
655
|
steps.insert = { success: !!logicId, logicId, uuid };
|
|
418
656
|
if (!logicId) return { success: false, steps, error: 'GraphQL flow logic INSERT returned no ID' };
|
|
419
657
|
|
|
420
|
-
// Update with input values if provided
|
|
421
|
-
if (inputs && Object.keys(inputs).length > 0) {
|
|
422
|
-
const updateInputs = Object.entries(inputs).map(([name, value]) => ({
|
|
423
|
-
name,
|
|
424
|
-
value: { schemaless: false, schemalessValue: '', value: String(value) }
|
|
425
|
-
}));
|
|
426
|
-
try {
|
|
427
|
-
await executeFlowPatchMutation(client, {
|
|
428
|
-
flowId: flowId,
|
|
429
|
-
flowLogics: { update: [{ uiUniqueIdentifier: uuid, type: 'flowlogic', inputs: updateInputs }] }
|
|
430
|
-
}, logicResponseFields);
|
|
431
|
-
steps.value_update = { success: true, inputs: updateInputs.map(i => i.name) };
|
|
432
|
-
} catch (e: any) {
|
|
433
|
-
steps.value_update = { success: false, error: e.message };
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
658
|
return { success: true, logicId, steps };
|
|
438
659
|
} catch (e: any) {
|
|
439
660
|
steps.insert = { success: false, error: e.message };
|
|
@@ -499,10 +720,24 @@ async function addSubflowCallViaGraphQL(
|
|
|
499
720
|
|
|
500
721
|
if (!subflowName) subflowName = subflowId;
|
|
501
722
|
|
|
723
|
+
// Calculate insertion order with reordering
|
|
724
|
+
const orderCalc = await calculateInsertOrder(client, flowId, parentUiId, order);
|
|
725
|
+
const resolvedOrder = orderCalc.insertOrder;
|
|
726
|
+
steps.insert_order = resolvedOrder;
|
|
727
|
+
|
|
502
728
|
const uuid = generateUUID();
|
|
503
|
-
const resolvedOrder = order || await getNextOrder(client, flowId);
|
|
504
729
|
const subflowResponseFields = 'subflows { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
505
|
-
|
|
730
|
+
' flowLogics { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
731
|
+
' actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
|
|
732
|
+
|
|
733
|
+
// Build subflow input objects for INSERT
|
|
734
|
+
var subInputObjects: any[] = [];
|
|
735
|
+
if (inputs && Object.keys(inputs).length > 0) {
|
|
736
|
+
subInputObjects = Object.entries(inputs).map(function ([name, value]) {
|
|
737
|
+
return { name: name, value: { schemaless: false, schemalessValue: '', value: String(value) } };
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
506
741
|
const subPatch: any = {
|
|
507
742
|
flowId: flowId,
|
|
508
743
|
subflows: {
|
|
@@ -517,37 +752,35 @@ async function addSubflowCallViaGraphQL(
|
|
|
517
752
|
uiUniqueIdentifier: uuid,
|
|
518
753
|
type: 'subflow',
|
|
519
754
|
parentUiId: parentUiId || '',
|
|
520
|
-
inputs:
|
|
755
|
+
inputs: subInputObjects
|
|
521
756
|
}]
|
|
522
757
|
}
|
|
523
758
|
};
|
|
759
|
+
|
|
760
|
+
// Merge reorder updates + parent flow logic update
|
|
761
|
+
var subFlowLogicUpdates: any[] = orderCalc.reorders.flowLogicUpdates.slice();
|
|
524
762
|
if (parentUiId) {
|
|
525
|
-
|
|
763
|
+
var parentIncluded = subFlowLogicUpdates.some(function (u: any) { return u.uiUniqueIdentifier === parentUiId; });
|
|
764
|
+
if (!parentIncluded) {
|
|
765
|
+
subFlowLogicUpdates.push({ uiUniqueIdentifier: parentUiId, type: 'flowlogic' });
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
if (subFlowLogicUpdates.length > 0) {
|
|
769
|
+
subPatch.flowLogics = { update: subFlowLogicUpdates };
|
|
770
|
+
}
|
|
771
|
+
if (orderCalc.reorders.actionUpdates.length > 0) {
|
|
772
|
+
subPatch.actions = { update: orderCalc.reorders.actionUpdates };
|
|
526
773
|
}
|
|
774
|
+
if (orderCalc.reorders.subflowUpdates.length > 0) {
|
|
775
|
+
if (!subPatch.subflows.update) subPatch.subflows.update = [];
|
|
776
|
+
subPatch.subflows.update = subPatch.subflows.update.concat(orderCalc.reorders.subflowUpdates);
|
|
777
|
+
}
|
|
778
|
+
|
|
527
779
|
try {
|
|
528
780
|
const result = await executeFlowPatchMutation(client, subPatch, subflowResponseFields);
|
|
529
|
-
|
|
530
781
|
const callId = result?.subflows?.inserts?.[0]?.sysId;
|
|
531
782
|
steps.insert = { success: !!callId, callId, uuid };
|
|
532
783
|
if (!callId) return { success: false, steps, error: 'GraphQL subflow INSERT returned no ID' };
|
|
533
|
-
|
|
534
|
-
// Update with input values if provided
|
|
535
|
-
if (inputs && Object.keys(inputs).length > 0) {
|
|
536
|
-
const updateInputs = Object.entries(inputs).map(([name, value]) => ({
|
|
537
|
-
name,
|
|
538
|
-
value: { schemaless: false, schemalessValue: '', value: String(value) }
|
|
539
|
-
}));
|
|
540
|
-
try {
|
|
541
|
-
await executeFlowPatchMutation(client, {
|
|
542
|
-
flowId: flowId,
|
|
543
|
-
subflows: { update: [{ uiUniqueIdentifier: uuid, type: 'subflow', inputs: updateInputs }] }
|
|
544
|
-
}, subflowResponseFields);
|
|
545
|
-
steps.value_update = { success: true, inputs: updateInputs.map(i => i.name) };
|
|
546
|
-
} catch (e: any) {
|
|
547
|
-
steps.value_update = { success: false, error: e.message };
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
784
|
return { success: true, callId, steps };
|
|
552
785
|
} catch (e: any) {
|
|
553
786
|
steps.insert = { success: false, error: e.message };
|