@burdenoff/fluidgrids-fe-sdk 2026.1022.13 → 2026.1022.17
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/ExecutionDetailPage-K3MPJLTL.js +16 -0
- package/dist/ExecutionsListPage-UGC5KFAT.js +16 -0
- package/dist/WorkflowBuilder-5A3NUIUI.js +19 -0
- package/dist/WorkflowsList-DEQZUFDG.js +16 -0
- package/dist/{chunk-KNFGMDDU.js → chunk-2QTKDR23.js} +32 -7
- package/dist/{chunk-QEPYK454.js → chunk-CZURRUDX.js} +32 -1
- package/dist/{chunk-IEHL6TYP.js → chunk-E7NQZB2E.js} +5 -5
- package/dist/{chunk-VM2BTPX3.js → chunk-HAYSY6TZ.js} +1 -2
- package/dist/{chunk-GO4UTLV4.js → chunk-IULOX3NQ.js} +1 -1
- package/dist/{chunk-3B3624QM.js → chunk-J3XDX5HG.js} +112 -58
- package/dist/{chunk-2M43OY55.js → chunk-KAOLPDNX.js} +1 -1
- package/dist/{chunk-AN7H42WZ.js → chunk-L7F7DLUP.js} +3 -3
- package/dist/{chunk-EZF3VWUB.js → chunk-LLPLOWMA.js} +44 -10
- package/dist/{chunk-G7RP3WRM.js → chunk-MP7MRTB4.js} +5 -6
- package/dist/chunk-MR4OTF7D.js +8026 -0
- package/dist/{chunk-SOPYCZCR.js → chunk-NJZAWUGC.js} +1 -1
- package/dist/{chunk-SYVLFHWV.js → chunk-OD2XBMS6.js} +21 -2
- package/dist/{chunk-OF33XHOO.js → chunk-ORVIG2XW.js} +2 -2
- package/dist/{chunk-MY3T465I.js → chunk-Q7NNS2FW.js} +3 -3
- package/dist/{chunk-5KPXP4JF.js → chunk-TQRBDECQ.js} +329 -6886
- package/dist/{chunk-C2RCYSRB.js → chunk-UQWPZVOS.js} +3 -3
- package/dist/{chunk-NQZFS6N7.js → chunk-V75733EN.js} +18 -6
- package/dist/{chunk-ZKCLX2VR.js → chunk-XCQROWIZ.js} +3 -3
- package/dist/{chunk-KCXRF6DF.js → chunk-ZQDMK22B.js} +5 -6
- package/dist/executions.js +13 -12
- package/dist/history.js +8 -5
- package/dist/index.d.ts +110 -3
- package/dist/index.js +35 -39
- package/dist/nodes.js +2 -3
- package/dist/observability.js +8 -3
- package/dist/settings.js +8 -5
- package/dist/templates.js +12 -15
- package/dist/workflow-builder.js +11 -14
- package/dist/workflows-list.js +10 -10
- package/package.json +1 -1
- package/dist/ExecutionDetailPage-ZPM3HVVX.js +0 -15
- package/dist/ExecutionsListPage-BURTBLWB.js +0 -13
- package/dist/WorkflowBuilder-YBJ5FIVW.js +0 -22
- package/dist/WorkflowsList-QQLKSYVM.js +0 -16
- package/dist/chunk-4UAWCWS7.js +0 -162
- package/dist/chunk-AVJIWVHL.js +0 -34
- package/dist/chunk-ONVGFVNH.js +0 -167
- package/dist/chunk-VI2RFS65.js +0 -880
package/dist/chunk-VI2RFS65.js
DELETED
|
@@ -1,880 +0,0 @@
|
|
|
1
|
-
import { nanoid } from 'nanoid/non-secure';
|
|
2
|
-
import { addEdge, applyEdgeChanges, applyNodeChanges } from '@xyflow/react';
|
|
3
|
-
import { create } from 'zustand';
|
|
4
|
-
import { produce } from 'immer';
|
|
5
|
-
import { useCallback } from 'react';
|
|
6
|
-
|
|
7
|
-
// src/builder/lib/node-role.ts
|
|
8
|
-
function isRecord(value) {
|
|
9
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
|
-
}
|
|
11
|
-
function readRecord(value) {
|
|
12
|
-
return isRecord(value) ? value : void 0;
|
|
13
|
-
}
|
|
14
|
-
function readString(value) {
|
|
15
|
-
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
16
|
-
}
|
|
17
|
-
function operationRole(operation) {
|
|
18
|
-
const metadata = readRecord(operation);
|
|
19
|
-
const role = readString(metadata?.role);
|
|
20
|
-
if (role) return role === "trigger" ? "trigger" : "action";
|
|
21
|
-
const type = readString(metadata?.type);
|
|
22
|
-
if (type === "trigger" || type === "subscription" || readString(metadata?.delivery)) {
|
|
23
|
-
return "trigger";
|
|
24
|
-
}
|
|
25
|
-
if (type === "action" || type === "query" || type === "mutation") {
|
|
26
|
-
return "action";
|
|
27
|
-
}
|
|
28
|
-
return void 0;
|
|
29
|
-
}
|
|
30
|
-
function isTriggerOperation(operation) {
|
|
31
|
-
return operationRole(operation) === "trigger";
|
|
32
|
-
}
|
|
33
|
-
function isLegacyTriggerType(type) {
|
|
34
|
-
return type === "trigger" || type.startsWith("trigger:") || type.startsWith("internal:schedule") || type.startsWith("internal:webhook") || type.startsWith("internal:api") || type.startsWith("internal:form") || type.startsWith("internal:mcp") || type.endsWith("_trigger") || type.endsWith("Trigger") || type.endsWith("-trigger");
|
|
35
|
-
}
|
|
36
|
-
function getSelectedOperationRole(nodeType, nodeData) {
|
|
37
|
-
const data = readRecord(nodeData);
|
|
38
|
-
const operationName = data?.operation_name;
|
|
39
|
-
if (typeof operationName !== "string" || !operationName.trim())
|
|
40
|
-
return void 0;
|
|
41
|
-
const manifest = readRecord(data?.nodeData);
|
|
42
|
-
const declared = manifest?.operations;
|
|
43
|
-
const operations = Array.isArray(declared) ? declared : readRecord(declared)?.operations;
|
|
44
|
-
const operation = Array.isArray(operations) ? operations.find(
|
|
45
|
-
(entry) => readRecord(entry)?.name === operationName
|
|
46
|
-
) : void 0;
|
|
47
|
-
const selectedRole = operationRole(operation) ?? operationRole({ type: data?.operation_type });
|
|
48
|
-
if (selectedRole) return selectedRole;
|
|
49
|
-
if (nodeType === "integration/channel" || nodeType?.startsWith("store/")) {
|
|
50
|
-
return operationName.startsWith("on") ? "trigger" : "action";
|
|
51
|
-
}
|
|
52
|
-
return void 0;
|
|
53
|
-
}
|
|
54
|
-
function isNodeTrigger(node) {
|
|
55
|
-
const data = readRecord(node.data);
|
|
56
|
-
const selectedRole = getSelectedOperationRole(node.type, data);
|
|
57
|
-
if (selectedRole) return selectedRole === "trigger";
|
|
58
|
-
const state = readRecord(readRecord(data?.args)?.state);
|
|
59
|
-
for (const legacyRole of [data?.role, state?.role]) {
|
|
60
|
-
const explicitRole = readString(legacyRole);
|
|
61
|
-
if (explicitRole === "trigger" || explicitRole === "action") {
|
|
62
|
-
return explicitRole === "trigger";
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const savedRole = operationRole({ type: data?.operation_type });
|
|
66
|
-
if (savedRole) return savedRole === "trigger";
|
|
67
|
-
const type = node.type ?? "";
|
|
68
|
-
if (isLegacyTriggerType(type)) return true;
|
|
69
|
-
const manifest = readRecord(data?.nodeData);
|
|
70
|
-
if (!data?.operation_name && Array.isArray(manifest?.kind) && manifest.kind.includes("trigger")) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/builder/hooks/use-is-valid-connection.ts
|
|
77
|
-
function isLoopController(source) {
|
|
78
|
-
const type = source?.type?.toLowerCase();
|
|
79
|
-
const disabled = source?.data?.disabled === true || source !== void 0 && "disabled" in source && source.disabled === true;
|
|
80
|
-
return (type === "internal:loop" || type === "loop") && !disabled;
|
|
81
|
-
}
|
|
82
|
-
function isRecord2(value) {
|
|
83
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
84
|
-
}
|
|
85
|
-
function readRecord2(value) {
|
|
86
|
-
return isRecord2(value) ? value : void 0;
|
|
87
|
-
}
|
|
88
|
-
function loopBodyHandle(source) {
|
|
89
|
-
const node = readRecord2(source);
|
|
90
|
-
const data = readRecord2(node?.data);
|
|
91
|
-
const parameters = {
|
|
92
|
-
...data,
|
|
93
|
-
...readRecord2(node?.config),
|
|
94
|
-
...readRecord2(readRecord2(data?.args)?.state),
|
|
95
|
-
...readRecord2(readRecord2(node?.args)?.state)
|
|
96
|
-
};
|
|
97
|
-
return typeof parameters.loopHandle === "string" && parameters.loopHandle ? parameters.loopHandle : "loop";
|
|
98
|
-
}
|
|
99
|
-
function isLoopBodyEdge(edge, nodes) {
|
|
100
|
-
const source = nodes.find((node) => node.id === edge.source);
|
|
101
|
-
return source !== void 0 && isLoopController(source) && edge.sourceHandle === loopBodyHandle(source);
|
|
102
|
-
}
|
|
103
|
-
function adjacency(edges) {
|
|
104
|
-
const outgoing = /* @__PURE__ */ new Map();
|
|
105
|
-
for (const edge of edges) {
|
|
106
|
-
const targets = outgoing.get(edge.source) ?? /* @__PURE__ */ new Set();
|
|
107
|
-
targets.add(edge.target);
|
|
108
|
-
outgoing.set(edge.source, targets);
|
|
109
|
-
}
|
|
110
|
-
return outgoing;
|
|
111
|
-
}
|
|
112
|
-
function reachable(starts, outgoing, blocked = /* @__PURE__ */ new Set()) {
|
|
113
|
-
const pending = [...starts];
|
|
114
|
-
const visited = /* @__PURE__ */ new Set();
|
|
115
|
-
while (pending.length > 0) {
|
|
116
|
-
const current = pending.pop();
|
|
117
|
-
if (current === void 0 || visited.has(current) || blocked.has(current))
|
|
118
|
-
continue;
|
|
119
|
-
visited.add(current);
|
|
120
|
-
pending.push(...outgoing.get(current) ?? []);
|
|
121
|
-
}
|
|
122
|
-
return visited;
|
|
123
|
-
}
|
|
124
|
-
function controlledReturns(nodes, edges) {
|
|
125
|
-
const outgoing = adjacency(edges);
|
|
126
|
-
const incomingTargets = new Set(edges.map((edge) => edge.target));
|
|
127
|
-
const entries = nodes.filter((node) => !incomingTargets.has(node.id) || isNodeTrigger(node)).map((node) => node.id);
|
|
128
|
-
const returns = /* @__PURE__ */ new Set();
|
|
129
|
-
for (const controller of nodes.filter(isLoopController)) {
|
|
130
|
-
const bodyHandle = loopBodyHandle(controller);
|
|
131
|
-
const controllerEdges = edges.filter(
|
|
132
|
-
(edge) => edge.source === controller.id
|
|
133
|
-
);
|
|
134
|
-
const outside = reachable(
|
|
135
|
-
[
|
|
136
|
-
...entries,
|
|
137
|
-
...controllerEdges.filter((edge) => edge.sourceHandle !== bodyHandle).map((edge) => edge.target)
|
|
138
|
-
],
|
|
139
|
-
outgoing,
|
|
140
|
-
/* @__PURE__ */ new Set([controller.id])
|
|
141
|
-
);
|
|
142
|
-
const body = reachable(
|
|
143
|
-
controllerEdges.filter((edge) => edge.sourceHandle === bodyHandle).map((edge) => edge.target),
|
|
144
|
-
outgoing,
|
|
145
|
-
/* @__PURE__ */ new Set([controller.id, ...outside])
|
|
146
|
-
);
|
|
147
|
-
for (const edge of edges) {
|
|
148
|
-
if (edge.target === controller.id && body.has(edge.source))
|
|
149
|
-
returns.add(edge);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return returns;
|
|
153
|
-
}
|
|
154
|
-
function isValidWorkflowConnection(nodes, edges, connection) {
|
|
155
|
-
if (connection.target === connection.source) return false;
|
|
156
|
-
const candidates = [...edges, connection];
|
|
157
|
-
const previousReturns = controlledReturns(nodes, edges);
|
|
158
|
-
const nextReturns = controlledReturns(nodes, candidates);
|
|
159
|
-
const outgoing = adjacency(
|
|
160
|
-
candidates.filter((edge) => !nextReturns.has(edge))
|
|
161
|
-
);
|
|
162
|
-
const invalidated = [connection, ...previousReturns].filter(
|
|
163
|
-
(edge) => !nextReturns.has(edge)
|
|
164
|
-
);
|
|
165
|
-
return invalidated.every(
|
|
166
|
-
(edge) => !reachable([edge.target], outgoing).has(edge.source)
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
function useIsValidConnection(nodes, edges) {
|
|
170
|
-
return useCallback(
|
|
171
|
-
(connection) => isValidWorkflowConnection(nodes, edges, connection),
|
|
172
|
-
[nodes, edges]
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// src/builder/stores/flow-store.ts
|
|
177
|
-
var HISTORY_LIMIT = 100;
|
|
178
|
-
var CLONE_OFFSET = 48;
|
|
179
|
-
function cloneValue(value) {
|
|
180
|
-
try {
|
|
181
|
-
return structuredClone(value);
|
|
182
|
-
} catch {
|
|
183
|
-
return JSON.parse(JSON.stringify(value));
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
var TAGS = [
|
|
187
|
-
{ value: "marketing", label: "Marketing", color: "var(--color-chart-5)" },
|
|
188
|
-
{ value: "support", label: "Support", color: "var(--color-chart-5)" },
|
|
189
|
-
{ value: "lead", label: "Lead", color: "var(--color-chart-4)" },
|
|
190
|
-
{ value: "new", label: "New", color: "var(--color-chart-7)" }
|
|
191
|
-
];
|
|
192
|
-
var INITIAL_EXECUTION = {
|
|
193
|
-
isExecuting: false,
|
|
194
|
-
executingNodeId: null,
|
|
195
|
-
currentRunId: null,
|
|
196
|
-
sourceRun: null,
|
|
197
|
-
stepPlan: null,
|
|
198
|
-
logs: [],
|
|
199
|
-
selectedLogId: null,
|
|
200
|
-
panelExpanded: false,
|
|
201
|
-
nodeStatuses: {},
|
|
202
|
-
nodeItemCounts: {},
|
|
203
|
-
followRequest: null
|
|
204
|
-
};
|
|
205
|
-
var INITIAL_HISTORY = { past: [], future: [] };
|
|
206
|
-
var useFlowStore = create()((set, get) => {
|
|
207
|
-
let lastCheckpointKind = null;
|
|
208
|
-
let lastCheckpointAt = 0;
|
|
209
|
-
function pushCheckpoint(kind, coalesce) {
|
|
210
|
-
const now = Date.now();
|
|
211
|
-
const isCoalesced = coalesce && kind === lastCheckpointKind && now - lastCheckpointAt < 800;
|
|
212
|
-
if (!isCoalesced) {
|
|
213
|
-
const state = get();
|
|
214
|
-
const snapshot = {
|
|
215
|
-
nodes: cloneValue(state.workflow.nodes),
|
|
216
|
-
edges: cloneValue(state.workflow.edges)
|
|
217
|
-
};
|
|
218
|
-
set((s) => ({
|
|
219
|
-
history: {
|
|
220
|
-
past: [...s.history.past, snapshot].slice(-HISTORY_LIMIT),
|
|
221
|
-
future: []
|
|
222
|
-
}
|
|
223
|
-
}));
|
|
224
|
-
} else if (get().history.future.length > 0) {
|
|
225
|
-
set((s) => ({ history: { ...s.history, future: [] } }));
|
|
226
|
-
}
|
|
227
|
-
lastCheckpointKind = kind;
|
|
228
|
-
lastCheckpointAt = now;
|
|
229
|
-
}
|
|
230
|
-
const REMOVAL_KINDS = /* @__PURE__ */ new Set(["nodes:remove", "edges:remove"]);
|
|
231
|
-
const SAME_ACTION_WINDOW_MS = 150;
|
|
232
|
-
function joinsPrecedingRemoval(kind) {
|
|
233
|
-
return lastCheckpointKind !== null && lastCheckpointKind !== kind && REMOVAL_KINDS.has(kind) && REMOVAL_KINDS.has(lastCheckpointKind) && Date.now() - lastCheckpointAt < SAME_ACTION_WINDOW_MS;
|
|
234
|
-
}
|
|
235
|
-
function resetCoalescing() {
|
|
236
|
-
lastCheckpointKind = null;
|
|
237
|
-
lastCheckpointAt = 0;
|
|
238
|
-
}
|
|
239
|
-
return {
|
|
240
|
-
tags: TAGS,
|
|
241
|
-
history: { ...INITIAL_HISTORY },
|
|
242
|
-
workflow: {
|
|
243
|
-
id: nanoid(),
|
|
244
|
-
workflowKey: "",
|
|
245
|
-
name: "",
|
|
246
|
-
version: "",
|
|
247
|
-
alias: "",
|
|
248
|
-
edges: [],
|
|
249
|
-
nodes: [],
|
|
250
|
-
ndv: null,
|
|
251
|
-
quickConfig: null,
|
|
252
|
-
pendingConnection: null,
|
|
253
|
-
renamingNodeId: null,
|
|
254
|
-
sidebar: {
|
|
255
|
-
active: "none",
|
|
256
|
-
panels: {
|
|
257
|
-
nodeProperties: {
|
|
258
|
-
selectedNode: null
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
execution: { ...INITIAL_EXECUTION },
|
|
264
|
-
actions: {
|
|
265
|
-
saveWorkflow: () => {
|
|
266
|
-
const { workflow } = get();
|
|
267
|
-
const { id, name, version, alias, dbId, status, nodes, edges } = workflow;
|
|
268
|
-
set({ workflow });
|
|
269
|
-
return { id, name, version, alias, dbId, status, nodes, edges };
|
|
270
|
-
},
|
|
271
|
-
setWorkflow: (workflow) => {
|
|
272
|
-
set((state) => ({
|
|
273
|
-
workflow: {
|
|
274
|
-
...state.workflow,
|
|
275
|
-
...workflow
|
|
276
|
-
}
|
|
277
|
-
}));
|
|
278
|
-
},
|
|
279
|
-
resetWorkflow: () => {
|
|
280
|
-
resetCoalescing();
|
|
281
|
-
set(() => ({
|
|
282
|
-
workflow: {
|
|
283
|
-
id: nanoid(),
|
|
284
|
-
workflowKey: "",
|
|
285
|
-
name: "",
|
|
286
|
-
version: "",
|
|
287
|
-
alias: "",
|
|
288
|
-
dbId: void 0,
|
|
289
|
-
status: void 0,
|
|
290
|
-
edges: [],
|
|
291
|
-
nodes: [],
|
|
292
|
-
ndv: null,
|
|
293
|
-
quickConfig: null,
|
|
294
|
-
pendingConnection: null,
|
|
295
|
-
renamingNodeId: null,
|
|
296
|
-
sidebar: {
|
|
297
|
-
active: "none",
|
|
298
|
-
panels: {
|
|
299
|
-
nodeProperties: {
|
|
300
|
-
selectedNode: null
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
},
|
|
305
|
-
// Wipe run state too — resetWorkflow fires when the builder loads a
|
|
306
|
-
// (different) workflow, so the previous workflow's logs must not carry
|
|
307
|
-
// over into this one's Logs panel.
|
|
308
|
-
execution: { ...INITIAL_EXECUTION },
|
|
309
|
-
// A freshly loaded workflow must not be undo-able back to empty —
|
|
310
|
-
// undo/redo only ever applies within the currently open workflow.
|
|
311
|
-
history: { ...INITIAL_HISTORY }
|
|
312
|
-
}));
|
|
313
|
-
},
|
|
314
|
-
history: {
|
|
315
|
-
undo: () => {
|
|
316
|
-
const { past, future } = get().history;
|
|
317
|
-
const previous = past[past.length - 1];
|
|
318
|
-
if (!previous) return;
|
|
319
|
-
const { nodes, edges } = get().workflow;
|
|
320
|
-
const current = {
|
|
321
|
-
nodes: cloneValue(nodes),
|
|
322
|
-
edges: cloneValue(edges)
|
|
323
|
-
};
|
|
324
|
-
resetCoalescing();
|
|
325
|
-
set((s) => ({
|
|
326
|
-
workflow: {
|
|
327
|
-
...s.workflow,
|
|
328
|
-
nodes: previous.nodes,
|
|
329
|
-
edges: previous.edges
|
|
330
|
-
},
|
|
331
|
-
history: {
|
|
332
|
-
past: past.slice(0, -1),
|
|
333
|
-
future: [current, ...future].slice(0, HISTORY_LIMIT)
|
|
334
|
-
}
|
|
335
|
-
}));
|
|
336
|
-
},
|
|
337
|
-
redo: () => {
|
|
338
|
-
const { past, future } = get().history;
|
|
339
|
-
const next = future[0];
|
|
340
|
-
if (!next) return;
|
|
341
|
-
const { nodes, edges } = get().workflow;
|
|
342
|
-
const current = {
|
|
343
|
-
nodes: cloneValue(nodes),
|
|
344
|
-
edges: cloneValue(edges)
|
|
345
|
-
};
|
|
346
|
-
resetCoalescing();
|
|
347
|
-
set((s) => ({
|
|
348
|
-
workflow: {
|
|
349
|
-
...s.workflow,
|
|
350
|
-
nodes: next.nodes,
|
|
351
|
-
edges: next.edges
|
|
352
|
-
},
|
|
353
|
-
history: {
|
|
354
|
-
past: [...past, current].slice(-HISTORY_LIMIT),
|
|
355
|
-
future: future.slice(1)
|
|
356
|
-
}
|
|
357
|
-
}));
|
|
358
|
-
},
|
|
359
|
-
clear: () => {
|
|
360
|
-
resetCoalescing();
|
|
361
|
-
set({ history: { ...INITIAL_HISTORY } });
|
|
362
|
-
}
|
|
363
|
-
},
|
|
364
|
-
ndv: {
|
|
365
|
-
// Opening the full NDV supersedes the floating quick-config panel — the
|
|
366
|
-
// two edit the same node data, so only one should be visible at a time.
|
|
367
|
-
open: (node) => set((state) => ({
|
|
368
|
-
workflow: { ...state.workflow, ndv: node, quickConfig: null }
|
|
369
|
-
})),
|
|
370
|
-
close: () => set((state) => ({
|
|
371
|
-
workflow: { ...state.workflow, ndv: null }
|
|
372
|
-
}))
|
|
373
|
-
},
|
|
374
|
-
quickConfig: {
|
|
375
|
-
open: (node) => set((state) => ({
|
|
376
|
-
workflow: { ...state.workflow, quickConfig: node }
|
|
377
|
-
})),
|
|
378
|
-
close: () => set((state) => ({
|
|
379
|
-
workflow: { ...state.workflow, quickConfig: null }
|
|
380
|
-
}))
|
|
381
|
-
},
|
|
382
|
-
pendingConnection: {
|
|
383
|
-
start: (connection) => set((state) => ({
|
|
384
|
-
workflow: {
|
|
385
|
-
...state.workflow,
|
|
386
|
-
pendingConnection: connection,
|
|
387
|
-
sidebar: { ...state.workflow.sidebar, active: "store-browse" }
|
|
388
|
-
}
|
|
389
|
-
})),
|
|
390
|
-
clear: () => set((state) => ({
|
|
391
|
-
workflow: { ...state.workflow, pendingConnection: null }
|
|
392
|
-
}))
|
|
393
|
-
},
|
|
394
|
-
sidebar: {
|
|
395
|
-
// Leaving the store panel abandons any armed "+" attach mode — the
|
|
396
|
-
// pending handle would otherwise silently capture a later insert.
|
|
397
|
-
setActivePanel: (panel) => set((state) => ({
|
|
398
|
-
workflow: {
|
|
399
|
-
...state.workflow,
|
|
400
|
-
sidebar: { ...state.workflow.sidebar, active: panel },
|
|
401
|
-
...panel !== "store-browse" ? { pendingConnection: null } : {}
|
|
402
|
-
}
|
|
403
|
-
})),
|
|
404
|
-
showNodePropertiesOf: (node) => {
|
|
405
|
-
set((state) => ({
|
|
406
|
-
workflow: {
|
|
407
|
-
...state.workflow,
|
|
408
|
-
pendingConnection: null,
|
|
409
|
-
sidebar: {
|
|
410
|
-
...state.workflow.sidebar,
|
|
411
|
-
active: "node-properties",
|
|
412
|
-
panels: {
|
|
413
|
-
...state.workflow.sidebar.panels,
|
|
414
|
-
nodeProperties: {
|
|
415
|
-
...state.workflow.sidebar.panels.nodeProperties,
|
|
416
|
-
selectedNode: node
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}));
|
|
422
|
-
},
|
|
423
|
-
panels: {
|
|
424
|
-
nodeProperties: {
|
|
425
|
-
setSelectedNode: (node) => set((state) => ({
|
|
426
|
-
workflow: {
|
|
427
|
-
...state.workflow,
|
|
428
|
-
sidebar: {
|
|
429
|
-
...state.workflow.sidebar,
|
|
430
|
-
panels: {
|
|
431
|
-
...state.workflow.sidebar.panels,
|
|
432
|
-
nodeProperties: {
|
|
433
|
-
...state.workflow.sidebar.panels.nodeProperties,
|
|
434
|
-
selectedNode: node
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}))
|
|
440
|
-
},
|
|
441
|
-
tags: {
|
|
442
|
-
setTags: (tags) => set({ tags }),
|
|
443
|
-
createTag: (tag) => set((state) => ({
|
|
444
|
-
tags: [...state.tags, tag]
|
|
445
|
-
})),
|
|
446
|
-
updateTag: (tag, newTag) => set((state) => ({
|
|
447
|
-
tags: state.tags.map(
|
|
448
|
-
(f) => f.value === tag.value ? newTag : f
|
|
449
|
-
)
|
|
450
|
-
})),
|
|
451
|
-
deleteTag: (tag) => set((state) => ({
|
|
452
|
-
tags: state.tags.filter((f) => f.value !== tag.value)
|
|
453
|
-
}))
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
nodes: {
|
|
458
|
-
onNodesChange: (changes) => {
|
|
459
|
-
const removedIds = new Set(
|
|
460
|
-
changes.filter(
|
|
461
|
-
(c) => c.type === "remove"
|
|
462
|
-
).map((c) => c.id)
|
|
463
|
-
);
|
|
464
|
-
const addedCount = changes.filter((c) => c.type === "add").length;
|
|
465
|
-
if (removedIds.size > 0) {
|
|
466
|
-
const stillPresent = get().workflow.nodes.some(
|
|
467
|
-
(n) => removedIds.has(n.id)
|
|
468
|
-
);
|
|
469
|
-
if (stillPresent && !joinsPrecedingRemoval("nodes:remove")) {
|
|
470
|
-
pushCheckpoint("nodes:remove", false);
|
|
471
|
-
}
|
|
472
|
-
} else if (addedCount > 0) {
|
|
473
|
-
pushCheckpoint("nodes:add", false);
|
|
474
|
-
} else {
|
|
475
|
-
const finishedDragIds = changes.filter(
|
|
476
|
-
(c) => c.type === "position" && c.dragging === false
|
|
477
|
-
);
|
|
478
|
-
const actuallyMoved = finishedDragIds.some((c) => {
|
|
479
|
-
const current = get().workflow.nodes.find((n) => n.id === c.id);
|
|
480
|
-
return current && c.position && (current.position.x !== c.position.x || current.position.y !== c.position.y);
|
|
481
|
-
});
|
|
482
|
-
if (actuallyMoved) pushCheckpoint("nodes:move", false);
|
|
483
|
-
}
|
|
484
|
-
set(
|
|
485
|
-
(state) => produce(state, (draft) => {
|
|
486
|
-
const updatedNodes = applyNodeChanges(
|
|
487
|
-
changes,
|
|
488
|
-
draft.workflow.nodes
|
|
489
|
-
);
|
|
490
|
-
draft.workflow.nodes = updatedNodes;
|
|
491
|
-
})
|
|
492
|
-
);
|
|
493
|
-
},
|
|
494
|
-
setNodes: (nodes, opts) => {
|
|
495
|
-
if (!opts?.skipHistory) {
|
|
496
|
-
pushCheckpoint(
|
|
497
|
-
opts?.historyKind ?? "nodes:set",
|
|
498
|
-
!!opts?.historyKind
|
|
499
|
-
);
|
|
500
|
-
}
|
|
501
|
-
set({ workflow: { ...get().workflow, nodes } });
|
|
502
|
-
},
|
|
503
|
-
deleteNode: (node) => {
|
|
504
|
-
const exists = get().workflow.nodes.some((n) => n.id === node.id);
|
|
505
|
-
if (exists) pushCheckpoint("nodes:delete", false);
|
|
506
|
-
set((state) => ({
|
|
507
|
-
workflow: {
|
|
508
|
-
...state.workflow,
|
|
509
|
-
nodes: state.workflow.nodes.filter((n) => n.id !== node.id),
|
|
510
|
-
// Drop any UI state pointing at the removed node.
|
|
511
|
-
...state.workflow.quickConfig?.nodeId === node.id ? { quickConfig: null } : {},
|
|
512
|
-
...state.workflow.pendingConnection?.nodeId === node.id ? { pendingConnection: null } : {}
|
|
513
|
-
}
|
|
514
|
-
}));
|
|
515
|
-
},
|
|
516
|
-
deleteNodes: (nodes) => {
|
|
517
|
-
const ids = new Set(nodes.map((n) => n.id));
|
|
518
|
-
if (ids.size === 0) return;
|
|
519
|
-
const anyExist = get().workflow.nodes.some((n) => ids.has(n.id));
|
|
520
|
-
if (anyExist) pushCheckpoint("nodes:delete", false);
|
|
521
|
-
set((state) => ({
|
|
522
|
-
workflow: {
|
|
523
|
-
...state.workflow,
|
|
524
|
-
nodes: state.workflow.nodes.filter((n) => !ids.has(n.id)),
|
|
525
|
-
edges: state.workflow.edges.filter(
|
|
526
|
-
(e) => !ids.has(e.source) && !ids.has(e.target)
|
|
527
|
-
),
|
|
528
|
-
...state.workflow.quickConfig && ids.has(state.workflow.quickConfig.nodeId) ? { quickConfig: null } : {},
|
|
529
|
-
...state.workflow.pendingConnection && ids.has(state.workflow.pendingConnection.nodeId) ? { pendingConnection: null } : {}
|
|
530
|
-
}
|
|
531
|
-
}));
|
|
532
|
-
},
|
|
533
|
-
duplicateNodes: (nodeIds) => {
|
|
534
|
-
const { nodes, edges } = get().workflow;
|
|
535
|
-
const idSet = new Set(nodeIds);
|
|
536
|
-
const selected = nodes.filter((n) => idSet.has(n.id));
|
|
537
|
-
if (selected.length === 0) return;
|
|
538
|
-
pushCheckpoint("nodes:duplicate", false);
|
|
539
|
-
const idMap = /* @__PURE__ */ new Map();
|
|
540
|
-
const clones = selected.map((n) => {
|
|
541
|
-
const newId = nanoid();
|
|
542
|
-
idMap.set(n.id, newId);
|
|
543
|
-
const cloned = cloneValue(n);
|
|
544
|
-
return {
|
|
545
|
-
...cloned,
|
|
546
|
-
id: newId,
|
|
547
|
-
position: {
|
|
548
|
-
x: cloned.position.x + CLONE_OFFSET,
|
|
549
|
-
y: cloned.position.y + CLONE_OFFSET
|
|
550
|
-
},
|
|
551
|
-
selected: true
|
|
552
|
-
};
|
|
553
|
-
});
|
|
554
|
-
const clonedEdges = edges.filter((e) => idMap.has(e.source) && idMap.has(e.target)).map((e) => {
|
|
555
|
-
const cloned = cloneValue(e);
|
|
556
|
-
return {
|
|
557
|
-
...cloned,
|
|
558
|
-
id: nanoid(),
|
|
559
|
-
source: idMap.get(e.source),
|
|
560
|
-
target: idMap.get(e.target),
|
|
561
|
-
selected: false
|
|
562
|
-
};
|
|
563
|
-
});
|
|
564
|
-
set((state) => ({
|
|
565
|
-
workflow: {
|
|
566
|
-
...state.workflow,
|
|
567
|
-
nodes: [
|
|
568
|
-
...state.workflow.nodes.map(
|
|
569
|
-
(n) => idSet.has(n.id) ? { ...n, selected: false } : n
|
|
570
|
-
),
|
|
571
|
-
...clones
|
|
572
|
-
],
|
|
573
|
-
edges: [...state.workflow.edges, ...clonedEdges]
|
|
574
|
-
}
|
|
575
|
-
}));
|
|
576
|
-
},
|
|
577
|
-
pasteNodes: (payload) => {
|
|
578
|
-
const pasteNodesIn = payload.nodes ?? [];
|
|
579
|
-
if (pasteNodesIn.length === 0) return;
|
|
580
|
-
pushCheckpoint("nodes:paste", false);
|
|
581
|
-
const idMap = /* @__PURE__ */ new Map();
|
|
582
|
-
const clones = pasteNodesIn.map((n) => {
|
|
583
|
-
const newId = nanoid();
|
|
584
|
-
idMap.set(n.id, newId);
|
|
585
|
-
const cloned = cloneValue(n);
|
|
586
|
-
return {
|
|
587
|
-
...cloned,
|
|
588
|
-
id: newId,
|
|
589
|
-
position: {
|
|
590
|
-
x: (cloned.position?.x ?? 0) + CLONE_OFFSET,
|
|
591
|
-
y: (cloned.position?.y ?? 0) + CLONE_OFFSET
|
|
592
|
-
},
|
|
593
|
-
selected: true
|
|
594
|
-
};
|
|
595
|
-
});
|
|
596
|
-
const clonedEdges = (payload.edges ?? []).filter((e) => idMap.has(e.source) && idMap.has(e.target)).map((e) => {
|
|
597
|
-
const cloned = cloneValue(e);
|
|
598
|
-
return {
|
|
599
|
-
...cloned,
|
|
600
|
-
id: nanoid(),
|
|
601
|
-
source: idMap.get(e.source),
|
|
602
|
-
target: idMap.get(e.target),
|
|
603
|
-
selected: false
|
|
604
|
-
};
|
|
605
|
-
});
|
|
606
|
-
set((state) => ({
|
|
607
|
-
workflow: {
|
|
608
|
-
...state.workflow,
|
|
609
|
-
nodes: [
|
|
610
|
-
...state.workflow.nodes.map((n) => ({ ...n, selected: false })),
|
|
611
|
-
...clones
|
|
612
|
-
],
|
|
613
|
-
edges: [...state.workflow.edges, ...clonedEdges]
|
|
614
|
-
}
|
|
615
|
-
}));
|
|
616
|
-
},
|
|
617
|
-
toggleDisabled: (nodeId) => {
|
|
618
|
-
const { nodes, edges } = get().workflow;
|
|
619
|
-
const updatedNodes = nodes.map((node) => {
|
|
620
|
-
if (node.id !== nodeId) return node;
|
|
621
|
-
const data = node.data ?? {};
|
|
622
|
-
return {
|
|
623
|
-
...node,
|
|
624
|
-
data: { ...data, disabled: !(data.disabled === true) }
|
|
625
|
-
};
|
|
626
|
-
});
|
|
627
|
-
const breaksLoop = edges.some(
|
|
628
|
-
(edge) => edge.source === nodeId && isLoopBodyEdge(edge, nodes) && !isValidWorkflowConnection(updatedNodes, edges, edge)
|
|
629
|
-
);
|
|
630
|
-
if (breaksLoop) return false;
|
|
631
|
-
pushCheckpoint("nodes:disable", false);
|
|
632
|
-
set((state) => ({
|
|
633
|
-
workflow: {
|
|
634
|
-
...state.workflow,
|
|
635
|
-
nodes: updatedNodes
|
|
636
|
-
}
|
|
637
|
-
}));
|
|
638
|
-
return true;
|
|
639
|
-
},
|
|
640
|
-
renameNode: (nodeId, label) => {
|
|
641
|
-
pushCheckpoint("nodes:rename", false);
|
|
642
|
-
set((state) => ({
|
|
643
|
-
workflow: {
|
|
644
|
-
...state.workflow,
|
|
645
|
-
nodes: state.workflow.nodes.map(
|
|
646
|
-
(n) => n.id === nodeId ? { ...n, data: { ...n.data ?? {}, label } } : n
|
|
647
|
-
),
|
|
648
|
-
renamingNodeId: null
|
|
649
|
-
}
|
|
650
|
-
}));
|
|
651
|
-
},
|
|
652
|
-
startRename: (nodeId) => {
|
|
653
|
-
set((state) => ({
|
|
654
|
-
workflow: { ...state.workflow, renamingNodeId: nodeId }
|
|
655
|
-
}));
|
|
656
|
-
},
|
|
657
|
-
endRename: () => {
|
|
658
|
-
set((state) => ({
|
|
659
|
-
workflow: { ...state.workflow, renamingNodeId: null }
|
|
660
|
-
}));
|
|
661
|
-
}
|
|
662
|
-
},
|
|
663
|
-
edges: {
|
|
664
|
-
onEdgesChange: (changes) => {
|
|
665
|
-
const removedIds = new Set(
|
|
666
|
-
changes.filter(
|
|
667
|
-
(c) => c.type === "remove"
|
|
668
|
-
).map((c) => c.id)
|
|
669
|
-
);
|
|
670
|
-
if (removedIds.size > 0) {
|
|
671
|
-
const stillPresent = get().workflow.edges.some(
|
|
672
|
-
(e) => removedIds.has(e.id)
|
|
673
|
-
);
|
|
674
|
-
if (stillPresent && !joinsPrecedingRemoval("edges:remove")) {
|
|
675
|
-
pushCheckpoint("edges:remove", false);
|
|
676
|
-
}
|
|
677
|
-
} else if (changes.some((c) => c.type === "add")) {
|
|
678
|
-
pushCheckpoint("edges:add", false);
|
|
679
|
-
}
|
|
680
|
-
set(
|
|
681
|
-
(state) => produce(state, (draft) => {
|
|
682
|
-
const updatedEdges = applyEdgeChanges(
|
|
683
|
-
changes,
|
|
684
|
-
draft.workflow.edges
|
|
685
|
-
);
|
|
686
|
-
draft.workflow.edges = updatedEdges;
|
|
687
|
-
})
|
|
688
|
-
);
|
|
689
|
-
},
|
|
690
|
-
onConnect: (connection) => {
|
|
691
|
-
pushCheckpoint("edges:connect", false);
|
|
692
|
-
const edge = {
|
|
693
|
-
...connection,
|
|
694
|
-
id: nanoid(),
|
|
695
|
-
type: "deletable"
|
|
696
|
-
};
|
|
697
|
-
set({
|
|
698
|
-
workflow: {
|
|
699
|
-
...get().workflow,
|
|
700
|
-
edges: addEdge(edge, get().workflow.edges)
|
|
701
|
-
}
|
|
702
|
-
});
|
|
703
|
-
},
|
|
704
|
-
setEdges: (edges, opts) => {
|
|
705
|
-
if (!opts?.skipHistory) {
|
|
706
|
-
pushCheckpoint(
|
|
707
|
-
opts?.historyKind ?? "edges:set",
|
|
708
|
-
!!opts?.historyKind
|
|
709
|
-
);
|
|
710
|
-
}
|
|
711
|
-
set({ workflow: { ...get().workflow, edges } });
|
|
712
|
-
},
|
|
713
|
-
deleteEdge: (edge) => {
|
|
714
|
-
const exists = get().workflow.edges.some((e) => e.id === edge.id);
|
|
715
|
-
if (exists) pushCheckpoint("edges:delete", false);
|
|
716
|
-
set((state) => ({
|
|
717
|
-
workflow: {
|
|
718
|
-
...state.workflow,
|
|
719
|
-
edges: state.workflow.edges.filter((e) => e.id !== edge.id)
|
|
720
|
-
}
|
|
721
|
-
}));
|
|
722
|
-
}
|
|
723
|
-
},
|
|
724
|
-
execution: {
|
|
725
|
-
startExecution: (nodeId, runId, metadata) => {
|
|
726
|
-
set((state) => ({
|
|
727
|
-
execution: {
|
|
728
|
-
...state.execution,
|
|
729
|
-
isExecuting: true,
|
|
730
|
-
executingNodeId: nodeId,
|
|
731
|
-
currentRunId: runId,
|
|
732
|
-
sourceRun: metadata ? { runId, ...metadata } : { runId, workflowKey: "", version: "" },
|
|
733
|
-
panelExpanded: true,
|
|
734
|
-
nodeStatuses: {
|
|
735
|
-
...state.execution.nodeStatuses,
|
|
736
|
-
[nodeId]: "running"
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
}));
|
|
740
|
-
},
|
|
741
|
-
setRunMetadata: (metadata) => {
|
|
742
|
-
set((state) => {
|
|
743
|
-
if (state.execution.currentRunId !== metadata.runId && state.execution.sourceRun?.runId !== metadata.runId) {
|
|
744
|
-
return state;
|
|
745
|
-
}
|
|
746
|
-
return {
|
|
747
|
-
execution: {
|
|
748
|
-
...state.execution,
|
|
749
|
-
currentRunId: metadata.runId,
|
|
750
|
-
sourceRun: metadata
|
|
751
|
-
}
|
|
752
|
-
};
|
|
753
|
-
});
|
|
754
|
-
},
|
|
755
|
-
setStepPlan: (plan) => {
|
|
756
|
-
set((state) => ({
|
|
757
|
-
execution: {
|
|
758
|
-
...state.execution,
|
|
759
|
-
stepPlan: plan
|
|
760
|
-
}
|
|
761
|
-
}));
|
|
762
|
-
},
|
|
763
|
-
addLog: (log) => {
|
|
764
|
-
set((state) => ({
|
|
765
|
-
execution: {
|
|
766
|
-
...state.execution,
|
|
767
|
-
logs: [...state.execution.logs, log],
|
|
768
|
-
selectedLogId: log.id
|
|
769
|
-
}
|
|
770
|
-
}));
|
|
771
|
-
},
|
|
772
|
-
updateLog: (logId, updates) => {
|
|
773
|
-
set((state) => ({
|
|
774
|
-
execution: {
|
|
775
|
-
...state.execution,
|
|
776
|
-
logs: state.execution.logs.map(
|
|
777
|
-
(log) => log.id === logId ? { ...log, ...updates } : log
|
|
778
|
-
)
|
|
779
|
-
}
|
|
780
|
-
}));
|
|
781
|
-
},
|
|
782
|
-
setNodeStatus: (nodeId, status) => {
|
|
783
|
-
set((state) => ({
|
|
784
|
-
execution: {
|
|
785
|
-
...state.execution,
|
|
786
|
-
nodeStatuses: {
|
|
787
|
-
...state.execution.nodeStatuses,
|
|
788
|
-
[nodeId]: status
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}));
|
|
792
|
-
},
|
|
793
|
-
setNodeItemCount: (nodeId, count) => {
|
|
794
|
-
set((state) => ({
|
|
795
|
-
execution: {
|
|
796
|
-
...state.execution,
|
|
797
|
-
nodeItemCounts: {
|
|
798
|
-
...state.execution.nodeItemCounts,
|
|
799
|
-
[nodeId]: count
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}));
|
|
803
|
-
},
|
|
804
|
-
selectLog: (logId) => {
|
|
805
|
-
set((state) => ({
|
|
806
|
-
execution: {
|
|
807
|
-
...state.execution,
|
|
808
|
-
selectedLogId: logId
|
|
809
|
-
}
|
|
810
|
-
}));
|
|
811
|
-
},
|
|
812
|
-
togglePanel: () => {
|
|
813
|
-
set((state) => ({
|
|
814
|
-
execution: {
|
|
815
|
-
...state.execution,
|
|
816
|
-
panelExpanded: !state.execution.panelExpanded
|
|
817
|
-
}
|
|
818
|
-
}));
|
|
819
|
-
},
|
|
820
|
-
clearLogs: () => {
|
|
821
|
-
set((state) => ({
|
|
822
|
-
execution: {
|
|
823
|
-
...state.execution,
|
|
824
|
-
logs: [],
|
|
825
|
-
stepPlan: null,
|
|
826
|
-
currentRunId: null,
|
|
827
|
-
sourceRun: null,
|
|
828
|
-
selectedLogId: null,
|
|
829
|
-
nodeStatuses: {},
|
|
830
|
-
nodeItemCounts: {}
|
|
831
|
-
}
|
|
832
|
-
}));
|
|
833
|
-
},
|
|
834
|
-
completeExecution: () => {
|
|
835
|
-
set((state) => ({
|
|
836
|
-
execution: {
|
|
837
|
-
...state.execution,
|
|
838
|
-
isExecuting: false,
|
|
839
|
-
executingNodeId: null
|
|
840
|
-
}
|
|
841
|
-
}));
|
|
842
|
-
},
|
|
843
|
-
requestFollowRun: (runId, triggerNodeId) => {
|
|
844
|
-
set((state) => ({
|
|
845
|
-
execution: {
|
|
846
|
-
...state.execution,
|
|
847
|
-
followRequest: { runId, triggerNodeId }
|
|
848
|
-
}
|
|
849
|
-
}));
|
|
850
|
-
},
|
|
851
|
-
clearFollowRequest: () => {
|
|
852
|
-
set((state) => ({
|
|
853
|
-
execution: { ...state.execution, followRequest: null }
|
|
854
|
-
}));
|
|
855
|
-
},
|
|
856
|
-
loadDebugRun: (runId, logs, metadata) => {
|
|
857
|
-
const nodeStatuses = {};
|
|
858
|
-
for (const log of logs) {
|
|
859
|
-
nodeStatuses[log.nodeId] = log.status === "completed" ? "success" : log.status === "failed" ? "error" : log.status === "running" ? "running" : "idle";
|
|
860
|
-
}
|
|
861
|
-
set(() => ({
|
|
862
|
-
execution: {
|
|
863
|
-
...INITIAL_EXECUTION,
|
|
864
|
-
currentRunId: runId,
|
|
865
|
-
sourceRun: metadata ? { runId, ...metadata } : { runId, workflowKey: "", version: "" },
|
|
866
|
-
logs,
|
|
867
|
-
nodeStatuses,
|
|
868
|
-
panelExpanded: true
|
|
869
|
-
}
|
|
870
|
-
}));
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
};
|
|
875
|
-
});
|
|
876
|
-
if (typeof window !== "undefined" && import.meta.env?.DEV) {
|
|
877
|
-
window.__fgFlowStore = useFlowStore;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
export { isNodeTrigger, isTriggerOperation, useFlowStore, useIsValidConnection };
|