snow-flow 10.0.1-dev.449 → 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
|
@@ -38,15 +38,14 @@ function generateUUID(): string {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
async function getNextOrder(client: any, flowId: string
|
|
41
|
+
async function getNextOrder(client: any, flowId: string): Promise<number> {
|
|
42
42
|
let maxOrder = 0;
|
|
43
|
-
//
|
|
44
|
-
const parentFilter = parentId ? '^parent=' + parentId : '^parentISEMPTY';
|
|
43
|
+
// Order is global across all elements in the flow (not per-parent)
|
|
45
44
|
for (const table of ['sys_hub_action_instance', 'sys_hub_flow_logic', 'sys_hub_sub_flow_instance']) {
|
|
46
45
|
try {
|
|
47
46
|
const resp = await client.get('/api/now/table/' + table, {
|
|
48
47
|
params: {
|
|
49
|
-
sysparm_query: 'flow=' + flowId +
|
|
48
|
+
sysparm_query: 'flow=' + flowId + '^ORDERBYDESCorder',
|
|
50
49
|
sysparm_fields: 'order',
|
|
51
50
|
sysparm_limit: 1
|
|
52
51
|
}
|
|
@@ -73,6 +72,239 @@ async function executeFlowPatchMutation(
|
|
|
73
72
|
return resp.data?.data?.global?.snFlowDesigner?.flow || resp.data;
|
|
74
73
|
}
|
|
75
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
|
+
|
|
76
308
|
async function addTriggerViaGraphQL(
|
|
77
309
|
client: any,
|
|
78
310
|
flowId: string,
|
|
@@ -210,7 +442,6 @@ async function addActionViaGraphQL(
|
|
|
210
442
|
|
|
211
443
|
// Dynamically look up action definition in sys_hub_action_type_snapshot
|
|
212
444
|
let actionDefId: string | null = null;
|
|
213
|
-
// Try exact match on internal_name first, then name
|
|
214
445
|
for (const field of ['internal_name', 'name']) {
|
|
215
446
|
if (actionDefId) break;
|
|
216
447
|
try {
|
|
@@ -224,7 +455,6 @@ async function addActionViaGraphQL(
|
|
|
224
455
|
}
|
|
225
456
|
} catch (_) {}
|
|
226
457
|
}
|
|
227
|
-
// Fallback: LIKE search on both fields
|
|
228
458
|
if (!actionDefId) {
|
|
229
459
|
try {
|
|
230
460
|
const resp = await client.get('/api/now/table/sys_hub_action_type_snapshot', {
|
|
@@ -243,89 +473,71 @@ async function addActionViaGraphQL(
|
|
|
243
473
|
}
|
|
244
474
|
if (!actionDefId) return { success: false, error: 'Action definition not found for: ' + actionType, steps };
|
|
245
475
|
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
internal_type: r.internal_type || ''
|
|
263
|
-
}));
|
|
264
|
-
steps.available_inputs = actionParams;
|
|
265
|
-
} catch (_) {}
|
|
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
|
+
};
|
|
491
|
+
}
|
|
266
492
|
|
|
267
|
-
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
493
|
+
const uuid = generateUUID();
|
|
494
|
+
const actionResponseFields = 'actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
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)
|
|
499
|
+
const flowPatch: any = {
|
|
500
|
+
flowId: flowId,
|
|
501
|
+
actions: {
|
|
502
|
+
insert: [{
|
|
503
|
+
actionTypeSysId: actionDefId,
|
|
504
|
+
metadata: '{"predicates":[]}',
|
|
505
|
+
flowSysId: flowId,
|
|
506
|
+
generationSource: '',
|
|
507
|
+
order: String(resolvedOrder),
|
|
508
|
+
parent: parentUiId || '',
|
|
509
|
+
uiUniqueIdentifier: uuid,
|
|
510
|
+
type: 'action',
|
|
511
|
+
parentUiId: parentUiId || '',
|
|
512
|
+
inputs: inputResult.inputs
|
|
513
|
+
}]
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
// Merge reorder updates + parent flow logic update into the mutation
|
|
518
|
+
var flowLogicUpdates: any[] = orderCalc.reorders.flowLogicUpdates.slice();
|
|
519
|
+
if (parentUiId) {
|
|
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' });
|
|
284
525
|
}
|
|
285
|
-
|
|
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;
|
|
532
|
+
}
|
|
533
|
+
if (orderCalc.reorders.subflowUpdates.length > 0) {
|
|
534
|
+
flowPatch.subflows = { update: orderCalc.reorders.subflowUpdates };
|
|
286
535
|
}
|
|
287
536
|
|
|
288
|
-
const uuid = generateUUID();
|
|
289
|
-
const resolvedOrder = order || await getNextOrder(client, flowId, parentUiId);
|
|
290
|
-
const actionResponseFields = 'actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
|
|
291
537
|
try {
|
|
292
|
-
const result = await executeFlowPatchMutation(client,
|
|
293
|
-
flowId: flowId,
|
|
294
|
-
actions: {
|
|
295
|
-
insert: [{
|
|
296
|
-
actionTypeSysId: actionDefId,
|
|
297
|
-
metadata: '{"predicates":[]}',
|
|
298
|
-
flowSysId: flowId,
|
|
299
|
-
generationSource: '',
|
|
300
|
-
order: String(resolvedOrder),
|
|
301
|
-
parent: parentUiId || '',
|
|
302
|
-
uiUniqueIdentifier: uuid,
|
|
303
|
-
type: 'action',
|
|
304
|
-
parentUiId: parentUiId || '',
|
|
305
|
-
inputs: []
|
|
306
|
-
}]
|
|
307
|
-
}
|
|
308
|
-
}, actionResponseFields);
|
|
309
|
-
|
|
538
|
+
const result = await executeFlowPatchMutation(client, flowPatch, actionResponseFields);
|
|
310
539
|
const actionId = result?.actions?.inserts?.[0]?.sysId;
|
|
311
540
|
steps.insert = { success: !!actionId, actionId, uuid };
|
|
312
|
-
|
|
313
|
-
if (actionId && Object.keys(resolvedInputs).length > 0) {
|
|
314
|
-
const updateInputs = Object.entries(resolvedInputs).map(([name, value]) => ({
|
|
315
|
-
name,
|
|
316
|
-
value: { schemaless: false, schemalessValue: '', value: String(value) }
|
|
317
|
-
}));
|
|
318
|
-
try {
|
|
319
|
-
await executeFlowPatchMutation(client, {
|
|
320
|
-
flowId: flowId,
|
|
321
|
-
actions: { update: [{ uiUniqueIdentifier: uuid, type: 'action', inputs: updateInputs }] }
|
|
322
|
-
}, actionResponseFields);
|
|
323
|
-
steps.value_update = { success: true, inputs: updateInputs.map(i => i.name) };
|
|
324
|
-
} catch (e: any) {
|
|
325
|
-
steps.value_update = { success: false, error: e.message };
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
541
|
return { success: true, actionId: actionId || undefined, steps };
|
|
330
542
|
} catch (e: any) {
|
|
331
543
|
steps.insert = { success: false, error: e.message };
|
|
@@ -386,49 +598,63 @@ async function addFlowLogicViaGraphQL(
|
|
|
386
598
|
}
|
|
387
599
|
if (!defId) return { success: false, error: 'Flow logic definition not found for: ' + logicType, steps };
|
|
388
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
|
+
|
|
389
606
|
const uuid = generateUUID();
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
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
|
+
}
|
|
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
|
+
}
|
|
410
651
|
|
|
652
|
+
try {
|
|
653
|
+
const result = await executeFlowPatchMutation(client, flowPatch, logicResponseFields);
|
|
411
654
|
const logicId = result?.flowLogics?.inserts?.[0]?.sysId;
|
|
412
655
|
steps.insert = { success: !!logicId, logicId, uuid };
|
|
413
656
|
if (!logicId) return { success: false, steps, error: 'GraphQL flow logic INSERT returned no ID' };
|
|
414
657
|
|
|
415
|
-
// Update with input values if provided
|
|
416
|
-
if (inputs && Object.keys(inputs).length > 0) {
|
|
417
|
-
const updateInputs = Object.entries(inputs).map(([name, value]) => ({
|
|
418
|
-
name,
|
|
419
|
-
value: { schemaless: false, schemalessValue: '', value: String(value) }
|
|
420
|
-
}));
|
|
421
|
-
try {
|
|
422
|
-
await executeFlowPatchMutation(client, {
|
|
423
|
-
flowId: flowId,
|
|
424
|
-
flowLogics: { update: [{ uiUniqueIdentifier: uuid, type: 'flowlogic', inputs: updateInputs }] }
|
|
425
|
-
}, logicResponseFields);
|
|
426
|
-
steps.value_update = { success: true, inputs: updateInputs.map(i => i.name) };
|
|
427
|
-
} catch (e: any) {
|
|
428
|
-
steps.value_update = { success: false, error: e.message };
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
658
|
return { success: true, logicId, steps };
|
|
433
659
|
} catch (e: any) {
|
|
434
660
|
steps.insert = { success: false, error: e.message };
|
|
@@ -494,50 +720,67 @@ async function addSubflowCallViaGraphQL(
|
|
|
494
720
|
|
|
495
721
|
if (!subflowName) subflowName = subflowId;
|
|
496
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
|
+
|
|
497
728
|
const uuid = generateUUID();
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
order: String(resolvedOrder),
|
|
510
|
-
parent: parentUiId || '',
|
|
511
|
-
subflowSysId: subflowSysId,
|
|
512
|
-
uiUniqueIdentifier: uuid,
|
|
513
|
-
type: 'subflow',
|
|
514
|
-
parentUiId: parentUiId || '',
|
|
515
|
-
inputs: []
|
|
516
|
-
}]
|
|
517
|
-
}
|
|
518
|
-
}, subflowResponseFields);
|
|
729
|
+
const subflowResponseFields = 'subflows { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
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
|
+
}
|
|
519
740
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
741
|
+
const subPatch: any = {
|
|
742
|
+
flowId: flowId,
|
|
743
|
+
subflows: {
|
|
744
|
+
insert: [{
|
|
745
|
+
metadata: '{"predicates":[]}',
|
|
746
|
+
flowSysId: flowId,
|
|
747
|
+
generationSource: '',
|
|
748
|
+
name: subflowName,
|
|
749
|
+
order: String(resolvedOrder),
|
|
750
|
+
parent: parentUiId || '',
|
|
751
|
+
subflowSysId: subflowSysId,
|
|
752
|
+
uiUniqueIdentifier: uuid,
|
|
753
|
+
type: 'subflow',
|
|
754
|
+
parentUiId: parentUiId || '',
|
|
755
|
+
inputs: subInputObjects
|
|
756
|
+
}]
|
|
757
|
+
}
|
|
758
|
+
};
|
|
523
759
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
})
|
|
530
|
-
try {
|
|
531
|
-
await executeFlowPatchMutation(client, {
|
|
532
|
-
flowId: flowId,
|
|
533
|
-
subflows: { update: [{ uiUniqueIdentifier: uuid, type: 'subflow', inputs: updateInputs }] }
|
|
534
|
-
}, subflowResponseFields);
|
|
535
|
-
steps.value_update = { success: true, inputs: updateInputs.map(i => i.name) };
|
|
536
|
-
} catch (e: any) {
|
|
537
|
-
steps.value_update = { success: false, error: e.message };
|
|
538
|
-
}
|
|
760
|
+
// Merge reorder updates + parent flow logic update
|
|
761
|
+
var subFlowLogicUpdates: any[] = orderCalc.reorders.flowLogicUpdates.slice();
|
|
762
|
+
if (parentUiId) {
|
|
763
|
+
var parentIncluded = subFlowLogicUpdates.some(function (u: any) { return u.uiUniqueIdentifier === parentUiId; });
|
|
764
|
+
if (!parentIncluded) {
|
|
765
|
+
subFlowLogicUpdates.push({ uiUniqueIdentifier: parentUiId, type: 'flowlogic' });
|
|
539
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 };
|
|
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
|
+
}
|
|
540
778
|
|
|
779
|
+
try {
|
|
780
|
+
const result = await executeFlowPatchMutation(client, subPatch, subflowResponseFields);
|
|
781
|
+
const callId = result?.subflows?.inserts?.[0]?.sysId;
|
|
782
|
+
steps.insert = { success: !!callId, callId, uuid };
|
|
783
|
+
if (!callId) return { success: false, steps, error: 'GraphQL subflow INSERT returned no ID' };
|
|
541
784
|
return { success: true, callId, steps };
|
|
542
785
|
} catch (e: any) {
|
|
543
786
|
steps.insert = { success: false, error: e.message };
|