@genfeedai/workflow-ui 0.2.2 → 0.2.4
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/README.md +11 -33
- package/dist/canvas.d.ts +22 -22
- package/dist/canvas.mjs +16 -17
- package/dist/{chunk-WBR34V4L.mjs → chunk-2FUPL67V.mjs} +1593 -1045
- package/dist/{chunk-4VEN4UN7.mjs → chunk-53XDE62A.mjs} +818 -623
- package/dist/{chunk-PCIWWD37.mjs → chunk-7LV4UAUS.mjs} +19 -19
- package/dist/{chunk-7SKSRSS7.mjs → chunk-B4EAAKYF.mjs} +16 -16
- package/dist/{chunk-ZJD5WMR3.mjs → chunk-C6MQBJFC.mjs} +45 -13
- package/dist/{chunk-7H3WJJYS.mjs → chunk-ESVULCFY.mjs} +12 -6
- package/dist/{chunk-GWBGK3KL.mjs → chunk-FWJIAW2E.mjs} +82 -47
- package/dist/{chunk-R727OFBR.mjs → chunk-GPYIIWD5.mjs} +404 -350
- package/dist/{chunk-OQREHJXK.mjs → chunk-IYFWAJBB.mjs} +208 -203
- package/dist/{chunk-2JQSKIWR.mjs → chunk-MGLAKMDP.mjs} +24 -23
- package/dist/{chunk-LT3ZJJL6.mjs → chunk-OJWVEEMM.mjs} +497 -399
- package/dist/{chunk-ZD2BADZO.mjs → chunk-ORVDYXDP.mjs} +221 -175
- package/dist/{chunk-CV4M7CNU.mjs → chunk-QQVHGJ2G.mjs} +149 -142
- package/dist/{chunk-6PSJTBNV.mjs → chunk-U4QPE4CY.mjs} +387 -347
- package/dist/{chunk-EFXQT23N.mjs → chunk-VVQ4CH77.mjs} +5 -5
- package/dist/{chunk-VRN3UWE5.mjs → chunk-XRC3O5GK.mjs} +73 -73
- package/dist/{chunk-FT33LFII.mjs → chunk-YUIK4AHM.mjs} +1 -1
- package/dist/{chunk-JT4Y5H3U.mjs → chunk-ZSITTZ4S.mjs} +630 -569
- package/dist/hooks.d.ts +37 -37
- package/dist/hooks.mjs +10 -10
- package/dist/index.d.ts +26 -11
- package/dist/index.mjs +99 -20
- package/dist/lib.d.ts +203 -203
- package/dist/lib.mjs +228 -199
- package/dist/nodes.d.ts +2 -2
- package/dist/nodes.mjs +12 -13
- package/dist/panels.d.ts +2 -3
- package/dist/panels.mjs +3 -3
- package/dist/provider.d.ts +2 -2
- package/dist/provider.mjs +2 -2
- package/dist/stores.d.ts +5 -5
- package/dist/stores.mjs +5 -5
- package/dist/toolbar.d.ts +42 -24
- package/dist/toolbar.mjs +4 -5
- package/dist/ui.d.ts +2 -2
- package/dist/ui.mjs +2 -2
- package/dist/{useCommentNavigation-BakbiiIc.d.ts → useRequiredInputs-ByoIS-fT.d.ts} +160 -160
- package/dist/{promptLibraryStore-Dl3Q3cP6.d.ts → workflowStore-Bsz0nd5c.d.ts} +368 -368
- package/dist/workflowStore-N2F7WIG3.mjs +2 -0
- package/package.json +79 -77
- package/src/styles/workflow-ui.css +56 -19
- package/dist/chunk-OY7BRSGG.mjs +0 -60
- package/dist/workflowStore-UAAKOOIK.mjs +0 -2
- package/dist/{types-IEKYuYhu.d.ts → types-CRXJnajq.d.ts} +1 -1
|
@@ -1,25 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { calculateWorkflowCost, formatCost } from './chunk-
|
|
3
|
-
import {
|
|
4
|
-
import { useUIStore, useSettingsStore, useExecutionStore } from './chunk-
|
|
5
|
-
import { useWorkflowStore, getHandleType } from './chunk-
|
|
1
|
+
import { useContextMenu, useCanvasKeyboardShortcuts, ContextMenu } from './chunk-ORVDYXDP.mjs';
|
|
2
|
+
import { calculateWorkflowCost, formatCost } from './chunk-MGLAKMDP.mjs';
|
|
3
|
+
import { nodeTypes, NodeDetailModal } from './chunk-2FUPL67V.mjs';
|
|
4
|
+
import { useUIStore, useSettingsStore, useExecutionStore } from './chunk-OJWVEEMM.mjs';
|
|
5
|
+
import { useWorkflowStore, getHandleType } from './chunk-GPYIIWD5.mjs';
|
|
6
|
+
import { CONNECTION_RULES, getNodesByCategory, NODE_DEFINITIONS } from '@genfeedai/types';
|
|
6
7
|
import { useReactFlow, getBezierPath, BaseEdge, useNodes, ViewportPortal, useViewport, useStore, ReactFlow, SelectionMode, ConnectionMode, Background, BackgroundVariant, Controls, MiniMap } from '@xyflow/react';
|
|
7
|
-
import { Plus, Search,
|
|
8
|
+
import { Plus, Search, Play, Pause, Trash2, AlignHorizontalSpaceAround, AlignVerticalSpaceAround, Grid3X3, Ungroup, Group, Palette, Lock, Unlock, X, Keyboard, PanelLeft, AlertTriangle, CheckCircle, Info, XCircle, Check, Copy, DollarSign } from 'lucide-react';
|
|
8
9
|
import { memo, useState, useRef, useMemo, useEffect, useCallback } from 'react';
|
|
9
|
-
import '@xyflow/react/dist/style.css';
|
|
10
|
-
import { CONNECTION_RULES, getNodesByCategory, NODE_DEFINITIONS } from '@genfeedai/types';
|
|
11
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
11
|
import { clsx } from 'clsx';
|
|
12
|
+
import '@xyflow/react/dist/style.css';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
|
|
15
15
|
var CATEGORY_LABELS = {
|
|
16
|
-
input: "Input",
|
|
17
16
|
ai: "AI",
|
|
18
|
-
|
|
17
|
+
composition: "Composition",
|
|
18
|
+
input: "Input",
|
|
19
19
|
output: "Output",
|
|
20
|
-
|
|
20
|
+
processing: "Processing"
|
|
21
21
|
};
|
|
22
|
-
var CATEGORY_ORDER = [
|
|
22
|
+
var CATEGORY_ORDER = [
|
|
23
|
+
"input",
|
|
24
|
+
"ai",
|
|
25
|
+
"processing",
|
|
26
|
+
"output",
|
|
27
|
+
"composition"
|
|
28
|
+
];
|
|
23
29
|
function ConnectionDropMenuComponent() {
|
|
24
30
|
const { connectionDropMenu, closeConnectionDropMenu } = useUIStore();
|
|
25
31
|
const { addNode, findCompatibleHandle, onConnect } = useWorkflowStore();
|
|
@@ -44,9 +50,9 @@ function ConnectionDropMenuComponent() {
|
|
|
44
50
|
);
|
|
45
51
|
if (hasCompatibleInput) {
|
|
46
52
|
result.push({
|
|
47
|
-
|
|
53
|
+
category,
|
|
48
54
|
label: def.label,
|
|
49
|
-
|
|
55
|
+
type: def.type
|
|
50
56
|
});
|
|
51
57
|
}
|
|
52
58
|
}
|
|
@@ -108,13 +114,22 @@ function ConnectionDropMenuComponent() {
|
|
|
108
114
|
}
|
|
109
115
|
closeConnectionDropMenu();
|
|
110
116
|
},
|
|
111
|
-
[
|
|
117
|
+
[
|
|
118
|
+
connectionDropMenu,
|
|
119
|
+
reactFlow,
|
|
120
|
+
addNode,
|
|
121
|
+
findCompatibleHandle,
|
|
122
|
+
onConnect,
|
|
123
|
+
closeConnectionDropMenu
|
|
124
|
+
]
|
|
112
125
|
);
|
|
113
126
|
const handleKeyDown = useCallback(
|
|
114
127
|
(e) => {
|
|
115
128
|
if (e.key === "ArrowDown") {
|
|
116
129
|
e.preventDefault();
|
|
117
|
-
setSelectedIndex(
|
|
130
|
+
setSelectedIndex(
|
|
131
|
+
(prev) => Math.min(prev + 1, filteredNodes.length - 1)
|
|
132
|
+
);
|
|
118
133
|
} else if (e.key === "ArrowUp") {
|
|
119
134
|
e.preventDefault();
|
|
120
135
|
setSelectedIndex((prev) => Math.max(prev - 1, 0));
|
|
@@ -135,81 +150,152 @@ function ConnectionDropMenuComponent() {
|
|
|
135
150
|
};
|
|
136
151
|
if (!isOpen || !connectionDropMenu) return null;
|
|
137
152
|
const menuStyle = {
|
|
138
|
-
position: "fixed",
|
|
139
153
|
left: connectionDropMenu.screenPosition.x,
|
|
154
|
+
position: "fixed",
|
|
140
155
|
top: connectionDropMenu.screenPosition.y,
|
|
141
156
|
zIndex: 50
|
|
142
157
|
};
|
|
143
158
|
let flatIndex = 0;
|
|
144
|
-
return /* @__PURE__ */ jsx(
|
|
159
|
+
return /* @__PURE__ */ jsx(
|
|
145
160
|
"div",
|
|
146
161
|
{
|
|
147
|
-
|
|
148
|
-
className: "
|
|
149
|
-
|
|
150
|
-
|
|
162
|
+
ref: backdropRef,
|
|
163
|
+
className: "fixed inset-0 z-40",
|
|
164
|
+
onClick: handleBackdropClick,
|
|
165
|
+
children: /* @__PURE__ */ jsxs(
|
|
166
|
+
"div",
|
|
167
|
+
{
|
|
168
|
+
style: menuStyle,
|
|
169
|
+
className: "bg-[var(--background)] border border-[var(--border)] rounded-lg shadow-xl w-64 max-h-80 flex flex-col",
|
|
170
|
+
role: "dialog",
|
|
171
|
+
"aria-label": "Add Node",
|
|
172
|
+
children: [
|
|
173
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-[var(--border)]", children: [
|
|
174
|
+
/* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5 text-[var(--muted-foreground)]" }),
|
|
175
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: "Add Connected Node" })
|
|
176
|
+
] }),
|
|
177
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-2", onKeyDown: handleKeyDown, children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
178
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[var(--muted-foreground)]" }),
|
|
179
|
+
/* @__PURE__ */ jsx(
|
|
180
|
+
"input",
|
|
181
|
+
{
|
|
182
|
+
ref: inputRef,
|
|
183
|
+
type: "text",
|
|
184
|
+
placeholder: "Search compatible nodes...",
|
|
185
|
+
value: search,
|
|
186
|
+
onChange: (e) => setSearch(e.target.value),
|
|
187
|
+
className: "w-full pl-7 pr-2 py-1.5 text-xs bg-[var(--secondary)] border border-[var(--border)] rounded-md outline-none focus:ring-1 focus:ring-[var(--ring)]"
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
] }) }),
|
|
191
|
+
/* @__PURE__ */ jsx(
|
|
192
|
+
"div",
|
|
193
|
+
{
|
|
194
|
+
ref: listRef,
|
|
195
|
+
className: "flex-1 overflow-y-auto px-1.5 pb-1.5",
|
|
196
|
+
onKeyDown: handleKeyDown,
|
|
197
|
+
children: filteredNodes.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center text-[var(--muted-foreground)] text-xs py-4", children: "No compatible nodes found" }) : Object.entries(groupedNodes).map(([category, nodes]) => {
|
|
198
|
+
if (!nodes || nodes.length === 0) return null;
|
|
199
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-1", children: [
|
|
200
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-semibold text-[var(--muted-foreground)] uppercase tracking-wider px-2 py-1", children: CATEGORY_LABELS[category] }),
|
|
201
|
+
nodes.map((node) => {
|
|
202
|
+
const currentIndex = flatIndex++;
|
|
203
|
+
return /* @__PURE__ */ jsx(
|
|
204
|
+
"button",
|
|
205
|
+
{
|
|
206
|
+
"data-node-item": true,
|
|
207
|
+
onClick: () => handleSelect(node.type),
|
|
208
|
+
className: `w-full text-left px-2 py-1.5 rounded text-xs transition-colors ${currentIndex === selectedIndex ? "bg-[var(--primary)]/10 text-[var(--foreground)]" : "text-[var(--foreground)] hover:bg-[var(--secondary)]"}`,
|
|
209
|
+
children: node.label
|
|
210
|
+
},
|
|
211
|
+
node.type
|
|
212
|
+
);
|
|
213
|
+
})
|
|
214
|
+
] }, category);
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
var ConnectionDropMenu = memo(ConnectionDropMenuComponent);
|
|
225
|
+
function EdgeToolbarComponent() {
|
|
226
|
+
const { selectedEdgeId, selectEdge } = useUIStore();
|
|
227
|
+
const { edges, toggleEdgePause, removeEdge } = useWorkflowStore();
|
|
228
|
+
const reactFlow = useReactFlow();
|
|
229
|
+
const selectedEdge = useMemo(
|
|
230
|
+
() => selectedEdgeId ? edges.find((e) => e.id === selectedEdgeId) : null,
|
|
231
|
+
[selectedEdgeId, edges]
|
|
232
|
+
);
|
|
233
|
+
const position = useMemo(() => {
|
|
234
|
+
if (!selectedEdge) return null;
|
|
235
|
+
const sourceNode = reactFlow.getNode(selectedEdge.source);
|
|
236
|
+
const targetNode = reactFlow.getNode(selectedEdge.target);
|
|
237
|
+
if (!sourceNode || !targetNode) return null;
|
|
238
|
+
const midX = (sourceNode.position.x + (sourceNode.measured?.width ?? 280) / 2 + (targetNode.position.x + (targetNode.measured?.width ?? 280) / 2)) / 2;
|
|
239
|
+
const midY = (sourceNode.position.y + (sourceNode.measured?.height ?? 200) / 2 + (targetNode.position.y + (targetNode.measured?.height ?? 200) / 2)) / 2;
|
|
240
|
+
return reactFlow.flowToScreenPosition({ x: midX, y: midY });
|
|
241
|
+
}, [selectedEdge, reactFlow]);
|
|
242
|
+
if (!selectedEdge || !position) return null;
|
|
243
|
+
const hasPause = selectedEdge.data?.hasPause === true;
|
|
244
|
+
const handleTogglePause = (e) => {
|
|
245
|
+
e.stopPropagation();
|
|
246
|
+
toggleEdgePause(selectedEdge.id);
|
|
247
|
+
};
|
|
248
|
+
const handleDelete = (e) => {
|
|
249
|
+
e.stopPropagation();
|
|
250
|
+
removeEdge(selectedEdge.id);
|
|
251
|
+
selectEdge(null);
|
|
252
|
+
};
|
|
253
|
+
return /* @__PURE__ */ jsxs(
|
|
254
|
+
"div",
|
|
255
|
+
{
|
|
256
|
+
className: "fixed z-30 flex items-center gap-1 bg-[var(--background)] border border-[var(--border)] rounded-lg shadow-lg px-1.5 py-1",
|
|
257
|
+
style: {
|
|
258
|
+
left: position.x,
|
|
259
|
+
top: position.y - 40,
|
|
260
|
+
transform: "translateX(-50%)"
|
|
261
|
+
},
|
|
262
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
151
263
|
children: [
|
|
152
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-[var(--border)]", children: [
|
|
153
|
-
/* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5 text-[var(--muted-foreground)]" }),
|
|
154
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: "Add Connected Node" })
|
|
155
|
-
] }),
|
|
156
|
-
/* @__PURE__ */ jsx("div", { className: "px-3 py-2", onKeyDown: handleKeyDown, children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
157
|
-
/* @__PURE__ */ jsx(Search, { className: "absolute left-2 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[var(--muted-foreground)]" }),
|
|
158
|
-
/* @__PURE__ */ jsx(
|
|
159
|
-
"input",
|
|
160
|
-
{
|
|
161
|
-
ref: inputRef,
|
|
162
|
-
type: "text",
|
|
163
|
-
placeholder: "Search compatible nodes...",
|
|
164
|
-
value: search,
|
|
165
|
-
onChange: (e) => setSearch(e.target.value),
|
|
166
|
-
className: "w-full pl-7 pr-2 py-1.5 text-xs bg-[var(--secondary)] border border-[var(--border)] rounded-md outline-none focus:ring-1 focus:ring-[var(--ring)]"
|
|
167
|
-
}
|
|
168
|
-
)
|
|
169
|
-
] }) }),
|
|
170
264
|
/* @__PURE__ */ jsx(
|
|
171
|
-
"
|
|
265
|
+
"button",
|
|
172
266
|
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
children:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
className: `w-full text-left px-2 py-1.5 rounded text-xs transition-colors ${currentIndex === selectedIndex ? "bg-[var(--primary)]/10 text-[var(--foreground)]" : "text-[var(--foreground)] hover:bg-[var(--secondary)]"}`,
|
|
188
|
-
children: node.label
|
|
189
|
-
},
|
|
190
|
-
node.type
|
|
191
|
-
);
|
|
192
|
-
})
|
|
193
|
-
] }, category);
|
|
194
|
-
})
|
|
267
|
+
onClick: handleTogglePause,
|
|
268
|
+
title: hasPause ? "Resume edge" : "Pause edge",
|
|
269
|
+
className: "flex h-7 w-7 items-center justify-center rounded text-[var(--muted-foreground)] transition hover:bg-[var(--secondary)] hover:text-[var(--foreground)]",
|
|
270
|
+
children: hasPause ? /* @__PURE__ */ jsx(Play, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Pause, { className: "h-3.5 w-3.5" })
|
|
271
|
+
}
|
|
272
|
+
),
|
|
273
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-[var(--border)]" }),
|
|
274
|
+
/* @__PURE__ */ jsx(
|
|
275
|
+
"button",
|
|
276
|
+
{
|
|
277
|
+
onClick: handleDelete,
|
|
278
|
+
title: "Delete edge",
|
|
279
|
+
className: "flex h-7 w-7 items-center justify-center rounded text-[var(--muted-foreground)] transition hover:bg-red-500/10 hover:text-red-500",
|
|
280
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
|
|
195
281
|
}
|
|
196
282
|
)
|
|
197
283
|
]
|
|
198
284
|
}
|
|
199
|
-
)
|
|
285
|
+
);
|
|
200
286
|
}
|
|
201
|
-
var
|
|
287
|
+
var EdgeToolbar = memo(EdgeToolbarComponent);
|
|
202
288
|
var DATA_TYPE_COLORS = {
|
|
289
|
+
audio: ["#f97316", "#fb923c"],
|
|
290
|
+
// orange
|
|
203
291
|
image: ["#3b82f6", "#60a5fa"],
|
|
204
292
|
// blue
|
|
205
|
-
|
|
206
|
-
//
|
|
293
|
+
number: ["#6b7280", "#9ca3af"],
|
|
294
|
+
// gray
|
|
207
295
|
text: ["#22c55e", "#4ade80"],
|
|
208
296
|
// green
|
|
209
|
-
|
|
210
|
-
//
|
|
211
|
-
number: ["#6b7280", "#9ca3af"]
|
|
212
|
-
// gray
|
|
297
|
+
video: ["#8b5cf6", "#a78bfa"]
|
|
298
|
+
// purple
|
|
213
299
|
};
|
|
214
300
|
var DEFAULT_COLORS = ["#6b7280", "#9ca3af"];
|
|
215
301
|
function EditableEdgeComponent({
|
|
@@ -226,12 +312,12 @@ function EditableEdgeComponent({
|
|
|
226
312
|
selected
|
|
227
313
|
}) {
|
|
228
314
|
const [edgePath, labelX, labelY] = getBezierPath({
|
|
315
|
+
sourcePosition,
|
|
229
316
|
sourceX,
|
|
230
317
|
sourceY,
|
|
231
|
-
|
|
318
|
+
targetPosition,
|
|
232
319
|
targetX,
|
|
233
|
-
targetY
|
|
234
|
-
targetPosition
|
|
320
|
+
targetY
|
|
235
321
|
});
|
|
236
322
|
const hasPause = data?.hasPause === true;
|
|
237
323
|
const dataType = data?.dataType ?? null;
|
|
@@ -298,201 +384,48 @@ function EditableEdgeComponent({
|
|
|
298
384
|
] });
|
|
299
385
|
}
|
|
300
386
|
var EditableEdge = memo(EditableEdgeComponent);
|
|
301
|
-
function EdgeToolbarComponent() {
|
|
302
|
-
const { selectedEdgeId, selectEdge } = useUIStore();
|
|
303
|
-
const { edges, toggleEdgePause, removeEdge } = useWorkflowStore();
|
|
304
|
-
const reactFlow = useReactFlow();
|
|
305
|
-
const selectedEdge = useMemo(
|
|
306
|
-
() => selectedEdgeId ? edges.find((e) => e.id === selectedEdgeId) : null,
|
|
307
|
-
[selectedEdgeId, edges]
|
|
308
|
-
);
|
|
309
|
-
const position = useMemo(() => {
|
|
310
|
-
if (!selectedEdge) return null;
|
|
311
|
-
const sourceNode = reactFlow.getNode(selectedEdge.source);
|
|
312
|
-
const targetNode = reactFlow.getNode(selectedEdge.target);
|
|
313
|
-
if (!sourceNode || !targetNode) return null;
|
|
314
|
-
const midX = (sourceNode.position.x + (sourceNode.measured?.width ?? 280) / 2 + (targetNode.position.x + (targetNode.measured?.width ?? 280) / 2)) / 2;
|
|
315
|
-
const midY = (sourceNode.position.y + (sourceNode.measured?.height ?? 200) / 2 + (targetNode.position.y + (targetNode.measured?.height ?? 200) / 2)) / 2;
|
|
316
|
-
return reactFlow.flowToScreenPosition({ x: midX, y: midY });
|
|
317
|
-
}, [selectedEdge, reactFlow]);
|
|
318
|
-
if (!selectedEdge || !position) return null;
|
|
319
|
-
const hasPause = selectedEdge.data?.hasPause === true;
|
|
320
|
-
const handleTogglePause = (e) => {
|
|
321
|
-
e.stopPropagation();
|
|
322
|
-
toggleEdgePause(selectedEdge.id);
|
|
323
|
-
};
|
|
324
|
-
const handleDelete = (e) => {
|
|
325
|
-
e.stopPropagation();
|
|
326
|
-
removeEdge(selectedEdge.id);
|
|
327
|
-
selectEdge(null);
|
|
328
|
-
};
|
|
329
|
-
return /* @__PURE__ */ jsxs(
|
|
330
|
-
"div",
|
|
331
|
-
{
|
|
332
|
-
className: "fixed z-30 flex items-center gap-1 bg-[var(--background)] border border-[var(--border)] rounded-lg shadow-lg px-1.5 py-1",
|
|
333
|
-
style: {
|
|
334
|
-
left: position.x,
|
|
335
|
-
top: position.y - 40,
|
|
336
|
-
transform: "translateX(-50%)"
|
|
337
|
-
},
|
|
338
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
339
|
-
children: [
|
|
340
|
-
/* @__PURE__ */ jsx(
|
|
341
|
-
"button",
|
|
342
|
-
{
|
|
343
|
-
onClick: handleTogglePause,
|
|
344
|
-
title: hasPause ? "Resume edge" : "Pause edge",
|
|
345
|
-
className: "flex h-7 w-7 items-center justify-center rounded text-[var(--muted-foreground)] transition hover:bg-[var(--secondary)] hover:text-[var(--foreground)]",
|
|
346
|
-
children: hasPause ? /* @__PURE__ */ jsx(Play, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Pause, { className: "h-3.5 w-3.5" })
|
|
347
|
-
}
|
|
348
|
-
),
|
|
349
|
-
/* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-[var(--border)]" }),
|
|
350
|
-
/* @__PURE__ */ jsx(
|
|
351
|
-
"button",
|
|
352
|
-
{
|
|
353
|
-
onClick: handleDelete,
|
|
354
|
-
title: "Delete edge",
|
|
355
|
-
className: "flex h-7 w-7 items-center justify-center rounded text-[var(--muted-foreground)] transition hover:bg-red-500/10 hover:text-red-500",
|
|
356
|
-
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
|
|
357
|
-
}
|
|
358
|
-
)
|
|
359
|
-
]
|
|
360
|
-
}
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
var EdgeToolbar = memo(EdgeToolbarComponent);
|
|
364
|
-
var REFERENCE_COLOR = "#52525b";
|
|
365
|
-
function ReferenceEdge({
|
|
366
|
-
id,
|
|
367
|
-
sourceX,
|
|
368
|
-
sourceY,
|
|
369
|
-
targetX,
|
|
370
|
-
targetY,
|
|
371
|
-
sourcePosition,
|
|
372
|
-
targetPosition,
|
|
373
|
-
style,
|
|
374
|
-
markerEnd,
|
|
375
|
-
source,
|
|
376
|
-
target
|
|
377
|
-
}) {
|
|
378
|
-
const nodes = useWorkflowStore((state) => state.nodes);
|
|
379
|
-
const isConnectedToSelection = useMemo(() => {
|
|
380
|
-
const selectedNodes = nodes.filter((n) => n.selected);
|
|
381
|
-
if (selectedNodes.length === 0) return false;
|
|
382
|
-
return selectedNodes.some((n) => n.id === source || n.id === target);
|
|
383
|
-
}, [nodes, source, target]);
|
|
384
|
-
const [edgePath] = useMemo(() => {
|
|
385
|
-
return getBezierPath({
|
|
386
|
-
sourceX,
|
|
387
|
-
sourceY,
|
|
388
|
-
sourcePosition,
|
|
389
|
-
targetX,
|
|
390
|
-
targetY,
|
|
391
|
-
targetPosition,
|
|
392
|
-
curvature: 0.25
|
|
393
|
-
});
|
|
394
|
-
}, [sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition]);
|
|
395
|
-
const gradientId = useMemo(() => {
|
|
396
|
-
const selectionKey = isConnectedToSelection ? "active" : "dimmed";
|
|
397
|
-
return `reference-gradient-${selectionKey}-${id}`;
|
|
398
|
-
}, [isConnectedToSelection, id]);
|
|
399
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
400
|
-
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradientId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: [
|
|
401
|
-
/* @__PURE__ */ jsx(
|
|
402
|
-
"stop",
|
|
403
|
-
{
|
|
404
|
-
offset: "0%",
|
|
405
|
-
stopColor: REFERENCE_COLOR,
|
|
406
|
-
stopOpacity: isConnectedToSelection ? 1 : 0.25
|
|
407
|
-
}
|
|
408
|
-
),
|
|
409
|
-
/* @__PURE__ */ jsx(
|
|
410
|
-
"stop",
|
|
411
|
-
{
|
|
412
|
-
offset: "50%",
|
|
413
|
-
stopColor: REFERENCE_COLOR,
|
|
414
|
-
stopOpacity: isConnectedToSelection ? 0.55 : 0.1
|
|
415
|
-
}
|
|
416
|
-
),
|
|
417
|
-
/* @__PURE__ */ jsx(
|
|
418
|
-
"stop",
|
|
419
|
-
{
|
|
420
|
-
offset: "100%",
|
|
421
|
-
stopColor: REFERENCE_COLOR,
|
|
422
|
-
stopOpacity: isConnectedToSelection ? 1 : 0.25
|
|
423
|
-
}
|
|
424
|
-
)
|
|
425
|
-
] }) }),
|
|
426
|
-
/* @__PURE__ */ jsx(
|
|
427
|
-
BaseEdge,
|
|
428
|
-
{
|
|
429
|
-
id,
|
|
430
|
-
path: edgePath,
|
|
431
|
-
markerEnd,
|
|
432
|
-
style: {
|
|
433
|
-
...style,
|
|
434
|
-
stroke: `url(#${gradientId})`,
|
|
435
|
-
strokeWidth: 2,
|
|
436
|
-
strokeDasharray: "6 4",
|
|
437
|
-
strokeLinecap: "round",
|
|
438
|
-
strokeLinejoin: "round"
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
),
|
|
442
|
-
/* @__PURE__ */ jsx(
|
|
443
|
-
"path",
|
|
444
|
-
{
|
|
445
|
-
d: edgePath,
|
|
446
|
-
fill: "none",
|
|
447
|
-
strokeWidth: 10,
|
|
448
|
-
stroke: "transparent",
|
|
449
|
-
className: "react-flow__edge-interaction"
|
|
450
|
-
}
|
|
451
|
-
)
|
|
452
|
-
] });
|
|
453
|
-
}
|
|
454
387
|
|
|
455
388
|
// src/types/groups.ts
|
|
456
389
|
var GROUP_COLORS = {
|
|
457
|
-
purple: {
|
|
458
|
-
bg: "bg-purple-500/10",
|
|
459
|
-
border: "border-purple-500/30",
|
|
460
|
-
text: "text-purple-400"
|
|
461
|
-
},
|
|
462
390
|
blue: {
|
|
463
391
|
bg: "bg-blue-500/10",
|
|
464
392
|
border: "border-blue-500/30",
|
|
465
393
|
text: "text-blue-400"
|
|
466
394
|
},
|
|
395
|
+
gray: {
|
|
396
|
+
bg: "bg-gray-500/10",
|
|
397
|
+
border: "border-gray-500/30",
|
|
398
|
+
text: "text-gray-400"
|
|
399
|
+
},
|
|
467
400
|
green: {
|
|
468
401
|
bg: "bg-green-500/10",
|
|
469
402
|
border: "border-green-500/30",
|
|
470
403
|
text: "text-green-400"
|
|
471
404
|
},
|
|
472
|
-
yellow: {
|
|
473
|
-
bg: "bg-yellow-500/10",
|
|
474
|
-
border: "border-yellow-500/30",
|
|
475
|
-
text: "text-yellow-400"
|
|
476
|
-
},
|
|
477
405
|
orange: {
|
|
478
406
|
bg: "bg-orange-500/10",
|
|
479
407
|
border: "border-orange-500/30",
|
|
480
408
|
text: "text-orange-400"
|
|
481
409
|
},
|
|
482
|
-
red: {
|
|
483
|
-
bg: "bg-red-500/10",
|
|
484
|
-
border: "border-red-500/30",
|
|
485
|
-
text: "text-red-400"
|
|
486
|
-
},
|
|
487
410
|
pink: {
|
|
488
411
|
bg: "bg-pink-500/10",
|
|
489
412
|
border: "border-pink-500/30",
|
|
490
413
|
text: "text-pink-400"
|
|
491
414
|
},
|
|
492
|
-
|
|
493
|
-
bg: "bg-
|
|
494
|
-
border: "border-
|
|
495
|
-
text: "text-
|
|
415
|
+
purple: {
|
|
416
|
+
bg: "bg-purple-500/10",
|
|
417
|
+
border: "border-purple-500/30",
|
|
418
|
+
text: "text-purple-400"
|
|
419
|
+
},
|
|
420
|
+
red: {
|
|
421
|
+
bg: "bg-red-500/10",
|
|
422
|
+
border: "border-red-500/30",
|
|
423
|
+
text: "text-red-400"
|
|
424
|
+
},
|
|
425
|
+
yellow: {
|
|
426
|
+
bg: "bg-yellow-500/10",
|
|
427
|
+
border: "border-yellow-500/30",
|
|
428
|
+
text: "text-yellow-400"
|
|
496
429
|
}
|
|
497
430
|
};
|
|
498
431
|
var DEFAULT_GROUP_COLORS = [
|
|
@@ -527,10 +460,10 @@ function calculateGroupBounds(nodeIds, nodeMap) {
|
|
|
527
460
|
if (!foundAny) return null;
|
|
528
461
|
const padding = 24;
|
|
529
462
|
return {
|
|
530
|
-
|
|
531
|
-
y: minY - padding - HEADER_HEIGHT,
|
|
463
|
+
height: maxY - minY + padding * 2 + HEADER_HEIGHT,
|
|
532
464
|
width: maxX - minX + padding * 2,
|
|
533
|
-
|
|
465
|
+
x: minX - padding,
|
|
466
|
+
y: minY - padding - HEADER_HEIGHT
|
|
534
467
|
};
|
|
535
468
|
}
|
|
536
469
|
function GroupBackground({ group, bounds }) {
|
|
@@ -545,10 +478,10 @@ function GroupBackground({ group, bounds }) {
|
|
|
545
478
|
group.isLocked && "opacity-60"
|
|
546
479
|
),
|
|
547
480
|
style: {
|
|
481
|
+
height: bounds.height,
|
|
548
482
|
left: bounds.x,
|
|
549
483
|
top: bounds.y,
|
|
550
|
-
width: bounds.width
|
|
551
|
-
height: bounds.height
|
|
484
|
+
width: bounds.width
|
|
552
485
|
}
|
|
553
486
|
}
|
|
554
487
|
);
|
|
@@ -563,7 +496,9 @@ function GroupControls({ group, bounds, nodeMap, zoom }) {
|
|
|
563
496
|
const colorPickerRef = useRef(null);
|
|
564
497
|
const [isDragging, setIsDragging] = useState(false);
|
|
565
498
|
const dragStartRef = useRef(null);
|
|
566
|
-
const nodeStartPositionsRef = useRef(
|
|
499
|
+
const nodeStartPositionsRef = useRef(
|
|
500
|
+
/* @__PURE__ */ new Map()
|
|
501
|
+
);
|
|
567
502
|
useEffect(() => {
|
|
568
503
|
if (!isEditing) {
|
|
569
504
|
setEditName(group.name);
|
|
@@ -678,10 +613,10 @@ function GroupControls({ group, bounds, nodeMap, zoom }) {
|
|
|
678
613
|
group.isLocked && "opacity-60"
|
|
679
614
|
),
|
|
680
615
|
style: {
|
|
616
|
+
height: HEADER_HEIGHT,
|
|
681
617
|
left: bounds.x,
|
|
682
618
|
top: bounds.y,
|
|
683
|
-
width: bounds.width
|
|
684
|
-
height: HEADER_HEIGHT
|
|
619
|
+
width: bounds.width
|
|
685
620
|
},
|
|
686
621
|
children: [
|
|
687
622
|
isEditing ? /* @__PURE__ */ jsx(
|
|
@@ -717,7 +652,10 @@ function GroupControls({ group, bounds, nodeMap, zoom }) {
|
|
|
717
652
|
e.stopPropagation();
|
|
718
653
|
setShowColorPicker(!showColorPicker);
|
|
719
654
|
},
|
|
720
|
-
className: clsx(
|
|
655
|
+
className: clsx(
|
|
656
|
+
"p-1 rounded hover:bg-white/10 transition-colors",
|
|
657
|
+
colors.text
|
|
658
|
+
),
|
|
721
659
|
title: "Change group color",
|
|
722
660
|
children: /* @__PURE__ */ jsx(Palette, { className: "w-4 h-4" })
|
|
723
661
|
}
|
|
@@ -746,7 +684,10 @@ function GroupControls({ group, bounds, nodeMap, zoom }) {
|
|
|
746
684
|
e.stopPropagation();
|
|
747
685
|
toggleGroupLock(group.id);
|
|
748
686
|
},
|
|
749
|
-
className: clsx(
|
|
687
|
+
className: clsx(
|
|
688
|
+
"p-1 rounded hover:bg-white/10 transition-colors",
|
|
689
|
+
colors.text
|
|
690
|
+
),
|
|
750
691
|
title: group.isLocked ? "Unlock group" : "Lock group",
|
|
751
692
|
children: group.isLocked ? /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Unlock, { className: "w-4 h-4" })
|
|
752
693
|
}
|
|
@@ -758,7 +699,10 @@ function GroupControls({ group, bounds, nodeMap, zoom }) {
|
|
|
758
699
|
e.stopPropagation();
|
|
759
700
|
deleteGroup(group.id);
|
|
760
701
|
},
|
|
761
|
-
className: clsx(
|
|
702
|
+
className: clsx(
|
|
703
|
+
"p-1 rounded hover:bg-white/10 transition-colors",
|
|
704
|
+
colors.text
|
|
705
|
+
),
|
|
762
706
|
title: "Delete group",
|
|
763
707
|
children: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" })
|
|
764
708
|
}
|
|
@@ -799,11 +743,23 @@ function GroupBackgroundsPortalComponent() {
|
|
|
799
743
|
return result;
|
|
800
744
|
}, [groups, nodeMap]);
|
|
801
745
|
if (groups.length === 0) return null;
|
|
802
|
-
return /* @__PURE__ */ jsx(ViewportPortal, { children: /* @__PURE__ */ jsx(
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
746
|
+
return /* @__PURE__ */ jsx(ViewportPortal, { children: /* @__PURE__ */ jsx(
|
|
747
|
+
"div",
|
|
748
|
+
{
|
|
749
|
+
style: {
|
|
750
|
+
left: 0,
|
|
751
|
+
pointerEvents: "none",
|
|
752
|
+
position: "absolute",
|
|
753
|
+
top: 0,
|
|
754
|
+
zIndex: -1
|
|
755
|
+
},
|
|
756
|
+
children: groups.map((group) => {
|
|
757
|
+
const bounds = groupBounds.get(group.id);
|
|
758
|
+
if (!bounds) return null;
|
|
759
|
+
return /* @__PURE__ */ jsx(GroupBackground, { group, bounds }, group.id);
|
|
760
|
+
})
|
|
761
|
+
}
|
|
762
|
+
) });
|
|
807
763
|
}
|
|
808
764
|
function GroupControlsOverlayComponent() {
|
|
809
765
|
const { groups } = useWorkflowStore();
|
|
@@ -821,20 +777,32 @@ function GroupControlsOverlayComponent() {
|
|
|
821
777
|
return result;
|
|
822
778
|
}, [groups, nodeMap]);
|
|
823
779
|
if (groups.length === 0) return null;
|
|
824
|
-
return /* @__PURE__ */ jsx(ViewportPortal, { children: /* @__PURE__ */ jsx(
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
zoom
|
|
780
|
+
return /* @__PURE__ */ jsx(ViewportPortal, { children: /* @__PURE__ */ jsx(
|
|
781
|
+
"div",
|
|
782
|
+
{
|
|
783
|
+
style: {
|
|
784
|
+
left: 0,
|
|
785
|
+
pointerEvents: "none",
|
|
786
|
+
position: "absolute",
|
|
787
|
+
top: 0,
|
|
788
|
+
zIndex: 1e3
|
|
834
789
|
},
|
|
835
|
-
group
|
|
836
|
-
|
|
837
|
-
|
|
790
|
+
children: groups.map((group) => {
|
|
791
|
+
const bounds = groupBounds.get(group.id);
|
|
792
|
+
if (!bounds) return null;
|
|
793
|
+
return /* @__PURE__ */ jsx(
|
|
794
|
+
GroupControls,
|
|
795
|
+
{
|
|
796
|
+
group,
|
|
797
|
+
bounds,
|
|
798
|
+
nodeMap,
|
|
799
|
+
zoom
|
|
800
|
+
},
|
|
801
|
+
group.id
|
|
802
|
+
);
|
|
803
|
+
})
|
|
804
|
+
}
|
|
805
|
+
) });
|
|
838
806
|
}
|
|
839
807
|
var GroupBackgroundsPortal = memo(GroupBackgroundsPortalComponent);
|
|
840
808
|
var GroupControlsOverlay = memo(GroupControlsOverlayComponent);
|
|
@@ -857,7 +825,9 @@ function HelperLinesComponent({ draggingNodeId }) {
|
|
|
857
825
|
setLines([]);
|
|
858
826
|
return;
|
|
859
827
|
}
|
|
860
|
-
const otherNodes = nodes.filter(
|
|
828
|
+
const otherNodes = nodes.filter(
|
|
829
|
+
(n) => n.id !== draggingId && !n.selected
|
|
830
|
+
);
|
|
861
831
|
if (otherNodes.length === 0) {
|
|
862
832
|
setLines([]);
|
|
863
833
|
return;
|
|
@@ -881,36 +851,44 @@ function HelperLinesComponent({ draggingNodeId }) {
|
|
|
881
851
|
const nodeCenterX = nodeLeft + nodeWidth / 2;
|
|
882
852
|
const nodeCenterY = nodeTop + nodeHeight / 2;
|
|
883
853
|
const verticalChecks = [
|
|
884
|
-
{ dragPos: dragLeft,
|
|
885
|
-
{ dragPos: dragLeft,
|
|
886
|
-
{ dragPos: dragRight,
|
|
887
|
-
{ dragPos: dragRight,
|
|
888
|
-
{
|
|
854
|
+
{ dragPos: dragLeft, label: "left-left", nodePos: nodeLeft },
|
|
855
|
+
{ dragPos: dragLeft, label: "left-right", nodePos: nodeRight },
|
|
856
|
+
{ dragPos: dragRight, label: "right-left", nodePos: nodeLeft },
|
|
857
|
+
{ dragPos: dragRight, label: "right-right", nodePos: nodeRight },
|
|
858
|
+
{
|
|
859
|
+
dragPos: dragCenterX,
|
|
860
|
+
label: "center-center-x",
|
|
861
|
+
nodePos: nodeCenterX
|
|
862
|
+
}
|
|
889
863
|
];
|
|
890
864
|
for (const check of verticalChecks) {
|
|
891
865
|
if (Math.abs(check.dragPos - check.nodePos) <= SNAP_THRESHOLD) {
|
|
892
866
|
newLines.push({
|
|
893
|
-
|
|
867
|
+
end: Math.max(dragBottom, nodeBottom) + 20,
|
|
894
868
|
position: check.nodePos,
|
|
895
869
|
start: Math.min(dragTop, nodeTop) - 20,
|
|
896
|
-
|
|
870
|
+
type: "vertical"
|
|
897
871
|
});
|
|
898
872
|
}
|
|
899
873
|
}
|
|
900
874
|
const horizontalChecks = [
|
|
901
|
-
{ dragPos: dragTop,
|
|
902
|
-
{ dragPos: dragTop,
|
|
903
|
-
{ dragPos: dragBottom,
|
|
904
|
-
{ dragPos: dragBottom,
|
|
905
|
-
{
|
|
875
|
+
{ dragPos: dragTop, label: "top-top", nodePos: nodeTop },
|
|
876
|
+
{ dragPos: dragTop, label: "top-bottom", nodePos: nodeBottom },
|
|
877
|
+
{ dragPos: dragBottom, label: "bottom-top", nodePos: nodeTop },
|
|
878
|
+
{ dragPos: dragBottom, label: "bottom-bottom", nodePos: nodeBottom },
|
|
879
|
+
{
|
|
880
|
+
dragPos: dragCenterY,
|
|
881
|
+
label: "center-center-y",
|
|
882
|
+
nodePos: nodeCenterY
|
|
883
|
+
}
|
|
906
884
|
];
|
|
907
885
|
for (const check of horizontalChecks) {
|
|
908
886
|
if (Math.abs(check.dragPos - check.nodePos) <= SNAP_THRESHOLD) {
|
|
909
887
|
newLines.push({
|
|
910
|
-
|
|
888
|
+
end: Math.max(dragRight, nodeRight) + 20,
|
|
911
889
|
position: check.nodePos,
|
|
912
890
|
start: Math.min(dragLeft, nodeLeft) - 20,
|
|
913
|
-
|
|
891
|
+
type: "horizontal"
|
|
914
892
|
});
|
|
915
893
|
}
|
|
916
894
|
}
|
|
@@ -949,7 +927,7 @@ function HelperLinesComponent({ draggingNodeId }) {
|
|
|
949
927
|
"svg",
|
|
950
928
|
{
|
|
951
929
|
className: "absolute inset-0 pointer-events-none z-[1000]",
|
|
952
|
-
style: {
|
|
930
|
+
style: { height: "100%", overflow: "visible", width: "100%" },
|
|
953
931
|
children: lines.map((line, index) => {
|
|
954
932
|
if (line.type === "vertical") {
|
|
955
933
|
const x = line.position * zoom + tx;
|
|
@@ -1030,9 +1008,9 @@ function NodeSearch() {
|
|
|
1030
1008
|
(node) => {
|
|
1031
1009
|
setSelectedNodeIds([node.id]);
|
|
1032
1010
|
reactFlow.fitView({
|
|
1011
|
+
duration: 300,
|
|
1033
1012
|
nodes: [node],
|
|
1034
|
-
padding: 0.5
|
|
1035
|
-
duration: 300
|
|
1013
|
+
padding: 0.5
|
|
1036
1014
|
});
|
|
1037
1015
|
closeModal();
|
|
1038
1016
|
setSearch("");
|
|
@@ -1043,7 +1021,9 @@ function NodeSearch() {
|
|
|
1043
1021
|
(e) => {
|
|
1044
1022
|
if (e.key === "ArrowDown") {
|
|
1045
1023
|
e.preventDefault();
|
|
1046
|
-
setSelectedIndex(
|
|
1024
|
+
setSelectedIndex(
|
|
1025
|
+
(prev) => Math.min(prev + 1, filteredNodes.length - 1)
|
|
1026
|
+
);
|
|
1047
1027
|
} else if (e.key === "ArrowUp") {
|
|
1048
1028
|
e.preventDefault();
|
|
1049
1029
|
setSelectedIndex((prev) => Math.max(prev - 1, 0));
|
|
@@ -1078,117 +1058,302 @@ function NodeSearch() {
|
|
|
1078
1058
|
children: /* @__PURE__ */ jsxs(
|
|
1079
1059
|
"div",
|
|
1080
1060
|
{
|
|
1081
|
-
className: "bg-[var(--background)] border border-[var(--border)] rounded-lg shadow-xl w-full max-w-lg",
|
|
1082
|
-
role: "dialog",
|
|
1083
|
-
"aria-label": "Find Node",
|
|
1084
|
-
children: [
|
|
1085
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-[var(--border)]", children: [
|
|
1086
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1087
|
-
/* @__PURE__ */ jsx(Search, { className: "w-4 h-4 text-[var(--muted-foreground)]" }),
|
|
1088
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Find Node" })
|
|
1089
|
-
] }),
|
|
1090
|
-
/* @__PURE__ */ jsx(
|
|
1091
|
-
"button",
|
|
1092
|
-
{
|
|
1093
|
-
onClick: handleClose,
|
|
1094
|
-
className: "p-1 rounded hover:bg-[var(--secondary)] transition-colors",
|
|
1095
|
-
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
|
|
1096
|
-
}
|
|
1097
|
-
)
|
|
1098
|
-
] }),
|
|
1099
|
-
/* @__PURE__ */ jsxs("div", { className: "p-4", onKeyDown: handleKeyDown, children: [
|
|
1100
|
-
/* @__PURE__ */ jsxs("div", { className: "relative mb-3", children: [
|
|
1101
|
-
/* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
1102
|
-
/* @__PURE__ */ jsx(
|
|
1103
|
-
"input",
|
|
1104
|
-
{
|
|
1105
|
-
ref: inputRef,
|
|
1106
|
-
type: "text",
|
|
1107
|
-
placeholder: "Search nodes by name, type, or comment...",
|
|
1108
|
-
value: search,
|
|
1109
|
-
onChange: (e) => setSearch(e.target.value),
|
|
1110
|
-
className: "w-full pl-9 pr-3 py-2 text-sm bg-[var(--secondary)] border border-[var(--border)] rounded-md outline-none focus:ring-1 focus:ring-[var(--ring)]",
|
|
1111
|
-
autoFocus: true
|
|
1112
|
-
}
|
|
1113
|
-
)
|
|
1114
|
-
] }),
|
|
1115
|
-
/* @__PURE__ */ jsx(
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
"
|
|
1120
|
-
{
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
"
|
|
1149
|
-
] })
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1061
|
+
className: "bg-[var(--background)] border border-[var(--border)] rounded-lg shadow-xl w-full max-w-lg",
|
|
1062
|
+
role: "dialog",
|
|
1063
|
+
"aria-label": "Find Node",
|
|
1064
|
+
children: [
|
|
1065
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-[var(--border)]", children: [
|
|
1066
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1067
|
+
/* @__PURE__ */ jsx(Search, { className: "w-4 h-4 text-[var(--muted-foreground)]" }),
|
|
1068
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Find Node" })
|
|
1069
|
+
] }),
|
|
1070
|
+
/* @__PURE__ */ jsx(
|
|
1071
|
+
"button",
|
|
1072
|
+
{
|
|
1073
|
+
onClick: handleClose,
|
|
1074
|
+
className: "p-1 rounded hover:bg-[var(--secondary)] transition-colors",
|
|
1075
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
|
|
1076
|
+
}
|
|
1077
|
+
)
|
|
1078
|
+
] }),
|
|
1079
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4", onKeyDown: handleKeyDown, children: [
|
|
1080
|
+
/* @__PURE__ */ jsxs("div", { className: "relative mb-3", children: [
|
|
1081
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
1082
|
+
/* @__PURE__ */ jsx(
|
|
1083
|
+
"input",
|
|
1084
|
+
{
|
|
1085
|
+
ref: inputRef,
|
|
1086
|
+
type: "text",
|
|
1087
|
+
placeholder: "Search nodes by name, type, or comment...",
|
|
1088
|
+
value: search,
|
|
1089
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1090
|
+
className: "w-full pl-9 pr-3 py-2 text-sm bg-[var(--secondary)] border border-[var(--border)] rounded-md outline-none focus:ring-1 focus:ring-[var(--ring)]",
|
|
1091
|
+
autoFocus: true
|
|
1092
|
+
}
|
|
1093
|
+
)
|
|
1094
|
+
] }),
|
|
1095
|
+
/* @__PURE__ */ jsx(
|
|
1096
|
+
"div",
|
|
1097
|
+
{
|
|
1098
|
+
ref: listRef,
|
|
1099
|
+
className: "max-h-[300px] overflow-y-auto space-y-1",
|
|
1100
|
+
children: filteredNodes.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center text-muted-foreground py-8", children: search ? `No nodes found for "${search}"` : "No nodes in workflow" }) : filteredNodes.map((node, index) => {
|
|
1101
|
+
const nodeDef = NODE_DEFINITIONS[node.type];
|
|
1102
|
+
const comment = node.data.comment;
|
|
1103
|
+
return /* @__PURE__ */ jsxs(
|
|
1104
|
+
"button",
|
|
1105
|
+
{
|
|
1106
|
+
onClick: () => handleSelectNode(node),
|
|
1107
|
+
className: `w-full flex items-center gap-3 p-2 rounded text-left transition-colors ${index === selectedIndex ? "bg-primary/10 border border-primary/30" : "hover:bg-secondary/50 border border-transparent"}`,
|
|
1108
|
+
children: [
|
|
1109
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-8 h-8 rounded bg-secondary flex items-center justify-center text-xs font-medium", children: nodeDef?.label?.charAt(0) || "?" }),
|
|
1110
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
1111
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium truncate text-sm", children: node.data.label }),
|
|
1112
|
+
/* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground truncate", children: [
|
|
1113
|
+
nodeDef?.label || node.type,
|
|
1114
|
+
comment && ` \xB7 ${comment}`
|
|
1115
|
+
] })
|
|
1116
|
+
] })
|
|
1117
|
+
]
|
|
1118
|
+
},
|
|
1119
|
+
node.id
|
|
1120
|
+
);
|
|
1121
|
+
})
|
|
1122
|
+
}
|
|
1123
|
+
),
|
|
1124
|
+
filteredNodes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 pt-3 border-t border-border text-xs text-muted-foreground flex gap-4", children: [
|
|
1125
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1126
|
+
/* @__PURE__ */ jsx("kbd", { className: "px-1.5 py-0.5 bg-secondary rounded", children: "up/down" }),
|
|
1127
|
+
" ",
|
|
1128
|
+
"Navigate"
|
|
1129
|
+
] }),
|
|
1130
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1131
|
+
/* @__PURE__ */ jsx("kbd", { className: "px-1.5 py-0.5 bg-secondary rounded", children: "Enter" }),
|
|
1132
|
+
" ",
|
|
1133
|
+
"Select"
|
|
1134
|
+
] }),
|
|
1135
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1136
|
+
/* @__PURE__ */ jsx("kbd", { className: "px-1.5 py-0.5 bg-secondary rounded", children: "Esc" }),
|
|
1137
|
+
" ",
|
|
1138
|
+
"Close"
|
|
1139
|
+
] })
|
|
1140
|
+
] })
|
|
1141
|
+
] })
|
|
1142
|
+
]
|
|
1143
|
+
}
|
|
1144
|
+
)
|
|
1145
|
+
}
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
function PauseEdgeComponent({
|
|
1149
|
+
id,
|
|
1150
|
+
sourceX,
|
|
1151
|
+
sourceY,
|
|
1152
|
+
targetX,
|
|
1153
|
+
targetY,
|
|
1154
|
+
sourcePosition,
|
|
1155
|
+
targetPosition,
|
|
1156
|
+
style = {},
|
|
1157
|
+
markerEnd,
|
|
1158
|
+
data
|
|
1159
|
+
}) {
|
|
1160
|
+
const [edgePath, labelX, labelY] = getBezierPath({
|
|
1161
|
+
sourcePosition,
|
|
1162
|
+
sourceX,
|
|
1163
|
+
sourceY,
|
|
1164
|
+
targetPosition,
|
|
1165
|
+
targetX,
|
|
1166
|
+
targetY
|
|
1167
|
+
});
|
|
1168
|
+
const hasPause = data?.hasPause === true;
|
|
1169
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1170
|
+
/* @__PURE__ */ jsx(
|
|
1171
|
+
BaseEdge,
|
|
1172
|
+
{
|
|
1173
|
+
path: edgePath,
|
|
1174
|
+
markerEnd,
|
|
1175
|
+
style: {
|
|
1176
|
+
...style,
|
|
1177
|
+
...hasPause && {
|
|
1178
|
+
stroke: "#f59e0b",
|
|
1179
|
+
strokeDasharray: "5 5"
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
),
|
|
1184
|
+
hasPause && /* @__PURE__ */ jsx(
|
|
1185
|
+
"foreignObject",
|
|
1186
|
+
{
|
|
1187
|
+
width: 20,
|
|
1188
|
+
height: 20,
|
|
1189
|
+
x: labelX - 10,
|
|
1190
|
+
y: labelY - 10,
|
|
1191
|
+
className: "pointer-events-none",
|
|
1192
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-5 h-5 rounded-full bg-amber-500 text-white", children: /* @__PURE__ */ jsx(Pause, { className: "w-3 h-3" }) })
|
|
1193
|
+
}
|
|
1194
|
+
)
|
|
1195
|
+
] });
|
|
1196
|
+
}
|
|
1197
|
+
var PauseEdge = memo(PauseEdgeComponent);
|
|
1198
|
+
var REFERENCE_COLOR = "#52525b";
|
|
1199
|
+
function ReferenceEdge({
|
|
1200
|
+
id,
|
|
1201
|
+
sourceX,
|
|
1202
|
+
sourceY,
|
|
1203
|
+
targetX,
|
|
1204
|
+
targetY,
|
|
1205
|
+
sourcePosition,
|
|
1206
|
+
targetPosition,
|
|
1207
|
+
style,
|
|
1208
|
+
markerEnd,
|
|
1209
|
+
source,
|
|
1210
|
+
target
|
|
1211
|
+
}) {
|
|
1212
|
+
const nodes = useWorkflowStore((state) => state.nodes);
|
|
1213
|
+
const isConnectedToSelection = useMemo(() => {
|
|
1214
|
+
const selectedNodes = nodes.filter((n) => n.selected);
|
|
1215
|
+
if (selectedNodes.length === 0) return false;
|
|
1216
|
+
return selectedNodes.some((n) => n.id === source || n.id === target);
|
|
1217
|
+
}, [nodes, source, target]);
|
|
1218
|
+
const [edgePath] = useMemo(() => {
|
|
1219
|
+
return getBezierPath({
|
|
1220
|
+
curvature: 0.25,
|
|
1221
|
+
sourcePosition,
|
|
1222
|
+
sourceX,
|
|
1223
|
+
sourceY,
|
|
1224
|
+
targetPosition,
|
|
1225
|
+
targetX,
|
|
1226
|
+
targetY
|
|
1227
|
+
});
|
|
1228
|
+
}, [sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition]);
|
|
1229
|
+
const gradientId = useMemo(() => {
|
|
1230
|
+
const selectionKey = isConnectedToSelection ? "active" : "dimmed";
|
|
1231
|
+
return `reference-gradient-${selectionKey}-${id}`;
|
|
1232
|
+
}, [isConnectedToSelection, id]);
|
|
1233
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1234
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradientId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: [
|
|
1235
|
+
/* @__PURE__ */ jsx(
|
|
1236
|
+
"stop",
|
|
1237
|
+
{
|
|
1238
|
+
offset: "0%",
|
|
1239
|
+
stopColor: REFERENCE_COLOR,
|
|
1240
|
+
stopOpacity: isConnectedToSelection ? 1 : 0.25
|
|
1241
|
+
}
|
|
1242
|
+
),
|
|
1243
|
+
/* @__PURE__ */ jsx(
|
|
1244
|
+
"stop",
|
|
1245
|
+
{
|
|
1246
|
+
offset: "50%",
|
|
1247
|
+
stopColor: REFERENCE_COLOR,
|
|
1248
|
+
stopOpacity: isConnectedToSelection ? 0.55 : 0.1
|
|
1249
|
+
}
|
|
1250
|
+
),
|
|
1251
|
+
/* @__PURE__ */ jsx(
|
|
1252
|
+
"stop",
|
|
1253
|
+
{
|
|
1254
|
+
offset: "100%",
|
|
1255
|
+
stopColor: REFERENCE_COLOR,
|
|
1256
|
+
stopOpacity: isConnectedToSelection ? 1 : 0.25
|
|
1153
1257
|
}
|
|
1154
1258
|
)
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1259
|
+
] }) }),
|
|
1260
|
+
/* @__PURE__ */ jsx(
|
|
1261
|
+
BaseEdge,
|
|
1262
|
+
{
|
|
1263
|
+
id,
|
|
1264
|
+
path: edgePath,
|
|
1265
|
+
markerEnd,
|
|
1266
|
+
style: {
|
|
1267
|
+
...style,
|
|
1268
|
+
stroke: `url(#${gradientId})`,
|
|
1269
|
+
strokeDasharray: "6 4",
|
|
1270
|
+
strokeLinecap: "round",
|
|
1271
|
+
strokeLinejoin: "round",
|
|
1272
|
+
strokeWidth: 2
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
),
|
|
1276
|
+
/* @__PURE__ */ jsx(
|
|
1277
|
+
"path",
|
|
1278
|
+
{
|
|
1279
|
+
d: edgePath,
|
|
1280
|
+
fill: "none",
|
|
1281
|
+
strokeWidth: 10,
|
|
1282
|
+
stroke: "transparent",
|
|
1283
|
+
className: "react-flow__edge-interaction"
|
|
1284
|
+
}
|
|
1285
|
+
)
|
|
1286
|
+
] });
|
|
1157
1287
|
}
|
|
1158
1288
|
var SHORTCUTS = [
|
|
1159
1289
|
// Navigation
|
|
1160
|
-
{
|
|
1161
|
-
{
|
|
1162
|
-
{
|
|
1163
|
-
|
|
1290
|
+
{ category: "Navigation", description: "Pan canvas", keys: "Scroll" },
|
|
1291
|
+
{ category: "Navigation", description: "Zoom in/out", keys: "Ctrl + Scroll" },
|
|
1292
|
+
{
|
|
1293
|
+
category: "Navigation",
|
|
1294
|
+
description: "Fit view to selection (or all)",
|
|
1295
|
+
keys: "F"
|
|
1296
|
+
},
|
|
1297
|
+
{ category: "Navigation", description: "Toggle sidebar", keys: "M" },
|
|
1164
1298
|
// Selection
|
|
1165
|
-
{
|
|
1166
|
-
{
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1299
|
+
{ category: "Selection", description: "Select node", keys: "Click" },
|
|
1300
|
+
{
|
|
1301
|
+
category: "Selection",
|
|
1302
|
+
description: "Add to selection",
|
|
1303
|
+
keys: "Shift + Click"
|
|
1304
|
+
},
|
|
1305
|
+
{ category: "Selection", description: "Marquee select", keys: "Drag" },
|
|
1306
|
+
{ category: "Selection", description: "Select all nodes", keys: "Ctrl + A" },
|
|
1307
|
+
{ category: "Selection", description: "Search nodes", keys: "Ctrl + F" },
|
|
1170
1308
|
// Editing
|
|
1171
|
-
{
|
|
1172
|
-
{
|
|
1173
|
-
{
|
|
1174
|
-
{
|
|
1175
|
-
{
|
|
1176
|
-
{
|
|
1177
|
-
{
|
|
1309
|
+
{ category: "Editing", description: "Undo", keys: "Ctrl + Z" },
|
|
1310
|
+
{ category: "Editing", description: "Redo", keys: "Ctrl + Shift + Z" },
|
|
1311
|
+
{ category: "Editing", description: "Copy", keys: "Ctrl + C" },
|
|
1312
|
+
{ category: "Editing", description: "Cut", keys: "Ctrl + X" },
|
|
1313
|
+
{ category: "Editing", description: "Paste", keys: "Ctrl + V" },
|
|
1314
|
+
{ category: "Editing", description: "Duplicate", keys: "Ctrl + D" },
|
|
1315
|
+
{
|
|
1316
|
+
category: "Editing",
|
|
1317
|
+
description: "Delete selected",
|
|
1318
|
+
keys: "Delete / Backspace"
|
|
1319
|
+
},
|
|
1178
1320
|
// Nodes
|
|
1179
|
-
{
|
|
1180
|
-
{
|
|
1181
|
-
{
|
|
1182
|
-
{
|
|
1321
|
+
{ category: "Nodes", description: "Add Image Gen node", keys: "Shift + I" },
|
|
1322
|
+
{ category: "Nodes", description: "Add Video Gen node", keys: "Shift + V" },
|
|
1323
|
+
{ category: "Nodes", description: "Add Prompt node", keys: "Shift + P" },
|
|
1324
|
+
{ category: "Nodes", description: "Add LLM node", keys: "Shift + L" },
|
|
1183
1325
|
// Organization
|
|
1184
|
-
{
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1326
|
+
{
|
|
1327
|
+
category: "Organization",
|
|
1328
|
+
description: "Toggle lock on selected",
|
|
1329
|
+
keys: "L"
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
category: "Organization",
|
|
1333
|
+
description: "Group selected nodes",
|
|
1334
|
+
keys: "Ctrl + G"
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
category: "Organization",
|
|
1338
|
+
description: "Ungroup",
|
|
1339
|
+
keys: "Ctrl + Shift + G"
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
category: "Organization",
|
|
1343
|
+
description: "Unlock all nodes",
|
|
1344
|
+
keys: "Ctrl + Shift + L"
|
|
1345
|
+
},
|
|
1188
1346
|
// Help
|
|
1189
|
-
{
|
|
1347
|
+
{ category: "Help", description: "Show this help", keys: "?" }
|
|
1348
|
+
];
|
|
1349
|
+
var CATEGORIES = [
|
|
1350
|
+
"Navigation",
|
|
1351
|
+
"Selection",
|
|
1352
|
+
"Editing",
|
|
1353
|
+
"Nodes",
|
|
1354
|
+
"Organization",
|
|
1355
|
+
"Help"
|
|
1190
1356
|
];
|
|
1191
|
-
var CATEGORIES = ["Navigation", "Selection", "Editing", "Nodes", "Organization", "Help"];
|
|
1192
1357
|
function ShortcutHelpModal() {
|
|
1193
1358
|
const { activeModal, closeModal } = useUIStore();
|
|
1194
1359
|
const [searchQuery, setSearchQuery] = useState("");
|
|
@@ -1346,7 +1511,7 @@ function CostModal() {
|
|
|
1346
1511
|
}
|
|
1347
1512
|
)
|
|
1348
1513
|
] }),
|
|
1349
|
-
/* @__PURE__ */ jsx("div", { className: "p-4", children: breakdown.
|
|
1514
|
+
/* @__PURE__ */ jsx("div", { className: "p-4", children: breakdown.items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center text-[var(--muted-foreground)] py-8", children: "No billable nodes in workflow" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1350
1515
|
/* @__PURE__ */ jsx("div", { className: "max-h-[40vh] overflow-y-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
1351
1516
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "text-left text-xs text-[var(--muted-foreground)] border-b border-[var(--border)]", children: [
|
|
1352
1517
|
/* @__PURE__ */ jsx("th", { className: "pb-2 font-medium", children: "Node" }),
|
|
@@ -1354,15 +1519,22 @@ function CostModal() {
|
|
|
1354
1519
|
/* @__PURE__ */ jsx("th", { className: "pb-2 font-medium", children: "Unit" }),
|
|
1355
1520
|
/* @__PURE__ */ jsx("th", { className: "pb-2 font-medium text-right", children: "Cost" })
|
|
1356
1521
|
] }) }),
|
|
1357
|
-
/* @__PURE__ */ jsx("tbody", { children: breakdown.
|
|
1522
|
+
/* @__PURE__ */ jsx("tbody", { children: breakdown.items.map((estimate) => /* @__PURE__ */ jsxs(
|
|
1358
1523
|
"tr",
|
|
1359
1524
|
{
|
|
1360
1525
|
className: "border-b border-[var(--border)] last:border-0",
|
|
1361
1526
|
children: [
|
|
1362
|
-
/* @__PURE__ */ jsx(
|
|
1527
|
+
/* @__PURE__ */ jsx(
|
|
1528
|
+
"td",
|
|
1529
|
+
{
|
|
1530
|
+
className: "py-2 truncate max-w-[120px]",
|
|
1531
|
+
title: estimate.nodeLabel,
|
|
1532
|
+
children: estimate.nodeLabel
|
|
1533
|
+
}
|
|
1534
|
+
),
|
|
1363
1535
|
/* @__PURE__ */ jsx("td", { className: "py-2 text-[var(--muted-foreground)] font-mono text-xs", children: estimate.model }),
|
|
1364
1536
|
/* @__PURE__ */ jsx("td", { className: "py-2 text-[var(--muted-foreground)] text-xs", children: estimate.unit }),
|
|
1365
|
-
/* @__PURE__ */ jsx("td", { className: "py-2 text-right font-mono", children: formatCost(estimate.
|
|
1537
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 text-right font-mono", children: formatCost(estimate.subtotal) })
|
|
1366
1538
|
]
|
|
1367
1539
|
},
|
|
1368
1540
|
estimate.nodeId
|
|
@@ -1527,7 +1699,14 @@ function HistorySidebar({
|
|
|
1527
1699
|
viewBox: "0 0 24 24",
|
|
1528
1700
|
stroke: "currentColor",
|
|
1529
1701
|
strokeWidth: 2,
|
|
1530
|
-
children: /* @__PURE__ */ jsx(
|
|
1702
|
+
children: /* @__PURE__ */ jsx(
|
|
1703
|
+
"path",
|
|
1704
|
+
{
|
|
1705
|
+
strokeLinecap: "round",
|
|
1706
|
+
strokeLinejoin: "round",
|
|
1707
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
1708
|
+
}
|
|
1709
|
+
)
|
|
1531
1710
|
}
|
|
1532
1711
|
)
|
|
1533
1712
|
}
|
|
@@ -1573,8 +1752,12 @@ function GlobalImageHistory() {
|
|
|
1573
1752
|
const [showSidebar, setShowSidebar] = useState(false);
|
|
1574
1753
|
const drawerRef = useRef(null);
|
|
1575
1754
|
const triggerRef = useRef(null);
|
|
1576
|
-
const history = useWorkflowStore(
|
|
1577
|
-
|
|
1755
|
+
const history = useWorkflowStore(
|
|
1756
|
+
(state) => state.globalImageHistory ?? EMPTY_HISTORY
|
|
1757
|
+
);
|
|
1758
|
+
const clearGlobalHistory = useWorkflowStore(
|
|
1759
|
+
(state) => state.clearGlobalHistory
|
|
1760
|
+
);
|
|
1578
1761
|
const fanItems = history.slice(0, 10);
|
|
1579
1762
|
const hasOverflow = history.length > 10;
|
|
1580
1763
|
useEffect(() => {
|
|
@@ -1603,21 +1786,24 @@ function GlobalImageHistory() {
|
|
|
1603
1786
|
}
|
|
1604
1787
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1605
1788
|
}, [isOpen, showSidebar]);
|
|
1606
|
-
const handleDragStart = useCallback(
|
|
1607
|
-
e
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1789
|
+
const handleDragStart = useCallback(
|
|
1790
|
+
(e, item) => {
|
|
1791
|
+
e.dataTransfer.setData(
|
|
1792
|
+
"application/history-image",
|
|
1793
|
+
JSON.stringify({
|
|
1794
|
+
image: item.image,
|
|
1795
|
+
prompt: item.prompt,
|
|
1796
|
+
timestamp: item.timestamp
|
|
1797
|
+
})
|
|
1798
|
+
);
|
|
1799
|
+
e.dataTransfer.effectAllowed = "copy";
|
|
1800
|
+
setTimeout(() => {
|
|
1801
|
+
setIsOpen(false);
|
|
1802
|
+
setShowSidebar(false);
|
|
1803
|
+
}, 0);
|
|
1804
|
+
},
|
|
1805
|
+
[]
|
|
1806
|
+
);
|
|
1621
1807
|
const handleShowAll = useCallback(() => {
|
|
1622
1808
|
setIsOpen(false);
|
|
1623
1809
|
setShowSidebar(true);
|
|
@@ -1679,7 +1865,10 @@ function GlobalImageHistory() {
|
|
|
1679
1865
|
item.id
|
|
1680
1866
|
)) }),
|
|
1681
1867
|
hasOverflow && (() => {
|
|
1682
|
-
const topItemPos = calculateFanPosition(
|
|
1868
|
+
const topItemPos = calculateFanPosition(
|
|
1869
|
+
fanItems.length - 1,
|
|
1870
|
+
fanItems.length
|
|
1871
|
+
);
|
|
1683
1872
|
return /* @__PURE__ */ jsxs(
|
|
1684
1873
|
"button",
|
|
1685
1874
|
{
|
|
@@ -1716,8 +1905,17 @@ function GlobalImageHistory() {
|
|
|
1716
1905
|
var NODE_GAP = 32;
|
|
1717
1906
|
var EST_NODE_WIDTH = 280;
|
|
1718
1907
|
var EST_NODE_HEIGHT = 200;
|
|
1719
|
-
function MultiSelectToolbarComponent({
|
|
1720
|
-
|
|
1908
|
+
function MultiSelectToolbarComponent({
|
|
1909
|
+
onDownloadAsZip
|
|
1910
|
+
}) {
|
|
1911
|
+
const {
|
|
1912
|
+
nodes,
|
|
1913
|
+
selectedNodeIds,
|
|
1914
|
+
onNodesChange,
|
|
1915
|
+
createGroup,
|
|
1916
|
+
deleteGroup,
|
|
1917
|
+
groups
|
|
1918
|
+
} = useWorkflowStore();
|
|
1721
1919
|
const reactFlow = useReactFlow();
|
|
1722
1920
|
const selectedNodes = useMemo(
|
|
1723
1921
|
() => nodes.filter((n) => selectedNodeIds.includes(n.id)),
|
|
@@ -1725,7 +1923,9 @@ function MultiSelectToolbarComponent({ onDownloadAsZip }) {
|
|
|
1725
1923
|
);
|
|
1726
1924
|
const selectedGroup = useMemo(() => {
|
|
1727
1925
|
if (selectedNodes.length < 2) return null;
|
|
1728
|
-
return groups.find(
|
|
1926
|
+
return groups.find(
|
|
1927
|
+
(g) => selectedNodeIds.every((id) => g.nodeIds.includes(id))
|
|
1928
|
+
) ?? null;
|
|
1729
1929
|
}, [groups, selectedNodeIds, selectedNodes.length]);
|
|
1730
1930
|
const toolbarPosition = useMemo(() => {
|
|
1731
1931
|
if (selectedNodes.length < 2) return null;
|
|
@@ -1746,29 +1946,33 @@ function MultiSelectToolbarComponent({ onDownloadAsZip }) {
|
|
|
1746
1946
|
}, [selectedNodes, reactFlow]);
|
|
1747
1947
|
const stackHorizontal = useCallback(() => {
|
|
1748
1948
|
if (selectedNodes.length < 2) return;
|
|
1749
|
-
const sorted = [...selectedNodes].sort(
|
|
1949
|
+
const sorted = [...selectedNodes].sort(
|
|
1950
|
+
(a, b) => a.position.x - b.position.x
|
|
1951
|
+
);
|
|
1750
1952
|
const baseY = sorted[0].position.y;
|
|
1751
1953
|
const changes = sorted.map((node, i) => ({
|
|
1752
|
-
type: "position",
|
|
1753
1954
|
id: node.id,
|
|
1754
1955
|
position: {
|
|
1755
1956
|
x: sorted[0].position.x + i * (EST_NODE_WIDTH + NODE_GAP),
|
|
1756
1957
|
y: baseY
|
|
1757
|
-
}
|
|
1958
|
+
},
|
|
1959
|
+
type: "position"
|
|
1758
1960
|
}));
|
|
1759
1961
|
onNodesChange(changes);
|
|
1760
1962
|
}, [selectedNodes, onNodesChange]);
|
|
1761
1963
|
const stackVertical = useCallback(() => {
|
|
1762
1964
|
if (selectedNodes.length < 2) return;
|
|
1763
|
-
const sorted = [...selectedNodes].sort(
|
|
1965
|
+
const sorted = [...selectedNodes].sort(
|
|
1966
|
+
(a, b) => a.position.y - b.position.y
|
|
1967
|
+
);
|
|
1764
1968
|
const baseX = sorted[0].position.x;
|
|
1765
1969
|
const changes = sorted.map((node, i) => ({
|
|
1766
|
-
type: "position",
|
|
1767
1970
|
id: node.id,
|
|
1768
1971
|
position: {
|
|
1769
1972
|
x: baseX,
|
|
1770
1973
|
y: sorted[0].position.y + i * (EST_NODE_HEIGHT + NODE_GAP)
|
|
1771
|
-
}
|
|
1974
|
+
},
|
|
1975
|
+
type: "position"
|
|
1772
1976
|
}));
|
|
1773
1977
|
onNodesChange(changes);
|
|
1774
1978
|
}, [selectedNodes, onNodesChange]);
|
|
@@ -1783,12 +1987,12 @@ function MultiSelectToolbarComponent({ onDownloadAsZip }) {
|
|
|
1783
1987
|
const baseX = sorted[0].position.x;
|
|
1784
1988
|
const baseY = sorted[0].position.y;
|
|
1785
1989
|
const changes = sorted.map((node, i) => ({
|
|
1786
|
-
type: "position",
|
|
1787
1990
|
id: node.id,
|
|
1788
1991
|
position: {
|
|
1789
1992
|
x: baseX + i % cols * (EST_NODE_WIDTH + NODE_GAP),
|
|
1790
1993
|
y: baseY + Math.floor(i / cols) * (EST_NODE_HEIGHT + NODE_GAP)
|
|
1791
|
-
}
|
|
1994
|
+
},
|
|
1995
|
+
type: "position"
|
|
1792
1996
|
}));
|
|
1793
1997
|
onNodesChange(changes);
|
|
1794
1998
|
}, [selectedNodes, onNodesChange]);
|
|
@@ -1865,16 +2069,16 @@ function MultiSelectToolbarComponent({ onDownloadAsZip }) {
|
|
|
1865
2069
|
}
|
|
1866
2070
|
var MultiSelectToolbar = memo(MultiSelectToolbarComponent);
|
|
1867
2071
|
var typeStyles = {
|
|
2072
|
+
error: "bg-red-900 border-red-700 text-red-100",
|
|
1868
2073
|
info: "bg-neutral-800 border-neutral-600 text-neutral-100",
|
|
1869
2074
|
success: "bg-green-900 border-green-700 text-green-100",
|
|
1870
|
-
warning: "bg-orange-900 border-orange-600 text-orange-100"
|
|
1871
|
-
error: "bg-red-900 border-red-700 text-red-100"
|
|
2075
|
+
warning: "bg-orange-900 border-orange-600 text-orange-100"
|
|
1872
2076
|
};
|
|
1873
2077
|
var typeIcons = {
|
|
2078
|
+
error: XCircle,
|
|
1874
2079
|
info: Info,
|
|
1875
2080
|
success: CheckCircle,
|
|
1876
|
-
warning: AlertTriangle
|
|
1877
|
-
error: XCircle
|
|
2081
|
+
warning: AlertTriangle
|
|
1878
2082
|
};
|
|
1879
2083
|
function NotificationItem({
|
|
1880
2084
|
id,
|
|
@@ -1955,11 +2159,14 @@ function getEdgeDataType(edge, nodeMap) {
|
|
|
1955
2159
|
return sourceHandle?.type ?? null;
|
|
1956
2160
|
}
|
|
1957
2161
|
var edgeTypesMap = {
|
|
1958
|
-
default: EditableEdge,
|
|
1959
2162
|
bezier: EditableEdge,
|
|
2163
|
+
default: EditableEdge,
|
|
1960
2164
|
reference: ReferenceEdge
|
|
1961
2165
|
};
|
|
1962
|
-
function WorkflowCanvas({
|
|
2166
|
+
function WorkflowCanvas({
|
|
2167
|
+
nodeTypes: nodeTypesProp,
|
|
2168
|
+
onDownloadAsZip
|
|
2169
|
+
} = {}) {
|
|
1963
2170
|
const {
|
|
1964
2171
|
nodes,
|
|
1965
2172
|
edges,
|
|
@@ -1993,8 +2200,12 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
1993
2200
|
const isRunning = useExecutionStore((state) => state.isRunning);
|
|
1994
2201
|
const currentNodeId = useExecutionStore((state) => state.currentNodeId);
|
|
1995
2202
|
const executingNodeIds = useExecutionStore((state) => state.executingNodeIds);
|
|
1996
|
-
const activeNodeExecutions = useExecutionStore(
|
|
1997
|
-
|
|
2203
|
+
const activeNodeExecutions = useExecutionStore(
|
|
2204
|
+
(state) => state.activeNodeExecutions
|
|
2205
|
+
);
|
|
2206
|
+
const hasActiveNodeExecutions = useExecutionStore(
|
|
2207
|
+
(state) => state.activeNodeExecutions.size > 0
|
|
2208
|
+
);
|
|
1998
2209
|
const [isMinimapVisible, setIsMinimapVisible] = useState(false);
|
|
1999
2210
|
const [draggingNodeId, setDraggingNodeId] = useState(null);
|
|
2000
2211
|
const hideTimeoutRef = useRef(null);
|
|
@@ -2009,32 +2220,42 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2009
2220
|
openSelectionMenu,
|
|
2010
2221
|
close: closeContextMenu
|
|
2011
2222
|
} = useContextMenu();
|
|
2012
|
-
const openShortcutHelp = useCallback(
|
|
2013
|
-
|
|
2223
|
+
const openShortcutHelp = useCallback(
|
|
2224
|
+
() => openModal("shortcutHelp"),
|
|
2225
|
+
[openModal]
|
|
2226
|
+
);
|
|
2227
|
+
const openNodeSearch = useCallback(
|
|
2228
|
+
() => openModal("nodeSearch"),
|
|
2229
|
+
[openModal]
|
|
2230
|
+
);
|
|
2014
2231
|
const deleteSelectedElements = useCallback(() => {
|
|
2015
2232
|
const nodesToDelete = nodes.filter((n) => selectedNodeIds.includes(n.id));
|
|
2016
2233
|
const edgesToDelete = edges.filter((e) => e.selected);
|
|
2017
2234
|
if (nodesToDelete.length > 0) {
|
|
2018
|
-
onNodesChange(
|
|
2235
|
+
onNodesChange(
|
|
2236
|
+
nodesToDelete.map((n) => ({ id: n.id, type: "remove" }))
|
|
2237
|
+
);
|
|
2019
2238
|
}
|
|
2020
2239
|
if (edgesToDelete.length > 0) {
|
|
2021
|
-
onEdgesChange(
|
|
2240
|
+
onEdgesChange(
|
|
2241
|
+
edgesToDelete.map((e) => ({ id: e.id, type: "remove" }))
|
|
2242
|
+
);
|
|
2022
2243
|
}
|
|
2023
2244
|
}, [nodes, edges, selectedNodeIds, onNodesChange, onEdgesChange]);
|
|
2024
2245
|
useCanvasKeyboardShortcuts({
|
|
2025
|
-
|
|
2026
|
-
groups,
|
|
2027
|
-
nodes,
|
|
2028
|
-
toggleNodeLock,
|
|
2246
|
+
addNode,
|
|
2029
2247
|
createGroup,
|
|
2030
2248
|
deleteGroup,
|
|
2031
|
-
|
|
2032
|
-
addNode,
|
|
2033
|
-
togglePalette,
|
|
2249
|
+
deleteSelectedElements,
|
|
2034
2250
|
fitView: reactFlow.fitView,
|
|
2035
|
-
|
|
2251
|
+
groups,
|
|
2252
|
+
nodes,
|
|
2036
2253
|
openNodeSearch,
|
|
2037
|
-
|
|
2254
|
+
openShortcutHelp,
|
|
2255
|
+
selectedNodeIds,
|
|
2256
|
+
toggleNodeLock,
|
|
2257
|
+
togglePalette,
|
|
2258
|
+
unlockAllNodes
|
|
2038
2259
|
});
|
|
2039
2260
|
useEffect(() => {
|
|
2040
2261
|
if (selectedNodeIds.length === 0) {
|
|
@@ -2051,13 +2272,17 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2051
2272
|
if (!targetNode) return false;
|
|
2052
2273
|
if (targetNode.type === "imageGen" && edge.targetHandle === "images") {
|
|
2053
2274
|
const nodeData = targetNode.data;
|
|
2054
|
-
const hasImageSupport = supportsImageInput(
|
|
2275
|
+
const hasImageSupport = supportsImageInput(
|
|
2276
|
+
nodeData?.selectedModel?.inputSchema
|
|
2277
|
+
);
|
|
2055
2278
|
return !hasImageSupport;
|
|
2056
2279
|
}
|
|
2057
2280
|
if (targetNode.type === "videoGen") {
|
|
2058
2281
|
if (edge.targetHandle === "image" || edge.targetHandle === "lastFrame") {
|
|
2059
2282
|
const nodeData = targetNode.data;
|
|
2060
|
-
const hasImageSupport = supportsImageInput(
|
|
2283
|
+
const hasImageSupport = supportsImageInput(
|
|
2284
|
+
nodeData?.selectedModel?.inputSchema
|
|
2285
|
+
);
|
|
2061
2286
|
return !hasImageSupport;
|
|
2062
2287
|
}
|
|
2063
2288
|
}
|
|
@@ -2078,9 +2303,9 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2078
2303
|
if (isActiveEdge && !isDisabledTarget) {
|
|
2079
2304
|
return {
|
|
2080
2305
|
...edge,
|
|
2081
|
-
data: enrichedData,
|
|
2082
2306
|
animated: false,
|
|
2083
|
-
className: `${typeClass} executing`.trim()
|
|
2307
|
+
className: `${typeClass} executing`.trim(),
|
|
2308
|
+
data: enrichedData
|
|
2084
2309
|
};
|
|
2085
2310
|
}
|
|
2086
2311
|
}
|
|
@@ -2090,45 +2315,45 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2090
2315
|
if (isDisabledTarget) {
|
|
2091
2316
|
return {
|
|
2092
2317
|
...edge,
|
|
2093
|
-
data: enrichedData,
|
|
2094
2318
|
animated: false,
|
|
2095
|
-
className: `${typeClass} edge-disabled`.trim()
|
|
2319
|
+
className: `${typeClass} edge-disabled`.trim(),
|
|
2320
|
+
data: enrichedData
|
|
2096
2321
|
};
|
|
2097
2322
|
}
|
|
2098
2323
|
if (!isInExecutionScope) {
|
|
2099
2324
|
return {
|
|
2100
2325
|
...edge,
|
|
2101
|
-
data: enrichedData,
|
|
2102
2326
|
animated: false,
|
|
2103
|
-
className: typeClass
|
|
2327
|
+
className: typeClass,
|
|
2328
|
+
data: enrichedData
|
|
2104
2329
|
};
|
|
2105
2330
|
}
|
|
2106
2331
|
return {
|
|
2107
2332
|
...edge,
|
|
2108
|
-
data: enrichedData,
|
|
2109
2333
|
animated: false,
|
|
2110
|
-
className: `${typeClass} ${isExecutingEdge ? "executing" : "active-pipe"}`.trim()
|
|
2334
|
+
className: `${typeClass} ${isExecutingEdge ? "executing" : "active-pipe"}`.trim(),
|
|
2335
|
+
data: enrichedData
|
|
2111
2336
|
};
|
|
2112
2337
|
}
|
|
2113
2338
|
if (isDisabledTarget) {
|
|
2114
2339
|
return {
|
|
2115
2340
|
...edge,
|
|
2116
|
-
|
|
2117
|
-
|
|
2341
|
+
className: `${typeClass} edge-disabled`.trim(),
|
|
2342
|
+
data: enrichedData
|
|
2118
2343
|
};
|
|
2119
2344
|
}
|
|
2120
2345
|
if (highlightedSet) {
|
|
2121
2346
|
const isConnected = highlightedSet.has(edge.source) && highlightedSet.has(edge.target);
|
|
2122
2347
|
return {
|
|
2123
2348
|
...edge,
|
|
2124
|
-
|
|
2125
|
-
|
|
2349
|
+
className: `${typeClass} ${isConnected ? "highlighted" : "dimmed"}`.trim(),
|
|
2350
|
+
data: enrichedData
|
|
2126
2351
|
};
|
|
2127
2352
|
}
|
|
2128
2353
|
return {
|
|
2129
2354
|
...edge,
|
|
2130
|
-
|
|
2131
|
-
|
|
2355
|
+
className: typeClass,
|
|
2356
|
+
data: enrichedData
|
|
2132
2357
|
};
|
|
2133
2358
|
});
|
|
2134
2359
|
}, [
|
|
@@ -2201,7 +2426,9 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2201
2426
|
const handleDrop = useCallback(
|
|
2202
2427
|
(event) => {
|
|
2203
2428
|
event.preventDefault();
|
|
2204
|
-
const historyData = event.dataTransfer.getData(
|
|
2429
|
+
const historyData = event.dataTransfer.getData(
|
|
2430
|
+
"application/history-image"
|
|
2431
|
+
);
|
|
2205
2432
|
if (historyData) {
|
|
2206
2433
|
try {
|
|
2207
2434
|
const parsed = JSON.parse(historyData);
|
|
@@ -2232,9 +2459,12 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2232
2459
|
event.preventDefault();
|
|
2233
2460
|
event.dataTransfer.dropEffect = "move";
|
|
2234
2461
|
}, []);
|
|
2235
|
-
const handleNodeDragStart = useCallback(
|
|
2236
|
-
|
|
2237
|
-
|
|
2462
|
+
const handleNodeDragStart = useCallback(
|
|
2463
|
+
(_event, node) => {
|
|
2464
|
+
setDraggingNodeId(node.id);
|
|
2465
|
+
},
|
|
2466
|
+
[]
|
|
2467
|
+
);
|
|
2238
2468
|
const handleNodeDrag = useCallback((_event, node) => {
|
|
2239
2469
|
setDraggingNodeId(node.id);
|
|
2240
2470
|
}, []);
|
|
@@ -2260,13 +2490,16 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2260
2490
|
if (!sourceHandleType) return;
|
|
2261
2491
|
const clientX = "clientX" in event ? event.clientX : event.touches?.[0]?.clientX ?? 0;
|
|
2262
2492
|
const clientY = "clientY" in event ? event.clientY : event.touches?.[0]?.clientY ?? 0;
|
|
2263
|
-
const flowPosition = reactFlow.screenToFlowPosition({
|
|
2493
|
+
const flowPosition = reactFlow.screenToFlowPosition({
|
|
2494
|
+
x: clientX,
|
|
2495
|
+
y: clientY
|
|
2496
|
+
});
|
|
2264
2497
|
openConnectionDropMenu({
|
|
2265
2498
|
position: flowPosition,
|
|
2266
2499
|
screenPosition: { x: clientX, y: clientY },
|
|
2267
|
-
sourceNodeId,
|
|
2268
2500
|
sourceHandleId,
|
|
2269
|
-
sourceHandleType
|
|
2501
|
+
sourceHandleType,
|
|
2502
|
+
sourceNodeId
|
|
2270
2503
|
});
|
|
2271
2504
|
return;
|
|
2272
2505
|
}
|
|
@@ -2274,7 +2507,11 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2274
2507
|
if (!targetNodeId || targetNodeId === sourceNodeId) return;
|
|
2275
2508
|
const droppedOnHandle = target.closest(".react-flow__handle");
|
|
2276
2509
|
if (droppedOnHandle) return;
|
|
2277
|
-
const compatibleHandle = findCompatibleHandle(
|
|
2510
|
+
const compatibleHandle = findCompatibleHandle(
|
|
2511
|
+
sourceNodeId,
|
|
2512
|
+
sourceHandleId,
|
|
2513
|
+
targetNodeId
|
|
2514
|
+
);
|
|
2278
2515
|
if (!compatibleHandle) return;
|
|
2279
2516
|
onConnect({
|
|
2280
2517
|
source: sourceNodeId,
|
|
@@ -2289,8 +2526,8 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2289
2526
|
(connection) => {
|
|
2290
2527
|
const conn = {
|
|
2291
2528
|
source: connection.source,
|
|
2292
|
-
target: connection.target,
|
|
2293
2529
|
sourceHandle: connection.sourceHandle ?? null,
|
|
2530
|
+
target: connection.target,
|
|
2294
2531
|
targetHandle: connection.targetHandle ?? null
|
|
2295
2532
|
};
|
|
2296
2533
|
return isValidConnection(conn);
|
|
@@ -2322,156 +2559,114 @@ function WorkflowCanvas({ nodeTypes: nodeTypesProp, onDownloadAsZip } = {}) {
|
|
|
2322
2559
|
}
|
|
2323
2560
|
};
|
|
2324
2561
|
}, []);
|
|
2325
|
-
return /* @__PURE__ */ jsxs(
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
edges: styledEdges,
|
|
2340
|
-
onNodesChange,
|
|
2341
|
-
onEdgesChange,
|
|
2342
|
-
onConnect,
|
|
2343
|
-
onConnectEnd: handleConnectEnd,
|
|
2344
|
-
onNodeClick: handleNodeClick,
|
|
2345
|
-
onPaneClick: handlePaneClick,
|
|
2346
|
-
onSelectionChange: handleSelectionChange,
|
|
2347
|
-
onNodeContextMenu: handleNodeContextMenu,
|
|
2348
|
-
onEdgeContextMenu: handleEdgeContextMenu,
|
|
2349
|
-
onPaneContextMenu: handlePaneContextMenu,
|
|
2350
|
-
onSelectionContextMenu: handleSelectionContextMenu,
|
|
2351
|
-
onNodeDragStart: handleNodeDragStart,
|
|
2352
|
-
onNodeDrag: handleNodeDrag,
|
|
2353
|
-
onNodeDragStop: handleNodeDragStop,
|
|
2354
|
-
onEdgeClick: handleEdgeClick,
|
|
2355
|
-
isValidConnection: checkValidConnection,
|
|
2356
|
-
nodeTypes: nodeTypesProp ?? nodeTypes,
|
|
2357
|
-
edgeTypes: edgeTypesMap,
|
|
2358
|
-
fitView: true,
|
|
2359
|
-
snapToGrid: true,
|
|
2360
|
-
snapGrid: [16, 16],
|
|
2361
|
-
minZoom: 0.1,
|
|
2362
|
-
maxZoom: 4,
|
|
2363
|
-
nodeDragThreshold: 5,
|
|
2364
|
-
connectionMode: ConnectionMode.Loose,
|
|
2365
|
-
selectionMode: SelectionMode.Partial,
|
|
2366
|
-
selectionOnDrag: true,
|
|
2367
|
-
panOnDrag: [1, 2],
|
|
2368
|
-
onMoveStart: handleMoveStart,
|
|
2369
|
-
onMoveEnd: handleMoveEnd,
|
|
2370
|
-
deleteKeyCode: ["Backspace", "Delete"],
|
|
2371
|
-
defaultEdgeOptions: {
|
|
2372
|
-
type: edgeStyle,
|
|
2373
|
-
animated: false
|
|
2374
|
-
},
|
|
2375
|
-
edgesFocusable: true,
|
|
2376
|
-
edgesReconnectable: true,
|
|
2377
|
-
proOptions: { hideAttribution: true },
|
|
2378
|
-
onlyRenderVisibleElements: nodes.length > 50,
|
|
2379
|
-
children: [
|
|
2380
|
-
/* @__PURE__ */ jsx(GroupOverlay, {}),
|
|
2381
|
-
/* @__PURE__ */ jsx(
|
|
2382
|
-
Background,
|
|
2383
|
-
{
|
|
2384
|
-
variant: BackgroundVariant.Dots,
|
|
2385
|
-
gap: 16,
|
|
2386
|
-
size: 1,
|
|
2387
|
-
color: "rgba(255, 255, 255, 0.08)"
|
|
2388
|
-
}
|
|
2389
|
-
),
|
|
2390
|
-
/* @__PURE__ */ jsx(Controls, {}),
|
|
2391
|
-
showMinimap && /* @__PURE__ */ jsx(
|
|
2392
|
-
MiniMap,
|
|
2393
|
-
{
|
|
2394
|
-
nodeStrokeWidth: 0,
|
|
2395
|
-
nodeColor: () => DEFAULT_NODE_COLOR,
|
|
2396
|
-
zoomable: true,
|
|
2397
|
-
pannable: true,
|
|
2398
|
-
maskColor: "rgba(0, 0, 0, 0.8)",
|
|
2399
|
-
className: `!bg-transparent !border-[var(--border)] !rounded-lg transition-opacity duration-300 ${isMinimapVisible ? "opacity-100" : "opacity-0 pointer-events-none"}`
|
|
2400
|
-
}
|
|
2401
|
-
),
|
|
2402
|
-
/* @__PURE__ */ jsx(HelperLines, { draggingNodeId })
|
|
2403
|
-
]
|
|
2404
|
-
}
|
|
2405
|
-
),
|
|
2406
|
-
isContextMenuOpen && /* @__PURE__ */ jsx(
|
|
2407
|
-
ContextMenu,
|
|
2408
|
-
{
|
|
2409
|
-
x: contextMenuPosition.x,
|
|
2410
|
-
y: contextMenuPosition.y,
|
|
2411
|
-
items: contextMenuItems,
|
|
2412
|
-
onClose: closeContextMenu
|
|
2413
|
-
}
|
|
2414
|
-
),
|
|
2415
|
-
/* @__PURE__ */ jsx(EdgeToolbar, {}),
|
|
2416
|
-
/* @__PURE__ */ jsx(MultiSelectToolbar, { onDownloadAsZip }),
|
|
2417
|
-
/* @__PURE__ */ jsx(NodeDetailModal, {}),
|
|
2418
|
-
/* @__PURE__ */ jsx(ShortcutHelpModal, {}),
|
|
2419
|
-
/* @__PURE__ */ jsx(NodeSearch, {}),
|
|
2420
|
-
/* @__PURE__ */ jsx(ConnectionDropMenu, {}),
|
|
2421
|
-
/* @__PURE__ */ jsx(CostModal, {}),
|
|
2422
|
-
/* @__PURE__ */ jsx(NotificationToast, {}),
|
|
2423
|
-
/* @__PURE__ */ jsx(GlobalImageHistory, {})
|
|
2424
|
-
] });
|
|
2425
|
-
}
|
|
2426
|
-
function PauseEdgeComponent({
|
|
2427
|
-
id,
|
|
2428
|
-
sourceX,
|
|
2429
|
-
sourceY,
|
|
2430
|
-
targetX,
|
|
2431
|
-
targetY,
|
|
2432
|
-
sourcePosition,
|
|
2433
|
-
targetPosition,
|
|
2434
|
-
style = {},
|
|
2435
|
-
markerEnd,
|
|
2436
|
-
data
|
|
2437
|
-
}) {
|
|
2438
|
-
const [edgePath, labelX, labelY] = getBezierPath({
|
|
2439
|
-
sourceX,
|
|
2440
|
-
sourceY,
|
|
2441
|
-
sourcePosition,
|
|
2442
|
-
targetX,
|
|
2443
|
-
targetY,
|
|
2444
|
-
targetPosition
|
|
2445
|
-
});
|
|
2446
|
-
const hasPause = data?.hasPause === true;
|
|
2447
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2448
|
-
/* @__PURE__ */ jsx(
|
|
2449
|
-
BaseEdge,
|
|
2450
|
-
{
|
|
2451
|
-
path: edgePath,
|
|
2452
|
-
markerEnd,
|
|
2453
|
-
style: {
|
|
2454
|
-
...style,
|
|
2455
|
-
...hasPause && {
|
|
2456
|
-
strokeDasharray: "5 5",
|
|
2457
|
-
stroke: "#f59e0b"
|
|
2562
|
+
return /* @__PURE__ */ jsxs(
|
|
2563
|
+
"div",
|
|
2564
|
+
{
|
|
2565
|
+
className: "w-full h-full relative",
|
|
2566
|
+
onDrop: handleDrop,
|
|
2567
|
+
onDragOver: handleDragOver,
|
|
2568
|
+
children: [
|
|
2569
|
+
!showPalette && /* @__PURE__ */ jsx(
|
|
2570
|
+
"button",
|
|
2571
|
+
{
|
|
2572
|
+
onClick: togglePalette,
|
|
2573
|
+
className: "absolute top-3 left-3 z-10 p-1.5 bg-[var(--background)] border border-[var(--border)] rounded-md hover:bg-[var(--secondary)] transition-colors group",
|
|
2574
|
+
title: "Open sidebar (M)",
|
|
2575
|
+
children: /* @__PURE__ */ jsx(PanelLeft, { className: "w-4 h-4 text-[var(--muted-foreground)] group-hover:text-[var(--foreground)]" })
|
|
2458
2576
|
}
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2577
|
+
),
|
|
2578
|
+
/* @__PURE__ */ jsxs(
|
|
2579
|
+
ReactFlow,
|
|
2580
|
+
{
|
|
2581
|
+
nodes,
|
|
2582
|
+
edges: styledEdges,
|
|
2583
|
+
onNodesChange,
|
|
2584
|
+
onEdgesChange,
|
|
2585
|
+
onConnect,
|
|
2586
|
+
onConnectEnd: handleConnectEnd,
|
|
2587
|
+
onNodeClick: handleNodeClick,
|
|
2588
|
+
onPaneClick: handlePaneClick,
|
|
2589
|
+
onSelectionChange: handleSelectionChange,
|
|
2590
|
+
onNodeContextMenu: handleNodeContextMenu,
|
|
2591
|
+
onEdgeContextMenu: handleEdgeContextMenu,
|
|
2592
|
+
onPaneContextMenu: handlePaneContextMenu,
|
|
2593
|
+
onSelectionContextMenu: handleSelectionContextMenu,
|
|
2594
|
+
onNodeDragStart: handleNodeDragStart,
|
|
2595
|
+
onNodeDrag: handleNodeDrag,
|
|
2596
|
+
onNodeDragStop: handleNodeDragStop,
|
|
2597
|
+
onEdgeClick: handleEdgeClick,
|
|
2598
|
+
isValidConnection: checkValidConnection,
|
|
2599
|
+
nodeTypes: nodeTypesProp ?? nodeTypes,
|
|
2600
|
+
edgeTypes: edgeTypesMap,
|
|
2601
|
+
fitView: true,
|
|
2602
|
+
snapToGrid: true,
|
|
2603
|
+
snapGrid: [16, 16],
|
|
2604
|
+
minZoom: 0.1,
|
|
2605
|
+
maxZoom: 4,
|
|
2606
|
+
nodeDragThreshold: 5,
|
|
2607
|
+
connectionMode: ConnectionMode.Loose,
|
|
2608
|
+
selectionMode: SelectionMode.Partial,
|
|
2609
|
+
selectionOnDrag: true,
|
|
2610
|
+
panOnDrag: [1, 2],
|
|
2611
|
+
onMoveStart: handleMoveStart,
|
|
2612
|
+
onMoveEnd: handleMoveEnd,
|
|
2613
|
+
deleteKeyCode: ["Backspace", "Delete"],
|
|
2614
|
+
defaultEdgeOptions: {
|
|
2615
|
+
animated: false,
|
|
2616
|
+
type: edgeStyle
|
|
2617
|
+
},
|
|
2618
|
+
edgesFocusable: true,
|
|
2619
|
+
edgesReconnectable: true,
|
|
2620
|
+
proOptions: { hideAttribution: true },
|
|
2621
|
+
onlyRenderVisibleElements: nodes.length > 50,
|
|
2622
|
+
children: [
|
|
2623
|
+
/* @__PURE__ */ jsx(GroupOverlay, {}),
|
|
2624
|
+
/* @__PURE__ */ jsx(
|
|
2625
|
+
Background,
|
|
2626
|
+
{
|
|
2627
|
+
variant: BackgroundVariant.Dots,
|
|
2628
|
+
gap: 16,
|
|
2629
|
+
size: 1,
|
|
2630
|
+
color: "rgba(255, 255, 255, 0.08)"
|
|
2631
|
+
}
|
|
2632
|
+
),
|
|
2633
|
+
/* @__PURE__ */ jsx(Controls, {}),
|
|
2634
|
+
showMinimap && /* @__PURE__ */ jsx(
|
|
2635
|
+
MiniMap,
|
|
2636
|
+
{
|
|
2637
|
+
nodeStrokeWidth: 0,
|
|
2638
|
+
nodeColor: () => DEFAULT_NODE_COLOR,
|
|
2639
|
+
zoomable: true,
|
|
2640
|
+
pannable: true,
|
|
2641
|
+
maskColor: "rgba(0, 0, 0, 0.8)",
|
|
2642
|
+
className: `!bg-transparent !border-[var(--border)] !rounded-lg transition-opacity duration-300 ${isMinimapVisible ? "opacity-100" : "opacity-0 pointer-events-none"}`
|
|
2643
|
+
}
|
|
2644
|
+
),
|
|
2645
|
+
/* @__PURE__ */ jsx(HelperLines, { draggingNodeId })
|
|
2646
|
+
]
|
|
2647
|
+
}
|
|
2648
|
+
),
|
|
2649
|
+
isContextMenuOpen && /* @__PURE__ */ jsx(
|
|
2650
|
+
ContextMenu,
|
|
2651
|
+
{
|
|
2652
|
+
x: contextMenuPosition.x,
|
|
2653
|
+
y: contextMenuPosition.y,
|
|
2654
|
+
items: contextMenuItems,
|
|
2655
|
+
onClose: closeContextMenu
|
|
2656
|
+
}
|
|
2657
|
+
),
|
|
2658
|
+
/* @__PURE__ */ jsx(EdgeToolbar, {}),
|
|
2659
|
+
/* @__PURE__ */ jsx(MultiSelectToolbar, { onDownloadAsZip }),
|
|
2660
|
+
/* @__PURE__ */ jsx(NodeDetailModal, {}),
|
|
2661
|
+
/* @__PURE__ */ jsx(ShortcutHelpModal, {}),
|
|
2662
|
+
/* @__PURE__ */ jsx(NodeSearch, {}),
|
|
2663
|
+
/* @__PURE__ */ jsx(ConnectionDropMenu, {}),
|
|
2664
|
+
/* @__PURE__ */ jsx(CostModal, {}),
|
|
2665
|
+
/* @__PURE__ */ jsx(NotificationToast, {}),
|
|
2666
|
+
/* @__PURE__ */ jsx(GlobalImageHistory, {})
|
|
2667
|
+
]
|
|
2668
|
+
}
|
|
2669
|
+
);
|
|
2474
2670
|
}
|
|
2475
|
-
var PauseEdge = memo(PauseEdgeComponent);
|
|
2476
2671
|
|
|
2477
2672
|
export { ConnectionDropMenu, DEFAULT_GROUP_COLORS, EdgeToolbar, EditableEdge, GROUP_COLORS, GlobalImageHistory, GroupOverlay, HelperLines, NodeSearch, NotificationToast, PauseEdge, ReferenceEdge, ShortcutHelpModal, WorkflowCanvas };
|