@runtypelabs/react-flow 1.0.39 → 1.0.40

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/index.mjs DELETED
@@ -1,3334 +0,0 @@
1
- import { memo, useState, useCallback, useRef, useEffect, useMemo } from 'react';
2
- import { Handle, Position, useNodesState, useEdgesState, addEdge, ReactFlow, ConnectionLineType, Background, BackgroundVariant, Controls, MiniMap, Panel } from '@xyflow/react';
3
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
-
5
- // src/types/index.ts
6
- var SUPPORTED_NODE_TYPES = [
7
- "prompt",
8
- "fetch-url",
9
- "transform-data",
10
- "conditional",
11
- "send-email"
12
- ];
13
- function isSupportedNodeType(type) {
14
- return SUPPORTED_NODE_TYPES.includes(type);
15
- }
16
-
17
- // src/utils/adapter.ts
18
- var NODE_WIDTH = 280;
19
- var NODE_HEIGHT = 200;
20
- var NODE_SPACING_X = 350;
21
- var NODE_SPACING_Y = 80;
22
- var BRANCH_OFFSET_X = 350;
23
- var BRANCH_OFFSET_Y = -80;
24
- var FALSE_BRANCH_GAP = 100;
25
- function flowStepsToNodes(steps, options) {
26
- const {
27
- onChange,
28
- onDelete,
29
- startPosition = { x: 50, y: 200 },
30
- idPrefix = "",
31
- parentId
32
- } = options ?? {};
33
- const sortedSteps = [...steps].sort((a, b) => a.order - b.order);
34
- const nodes = [];
35
- let currentX = startPosition.x;
36
- startPosition.y;
37
- for (const step of sortedSteps) {
38
- const nodeId = idPrefix ? `${idPrefix}${step.id}` : step.id;
39
- const nodeData = {
40
- step,
41
- label: step.name || getDefaultStepName(step.type),
42
- onChange,
43
- onDelete
44
- };
45
- const node = {
46
- id: nodeId,
47
- type: step.type,
48
- position: { x: currentX, y: startPosition.y },
49
- data: nodeData,
50
- draggable: true,
51
- selectable: true
52
- };
53
- if (parentId) {
54
- node.parentId = parentId;
55
- }
56
- nodes.push(node);
57
- console.log(`[flowStepsToNodes] Placed "${step.name}" (${step.type}) at x=${currentX}`);
58
- if (step.type === "conditional" && step.config) {
59
- const config = step.config;
60
- const branchX = currentX + BRANCH_OFFSET_X;
61
- const trueBranchLength = config.trueSteps?.length || 0;
62
- const falseBranchLength = config.falseSteps?.length || 0;
63
- const maxBranchLength = Math.max(trueBranchLength, falseBranchLength);
64
- const trueBranchHeight = trueBranchLength * (NODE_HEIGHT + NODE_SPACING_Y);
65
- if (config.trueSteps && config.trueSteps.length > 0) {
66
- const trueBranchY = startPosition.y + BRANCH_OFFSET_Y;
67
- const trueBranchNodes = flowStepsToNodes(config.trueSteps, {
68
- onChange,
69
- onDelete,
70
- startPosition: {
71
- x: branchX,
72
- y: trueBranchY
73
- },
74
- idPrefix: `${nodeId}-true-`,
75
- parentId: nodeId
76
- });
77
- nodes.push(...trueBranchNodes);
78
- }
79
- if (config.falseSteps && config.falseSteps.length > 0) {
80
- const falseBranchY = trueBranchLength > 0 ? startPosition.y + BRANCH_OFFSET_Y + trueBranchHeight + FALSE_BRANCH_GAP : startPosition.y + NODE_HEIGHT + NODE_SPACING_Y;
81
- const falseBranchNodes = flowStepsToNodes(config.falseSteps, {
82
- onChange,
83
- onDelete,
84
- startPosition: {
85
- x: branchX,
86
- y: falseBranchY
87
- },
88
- idPrefix: `${nodeId}-false-`,
89
- parentId: nodeId
90
- });
91
- nodes.push(...falseBranchNodes);
92
- config.falseSteps.length * (NODE_HEIGHT + NODE_SPACING_Y);
93
- }
94
- if (maxBranchLength > 0) {
95
- const advance = BRANCH_OFFSET_X + maxBranchLength * (NODE_WIDTH + NODE_SPACING_X);
96
- console.log(
97
- `[flowStepsToNodes] Conditional "${step.name}" has ${maxBranchLength} branch steps, advancing currentX by ${advance}`
98
- );
99
- currentX += advance;
100
- console.log(`[flowStepsToNodes] After conditional, currentX = ${currentX}`);
101
- } else {
102
- currentX += NODE_WIDTH + NODE_SPACING_X;
103
- }
104
- } else {
105
- currentX += NODE_WIDTH + NODE_SPACING_X;
106
- }
107
- }
108
- return nodes;
109
- }
110
- function nodesToFlowSteps(nodes) {
111
- const topLevelNodes = nodes.filter(
112
- (n) => !n.parentId && !n.id.includes("-true-") && !n.id.includes("-false-")
113
- );
114
- const sortedNodes = [...topLevelNodes].sort((a, b) => a.position.x - b.position.x);
115
- return sortedNodes.map((node, index) => {
116
- const step = node.data.step;
117
- if (step.type === "conditional") {
118
- const trueSteps = extractBranchSteps(nodes, node.id, "true");
119
- const falseSteps = extractBranchSteps(nodes, node.id, "false");
120
- return {
121
- ...step,
122
- order: index,
123
- config: {
124
- ...step.config,
125
- trueSteps,
126
- falseSteps
127
- }
128
- };
129
- }
130
- return {
131
- ...step,
132
- order: index
133
- };
134
- });
135
- }
136
- function extractBranchSteps(nodes, parentId, branch) {
137
- const branchPrefix = `${parentId}-${branch}-`;
138
- const branchNodes = nodes.filter((n) => n.id.startsWith(branchPrefix));
139
- const sortedBranchNodes = [...branchNodes].sort((a, b) => a.position.x - b.position.x);
140
- return sortedBranchNodes.map((node, index) => ({
141
- ...node.data.step,
142
- order: index
143
- }));
144
- }
145
- function createEdgesFromNodes(nodes) {
146
- const edges = [];
147
- const isBranchNode = (n) => n.parentId || n.id.includes("-true-") || n.id.includes("-false-");
148
- const topLevelNodes = nodes.filter((n) => !isBranchNode(n)).sort((a, b) => a.position.x - b.position.x);
149
- for (let i = 0; i < topLevelNodes.length - 1; i++) {
150
- const sourceNode = topLevelNodes[i];
151
- const targetNode = topLevelNodes[i + 1];
152
- if (sourceNode.data.step.type === "conditional") {
153
- continue;
154
- }
155
- edges.push({
156
- id: `edge-${sourceNode.id}-${targetNode.id}`,
157
- source: sourceNode.id,
158
- target: targetNode.id,
159
- sourceHandle: "output",
160
- type: "smoothstep",
161
- animated: false,
162
- data: { stepOrder: i }
163
- });
164
- }
165
- const conditionalNodes = nodes.filter(
166
- (n) => n.data.step.type === "conditional" && !isBranchNode(n)
167
- );
168
- for (const conditionalNode of conditionalNodes) {
169
- const conditionalId = conditionalNode.id;
170
- const conditionalIndex = topLevelNodes.findIndex((n) => n.id === conditionalId);
171
- const nextMainStep = conditionalIndex < topLevelNodes.length - 1 ? topLevelNodes[conditionalIndex + 1] : null;
172
- const trueBranchNodes = nodes.filter((n) => n.id.startsWith(`${conditionalId}-true-`)).sort((a, b) => a.position.x - b.position.x);
173
- const falseBranchNodes = nodes.filter((n) => n.id.startsWith(`${conditionalId}-false-`)).sort((a, b) => a.position.x - b.position.x);
174
- if (trueBranchNodes.length > 0) {
175
- edges.push({
176
- id: `edge-${conditionalId}-to-true-branch`,
177
- source: conditionalId,
178
- target: trueBranchNodes[0].id,
179
- sourceHandle: "true",
180
- type: "smoothstep",
181
- animated: false,
182
- label: "True",
183
- labelStyle: { fill: "#22c55e", fontWeight: 600, fontSize: 11 },
184
- labelBgStyle: { fill: "#f0fdf4", fillOpacity: 0.9 },
185
- labelBgPadding: [4, 6],
186
- labelBgBorderRadius: 4,
187
- style: { stroke: "#22c55e", strokeWidth: 2 }
188
- });
189
- for (let i = 0; i < trueBranchNodes.length - 1; i++) {
190
- edges.push({
191
- id: `edge-true-${trueBranchNodes[i].id}-${trueBranchNodes[i + 1].id}`,
192
- source: trueBranchNodes[i].id,
193
- target: trueBranchNodes[i + 1].id,
194
- sourceHandle: "output",
195
- type: "smoothstep",
196
- animated: false,
197
- style: { stroke: "#22c55e", strokeWidth: 1.5 }
198
- });
199
- }
200
- if (nextMainStep) {
201
- const lastTrueNode = trueBranchNodes[trueBranchNodes.length - 1];
202
- edges.push({
203
- id: `edge-true-${lastTrueNode.id}-to-${nextMainStep.id}`,
204
- source: lastTrueNode.id,
205
- target: nextMainStep.id,
206
- sourceHandle: "output",
207
- type: "smoothstep",
208
- animated: false,
209
- style: { stroke: "#22c55e", strokeWidth: 1.5 }
210
- });
211
- }
212
- } else if (nextMainStep) {
213
- edges.push({
214
- id: `edge-${conditionalId}-true-to-${nextMainStep.id}`,
215
- source: conditionalId,
216
- target: nextMainStep.id,
217
- sourceHandle: "true",
218
- type: "smoothstep",
219
- animated: false,
220
- label: "True",
221
- labelStyle: { fill: "#22c55e", fontWeight: 600, fontSize: 11 },
222
- labelBgStyle: { fill: "#f0fdf4", fillOpacity: 0.9 },
223
- labelBgPadding: [4, 6],
224
- labelBgBorderRadius: 4,
225
- style: { stroke: "#22c55e", strokeWidth: 2 }
226
- });
227
- }
228
- if (falseBranchNodes.length > 0) {
229
- edges.push({
230
- id: `edge-${conditionalId}-to-false-branch`,
231
- source: conditionalId,
232
- target: falseBranchNodes[0].id,
233
- sourceHandle: "false",
234
- type: "smoothstep",
235
- animated: false,
236
- label: "False",
237
- labelStyle: { fill: "#ef4444", fontWeight: 600, fontSize: 11 },
238
- labelBgStyle: { fill: "#fef2f2", fillOpacity: 0.9 },
239
- labelBgPadding: [4, 6],
240
- labelBgBorderRadius: 4,
241
- style: { stroke: "#ef4444", strokeWidth: 2 }
242
- });
243
- for (let i = 0; i < falseBranchNodes.length - 1; i++) {
244
- edges.push({
245
- id: `edge-false-${falseBranchNodes[i].id}-${falseBranchNodes[i + 1].id}`,
246
- source: falseBranchNodes[i].id,
247
- target: falseBranchNodes[i + 1].id,
248
- sourceHandle: "output",
249
- type: "smoothstep",
250
- animated: false,
251
- style: { stroke: "#ef4444", strokeWidth: 1.5 }
252
- });
253
- }
254
- if (nextMainStep) {
255
- const lastFalseNode = falseBranchNodes[falseBranchNodes.length - 1];
256
- edges.push({
257
- id: `edge-false-${lastFalseNode.id}-to-${nextMainStep.id}`,
258
- source: lastFalseNode.id,
259
- target: nextMainStep.id,
260
- sourceHandle: "output",
261
- type: "smoothstep",
262
- animated: false,
263
- style: { stroke: "#ef4444", strokeWidth: 1.5 }
264
- });
265
- }
266
- } else if (nextMainStep) {
267
- edges.push({
268
- id: `edge-${conditionalId}-false-to-${nextMainStep.id}`,
269
- source: conditionalId,
270
- target: nextMainStep.id,
271
- sourceHandle: "false",
272
- type: "smoothstep",
273
- animated: false,
274
- label: "False",
275
- labelStyle: { fill: "#ef4444", fontWeight: 600, fontSize: 11 },
276
- labelBgStyle: { fill: "#fef2f2", fillOpacity: 0.9 },
277
- labelBgPadding: [4, 6],
278
- labelBgBorderRadius: 4,
279
- style: { stroke: "#ef4444", strokeWidth: 2 }
280
- });
281
- }
282
- if (trueBranchNodes.length === 0 && falseBranchNodes.length === 0 && nextMainStep) {
283
- edges.push({
284
- id: `edge-${conditionalId}-to-${nextMainStep.id}`,
285
- source: conditionalId,
286
- target: nextMainStep.id,
287
- sourceHandle: "output",
288
- type: "smoothstep",
289
- animated: false
290
- });
291
- }
292
- }
293
- return edges;
294
- }
295
- function getDefaultStepName(type) {
296
- const names = {
297
- prompt: "AI Prompt",
298
- crawl: "Crawl Website",
299
- "fetch-url": "Fetch URL",
300
- "retrieve-record": "Retrieve Record",
301
- "get-record": "Get Record",
302
- "list-records": "List Records",
303
- "api-call": "API Call",
304
- "transform-data": "Transform Data",
305
- conditional: "Conditional",
306
- "set-variable": "Set Variable",
307
- "upsert-record": "Upsert Record",
308
- "send-email": "Send Email",
309
- "send-event": "Send Event",
310
- "send-stream": "Send Stream",
311
- "update-record": "Update Record",
312
- search: "Search",
313
- "generate-embedding": "Generate Embedding",
314
- "vector-search": "Vector Search",
315
- "tool-call": "Tool Call",
316
- "wait-until": "Wait Until",
317
- "paginate-api": "Paginate API",
318
- "store-vector": "Store Vector"
319
- };
320
- return names[type] || type;
321
- }
322
- function createDefaultStep(type, order = 0) {
323
- const id = `step-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
324
- const baseStep = {
325
- id,
326
- type,
327
- name: getDefaultStepName(type),
328
- order,
329
- enabled: true
330
- };
331
- switch (type) {
332
- case "prompt":
333
- return {
334
- ...baseStep,
335
- config: {
336
- mode: "instruction",
337
- model: "",
338
- userPrompt: "",
339
- responseFormat: "text",
340
- outputVariable: `${type}_result`
341
- }
342
- };
343
- case "crawl":
344
- return {
345
- ...baseStep,
346
- config: {
347
- url: "",
348
- formats: ["markdown"],
349
- render: false,
350
- outputVariable: "crawl_result"
351
- }
352
- };
353
- case "fetch-url":
354
- return {
355
- ...baseStep,
356
- config: {
357
- http: {
358
- url: "",
359
- method: "GET"
360
- },
361
- responseType: "json",
362
- outputVariable: "fetch_result"
363
- }
364
- };
365
- case "transform-data":
366
- return {
367
- ...baseStep,
368
- config: {
369
- script: "// Transform your data here\nreturn { result: input }",
370
- outputVariable: "transform_result"
371
- }
372
- };
373
- case "conditional":
374
- return {
375
- ...baseStep,
376
- config: {
377
- condition: "true",
378
- trueSteps: [],
379
- falseSteps: []
380
- }
381
- };
382
- case "send-email":
383
- return {
384
- ...baseStep,
385
- config: {
386
- from: "{{_flow.id}}@runtype.email",
387
- to: "",
388
- subject: "",
389
- html: "",
390
- outputVariable: "email_result"
391
- }
392
- };
393
- default:
394
- return {
395
- ...baseStep,
396
- config: {
397
- outputVariable: `${type.replace(/-/g, "_")}_result`
398
- }
399
- };
400
- }
401
- }
402
- function generateStepId(prefix = "step") {
403
- return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
404
- }
405
- function cloneStep(step) {
406
- return {
407
- ...step,
408
- id: generateStepId(step.type),
409
- config: JSON.parse(JSON.stringify(step.config))
410
- };
411
- }
412
-
413
- // src/utils/layout.ts
414
- var DEFAULT_NODE_WIDTH = 280;
415
- var DEFAULT_NODE_HEIGHT = 150;
416
- var HORIZONTAL_SPACING = 100;
417
- var VERTICAL_SPACING = 80;
418
- var BRANCH_OFFSET = 350;
419
- function autoLayout(nodes, edges, options = {}) {
420
- const {
421
- direction = "vertical",
422
- startPosition = { x: 400, y: 50 },
423
- nodeWidth = DEFAULT_NODE_WIDTH,
424
- nodeHeight = DEFAULT_NODE_HEIGHT,
425
- horizontalSpacing = HORIZONTAL_SPACING,
426
- verticalSpacing = VERTICAL_SPACING,
427
- branchOffset = BRANCH_OFFSET
428
- } = options;
429
- const adjacencyMap = /* @__PURE__ */ new Map();
430
- const incomingMap = /* @__PURE__ */ new Map();
431
- for (const edge of edges) {
432
- const existing = adjacencyMap.get(edge.source) || [];
433
- adjacencyMap.set(edge.source, [...existing, edge.target]);
434
- const incoming = incomingMap.get(edge.target) || [];
435
- incomingMap.set(edge.target, [...incoming, edge.source]);
436
- }
437
- const rootNodes = nodes.filter((node) => {
438
- const incoming = incomingMap.get(node.id);
439
- return !incoming || incoming.length === 0;
440
- });
441
- if (rootNodes.length === 0 && nodes.length > 0) {
442
- rootNodes.push(nodes[0]);
443
- }
444
- const positionedNodes = /* @__PURE__ */ new Map();
445
- const visited = /* @__PURE__ */ new Set();
446
- const queue = [];
447
- let startX = startPosition.x;
448
- for (const rootNode of rootNodes) {
449
- queue.push({ nodeId: rootNode.id, x: startX, y: startPosition.y, depth: 0 });
450
- startX += nodeWidth + horizontalSpacing;
451
- }
452
- while (queue.length > 0) {
453
- const { nodeId, x, y, depth } = queue.shift();
454
- if (visited.has(nodeId)) continue;
455
- visited.add(nodeId);
456
- positionedNodes.set(nodeId, { x, y });
457
- const children = adjacencyMap.get(nodeId) || [];
458
- const node = nodes.find((n) => n.id === nodeId);
459
- const isConditional = node?.data.step.type === "conditional";
460
- if (isConditional && children.length > 0) {
461
- const trueBranch = children.filter((c) => c.includes("-true-"));
462
- const falseBranch = children.filter((c) => c.includes("-false-"));
463
- const normalChildren = children.filter((c) => !c.includes("-true-") && !c.includes("-false-"));
464
- let trueY = y + nodeHeight + verticalSpacing;
465
- for (const childId of trueBranch) {
466
- if (!visited.has(childId)) {
467
- queue.push({
468
- nodeId: childId,
469
- x: x + branchOffset,
470
- y: trueY,
471
- depth: depth + 1
472
- });
473
- trueY += nodeHeight + verticalSpacing;
474
- }
475
- }
476
- let falseY = y + nodeHeight + verticalSpacing;
477
- for (const childId of falseBranch) {
478
- if (!visited.has(childId)) {
479
- queue.push({
480
- nodeId: childId,
481
- x: x - branchOffset,
482
- y: falseY,
483
- depth: depth + 1
484
- });
485
- falseY += nodeHeight + verticalSpacing;
486
- }
487
- }
488
- const maxBranchY = Math.max(trueY, falseY);
489
- let childY = maxBranchY;
490
- for (const childId of normalChildren) {
491
- if (!visited.has(childId)) {
492
- queue.push({
493
- nodeId: childId,
494
- x,
495
- y: childY,
496
- depth: depth + 1
497
- });
498
- childY += nodeHeight + verticalSpacing;
499
- }
500
- }
501
- } else {
502
- let childY = y + nodeHeight + verticalSpacing;
503
- let childX = x;
504
- for (let i = 0; i < children.length; i++) {
505
- const childId = children[i];
506
- if (!visited.has(childId)) {
507
- if (direction === "horizontal") {
508
- queue.push({
509
- nodeId: childId,
510
- x: childX + nodeWidth + horizontalSpacing,
511
- y,
512
- depth: depth + 1
513
- });
514
- childX += nodeWidth + horizontalSpacing;
515
- } else {
516
- queue.push({
517
- nodeId: childId,
518
- x,
519
- y: childY,
520
- depth: depth + 1
521
- });
522
- childY += nodeHeight + verticalSpacing;
523
- }
524
- }
525
- }
526
- }
527
- }
528
- return nodes.map((node) => {
529
- const position = positionedNodes.get(node.id);
530
- if (position) {
531
- return {
532
- ...node,
533
- position
534
- };
535
- }
536
- return node;
537
- });
538
- }
539
- function centerNodes(nodes, viewportWidth, viewportHeight) {
540
- if (nodes.length === 0) return nodes;
541
- let minX = Infinity;
542
- let maxX = -Infinity;
543
- let minY = Infinity;
544
- let maxY = -Infinity;
545
- for (const node of nodes) {
546
- minX = Math.min(minX, node.position.x);
547
- maxX = Math.max(maxX, node.position.x + DEFAULT_NODE_WIDTH);
548
- minY = Math.min(minY, node.position.y);
549
- maxY = Math.max(maxY, node.position.y + DEFAULT_NODE_HEIGHT);
550
- }
551
- const contentWidth = maxX - minX;
552
- const contentHeight = maxY - minY;
553
- const offsetX = (viewportWidth - contentWidth) / 2 - minX;
554
- const offsetY = (viewportHeight - contentHeight) / 2 - minY;
555
- return nodes.map((node) => ({
556
- ...node,
557
- position: {
558
- x: node.position.x + offsetX,
559
- y: node.position.y + offsetY
560
- }
561
- }));
562
- }
563
- function snapToGrid(nodes, gridSize = 20) {
564
- return nodes.map((node) => ({
565
- ...node,
566
- position: {
567
- x: Math.round(node.position.x / gridSize) * gridSize,
568
- y: Math.round(node.position.y / gridSize) * gridSize
569
- }
570
- }));
571
- }
572
- function getNodesBoundingBox(nodes) {
573
- if (nodes.length === 0) {
574
- return { minX: 0, maxX: 0, minY: 0, maxY: 0, width: 0, height: 0 };
575
- }
576
- let minX = Infinity;
577
- let maxX = -Infinity;
578
- let minY = Infinity;
579
- let maxY = -Infinity;
580
- for (const node of nodes) {
581
- minX = Math.min(minX, node.position.x);
582
- maxX = Math.max(maxX, node.position.x + DEFAULT_NODE_WIDTH);
583
- minY = Math.min(minY, node.position.y);
584
- maxY = Math.max(maxY, node.position.y + DEFAULT_NODE_HEIGHT);
585
- }
586
- return {
587
- minX,
588
- maxX,
589
- minY,
590
- maxY,
591
- width: maxX - minX,
592
- height: maxY - minY
593
- };
594
- }
595
-
596
- // src/hooks/useRuntypeFlow.ts
597
- function useRuntypeFlow(options) {
598
- const {
599
- client,
600
- flowId: initialFlowId,
601
- initialName = "",
602
- initialDescription = "",
603
- initialSteps = [],
604
- onChange,
605
- autoLayoutOnLoad = true
606
- } = options;
607
- const [flowId, setFlowId] = useState(initialFlowId || null);
608
- const [flowName, setFlowName] = useState(initialName);
609
- const [flowDescription, setFlowDescription] = useState(initialDescription);
610
- const [isLoading, setIsLoading] = useState(false);
611
- const [isSaving, setIsSaving] = useState(false);
612
- const [error, setError] = useState(null);
613
- const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
614
- const [nodes, setNodes, onNodesChange] = useNodesState([]);
615
- const [edges, setEdges, onEdgesChange] = useEdgesState([]);
616
- const lastSavedState = useRef("");
617
- const handleStepChange = useCallback(
618
- (stepId, updates) => {
619
- setNodes(
620
- (nds) => nds.map((node) => {
621
- if (node.id === stepId) {
622
- return {
623
- ...node,
624
- data: {
625
- ...node.data,
626
- step: {
627
- ...node.data.step,
628
- ...updates,
629
- config: updates.config ? { ...node.data.step.config, ...updates.config } : node.data.step.config
630
- }
631
- }
632
- };
633
- }
634
- return node;
635
- })
636
- );
637
- setHasUnsavedChanges(true);
638
- },
639
- [setNodes]
640
- );
641
- const handleStepDelete = useCallback(
642
- (stepId) => {
643
- setNodes((nds) => nds.filter((node) => node.id !== stepId));
644
- setEdges((eds) => eds.filter((edge) => edge.source !== stepId && edge.target !== stepId));
645
- setHasUnsavedChanges(true);
646
- },
647
- [setNodes, setEdges]
648
- );
649
- const handleConnect = useCallback(
650
- (connection) => {
651
- setEdges((eds) => addEdge({ ...connection, type: "smoothstep" }, eds));
652
- setHasUnsavedChanges(true);
653
- },
654
- [setEdges]
655
- );
656
- const loadFlow = useCallback(
657
- async (id) => {
658
- setIsLoading(true);
659
- setError(null);
660
- try {
661
- const flow = await client.flows.get(id);
662
- const steps = Array.isArray(flow.flowSteps) ? flow.flowSteps.map((s) => ({
663
- id: s.id,
664
- type: s.type,
665
- name: s.name ?? "",
666
- order: s.order ?? 0,
667
- enabled: s.enabled ?? true,
668
- config: s.config ?? {}
669
- })) : [];
670
- let newNodes = flowStepsToNodes(steps, {
671
- onChange: handleStepChange,
672
- onDelete: handleStepDelete
673
- });
674
- if (autoLayoutOnLoad) {
675
- const newEdges2 = createEdgesFromNodes(newNodes);
676
- newNodes = autoLayout(newNodes, newEdges2);
677
- }
678
- const newEdges = createEdgesFromNodes(newNodes);
679
- setFlowId(id);
680
- setFlowName(flow.name || "");
681
- setFlowDescription("");
682
- setNodes(newNodes);
683
- setEdges(newEdges);
684
- setHasUnsavedChanges(false);
685
- lastSavedState.current = JSON.stringify(nodesToFlowSteps(newNodes));
686
- } catch (err) {
687
- setError(err instanceof Error ? err : new Error("Failed to load flow"));
688
- throw err;
689
- } finally {
690
- setIsLoading(false);
691
- }
692
- },
693
- [client, handleStepChange, handleStepDelete, autoLayoutOnLoad, setNodes, setEdges]
694
- );
695
- const saveFlow = useCallback(async () => {
696
- if (!flowId) {
697
- throw new Error("No flow ID. Use createFlow() to create a new flow first.");
698
- }
699
- setIsSaving(true);
700
- setError(null);
701
- try {
702
- const steps = nodesToFlowSteps(nodes);
703
- await client.flows.update(flowId, {
704
- name: flowName,
705
- flowSteps: steps.map((step) => ({
706
- type: step.type,
707
- name: step.name,
708
- order: step.order,
709
- enabled: step.enabled,
710
- config: step.config
711
- }))
712
- });
713
- setHasUnsavedChanges(false);
714
- lastSavedState.current = JSON.stringify(steps);
715
- return {
716
- id: flowId,
717
- name: flowName,
718
- description: flowDescription,
719
- steps
720
- };
721
- } catch (err) {
722
- setError(err instanceof Error ? err : new Error("Failed to save flow"));
723
- throw err;
724
- } finally {
725
- setIsSaving(false);
726
- }
727
- }, [flowId, flowName, flowDescription, nodes, client]);
728
- const createFlow = useCallback(
729
- async (name, description) => {
730
- setIsSaving(true);
731
- setError(null);
732
- try {
733
- const flow = await client.flows.create({
734
- name,
735
- description
736
- });
737
- setFlowId(flow.id);
738
- setFlowName(name);
739
- setFlowDescription(description || "");
740
- setNodes([]);
741
- setEdges([]);
742
- setHasUnsavedChanges(false);
743
- lastSavedState.current = "[]";
744
- return {
745
- id: flow.id,
746
- name,
747
- description,
748
- steps: []
749
- };
750
- } catch (err) {
751
- setError(err instanceof Error ? err : new Error("Failed to create flow"));
752
- throw err;
753
- } finally {
754
- setIsSaving(false);
755
- }
756
- },
757
- [client, setNodes, setEdges]
758
- );
759
- const deleteStep = useCallback(
760
- (stepId) => {
761
- handleStepDelete(stepId);
762
- },
763
- [handleStepDelete]
764
- );
765
- const updateStep = useCallback(
766
- (stepId, updates) => {
767
- handleStepChange(stepId, updates);
768
- },
769
- [handleStepChange]
770
- );
771
- const addStep = useCallback(
772
- (type, position) => {
773
- const newStep = createDefaultStep(type, nodes.length);
774
- const newNode = {
775
- id: newStep.id,
776
- type: newStep.type,
777
- position: position || { x: 400, y: nodes.length * 230 + 50 },
778
- data: {
779
- step: newStep,
780
- label: newStep.name,
781
- onChange: handleStepChange,
782
- onDelete: handleStepDelete
783
- },
784
- draggable: true,
785
- selectable: true
786
- };
787
- setNodes((nds) => [...nds, newNode]);
788
- if (nodes.length > 0) {
789
- const lastNode = nodes[nodes.length - 1];
790
- setEdges((eds) => [
791
- ...eds,
792
- {
793
- id: `edge-${lastNode.id}-${newNode.id}`,
794
- source: lastNode.id,
795
- target: newNode.id,
796
- type: "smoothstep"
797
- }
798
- ]);
799
- }
800
- setHasUnsavedChanges(true);
801
- },
802
- [nodes, setNodes, setEdges, handleStepChange, handleStepDelete]
803
- );
804
- useEffect(() => {
805
- if (initialFlowId) {
806
- loadFlow(initialFlowId);
807
- } else if (initialSteps.length > 0) {
808
- let newNodes = flowStepsToNodes(initialSteps, {
809
- onChange: handleStepChange,
810
- onDelete: handleStepDelete
811
- });
812
- if (autoLayoutOnLoad) {
813
- const newEdges2 = createEdgesFromNodes(newNodes);
814
- newNodes = autoLayout(newNodes, newEdges2);
815
- }
816
- const newEdges = createEdgesFromNodes(newNodes);
817
- setNodes(newNodes);
818
- setEdges(newEdges);
819
- }
820
- }, []);
821
- useEffect(() => {
822
- onChange?.(nodes, edges);
823
- }, [nodes, edges, onChange]);
824
- useEffect(() => {
825
- const currentState = JSON.stringify(nodesToFlowSteps(nodes));
826
- if (lastSavedState.current && currentState !== lastSavedState.current) {
827
- setHasUnsavedChanges(true);
828
- }
829
- }, [nodes]);
830
- return {
831
- // React Flow state
832
- nodes,
833
- edges,
834
- onNodesChange,
835
- onEdgesChange,
836
- onConnect: handleConnect,
837
- // Flow metadata
838
- flowName,
839
- flowDescription,
840
- flowId,
841
- setFlowName,
842
- setFlowDescription,
843
- // API operations
844
- loadFlow,
845
- saveFlow,
846
- createFlow,
847
- deleteStep,
848
- updateStep,
849
- addStep,
850
- // Status
851
- isLoading,
852
- isSaving,
853
- error,
854
- hasUnsavedChanges
855
- };
856
- }
857
- var promptValidation = {
858
- validate: (step) => {
859
- const errors = [];
860
- const config = step.config;
861
- if (!config.model) {
862
- errors.push({
863
- stepId: step.id,
864
- field: "model",
865
- message: "Model is required"
866
- });
867
- }
868
- if (!config.userPrompt?.trim()) {
869
- errors.push({
870
- stepId: step.id,
871
- field: "userPrompt",
872
- message: "User prompt is required"
873
- });
874
- }
875
- if (!config.outputVariable?.trim()) {
876
- errors.push({
877
- stepId: step.id,
878
- field: "outputVariable",
879
- message: "Output variable is required"
880
- });
881
- }
882
- return errors;
883
- }
884
- };
885
- var fetchUrlValidation = {
886
- validate: (step) => {
887
- const errors = [];
888
- const config = step.config;
889
- if (!config.http?.url?.trim()) {
890
- errors.push({
891
- stepId: step.id,
892
- field: "http.url",
893
- message: "URL is required"
894
- });
895
- } else {
896
- const url = config.http.url;
897
- if (!url.startsWith("http://") && !url.startsWith("https://") && !url.includes("{{")) {
898
- errors.push({
899
- stepId: step.id,
900
- field: "http.url",
901
- message: "URL must start with http:// or https://"
902
- });
903
- }
904
- }
905
- if (!config.outputVariable?.trim()) {
906
- errors.push({
907
- stepId: step.id,
908
- field: "outputVariable",
909
- message: "Output variable is required"
910
- });
911
- }
912
- return errors;
913
- }
914
- };
915
- var transformDataValidation = {
916
- validate: (step) => {
917
- const errors = [];
918
- const config = step.config;
919
- if (!config.script?.trim()) {
920
- errors.push({
921
- stepId: step.id,
922
- field: "script",
923
- message: "Script is required"
924
- });
925
- }
926
- if (!config.outputVariable?.trim()) {
927
- errors.push({
928
- stepId: step.id,
929
- field: "outputVariable",
930
- message: "Output variable is required"
931
- });
932
- }
933
- return errors;
934
- }
935
- };
936
- var conditionalValidation = {
937
- validate: (step, allSteps) => {
938
- const errors = [];
939
- const config = step.config;
940
- if (!config.condition?.trim()) {
941
- errors.push({
942
- stepId: step.id,
943
- field: "condition",
944
- message: "Condition is required"
945
- });
946
- }
947
- if (config.trueSteps && config.trueSteps.length > 0) {
948
- for (const nestedStep of config.trueSteps) {
949
- const nestedErrors = validateStep(nestedStep, allSteps);
950
- errors.push(
951
- ...nestedErrors.map((e) => ({
952
- ...e,
953
- message: `True branch: ${e.message}`
954
- }))
955
- );
956
- }
957
- }
958
- if (config.falseSteps && config.falseSteps.length > 0) {
959
- for (const nestedStep of config.falseSteps) {
960
- const nestedErrors = validateStep(nestedStep, allSteps);
961
- errors.push(
962
- ...nestedErrors.map((e) => ({
963
- ...e,
964
- message: `False branch: ${e.message}`
965
- }))
966
- );
967
- }
968
- }
969
- return errors;
970
- }
971
- };
972
- var sendEmailValidation = {
973
- validate: (step) => {
974
- const errors = [];
975
- const config = step.config;
976
- if (!config.to?.trim()) {
977
- errors.push({
978
- stepId: step.id,
979
- field: "to",
980
- message: "Recipient (To) is required"
981
- });
982
- } else {
983
- const to = config.to;
984
- if (!to.includes("@") && !to.includes("{{")) {
985
- errors.push({
986
- stepId: step.id,
987
- field: "to",
988
- message: "Invalid email address"
989
- });
990
- }
991
- }
992
- if (!config.subject?.trim()) {
993
- errors.push({
994
- stepId: step.id,
995
- field: "subject",
996
- message: "Subject is required"
997
- });
998
- }
999
- if (!config.html?.trim() && !config.text?.trim()) {
1000
- errors.push({
1001
- stepId: step.id,
1002
- field: "html",
1003
- message: "Email content (HTML or text) is required"
1004
- });
1005
- }
1006
- if (!config.outputVariable?.trim()) {
1007
- errors.push({
1008
- stepId: step.id,
1009
- field: "outputVariable",
1010
- message: "Output variable is required"
1011
- });
1012
- }
1013
- return errors;
1014
- }
1015
- };
1016
- var outputVariableWarning = {
1017
- check: (step, allSteps) => {
1018
- const warnings = [];
1019
- const config = step.config;
1020
- if (config.outputVariable) {
1021
- const duplicates = allSteps.filter(
1022
- (s) => s.id !== step.id && s.config.outputVariable === config.outputVariable
1023
- );
1024
- if (duplicates.length > 0) {
1025
- warnings.push({
1026
- stepId: step.id,
1027
- field: "outputVariable",
1028
- message: `Output variable "${config.outputVariable}" is also used by another step`
1029
- });
1030
- }
1031
- }
1032
- return warnings;
1033
- }
1034
- };
1035
- var emptyBranchWarning = {
1036
- check: (step) => {
1037
- const warnings = [];
1038
- if (step.type === "conditional") {
1039
- const config = step.config;
1040
- if (!config.trueSteps || config.trueSteps.length === 0) {
1041
- warnings.push({
1042
- stepId: step.id,
1043
- field: "trueSteps",
1044
- message: "True branch has no steps"
1045
- });
1046
- }
1047
- if (!config.falseSteps || config.falseSteps.length === 0) {
1048
- warnings.push({
1049
- stepId: step.id,
1050
- field: "falseSteps",
1051
- message: "False branch has no steps"
1052
- });
1053
- }
1054
- }
1055
- return warnings;
1056
- }
1057
- };
1058
- var validationRules = {
1059
- prompt: promptValidation,
1060
- "fetch-url": fetchUrlValidation,
1061
- "transform-data": transformDataValidation,
1062
- conditional: conditionalValidation,
1063
- "send-email": sendEmailValidation
1064
- };
1065
- var warningRules = [outputVariableWarning, emptyBranchWarning];
1066
- function validateStep(step, allSteps) {
1067
- const errors = [];
1068
- if (!step.name?.trim()) {
1069
- errors.push({
1070
- stepId: step.id,
1071
- field: "name",
1072
- message: "Step name is required"
1073
- });
1074
- }
1075
- const rule = validationRules[step.type];
1076
- if (rule) {
1077
- errors.push(...rule.validate(step, allSteps));
1078
- }
1079
- return errors;
1080
- }
1081
- function checkWarnings(step, allSteps) {
1082
- const warnings = [];
1083
- for (const rule of warningRules) {
1084
- warnings.push(...rule.check(step, allSteps));
1085
- }
1086
- return warnings;
1087
- }
1088
- function useFlowValidation(options) {
1089
- const { steps: providedSteps, nodes } = options;
1090
- const steps = useMemo(() => {
1091
- if (providedSteps) return providedSteps;
1092
- if (nodes) return nodes.map((n) => n.data.step);
1093
- return [];
1094
- }, [providedSteps, nodes]);
1095
- const result = useMemo(() => {
1096
- const errors = [];
1097
- const warnings = [];
1098
- for (const step of steps) {
1099
- errors.push(...validateStep(step, steps));
1100
- warnings.push(...checkWarnings(step, steps));
1101
- }
1102
- return {
1103
- isValid: errors.length === 0,
1104
- errors,
1105
- warnings
1106
- };
1107
- }, [steps]);
1108
- const validateStepFn = useCallback((step) => validateStep(step, steps), [steps]);
1109
- const isStepValid = useCallback(
1110
- (stepId) => {
1111
- return !result.errors.some((e) => e.stepId === stepId);
1112
- },
1113
- [result.errors]
1114
- );
1115
- const getStepErrors = useCallback(
1116
- (stepId) => {
1117
- return result.errors.filter((e) => e.stepId === stepId);
1118
- },
1119
- [result.errors]
1120
- );
1121
- const getStepWarnings = useCallback(
1122
- (stepId) => {
1123
- return result.warnings.filter((w) => w.stepId === stepId);
1124
- },
1125
- [result.warnings]
1126
- );
1127
- return {
1128
- result,
1129
- validateStep: validateStepFn,
1130
- isStepValid,
1131
- getStepErrors,
1132
- getStepWarnings
1133
- };
1134
- }
1135
- var styles = {
1136
- container: (selected) => ({
1137
- minWidth: "280px",
1138
- maxWidth: "320px",
1139
- backgroundColor: "#ffffff",
1140
- borderRadius: "12px",
1141
- border: selected ? "2px solid #6366f1" : "1px solid #e5e7eb",
1142
- boxShadow: selected ? "0 0 0 2px rgba(99, 102, 241, 0.2), 0 4px 6px -1px rgba(0, 0, 0, 0.1)" : "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
1143
- overflow: "hidden",
1144
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1145
- }),
1146
- header: (color) => ({
1147
- display: "flex",
1148
- alignItems: "center",
1149
- gap: "8px",
1150
- padding: "10px 12px",
1151
- backgroundColor: color,
1152
- borderBottom: "1px solid rgba(0, 0, 0, 0.05)"
1153
- }),
1154
- iconWrapper: {
1155
- display: "flex",
1156
- alignItems: "center",
1157
- justifyContent: "center",
1158
- width: "28px",
1159
- height: "28px",
1160
- borderRadius: "6px",
1161
- backgroundColor: "rgba(255, 255, 255, 0.9)",
1162
- color: "#374151"
1163
- },
1164
- headerContent: {
1165
- flex: 1,
1166
- minWidth: 0
1167
- },
1168
- typeLabel: {
1169
- fontSize: "10px",
1170
- fontWeight: 600,
1171
- textTransform: "uppercase",
1172
- letterSpacing: "0.05em",
1173
- color: "rgba(0, 0, 0, 0.5)",
1174
- marginBottom: "2px"
1175
- },
1176
- stepName: {
1177
- fontSize: "13px",
1178
- fontWeight: 600,
1179
- color: "#1f2937",
1180
- overflow: "hidden",
1181
- textOverflow: "ellipsis",
1182
- whiteSpace: "nowrap"
1183
- },
1184
- body: {
1185
- padding: "12px"
1186
- },
1187
- handle: {
1188
- width: "12px",
1189
- height: "12px",
1190
- borderRadius: "50%",
1191
- border: "2px solid #ffffff"
1192
- },
1193
- targetHandle: {
1194
- backgroundColor: "#6366f1"
1195
- },
1196
- sourceHandle: {
1197
- backgroundColor: "#10b981"
1198
- },
1199
- deleteButton: {
1200
- padding: "4px",
1201
- borderRadius: "4px",
1202
- backgroundColor: "transparent",
1203
- border: "none",
1204
- cursor: "pointer",
1205
- color: "#9ca3af",
1206
- display: "flex",
1207
- alignItems: "center",
1208
- justifyContent: "center",
1209
- transition: "color 0.15s ease, background-color 0.15s ease"
1210
- },
1211
- enabledBadge: (enabled) => ({
1212
- display: "inline-flex",
1213
- alignItems: "center",
1214
- padding: "2px 6px",
1215
- borderRadius: "4px",
1216
- fontSize: "10px",
1217
- fontWeight: 500,
1218
- backgroundColor: enabled ? "rgba(16, 185, 129, 0.1)" : "rgba(239, 68, 68, 0.1)",
1219
- color: enabled ? "#059669" : "#dc2626"
1220
- })
1221
- };
1222
- var NODE_HEADER_COLORS = {
1223
- prompt: "#f3e8ff",
1224
- // Purple tint
1225
- "fetch-url": "#dbeafe",
1226
- // Blue tint
1227
- "transform-data": "#fef3c7",
1228
- // Amber tint
1229
- conditional: "#fce7f3",
1230
- // Pink tint
1231
- "send-email": "#d1fae5",
1232
- // Green tint
1233
- default: "#f3f4f6"
1234
- // Gray tint
1235
- };
1236
- var BaseNode = memo(function BaseNode2({
1237
- data,
1238
- selected = false,
1239
- id,
1240
- typeLabel,
1241
- icon,
1242
- headerColor,
1243
- showSourceHandle = true,
1244
- showTargetHandle = true,
1245
- additionalSourceHandles,
1246
- children
1247
- }) {
1248
- const { step, onDelete } = data;
1249
- const color = headerColor || NODE_HEADER_COLORS[step.type] || NODE_HEADER_COLORS.default;
1250
- const handleDelete = (e) => {
1251
- e.stopPropagation();
1252
- onDelete?.(id);
1253
- };
1254
- return /* @__PURE__ */ jsxs("div", { style: styles.container(selected), children: [
1255
- showTargetHandle && /* @__PURE__ */ jsx(
1256
- Handle,
1257
- {
1258
- type: "target",
1259
- position: Position.Left,
1260
- style: { ...styles.handle, ...styles.targetHandle }
1261
- }
1262
- ),
1263
- /* @__PURE__ */ jsxs("div", { style: styles.header(color), children: [
1264
- /* @__PURE__ */ jsx("div", { style: styles.iconWrapper, children: icon }),
1265
- /* @__PURE__ */ jsxs("div", { style: styles.headerContent, children: [
1266
- /* @__PURE__ */ jsx("div", { style: styles.typeLabel, children: typeLabel }),
1267
- /* @__PURE__ */ jsx("div", { style: styles.stepName, title: step.name, children: step.name || "Untitled Step" })
1268
- ] }),
1269
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
1270
- /* @__PURE__ */ jsx("span", { style: styles.enabledBadge(step.enabled), children: step.enabled ? "Active" : "Disabled" }),
1271
- onDelete && /* @__PURE__ */ jsx(
1272
- "button",
1273
- {
1274
- style: styles.deleteButton,
1275
- onClick: handleDelete,
1276
- title: "Delete step",
1277
- onMouseEnter: (e) => {
1278
- e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.1)";
1279
- e.currentTarget.style.color = "#dc2626";
1280
- },
1281
- onMouseLeave: (e) => {
1282
- e.currentTarget.style.backgroundColor = "transparent";
1283
- e.currentTarget.style.color = "#9ca3af";
1284
- },
1285
- children: /* @__PURE__ */ jsx(DeleteIcon, {})
1286
- }
1287
- )
1288
- ] })
1289
- ] }),
1290
- /* @__PURE__ */ jsx("div", { style: styles.body, className: "nodrag", children }),
1291
- showSourceHandle && /* @__PURE__ */ jsx(
1292
- Handle,
1293
- {
1294
- type: "source",
1295
- position: Position.Right,
1296
- id: "output",
1297
- style: { ...styles.handle, ...styles.sourceHandle }
1298
- }
1299
- ),
1300
- additionalSourceHandles?.map((handle) => /* @__PURE__ */ jsx(
1301
- Handle,
1302
- {
1303
- type: "source",
1304
- position: handle.position,
1305
- id: handle.id,
1306
- style: {
1307
- ...styles.handle,
1308
- backgroundColor: handle.color || "#10b981",
1309
- ...handle.style
1310
- }
1311
- },
1312
- handle.id
1313
- ))
1314
- ] });
1315
- });
1316
- var DeleteIcon = () => /* @__PURE__ */ jsxs(
1317
- "svg",
1318
- {
1319
- width: "14",
1320
- height: "14",
1321
- viewBox: "0 0 24 24",
1322
- fill: "none",
1323
- stroke: "currentColor",
1324
- strokeWidth: "2",
1325
- strokeLinecap: "round",
1326
- strokeLinejoin: "round",
1327
- children: [
1328
- /* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
1329
- /* @__PURE__ */ jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
1330
- /* @__PURE__ */ jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })
1331
- ]
1332
- }
1333
- );
1334
- var BrainIcon = () => /* @__PURE__ */ jsxs(
1335
- "svg",
1336
- {
1337
- width: "16",
1338
- height: "16",
1339
- viewBox: "0 0 24 24",
1340
- fill: "none",
1341
- stroke: "currentColor",
1342
- strokeWidth: "2",
1343
- strokeLinecap: "round",
1344
- strokeLinejoin: "round",
1345
- children: [
1346
- /* @__PURE__ */ jsx("path", { d: "M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z" }),
1347
- /* @__PURE__ */ jsx("path", { d: "M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z" }),
1348
- /* @__PURE__ */ jsx("path", { d: "M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4" }),
1349
- /* @__PURE__ */ jsx("path", { d: "M17.599 6.5a3 3 0 0 0 .399-1.375" }),
1350
- /* @__PURE__ */ jsx("path", { d: "M6.003 5.125A3 3 0 0 0 6.401 6.5" }),
1351
- /* @__PURE__ */ jsx("path", { d: "M3.477 10.896a4 4 0 0 1 .585-.396" }),
1352
- /* @__PURE__ */ jsx("path", { d: "M19.938 10.5a4 4 0 0 1 .585.396" }),
1353
- /* @__PURE__ */ jsx("path", { d: "M6 18a4 4 0 0 1-1.967-.516" }),
1354
- /* @__PURE__ */ jsx("path", { d: "M19.967 17.484A4 4 0 0 1 18 18" })
1355
- ]
1356
- }
1357
- );
1358
- var GlobeIcon = () => /* @__PURE__ */ jsxs(
1359
- "svg",
1360
- {
1361
- width: "16",
1362
- height: "16",
1363
- viewBox: "0 0 24 24",
1364
- fill: "none",
1365
- stroke: "currentColor",
1366
- strokeWidth: "2",
1367
- strokeLinecap: "round",
1368
- strokeLinejoin: "round",
1369
- children: [
1370
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1371
- /* @__PURE__ */ jsx("path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }),
1372
- /* @__PURE__ */ jsx("path", { d: "M2 12h20" })
1373
- ]
1374
- }
1375
- );
1376
- var CodeIcon = () => /* @__PURE__ */ jsxs(
1377
- "svg",
1378
- {
1379
- width: "16",
1380
- height: "16",
1381
- viewBox: "0 0 24 24",
1382
- fill: "none",
1383
- stroke: "currentColor",
1384
- strokeWidth: "2",
1385
- strokeLinecap: "round",
1386
- strokeLinejoin: "round",
1387
- children: [
1388
- /* @__PURE__ */ jsx("polyline", { points: "16 18 22 12 16 6" }),
1389
- /* @__PURE__ */ jsx("polyline", { points: "8 6 2 12 8 18" })
1390
- ]
1391
- }
1392
- );
1393
- var GitBranchIcon = () => /* @__PURE__ */ jsxs(
1394
- "svg",
1395
- {
1396
- width: "16",
1397
- height: "16",
1398
- viewBox: "0 0 24 24",
1399
- fill: "none",
1400
- stroke: "currentColor",
1401
- strokeWidth: "2",
1402
- strokeLinecap: "round",
1403
- strokeLinejoin: "round",
1404
- children: [
1405
- /* @__PURE__ */ jsx("line", { x1: "6", y1: "3", x2: "6", y2: "15" }),
1406
- /* @__PURE__ */ jsx("circle", { cx: "18", cy: "6", r: "3" }),
1407
- /* @__PURE__ */ jsx("circle", { cx: "6", cy: "18", r: "3" }),
1408
- /* @__PURE__ */ jsx("path", { d: "M18 9a9 9 0 0 1-9 9" })
1409
- ]
1410
- }
1411
- );
1412
- var MailIcon = () => /* @__PURE__ */ jsxs(
1413
- "svg",
1414
- {
1415
- width: "16",
1416
- height: "16",
1417
- viewBox: "0 0 24 24",
1418
- fill: "none",
1419
- stroke: "currentColor",
1420
- strokeWidth: "2",
1421
- strokeLinecap: "round",
1422
- strokeLinejoin: "round",
1423
- children: [
1424
- /* @__PURE__ */ jsx("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }),
1425
- /* @__PURE__ */ jsx("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })
1426
- ]
1427
- }
1428
- );
1429
- var styles2 = {
1430
- field: {
1431
- marginBottom: "12px"
1432
- },
1433
- label: {
1434
- display: "block",
1435
- fontSize: "11px",
1436
- fontWeight: 600,
1437
- color: "#6b7280",
1438
- marginBottom: "4px",
1439
- textTransform: "uppercase",
1440
- letterSpacing: "0.03em"
1441
- },
1442
- input: {
1443
- width: "100%",
1444
- padding: "8px 10px",
1445
- fontSize: "12px",
1446
- border: "1px solid #e5e7eb",
1447
- borderRadius: "6px",
1448
- backgroundColor: "#f9fafb",
1449
- color: "#1f2937",
1450
- outline: "none",
1451
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1452
- },
1453
- textarea: {
1454
- width: "100%",
1455
- padding: "8px 10px",
1456
- fontSize: "12px",
1457
- border: "1px solid #e5e7eb",
1458
- borderRadius: "6px",
1459
- backgroundColor: "#f9fafb",
1460
- color: "#1f2937",
1461
- outline: "none",
1462
- resize: "vertical",
1463
- minHeight: "60px",
1464
- fontFamily: "inherit",
1465
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1466
- },
1467
- select: {
1468
- width: "100%",
1469
- padding: "8px 10px",
1470
- fontSize: "12px",
1471
- border: "1px solid #e5e7eb",
1472
- borderRadius: "6px",
1473
- backgroundColor: "#f9fafb",
1474
- color: "#1f2937",
1475
- outline: "none",
1476
- cursor: "pointer"
1477
- },
1478
- row: {
1479
- display: "flex",
1480
- gap: "8px"
1481
- },
1482
- modeBadge: (isAgent) => ({
1483
- display: "inline-flex",
1484
- alignItems: "center",
1485
- padding: "2px 8px",
1486
- borderRadius: "12px",
1487
- fontSize: "10px",
1488
- fontWeight: 600,
1489
- backgroundColor: isAgent ? "#dbeafe" : "#f3e8ff",
1490
- color: isAgent ? "#1d4ed8" : "#7c3aed",
1491
- textTransform: "uppercase",
1492
- letterSpacing: "0.05em"
1493
- }),
1494
- preview: {
1495
- fontSize: "11px",
1496
- color: "#6b7280",
1497
- backgroundColor: "#f3f4f6",
1498
- padding: "8px",
1499
- borderRadius: "6px",
1500
- fontFamily: "monospace",
1501
- whiteSpace: "pre-wrap",
1502
- wordBreak: "break-word",
1503
- maxHeight: "80px",
1504
- overflow: "auto"
1505
- }
1506
- };
1507
- var PromptNode = memo(function PromptNode2(props) {
1508
- const { data, selected, id } = props;
1509
- const { step, onChange } = data;
1510
- const config = step.config;
1511
- const [isExpanded, setIsExpanded] = useState(false);
1512
- const handleChange = useCallback(
1513
- (field, value) => {
1514
- onChange?.(id, {
1515
- config: {
1516
- ...config,
1517
- [field]: value
1518
- }
1519
- });
1520
- },
1521
- [id, config, onChange]
1522
- );
1523
- const handleNameChange = useCallback(
1524
- (e) => {
1525
- onChange?.(id, { name: e.target.value });
1526
- },
1527
- [id, onChange]
1528
- );
1529
- const isAgentMode = config.mode === "agent";
1530
- return /* @__PURE__ */ jsxs(
1531
- BaseNode,
1532
- {
1533
- data,
1534
- selected,
1535
- id,
1536
- typeLabel: "AI Prompt",
1537
- icon: /* @__PURE__ */ jsx(BrainIcon, {}),
1538
- headerColor: NODE_HEADER_COLORS.prompt,
1539
- children: [
1540
- /* @__PURE__ */ jsxs("div", { style: styles2.field, children: [
1541
- /* @__PURE__ */ jsx("label", { style: styles2.label, children: "Step Name" }),
1542
- /* @__PURE__ */ jsx(
1543
- "input",
1544
- {
1545
- style: styles2.input,
1546
- value: step.name,
1547
- onChange: handleNameChange,
1548
- placeholder: "Enter step name",
1549
- onKeyDown: (e) => e.stopPropagation(),
1550
- onFocus: (e) => {
1551
- e.target.style.borderColor = "#6366f1";
1552
- e.target.style.boxShadow = "0 0 0 2px rgba(99, 102, 241, 0.1)";
1553
- },
1554
- onBlur: (e) => {
1555
- e.target.style.borderColor = "#e5e7eb";
1556
- e.target.style.boxShadow = "none";
1557
- }
1558
- }
1559
- )
1560
- ] }),
1561
- /* @__PURE__ */ jsxs("div", { style: styles2.field, children: [
1562
- /* @__PURE__ */ jsxs(
1563
- "div",
1564
- {
1565
- style: {
1566
- display: "flex",
1567
- justifyContent: "space-between",
1568
- alignItems: "center",
1569
- marginBottom: "4px"
1570
- },
1571
- children: [
1572
- /* @__PURE__ */ jsx("label", { style: styles2.label, children: "Mode" }),
1573
- /* @__PURE__ */ jsx("span", { style: styles2.modeBadge(isAgentMode), children: isAgentMode ? "Agent" : "Instruction" })
1574
- ]
1575
- }
1576
- ),
1577
- /* @__PURE__ */ jsxs(
1578
- "select",
1579
- {
1580
- style: styles2.select,
1581
- value: config.mode || "instruction",
1582
- onChange: (e) => handleChange("mode", e.target.value),
1583
- onKeyDown: (e) => e.stopPropagation(),
1584
- children: [
1585
- /* @__PURE__ */ jsx("option", { value: "instruction", children: "Instruction Mode" }),
1586
- /* @__PURE__ */ jsx("option", { value: "agent", children: "Agent Mode" })
1587
- ]
1588
- }
1589
- )
1590
- ] }),
1591
- /* @__PURE__ */ jsxs("div", { style: styles2.field, children: [
1592
- /* @__PURE__ */ jsx("label", { style: styles2.label, children: "Model" }),
1593
- /* @__PURE__ */ jsx(
1594
- "input",
1595
- {
1596
- style: styles2.input,
1597
- value: config.model || "",
1598
- onChange: (e) => handleChange("model", e.target.value),
1599
- placeholder: "e.g., gpt-4, claude-3-sonnet",
1600
- onKeyDown: (e) => e.stopPropagation()
1601
- }
1602
- )
1603
- ] }),
1604
- /* @__PURE__ */ jsxs("div", { style: styles2.field, children: [
1605
- /* @__PURE__ */ jsx("label", { style: styles2.label, children: "User Prompt" }),
1606
- /* @__PURE__ */ jsx(
1607
- "textarea",
1608
- {
1609
- style: styles2.textarea,
1610
- value: config.userPrompt || "",
1611
- onChange: (e) => handleChange("userPrompt", e.target.value),
1612
- placeholder: "Enter your prompt...",
1613
- rows: 3,
1614
- onKeyDown: (e) => e.stopPropagation()
1615
- }
1616
- )
1617
- ] }),
1618
- isExpanded && /* @__PURE__ */ jsxs(Fragment, { children: [
1619
- config.systemPrompt !== void 0 && /* @__PURE__ */ jsxs("div", { style: styles2.field, children: [
1620
- /* @__PURE__ */ jsx("label", { style: styles2.label, children: "System Prompt" }),
1621
- /* @__PURE__ */ jsx(
1622
- "textarea",
1623
- {
1624
- style: styles2.textarea,
1625
- value: config.systemPrompt || "",
1626
- onChange: (e) => handleChange("systemPrompt", e.target.value),
1627
- placeholder: "System instructions...",
1628
- rows: 2,
1629
- onKeyDown: (e) => e.stopPropagation()
1630
- }
1631
- )
1632
- ] }),
1633
- /* @__PURE__ */ jsxs("div", { style: styles2.row, children: [
1634
- /* @__PURE__ */ jsxs("div", { style: { ...styles2.field, flex: 1 }, children: [
1635
- /* @__PURE__ */ jsx("label", { style: styles2.label, children: "Response Format" }),
1636
- /* @__PURE__ */ jsxs(
1637
- "select",
1638
- {
1639
- style: styles2.select,
1640
- value: config.responseFormat || "text",
1641
- onChange: (e) => handleChange("responseFormat", e.target.value),
1642
- onKeyDown: (e) => e.stopPropagation(),
1643
- children: [
1644
- /* @__PURE__ */ jsx("option", { value: "text", children: "Text" }),
1645
- /* @__PURE__ */ jsx("option", { value: "json", children: "JSON" }),
1646
- /* @__PURE__ */ jsx("option", { value: "markdown", children: "Markdown" }),
1647
- /* @__PURE__ */ jsx("option", { value: "html", children: "HTML" })
1648
- ]
1649
- }
1650
- )
1651
- ] }),
1652
- /* @__PURE__ */ jsxs("div", { style: { ...styles2.field, flex: 1 }, children: [
1653
- /* @__PURE__ */ jsx("label", { style: styles2.label, children: "Temperature" }),
1654
- /* @__PURE__ */ jsx(
1655
- "input",
1656
- {
1657
- style: styles2.input,
1658
- type: "number",
1659
- min: "0",
1660
- max: "2",
1661
- step: "0.1",
1662
- value: config.temperature ?? 0.7,
1663
- onChange: (e) => handleChange("temperature", parseFloat(e.target.value)),
1664
- onKeyDown: (e) => e.stopPropagation()
1665
- }
1666
- )
1667
- ] })
1668
- ] }),
1669
- /* @__PURE__ */ jsxs("div", { style: styles2.field, children: [
1670
- /* @__PURE__ */ jsx("label", { style: styles2.label, children: "Output Variable" }),
1671
- /* @__PURE__ */ jsx(
1672
- "input",
1673
- {
1674
- style: styles2.input,
1675
- value: config.outputVariable || "",
1676
- onChange: (e) => handleChange("outputVariable", e.target.value),
1677
- placeholder: "result",
1678
- onKeyDown: (e) => e.stopPropagation()
1679
- }
1680
- )
1681
- ] })
1682
- ] }),
1683
- /* @__PURE__ */ jsx(
1684
- "button",
1685
- {
1686
- onClick: () => setIsExpanded(!isExpanded),
1687
- style: {
1688
- width: "100%",
1689
- padding: "6px",
1690
- fontSize: "11px",
1691
- color: "#6366f1",
1692
- backgroundColor: "transparent",
1693
- border: "1px dashed #e5e7eb",
1694
- borderRadius: "6px",
1695
- cursor: "pointer",
1696
- marginTop: "4px"
1697
- },
1698
- children: isExpanded ? "Show Less" : "Show More Options"
1699
- }
1700
- )
1701
- ]
1702
- }
1703
- );
1704
- });
1705
- var styles3 = {
1706
- field: {
1707
- marginBottom: "12px"
1708
- },
1709
- label: {
1710
- display: "block",
1711
- fontSize: "11px",
1712
- fontWeight: 600,
1713
- color: "#6b7280",
1714
- marginBottom: "4px",
1715
- textTransform: "uppercase",
1716
- letterSpacing: "0.03em"
1717
- },
1718
- input: {
1719
- width: "100%",
1720
- padding: "8px 10px",
1721
- fontSize: "12px",
1722
- border: "1px solid #e5e7eb",
1723
- borderRadius: "6px",
1724
- backgroundColor: "#f9fafb",
1725
- color: "#1f2937",
1726
- outline: "none",
1727
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1728
- },
1729
- textarea: {
1730
- width: "100%",
1731
- padding: "8px 10px",
1732
- fontSize: "12px",
1733
- border: "1px solid #e5e7eb",
1734
- borderRadius: "6px",
1735
- backgroundColor: "#f9fafb",
1736
- color: "#1f2937",
1737
- outline: "none",
1738
- resize: "vertical",
1739
- minHeight: "60px",
1740
- fontFamily: "monospace",
1741
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
1742
- },
1743
- select: {
1744
- width: "100%",
1745
- padding: "8px 10px",
1746
- fontSize: "12px",
1747
- border: "1px solid #e5e7eb",
1748
- borderRadius: "6px",
1749
- backgroundColor: "#f9fafb",
1750
- color: "#1f2937",
1751
- outline: "none",
1752
- cursor: "pointer"
1753
- },
1754
- row: {
1755
- display: "flex",
1756
- gap: "8px"
1757
- },
1758
- methodBadge: (method) => {
1759
- const colors = {
1760
- GET: { bg: "#d1fae5", text: "#059669" },
1761
- POST: { bg: "#dbeafe", text: "#1d4ed8" },
1762
- PUT: { bg: "#fef3c7", text: "#d97706" },
1763
- DELETE: { bg: "#fee2e2", text: "#dc2626" },
1764
- PATCH: { bg: "#e0e7ff", text: "#4f46e5" }
1765
- };
1766
- const color = colors[method] || colors.GET;
1767
- return {
1768
- display: "inline-flex",
1769
- alignItems: "center",
1770
- padding: "2px 8px",
1771
- borderRadius: "4px",
1772
- fontSize: "10px",
1773
- fontWeight: 700,
1774
- backgroundColor: color.bg,
1775
- color: color.text,
1776
- fontFamily: "monospace"
1777
- };
1778
- },
1779
- urlPreview: {
1780
- fontSize: "11px",
1781
- color: "#6b7280",
1782
- backgroundColor: "#f3f4f6",
1783
- padding: "6px 8px",
1784
- borderRadius: "4px",
1785
- fontFamily: "monospace",
1786
- wordBreak: "break-all",
1787
- marginTop: "4px"
1788
- }
1789
- };
1790
- var FetchUrlNode = memo(function FetchUrlNode2(props) {
1791
- const { data, selected, id } = props;
1792
- const { step, onChange } = data;
1793
- const config = step.config;
1794
- const [isExpanded, setIsExpanded] = useState(false);
1795
- const handleChange = useCallback(
1796
- (field, value) => {
1797
- if (field.startsWith("http.")) {
1798
- const httpField = field.replace("http.", "");
1799
- onChange?.(id, {
1800
- config: {
1801
- ...config,
1802
- http: {
1803
- ...config.http,
1804
- [httpField]: value
1805
- }
1806
- }
1807
- });
1808
- } else {
1809
- onChange?.(id, {
1810
- config: {
1811
- ...config,
1812
- [field]: value
1813
- }
1814
- });
1815
- }
1816
- },
1817
- [id, config, onChange]
1818
- );
1819
- const handleNameChange = useCallback(
1820
- (e) => {
1821
- onChange?.(id, { name: e.target.value });
1822
- },
1823
- [id, onChange]
1824
- );
1825
- const method = config.http?.method || "GET";
1826
- return /* @__PURE__ */ jsxs(
1827
- BaseNode,
1828
- {
1829
- data,
1830
- selected,
1831
- id,
1832
- typeLabel: "Fetch URL",
1833
- icon: /* @__PURE__ */ jsx(GlobeIcon, {}),
1834
- headerColor: NODE_HEADER_COLORS["fetch-url"],
1835
- children: [
1836
- /* @__PURE__ */ jsxs("div", { style: styles3.field, children: [
1837
- /* @__PURE__ */ jsx("label", { style: styles3.label, children: "Step Name" }),
1838
- /* @__PURE__ */ jsx(
1839
- "input",
1840
- {
1841
- style: styles3.input,
1842
- value: step.name,
1843
- onChange: handleNameChange,
1844
- placeholder: "Enter step name",
1845
- onKeyDown: (e) => {
1846
- e.stopPropagation();
1847
- }
1848
- }
1849
- )
1850
- ] }),
1851
- /* @__PURE__ */ jsxs("div", { style: styles3.field, children: [
1852
- /* @__PURE__ */ jsxs(
1853
- "div",
1854
- {
1855
- style: {
1856
- display: "flex",
1857
- justifyContent: "space-between",
1858
- alignItems: "center",
1859
- marginBottom: "4px"
1860
- },
1861
- children: [
1862
- /* @__PURE__ */ jsx("label", { style: styles3.label, children: "Method" }),
1863
- /* @__PURE__ */ jsx("span", { style: styles3.methodBadge(method), children: method })
1864
- ]
1865
- }
1866
- ),
1867
- /* @__PURE__ */ jsxs(
1868
- "select",
1869
- {
1870
- style: styles3.select,
1871
- value: method,
1872
- onChange: (e) => handleChange("http.method", e.target.value),
1873
- onKeyDown: (e) => e.stopPropagation(),
1874
- children: [
1875
- /* @__PURE__ */ jsx("option", { value: "GET", children: "GET" }),
1876
- /* @__PURE__ */ jsx("option", { value: "POST", children: "POST" }),
1877
- /* @__PURE__ */ jsx("option", { value: "PUT", children: "PUT" }),
1878
- /* @__PURE__ */ jsx("option", { value: "DELETE", children: "DELETE" }),
1879
- /* @__PURE__ */ jsx("option", { value: "PATCH", children: "PATCH" })
1880
- ]
1881
- }
1882
- )
1883
- ] }),
1884
- /* @__PURE__ */ jsxs("div", { style: styles3.field, children: [
1885
- /* @__PURE__ */ jsx("label", { style: styles3.label, children: "URL" }),
1886
- /* @__PURE__ */ jsx(
1887
- "input",
1888
- {
1889
- style: styles3.input,
1890
- value: config.http?.url || "",
1891
- onChange: (e) => handleChange("http.url", e.target.value),
1892
- placeholder: "https://api.example.com/endpoint",
1893
- onKeyDown: (e) => e.stopPropagation()
1894
- }
1895
- ),
1896
- config.http?.url && /* @__PURE__ */ jsx("div", { style: styles3.urlPreview, children: config.http.url })
1897
- ] }),
1898
- isExpanded && /* @__PURE__ */ jsxs(Fragment, { children: [
1899
- (method === "POST" || method === "PUT" || method === "PATCH") && /* @__PURE__ */ jsxs("div", { style: styles3.field, children: [
1900
- /* @__PURE__ */ jsx("label", { style: styles3.label, children: "Request Body" }),
1901
- /* @__PURE__ */ jsx(
1902
- "textarea",
1903
- {
1904
- style: styles3.textarea,
1905
- value: config.http?.body || "",
1906
- onChange: (e) => handleChange("http.body", e.target.value),
1907
- placeholder: '{"key": "value"}',
1908
- rows: 3,
1909
- onKeyDown: (e) => e.stopPropagation()
1910
- }
1911
- )
1912
- ] }),
1913
- /* @__PURE__ */ jsxs("div", { style: styles3.field, children: [
1914
- /* @__PURE__ */ jsx("label", { style: styles3.label, children: "Headers (JSON)" }),
1915
- /* @__PURE__ */ jsx(
1916
- "textarea",
1917
- {
1918
- style: styles3.textarea,
1919
- value: config.http?.headers ? JSON.stringify(config.http.headers, null, 2) : "",
1920
- onChange: (e) => {
1921
- try {
1922
- const headers = JSON.parse(e.target.value);
1923
- handleChange("http.headers", headers);
1924
- } catch {
1925
- }
1926
- },
1927
- placeholder: '{"Content-Type": "application/json"}',
1928
- rows: 2,
1929
- onKeyDown: (e) => e.stopPropagation()
1930
- }
1931
- )
1932
- ] }),
1933
- /* @__PURE__ */ jsxs("div", { style: styles3.row, children: [
1934
- /* @__PURE__ */ jsxs("div", { style: { ...styles3.field, flex: 1 }, children: [
1935
- /* @__PURE__ */ jsx("label", { style: styles3.label, children: "Response Type" }),
1936
- /* @__PURE__ */ jsxs(
1937
- "select",
1938
- {
1939
- style: styles3.select,
1940
- value: config.responseType || "json",
1941
- onChange: (e) => handleChange("responseType", e.target.value),
1942
- onKeyDown: (e) => e.stopPropagation(),
1943
- children: [
1944
- /* @__PURE__ */ jsx("option", { value: "json", children: "JSON" }),
1945
- /* @__PURE__ */ jsx("option", { value: "text", children: "Text" }),
1946
- /* @__PURE__ */ jsx("option", { value: "xml", children: "XML" })
1947
- ]
1948
- }
1949
- )
1950
- ] }),
1951
- /* @__PURE__ */ jsxs("div", { style: { ...styles3.field, flex: 1 }, children: [
1952
- /* @__PURE__ */ jsx("label", { style: styles3.label, children: "On Error" }),
1953
- /* @__PURE__ */ jsxs(
1954
- "select",
1955
- {
1956
- style: styles3.select,
1957
- value: config.errorHandling || "fail",
1958
- onChange: (e) => handleChange("errorHandling", e.target.value),
1959
- onKeyDown: (e) => e.stopPropagation(),
1960
- children: [
1961
- /* @__PURE__ */ jsx("option", { value: "fail", children: "Fail" }),
1962
- /* @__PURE__ */ jsx("option", { value: "continue", children: "Continue" }),
1963
- /* @__PURE__ */ jsx("option", { value: "default", children: "Use Default" })
1964
- ]
1965
- }
1966
- )
1967
- ] })
1968
- ] }),
1969
- /* @__PURE__ */ jsxs("div", { style: styles3.field, children: [
1970
- /* @__PURE__ */ jsx("label", { style: styles3.label, children: "Output Variable" }),
1971
- /* @__PURE__ */ jsx(
1972
- "input",
1973
- {
1974
- style: styles3.input,
1975
- value: config.outputVariable || "",
1976
- onChange: (e) => handleChange("outputVariable", e.target.value),
1977
- placeholder: "api_response",
1978
- onKeyDown: (e) => e.stopPropagation()
1979
- }
1980
- )
1981
- ] })
1982
- ] }),
1983
- /* @__PURE__ */ jsx(
1984
- "button",
1985
- {
1986
- onClick: () => setIsExpanded(!isExpanded),
1987
- style: {
1988
- width: "100%",
1989
- padding: "6px",
1990
- fontSize: "11px",
1991
- color: "#6366f1",
1992
- backgroundColor: "transparent",
1993
- border: "1px dashed #e5e7eb",
1994
- borderRadius: "6px",
1995
- cursor: "pointer",
1996
- marginTop: "4px"
1997
- },
1998
- children: isExpanded ? "Show Less" : "Show More Options"
1999
- }
2000
- )
2001
- ]
2002
- }
2003
- );
2004
- });
2005
- var styles4 = {
2006
- field: {
2007
- marginBottom: "12px"
2008
- },
2009
- label: {
2010
- display: "block",
2011
- fontSize: "11px",
2012
- fontWeight: 600,
2013
- color: "#6b7280",
2014
- marginBottom: "4px",
2015
- textTransform: "uppercase",
2016
- letterSpacing: "0.03em"
2017
- },
2018
- input: {
2019
- width: "100%",
2020
- padding: "8px 10px",
2021
- fontSize: "12px",
2022
- border: "1px solid #e5e7eb",
2023
- borderRadius: "6px",
2024
- backgroundColor: "#f9fafb",
2025
- color: "#1f2937",
2026
- outline: "none",
2027
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
2028
- },
2029
- codeArea: {
2030
- width: "100%",
2031
- padding: "10px",
2032
- fontSize: "11px",
2033
- border: "1px solid #e5e7eb",
2034
- borderRadius: "6px",
2035
- backgroundColor: "#1e1e1e",
2036
- color: "#d4d4d4",
2037
- outline: "none",
2038
- resize: "vertical",
2039
- minHeight: "100px",
2040
- fontFamily: '"Fira Code", "Monaco", "Consolas", monospace',
2041
- lineHeight: 1.5,
2042
- tabSize: 2
2043
- },
2044
- select: {
2045
- width: "100%",
2046
- padding: "8px 10px",
2047
- fontSize: "12px",
2048
- border: "1px solid #e5e7eb",
2049
- borderRadius: "6px",
2050
- backgroundColor: "#f9fafb",
2051
- color: "#1f2937",
2052
- outline: "none",
2053
- cursor: "pointer"
2054
- },
2055
- row: {
2056
- display: "flex",
2057
- gap: "8px"
2058
- },
2059
- languageBadge: (language) => {
2060
- const colors = {
2061
- javascript: { bg: "#fef3c7", text: "#d97706" },
2062
- typescript: { bg: "#dbeafe", text: "#1d4ed8" },
2063
- python: { bg: "#d1fae5", text: "#059669" }
2064
- };
2065
- const color = colors[language] || colors.javascript;
2066
- return {
2067
- display: "inline-flex",
2068
- alignItems: "center",
2069
- padding: "2px 8px",
2070
- borderRadius: "4px",
2071
- fontSize: "10px",
2072
- fontWeight: 600,
2073
- backgroundColor: color.bg,
2074
- color: color.text,
2075
- textTransform: "capitalize"
2076
- };
2077
- },
2078
- lineNumbers: {
2079
- display: "flex",
2080
- flexDirection: "column",
2081
- alignItems: "flex-end",
2082
- paddingRight: "8px",
2083
- marginRight: "8px",
2084
- borderRight: "1px solid #3f3f46",
2085
- color: "#6b7280",
2086
- fontSize: "11px",
2087
- fontFamily: '"Fira Code", "Monaco", "Consolas", monospace',
2088
- lineHeight: 1.5,
2089
- userSelect: "none"
2090
- },
2091
- codePreview: {
2092
- fontSize: "10px",
2093
- color: "#9ca3af",
2094
- marginTop: "4px"
2095
- }
2096
- };
2097
- var CodeNode = memo(function CodeNode2(props) {
2098
- const { data, selected, id } = props;
2099
- const { step, onChange } = data;
2100
- const config = step.config;
2101
- const [isExpanded, setIsExpanded] = useState(false);
2102
- const handleChange = useCallback(
2103
- (field, value) => {
2104
- onChange?.(id, {
2105
- config: {
2106
- ...config,
2107
- [field]: value
2108
- }
2109
- });
2110
- },
2111
- [id, config, onChange]
2112
- );
2113
- const handleNameChange = useCallback(
2114
- (e) => {
2115
- onChange?.(id, { name: e.target.value });
2116
- },
2117
- [id, onChange]
2118
- );
2119
- const language = config.language || "javascript";
2120
- const lineCount = (config.script || "").split("\n").length;
2121
- return /* @__PURE__ */ jsxs(
2122
- BaseNode,
2123
- {
2124
- data,
2125
- selected,
2126
- id,
2127
- typeLabel: "Run Code",
2128
- icon: /* @__PURE__ */ jsx(CodeIcon, {}),
2129
- headerColor: NODE_HEADER_COLORS["transform-data"],
2130
- children: [
2131
- /* @__PURE__ */ jsxs("div", { style: styles4.field, children: [
2132
- /* @__PURE__ */ jsx("label", { style: styles4.label, children: "Step Name" }),
2133
- /* @__PURE__ */ jsx(
2134
- "input",
2135
- {
2136
- style: styles4.input,
2137
- value: step.name,
2138
- onChange: handleNameChange,
2139
- placeholder: "Enter step name",
2140
- onKeyDown: (e) => e.stopPropagation()
2141
- }
2142
- )
2143
- ] }),
2144
- /* @__PURE__ */ jsxs("div", { style: styles4.field, children: [
2145
- /* @__PURE__ */ jsxs(
2146
- "div",
2147
- {
2148
- style: {
2149
- display: "flex",
2150
- justifyContent: "space-between",
2151
- alignItems: "center",
2152
- marginBottom: "4px"
2153
- },
2154
- children: [
2155
- /* @__PURE__ */ jsx("label", { style: styles4.label, children: "Code" }),
2156
- /* @__PURE__ */ jsx("span", { style: styles4.languageBadge(language), children: language })
2157
- ]
2158
- }
2159
- ),
2160
- /* @__PURE__ */ jsx(
2161
- "textarea",
2162
- {
2163
- style: styles4.codeArea,
2164
- value: config.script || "",
2165
- onChange: (e) => handleChange("script", e.target.value),
2166
- placeholder: `// Write your ${language} code here
2167
- return { result: input }`,
2168
- spellCheck: false,
2169
- onKeyDown: (e) => e.stopPropagation()
2170
- }
2171
- ),
2172
- /* @__PURE__ */ jsxs("div", { style: styles4.codePreview, children: [
2173
- lineCount,
2174
- " line",
2175
- lineCount !== 1 ? "s" : ""
2176
- ] })
2177
- ] }),
2178
- isExpanded && /* @__PURE__ */ jsxs(Fragment, { children: [
2179
- /* @__PURE__ */ jsxs("div", { style: styles4.row, children: [
2180
- /* @__PURE__ */ jsxs("div", { style: { ...styles4.field, flex: 1 }, children: [
2181
- /* @__PURE__ */ jsx("label", { style: styles4.label, children: "Language" }),
2182
- /* @__PURE__ */ jsxs(
2183
- "select",
2184
- {
2185
- style: styles4.select,
2186
- value: language,
2187
- onChange: (e) => handleChange("language", e.target.value),
2188
- onKeyDown: (e) => e.stopPropagation(),
2189
- children: [
2190
- /* @__PURE__ */ jsx("option", { value: "javascript", children: "JavaScript" }),
2191
- /* @__PURE__ */ jsx("option", { value: "typescript", children: "TypeScript" }),
2192
- /* @__PURE__ */ jsx("option", { value: "python", children: "Python" })
2193
- ]
2194
- }
2195
- )
2196
- ] }),
2197
- /* @__PURE__ */ jsxs("div", { style: { ...styles4.field, flex: 1 }, children: [
2198
- /* @__PURE__ */ jsx("label", { style: styles4.label, children: "Sandbox" }),
2199
- /* @__PURE__ */ jsxs(
2200
- "select",
2201
- {
2202
- style: styles4.select,
2203
- value: config.sandboxProvider || "quickjs",
2204
- onChange: (e) => handleChange("sandboxProvider", e.target.value),
2205
- onKeyDown: (e) => e.stopPropagation(),
2206
- children: [
2207
- /* @__PURE__ */ jsx("option", { value: "quickjs", children: "QuickJS (Fast)" }),
2208
- /* @__PURE__ */ jsx("option", { value: "daytona", children: "Daytona (Full)" })
2209
- ]
2210
- }
2211
- )
2212
- ] })
2213
- ] }),
2214
- /* @__PURE__ */ jsxs("div", { style: styles4.field, children: [
2215
- /* @__PURE__ */ jsx("label", { style: styles4.label, children: "On Error" }),
2216
- /* @__PURE__ */ jsxs(
2217
- "select",
2218
- {
2219
- style: styles4.select,
2220
- value: config.errorHandling || "fail",
2221
- onChange: (e) => handleChange("errorHandling", e.target.value),
2222
- onKeyDown: (e) => e.stopPropagation(),
2223
- children: [
2224
- /* @__PURE__ */ jsx("option", { value: "fail", children: "Fail" }),
2225
- /* @__PURE__ */ jsx("option", { value: "continue", children: "Continue" }),
2226
- /* @__PURE__ */ jsx("option", { value: "default", children: "Use Default" })
2227
- ]
2228
- }
2229
- )
2230
- ] }),
2231
- /* @__PURE__ */ jsxs("div", { style: styles4.field, children: [
2232
- /* @__PURE__ */ jsx("label", { style: styles4.label, children: "Output Variable" }),
2233
- /* @__PURE__ */ jsx(
2234
- "input",
2235
- {
2236
- style: styles4.input,
2237
- value: config.outputVariable || "",
2238
- onChange: (e) => handleChange("outputVariable", e.target.value),
2239
- placeholder: "transform_result",
2240
- onKeyDown: (e) => e.stopPropagation()
2241
- }
2242
- )
2243
- ] })
2244
- ] }),
2245
- /* @__PURE__ */ jsx(
2246
- "button",
2247
- {
2248
- onClick: () => setIsExpanded(!isExpanded),
2249
- style: {
2250
- width: "100%",
2251
- padding: "6px",
2252
- fontSize: "11px",
2253
- color: "#6366f1",
2254
- backgroundColor: "transparent",
2255
- border: "1px dashed #e5e7eb",
2256
- borderRadius: "6px",
2257
- cursor: "pointer",
2258
- marginTop: "4px"
2259
- },
2260
- children: isExpanded ? "Show Less" : "Show More Options"
2261
- }
2262
- )
2263
- ]
2264
- }
2265
- );
2266
- });
2267
- var styles5 = {
2268
- field: {
2269
- marginBottom: "12px"
2270
- },
2271
- label: {
2272
- display: "block",
2273
- fontSize: "11px",
2274
- fontWeight: 600,
2275
- color: "#6b7280",
2276
- marginBottom: "4px",
2277
- textTransform: "uppercase",
2278
- letterSpacing: "0.03em"
2279
- },
2280
- input: {
2281
- width: "100%",
2282
- padding: "8px 10px",
2283
- fontSize: "12px",
2284
- border: "1px solid #e5e7eb",
2285
- borderRadius: "6px",
2286
- backgroundColor: "#f9fafb",
2287
- color: "#1f2937",
2288
- outline: "none",
2289
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
2290
- },
2291
- conditionArea: {
2292
- width: "100%",
2293
- padding: "10px",
2294
- fontSize: "12px",
2295
- border: "1px solid #e5e7eb",
2296
- borderRadius: "6px",
2297
- backgroundColor: "#fef7ee",
2298
- color: "#92400e",
2299
- outline: "none",
2300
- resize: "vertical",
2301
- minHeight: "60px",
2302
- fontFamily: '"Fira Code", "Monaco", "Consolas", monospace',
2303
- lineHeight: 1.5
2304
- },
2305
- branchInfo: {
2306
- display: "flex",
2307
- gap: "12px",
2308
- marginTop: "8px"
2309
- },
2310
- branchCard: (type) => ({
2311
- flex: 1,
2312
- padding: "10px",
2313
- borderRadius: "8px",
2314
- backgroundColor: type === "true" ? "#d1fae5" : "#fee2e2",
2315
- border: `1px solid ${type === "true" ? "#a7f3d0" : "#fecaca"}`
2316
- }),
2317
- branchLabel: (type) => ({
2318
- fontSize: "10px",
2319
- fontWeight: 700,
2320
- textTransform: "uppercase",
2321
- letterSpacing: "0.05em",
2322
- color: type === "true" ? "#059669" : "#dc2626",
2323
- marginBottom: "4px"
2324
- }),
2325
- branchCount: {
2326
- fontSize: "18px",
2327
- fontWeight: 700,
2328
- color: "#1f2937"
2329
- },
2330
- branchCountLabel: {
2331
- fontSize: "10px",
2332
- color: "#6b7280"
2333
- },
2334
- helpText: {
2335
- fontSize: "10px",
2336
- color: "#9ca3af",
2337
- marginTop: "4px",
2338
- fontStyle: "italic"
2339
- }
2340
- };
2341
- var ConditionalNode = memo(function ConditionalNode2(props) {
2342
- const { data, selected, id } = props;
2343
- const { step, onChange } = data;
2344
- const config = step.config;
2345
- const [isExpanded, setIsExpanded] = useState(false);
2346
- const handleChange = useCallback(
2347
- (field, value) => {
2348
- onChange?.(id, {
2349
- config: {
2350
- ...config,
2351
- [field]: value
2352
- }
2353
- });
2354
- },
2355
- [id, config, onChange]
2356
- );
2357
- const handleNameChange = useCallback(
2358
- (e) => {
2359
- onChange?.(id, { name: e.target.value });
2360
- },
2361
- [id, onChange]
2362
- );
2363
- const trueStepsCount = config.trueSteps?.length || 0;
2364
- const falseStepsCount = config.falseSteps?.length || 0;
2365
- return /* @__PURE__ */ jsxs(
2366
- BaseNode,
2367
- {
2368
- data,
2369
- selected,
2370
- id,
2371
- typeLabel: "Conditional",
2372
- icon: /* @__PURE__ */ jsx(GitBranchIcon, {}),
2373
- headerColor: NODE_HEADER_COLORS.conditional,
2374
- showSourceHandle: false,
2375
- additionalSourceHandles: [
2376
- {
2377
- id: "true",
2378
- position: Position.Right,
2379
- label: "True",
2380
- color: "#22c55e",
2381
- style: { top: "40%" }
2382
- },
2383
- {
2384
- id: "false",
2385
- position: Position.Right,
2386
- label: "False",
2387
- color: "#ef4444",
2388
- style: { top: "60%" }
2389
- }
2390
- ],
2391
- children: [
2392
- /* @__PURE__ */ jsxs("div", { style: styles5.field, children: [
2393
- /* @__PURE__ */ jsx("label", { style: styles5.label, children: "Step Name" }),
2394
- /* @__PURE__ */ jsx(
2395
- "input",
2396
- {
2397
- style: styles5.input,
2398
- value: step.name,
2399
- onChange: handleNameChange,
2400
- placeholder: "Enter step name",
2401
- onKeyDown: (e) => e.stopPropagation()
2402
- }
2403
- )
2404
- ] }),
2405
- /* @__PURE__ */ jsxs("div", { style: styles5.field, children: [
2406
- /* @__PURE__ */ jsx("label", { style: styles5.label, children: "Condition (JavaScript)" }),
2407
- /* @__PURE__ */ jsx(
2408
- "textarea",
2409
- {
2410
- style: styles5.conditionArea,
2411
- value: config.condition || "",
2412
- onChange: (e) => handleChange("condition", e.target.value),
2413
- placeholder: "user_type === 'premium'",
2414
- spellCheck: false,
2415
- onKeyDown: (e) => e.stopPropagation()
2416
- }
2417
- ),
2418
- /* @__PURE__ */ jsxs("div", { style: styles5.helpText, children: [
2419
- "Access variables directly: ",
2420
- /* @__PURE__ */ jsx("code", { children: "variable_name" }),
2421
- ", ",
2422
- /* @__PURE__ */ jsx("code", { children: "_record.metadata.field" })
2423
- ] })
2424
- ] }),
2425
- /* @__PURE__ */ jsxs("div", { style: styles5.branchInfo, children: [
2426
- /* @__PURE__ */ jsxs("div", { style: styles5.branchCard("true"), children: [
2427
- /* @__PURE__ */ jsxs("div", { style: styles5.branchLabel("true"), children: [
2428
- /* @__PURE__ */ jsx(TrueIcon, {}),
2429
- " True Branch"
2430
- ] }),
2431
- /* @__PURE__ */ jsx("div", { style: styles5.branchCount, children: trueStepsCount }),
2432
- /* @__PURE__ */ jsxs("div", { style: styles5.branchCountLabel, children: [
2433
- "step",
2434
- trueStepsCount !== 1 ? "s" : ""
2435
- ] })
2436
- ] }),
2437
- /* @__PURE__ */ jsxs("div", { style: styles5.branchCard("false"), children: [
2438
- /* @__PURE__ */ jsxs("div", { style: styles5.branchLabel("false"), children: [
2439
- /* @__PURE__ */ jsx(FalseIcon, {}),
2440
- " False Branch"
2441
- ] }),
2442
- /* @__PURE__ */ jsx("div", { style: styles5.branchCount, children: falseStepsCount }),
2443
- /* @__PURE__ */ jsxs("div", { style: styles5.branchCountLabel, children: [
2444
- "step",
2445
- falseStepsCount !== 1 ? "s" : ""
2446
- ] })
2447
- ] })
2448
- ] }),
2449
- isExpanded && /* @__PURE__ */ jsx("div", { style: { marginTop: "12px" }, children: /* @__PURE__ */ jsxs("div", { style: styles5.field, children: [
2450
- /* @__PURE__ */ jsx("label", { style: styles5.label, children: "Condition Examples" }),
2451
- /* @__PURE__ */ jsxs("div", { style: { fontSize: "11px", color: "#6b7280", lineHeight: 1.6 }, children: [
2452
- /* @__PURE__ */ jsxs("div", { children: [
2453
- /* @__PURE__ */ jsx("code", { children: "status === 'active'" }),
2454
- " - Check equality"
2455
- ] }),
2456
- /* @__PURE__ */ jsxs("div", { children: [
2457
- /* @__PURE__ */ jsxs("code", { children: [
2458
- "count ",
2459
- ">",
2460
- " 10"
2461
- ] }),
2462
- " - Numeric comparison"
2463
- ] }),
2464
- /* @__PURE__ */ jsxs("div", { children: [
2465
- /* @__PURE__ */ jsxs("code", { children: [
2466
- "data && data.length ",
2467
- ">",
2468
- " 0"
2469
- ] }),
2470
- " - Check array"
2471
- ] }),
2472
- /* @__PURE__ */ jsxs("div", { children: [
2473
- /* @__PURE__ */ jsx("code", { children: "_record.metadata.type === 'premium'" }),
2474
- " - API input"
2475
- ] })
2476
- ] })
2477
- ] }) }),
2478
- /* @__PURE__ */ jsx(
2479
- "button",
2480
- {
2481
- onClick: () => setIsExpanded(!isExpanded),
2482
- style: {
2483
- width: "100%",
2484
- padding: "6px",
2485
- fontSize: "11px",
2486
- color: "#6366f1",
2487
- backgroundColor: "transparent",
2488
- border: "1px dashed #e5e7eb",
2489
- borderRadius: "6px",
2490
- cursor: "pointer",
2491
- marginTop: "12px"
2492
- },
2493
- children: isExpanded ? "Hide Examples" : "Show Examples"
2494
- }
2495
- )
2496
- ]
2497
- }
2498
- );
2499
- });
2500
- var TrueIcon = () => /* @__PURE__ */ jsx(
2501
- "svg",
2502
- {
2503
- width: "12",
2504
- height: "12",
2505
- viewBox: "0 0 24 24",
2506
- fill: "none",
2507
- stroke: "currentColor",
2508
- strokeWidth: "2",
2509
- strokeLinecap: "round",
2510
- strokeLinejoin: "round",
2511
- style: { display: "inline", marginRight: "4px", verticalAlign: "middle" },
2512
- children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
2513
- }
2514
- );
2515
- var FalseIcon = () => /* @__PURE__ */ jsxs(
2516
- "svg",
2517
- {
2518
- width: "12",
2519
- height: "12",
2520
- viewBox: "0 0 24 24",
2521
- fill: "none",
2522
- stroke: "currentColor",
2523
- strokeWidth: "2",
2524
- strokeLinecap: "round",
2525
- strokeLinejoin: "round",
2526
- style: { display: "inline", marginRight: "4px", verticalAlign: "middle" },
2527
- children: [
2528
- /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2529
- /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2530
- ]
2531
- }
2532
- );
2533
- var styles6 = {
2534
- field: {
2535
- marginBottom: "12px"
2536
- },
2537
- label: {
2538
- display: "block",
2539
- fontSize: "11px",
2540
- fontWeight: 600,
2541
- color: "#6b7280",
2542
- marginBottom: "4px",
2543
- textTransform: "uppercase",
2544
- letterSpacing: "0.03em"
2545
- },
2546
- input: {
2547
- width: "100%",
2548
- padding: "8px 10px",
2549
- fontSize: "12px",
2550
- border: "1px solid #e5e7eb",
2551
- borderRadius: "6px",
2552
- backgroundColor: "#f9fafb",
2553
- color: "#1f2937",
2554
- outline: "none",
2555
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
2556
- },
2557
- textarea: {
2558
- width: "100%",
2559
- padding: "8px 10px",
2560
- fontSize: "12px",
2561
- border: "1px solid #e5e7eb",
2562
- borderRadius: "6px",
2563
- backgroundColor: "#f9fafb",
2564
- color: "#1f2937",
2565
- outline: "none",
2566
- resize: "vertical",
2567
- minHeight: "80px",
2568
- fontFamily: "inherit",
2569
- transition: "border-color 0.15s ease, box-shadow 0.15s ease"
2570
- },
2571
- select: {
2572
- width: "100%",
2573
- padding: "8px 10px",
2574
- fontSize: "12px",
2575
- border: "1px solid #e5e7eb",
2576
- borderRadius: "6px",
2577
- backgroundColor: "#f9fafb",
2578
- color: "#1f2937",
2579
- outline: "none",
2580
- cursor: "pointer"
2581
- },
2582
- row: {
2583
- display: "flex",
2584
- gap: "8px"
2585
- },
2586
- emailPreview: {
2587
- backgroundColor: "#f8fafc",
2588
- border: "1px solid #e2e8f0",
2589
- borderRadius: "8px",
2590
- padding: "10px",
2591
- marginTop: "8px"
2592
- },
2593
- previewHeader: {
2594
- fontSize: "10px",
2595
- color: "#64748b",
2596
- marginBottom: "4px"
2597
- },
2598
- previewValue: {
2599
- fontSize: "12px",
2600
- color: "#1e293b",
2601
- fontWeight: 500,
2602
- marginBottom: "8px",
2603
- wordBreak: "break-all"
2604
- },
2605
- variableHint: {
2606
- display: "inline-flex",
2607
- alignItems: "center",
2608
- padding: "2px 6px",
2609
- borderRadius: "4px",
2610
- fontSize: "10px",
2611
- backgroundColor: "#f0f9ff",
2612
- color: "#0369a1",
2613
- fontFamily: "monospace",
2614
- marginRight: "4px",
2615
- marginTop: "4px"
2616
- }
2617
- };
2618
- var SendEmailNode = memo(function SendEmailNode2(props) {
2619
- const { data, selected, id } = props;
2620
- const { step, onChange } = data;
2621
- const config = step.config;
2622
- const [isExpanded, setIsExpanded] = useState(false);
2623
- const handleChange = useCallback(
2624
- (field, value) => {
2625
- onChange?.(id, {
2626
- config: {
2627
- ...config,
2628
- [field]: value
2629
- }
2630
- });
2631
- },
2632
- [id, config, onChange]
2633
- );
2634
- const handleNameChange = useCallback(
2635
- (e) => {
2636
- onChange?.(id, { name: e.target.value });
2637
- },
2638
- [id, onChange]
2639
- );
2640
- const hasVariables = (value) => /\{\{[\w._]+\}\}/.test(value);
2641
- return /* @__PURE__ */ jsxs(
2642
- BaseNode,
2643
- {
2644
- data,
2645
- selected,
2646
- id,
2647
- typeLabel: "Send Email",
2648
- icon: /* @__PURE__ */ jsx(MailIcon, {}),
2649
- headerColor: NODE_HEADER_COLORS["send-email"],
2650
- children: [
2651
- /* @__PURE__ */ jsxs("div", { style: styles6.field, children: [
2652
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "Step Name" }),
2653
- /* @__PURE__ */ jsx(
2654
- "input",
2655
- {
2656
- style: styles6.input,
2657
- value: step.name,
2658
- onChange: handleNameChange,
2659
- placeholder: "Enter step name",
2660
- onKeyDown: (e) => e.stopPropagation()
2661
- }
2662
- )
2663
- ] }),
2664
- /* @__PURE__ */ jsxs("div", { style: styles6.field, children: [
2665
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "To" }),
2666
- /* @__PURE__ */ jsx(
2667
- "input",
2668
- {
2669
- style: styles6.input,
2670
- value: config.to || "",
2671
- onChange: (e) => handleChange("to", e.target.value),
2672
- placeholder: "recipient@example.com or {{_record.metadata.email}}",
2673
- onKeyDown: (e) => e.stopPropagation()
2674
- }
2675
- ),
2676
- hasVariables(config.to || "") && /* @__PURE__ */ jsx("span", { style: styles6.variableHint, children: "Uses variable" })
2677
- ] }),
2678
- /* @__PURE__ */ jsxs("div", { style: styles6.field, children: [
2679
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "Subject" }),
2680
- /* @__PURE__ */ jsx(
2681
- "input",
2682
- {
2683
- style: styles6.input,
2684
- value: config.subject || "",
2685
- onChange: (e) => handleChange("subject", e.target.value),
2686
- placeholder: "Your subject line",
2687
- onKeyDown: (e) => e.stopPropagation()
2688
- }
2689
- )
2690
- ] }),
2691
- /* @__PURE__ */ jsxs("div", { style: styles6.field, children: [
2692
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "HTML Content" }),
2693
- /* @__PURE__ */ jsx(
2694
- "textarea",
2695
- {
2696
- style: styles6.textarea,
2697
- value: config.html || "",
2698
- onChange: (e) => handleChange("html", e.target.value),
2699
- placeholder: "<p>Your email content...</p>\n\nUse {{variable}} for dynamic content",
2700
- rows: 4,
2701
- onKeyDown: (e) => e.stopPropagation()
2702
- }
2703
- )
2704
- ] }),
2705
- isExpanded && /* @__PURE__ */ jsxs(Fragment, { children: [
2706
- /* @__PURE__ */ jsxs("div", { style: styles6.field, children: [
2707
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "From" }),
2708
- /* @__PURE__ */ jsx(
2709
- "input",
2710
- {
2711
- style: styles6.input,
2712
- value: config.from || "",
2713
- onChange: (e) => handleChange("from", e.target.value),
2714
- placeholder: "{{_flow.id}}@runtype.email",
2715
- onKeyDown: (e) => e.stopPropagation()
2716
- }
2717
- )
2718
- ] }),
2719
- /* @__PURE__ */ jsxs("div", { style: styles6.row, children: [
2720
- /* @__PURE__ */ jsxs("div", { style: { ...styles6.field, flex: 1 }, children: [
2721
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "CC" }),
2722
- /* @__PURE__ */ jsx(
2723
- "input",
2724
- {
2725
- style: styles6.input,
2726
- value: config.cc || "",
2727
- onChange: (e) => handleChange("cc", e.target.value),
2728
- placeholder: "cc@example.com",
2729
- onKeyDown: (e) => e.stopPropagation()
2730
- }
2731
- )
2732
- ] }),
2733
- /* @__PURE__ */ jsxs("div", { style: { ...styles6.field, flex: 1 }, children: [
2734
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "BCC" }),
2735
- /* @__PURE__ */ jsx(
2736
- "input",
2737
- {
2738
- style: styles6.input,
2739
- value: config.bcc || "",
2740
- onChange: (e) => handleChange("bcc", e.target.value),
2741
- placeholder: "bcc@example.com",
2742
- onKeyDown: (e) => e.stopPropagation()
2743
- }
2744
- )
2745
- ] })
2746
- ] }),
2747
- /* @__PURE__ */ jsxs("div", { style: styles6.field, children: [
2748
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "Reply To" }),
2749
- /* @__PURE__ */ jsx(
2750
- "input",
2751
- {
2752
- style: styles6.input,
2753
- value: config.replyTo || "",
2754
- onChange: (e) => handleChange("replyTo", e.target.value),
2755
- placeholder: "reply@example.com",
2756
- onKeyDown: (e) => e.stopPropagation()
2757
- }
2758
- )
2759
- ] }),
2760
- /* @__PURE__ */ jsxs("div", { style: styles6.field, children: [
2761
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "Plain Text (Fallback)" }),
2762
- /* @__PURE__ */ jsx(
2763
- "textarea",
2764
- {
2765
- style: styles6.textarea,
2766
- value: config.text || "",
2767
- onChange: (e) => handleChange("text", e.target.value),
2768
- placeholder: "Plain text version of your email...",
2769
- rows: 2,
2770
- onKeyDown: (e) => e.stopPropagation()
2771
- }
2772
- )
2773
- ] }),
2774
- /* @__PURE__ */ jsxs("div", { style: styles6.row, children: [
2775
- /* @__PURE__ */ jsxs("div", { style: { ...styles6.field, flex: 1 }, children: [
2776
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "On Error" }),
2777
- /* @__PURE__ */ jsxs(
2778
- "select",
2779
- {
2780
- style: styles6.select,
2781
- value: config.errorHandling || "fail",
2782
- onChange: (e) => handleChange("errorHandling", e.target.value),
2783
- onKeyDown: (e) => e.stopPropagation(),
2784
- children: [
2785
- /* @__PURE__ */ jsx("option", { value: "fail", children: "Fail" }),
2786
- /* @__PURE__ */ jsx("option", { value: "continue", children: "Continue" }),
2787
- /* @__PURE__ */ jsx("option", { value: "default", children: "Use Default" })
2788
- ]
2789
- }
2790
- )
2791
- ] }),
2792
- /* @__PURE__ */ jsxs("div", { style: { ...styles6.field, flex: 1 }, children: [
2793
- /* @__PURE__ */ jsx("label", { style: styles6.label, children: "Output Variable" }),
2794
- /* @__PURE__ */ jsx(
2795
- "input",
2796
- {
2797
- style: styles6.input,
2798
- value: config.outputVariable || "",
2799
- onChange: (e) => handleChange("outputVariable", e.target.value),
2800
- placeholder: "email_result",
2801
- onKeyDown: (e) => e.stopPropagation()
2802
- }
2803
- )
2804
- ] })
2805
- ] })
2806
- ] }),
2807
- (config.to || config.subject) && /* @__PURE__ */ jsxs("div", { style: styles6.emailPreview, children: [
2808
- /* @__PURE__ */ jsx("div", { style: styles6.previewHeader, children: "Preview" }),
2809
- config.to && /* @__PURE__ */ jsxs("div", { style: styles6.previewValue, children: [
2810
- /* @__PURE__ */ jsx("strong", { children: "To:" }),
2811
- " ",
2812
- config.to
2813
- ] }),
2814
- config.subject && /* @__PURE__ */ jsxs("div", { style: styles6.previewValue, children: [
2815
- /* @__PURE__ */ jsx("strong", { children: "Subject:" }),
2816
- " ",
2817
- config.subject
2818
- ] })
2819
- ] }),
2820
- /* @__PURE__ */ jsx(
2821
- "button",
2822
- {
2823
- onClick: () => setIsExpanded(!isExpanded),
2824
- style: {
2825
- width: "100%",
2826
- padding: "6px",
2827
- fontSize: "11px",
2828
- color: "#6366f1",
2829
- backgroundColor: "transparent",
2830
- border: "1px dashed #e5e7eb",
2831
- borderRadius: "6px",
2832
- cursor: "pointer",
2833
- marginTop: "8px"
2834
- },
2835
- children: isExpanded ? "Show Less" : "Show More Options"
2836
- }
2837
- )
2838
- ]
2839
- }
2840
- );
2841
- });
2842
- var styles7 = {
2843
- container: {
2844
- width: "100%",
2845
- height: "100%",
2846
- position: "relative"
2847
- },
2848
- toolbar: {
2849
- display: "flex",
2850
- alignItems: "center",
2851
- gap: "8px",
2852
- padding: "8px 12px",
2853
- backgroundColor: "#ffffff",
2854
- borderRadius: "8px",
2855
- boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
2856
- border: "1px solid #e5e7eb"
2857
- },
2858
- toolbarButton: {
2859
- display: "flex",
2860
- alignItems: "center",
2861
- gap: "6px",
2862
- padding: "8px 12px",
2863
- fontSize: "12px",
2864
- fontWeight: 500,
2865
- backgroundColor: "#f9fafb",
2866
- border: "1px solid #e5e7eb",
2867
- borderRadius: "6px",
2868
- cursor: "pointer",
2869
- color: "#374151",
2870
- transition: "all 0.15s ease"
2871
- },
2872
- toolbarButtonPrimary: {
2873
- backgroundColor: "#6366f1",
2874
- borderColor: "#6366f1",
2875
- color: "#ffffff"
2876
- },
2877
- toolbarDivider: {
2878
- width: "1px",
2879
- height: "24px",
2880
- backgroundColor: "#e5e7eb",
2881
- margin: "0 4px"
2882
- },
2883
- statusPanel: {
2884
- display: "flex",
2885
- alignItems: "center",
2886
- gap: "8px",
2887
- padding: "8px 12px",
2888
- backgroundColor: "#ffffff",
2889
- borderRadius: "8px",
2890
- boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
2891
- border: "1px solid #e5e7eb",
2892
- fontSize: "12px",
2893
- color: "#6b7280"
2894
- },
2895
- statusBadge: (isValid) => ({
2896
- display: "inline-flex",
2897
- alignItems: "center",
2898
- padding: "2px 8px",
2899
- borderRadius: "12px",
2900
- fontSize: "10px",
2901
- fontWeight: 600,
2902
- backgroundColor: isValid ? "#d1fae5" : "#fee2e2",
2903
- color: isValid ? "#059669" : "#dc2626"
2904
- }),
2905
- addStepMenu: {
2906
- position: "absolute",
2907
- top: "100%",
2908
- left: 0,
2909
- marginTop: "4px",
2910
- backgroundColor: "#ffffff",
2911
- borderRadius: "8px",
2912
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
2913
- border: "1px solid #e5e7eb",
2914
- padding: "4px",
2915
- zIndex: 1e3,
2916
- minWidth: "200px"
2917
- },
2918
- addStepMenuItem: {
2919
- display: "flex",
2920
- alignItems: "center",
2921
- gap: "8px",
2922
- padding: "8px 12px",
2923
- fontSize: "12px",
2924
- color: "#374151",
2925
- backgroundColor: "transparent",
2926
- border: "none",
2927
- borderRadius: "4px",
2928
- cursor: "pointer",
2929
- width: "100%",
2930
- textAlign: "left",
2931
- transition: "background-color 0.15s ease"
2932
- },
2933
- flowNameInput: {
2934
- padding: "6px 10px",
2935
- fontSize: "14px",
2936
- fontWeight: 600,
2937
- border: "1px solid transparent",
2938
- borderRadius: "4px",
2939
- backgroundColor: "transparent",
2940
- color: "#1f2937",
2941
- outline: "none",
2942
- transition: "border-color 0.15s ease, background-color 0.15s ease",
2943
- minWidth: "200px"
2944
- },
2945
- unsavedBadge: {
2946
- display: "inline-flex",
2947
- alignItems: "center",
2948
- padding: "2px 6px",
2949
- borderRadius: "4px",
2950
- fontSize: "10px",
2951
- fontWeight: 500,
2952
- backgroundColor: "#fef3c7",
2953
- color: "#d97706"
2954
- }
2955
- };
2956
- var nodeTypes = {
2957
- prompt: PromptNode,
2958
- "fetch-url": FetchUrlNode,
2959
- "transform-data": CodeNode,
2960
- conditional: ConditionalNode,
2961
- "send-email": SendEmailNode,
2962
- // Default node for unsupported types
2963
- default: DefaultNode
2964
- };
2965
- function DefaultNode(props) {
2966
- const { data, selected, id } = props;
2967
- return /* @__PURE__ */ jsx(
2968
- BaseNode,
2969
- {
2970
- data,
2971
- selected,
2972
- id,
2973
- typeLabel: data.step.type,
2974
- icon: /* @__PURE__ */ jsx(BrainIcon, {}),
2975
- headerColor: NODE_HEADER_COLORS.default,
2976
- children: /* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "#6b7280" }, children: "This step type is not yet fully supported in the visual editor." })
2977
- }
2978
- );
2979
- }
2980
- var STEP_TYPE_OPTIONS = [
2981
- {
2982
- type: "prompt",
2983
- label: "AI Prompt",
2984
- icon: /* @__PURE__ */ jsx(PromptIcon, {}),
2985
- color: NODE_HEADER_COLORS.prompt
2986
- },
2987
- {
2988
- type: "fetch-url",
2989
- label: "Fetch URL",
2990
- icon: /* @__PURE__ */ jsx(GlobeIcon2, {}),
2991
- color: NODE_HEADER_COLORS["fetch-url"]
2992
- },
2993
- {
2994
- type: "transform-data",
2995
- label: "Run Code",
2996
- icon: /* @__PURE__ */ jsx(CodeIcon2, {}),
2997
- color: NODE_HEADER_COLORS["transform-data"]
2998
- },
2999
- {
3000
- type: "conditional",
3001
- label: "Conditional",
3002
- icon: /* @__PURE__ */ jsx(BranchIcon, {}),
3003
- color: NODE_HEADER_COLORS.conditional
3004
- },
3005
- {
3006
- type: "send-email",
3007
- label: "Send Email",
3008
- icon: /* @__PURE__ */ jsx(MailIcon2, {}),
3009
- color: NODE_HEADER_COLORS["send-email"]
3010
- }
3011
- ];
3012
- function RuntypeFlowEditor({
3013
- client,
3014
- flowId,
3015
- initialName = "Untitled Flow",
3016
- initialDescription = "",
3017
- initialSteps = [],
3018
- onSave,
3019
- onChange,
3020
- onStepSelect,
3021
- showToolbar = true,
3022
- readOnly = false,
3023
- className
3024
- }) {
3025
- const [showAddMenu, setShowAddMenu] = useState(false);
3026
- const [, setSelectedNode] = useState(null);
3027
- const {
3028
- nodes,
3029
- edges,
3030
- onNodesChange,
3031
- onEdgesChange,
3032
- onConnect,
3033
- flowName,
3034
- setFlowName,
3035
- saveFlow,
3036
- addStep,
3037
- isLoading,
3038
- isSaving,
3039
- error,
3040
- hasUnsavedChanges
3041
- } = useRuntypeFlow({
3042
- client,
3043
- flowId,
3044
- initialName,
3045
- initialDescription,
3046
- initialSteps,
3047
- onChange,
3048
- autoLayoutOnLoad: true
3049
- });
3050
- const { result: validationResult } = useFlowValidation({ nodes });
3051
- const handleSave = useCallback(async () => {
3052
- try {
3053
- const savedFlow = await saveFlow();
3054
- onSave?.(savedFlow);
3055
- } catch (err) {
3056
- console.error("Failed to save flow:", err);
3057
- }
3058
- }, [saveFlow, onSave]);
3059
- const handleAddStep = useCallback(
3060
- (type) => {
3061
- addStep(type);
3062
- setShowAddMenu(false);
3063
- },
3064
- [addStep]
3065
- );
3066
- const handleNodeClick = useCallback(
3067
- (_, node) => {
3068
- setSelectedNode(node);
3069
- onStepSelect?.(node.data.step);
3070
- },
3071
- [onStepSelect]
3072
- );
3073
- const handlePaneClick = useCallback(() => {
3074
- setSelectedNode(null);
3075
- onStepSelect?.(null);
3076
- }, [onStepSelect]);
3077
- const minimapNodeColor = useCallback((node) => {
3078
- return NODE_HEADER_COLORS[node.data.step.type] || NODE_HEADER_COLORS.default;
3079
- }, []);
3080
- return /* @__PURE__ */ jsxs("div", { style: styles7.container, className, children: [
3081
- /* @__PURE__ */ jsxs(
3082
- ReactFlow,
3083
- {
3084
- nodes,
3085
- edges,
3086
- onNodesChange: readOnly ? void 0 : onNodesChange,
3087
- onEdgesChange: readOnly ? void 0 : onEdgesChange,
3088
- onConnect: readOnly ? void 0 : onConnect,
3089
- onNodeClick: handleNodeClick,
3090
- onPaneClick: handlePaneClick,
3091
- nodeTypes,
3092
- fitView: true,
3093
- fitViewOptions: { padding: 0.2 },
3094
- snapToGrid: true,
3095
- snapGrid: [20, 20],
3096
- connectionLineType: ConnectionLineType.SmoothStep,
3097
- defaultEdgeOptions: {
3098
- type: "smoothstep",
3099
- animated: false
3100
- },
3101
- proOptions: { hideAttribution: true },
3102
- children: [
3103
- /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Dots, gap: 20, size: 1, color: "#d1d5db" }),
3104
- /* @__PURE__ */ jsx(Controls, { showInteractive: !readOnly }),
3105
- /* @__PURE__ */ jsx(
3106
- MiniMap,
3107
- {
3108
- nodeColor: minimapNodeColor,
3109
- nodeStrokeWidth: 3,
3110
- zoomable: true,
3111
- pannable: true,
3112
- style: {
3113
- backgroundColor: "#f9fafb",
3114
- border: "1px solid #e5e7eb",
3115
- borderRadius: "8px"
3116
- }
3117
- }
3118
- ),
3119
- showToolbar && /* @__PURE__ */ jsx(Panel, { position: "top-left", children: /* @__PURE__ */ jsxs("div", { style: styles7.toolbar, children: [
3120
- /* @__PURE__ */ jsx(
3121
- "input",
3122
- {
3123
- style: styles7.flowNameInput,
3124
- value: flowName,
3125
- onChange: (e) => setFlowName(e.target.value),
3126
- placeholder: "Flow name...",
3127
- disabled: readOnly,
3128
- onFocus: (e) => {
3129
- e.target.style.borderColor = "#6366f1";
3130
- e.target.style.backgroundColor = "#ffffff";
3131
- },
3132
- onBlur: (e) => {
3133
- e.target.style.borderColor = "transparent";
3134
- e.target.style.backgroundColor = "transparent";
3135
- }
3136
- }
3137
- ),
3138
- hasUnsavedChanges && /* @__PURE__ */ jsx("span", { style: styles7.unsavedBadge, children: "Unsaved" }),
3139
- /* @__PURE__ */ jsx("div", { style: styles7.toolbarDivider }),
3140
- !readOnly && /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
3141
- /* @__PURE__ */ jsxs(
3142
- "button",
3143
- {
3144
- style: styles7.toolbarButton,
3145
- onClick: () => setShowAddMenu(!showAddMenu),
3146
- onMouseEnter: (e) => {
3147
- e.currentTarget.style.backgroundColor = "#f3f4f6";
3148
- e.currentTarget.style.borderColor = "#d1d5db";
3149
- },
3150
- onMouseLeave: (e) => {
3151
- e.currentTarget.style.backgroundColor = "#f9fafb";
3152
- e.currentTarget.style.borderColor = "#e5e7eb";
3153
- },
3154
- children: [
3155
- /* @__PURE__ */ jsx(PlusIcon, {}),
3156
- " Add Step"
3157
- ]
3158
- }
3159
- ),
3160
- showAddMenu && /* @__PURE__ */ jsx("div", { style: styles7.addStepMenu, children: STEP_TYPE_OPTIONS.map((option) => /* @__PURE__ */ jsxs(
3161
- "button",
3162
- {
3163
- style: styles7.addStepMenuItem,
3164
- onClick: () => handleAddStep(option.type),
3165
- onMouseEnter: (e) => {
3166
- e.currentTarget.style.backgroundColor = option.color;
3167
- },
3168
- onMouseLeave: (e) => {
3169
- e.currentTarget.style.backgroundColor = "transparent";
3170
- },
3171
- children: [
3172
- option.icon,
3173
- option.label
3174
- ]
3175
- },
3176
- option.type
3177
- )) })
3178
- ] }),
3179
- !readOnly && flowId && /* @__PURE__ */ jsx(
3180
- "button",
3181
- {
3182
- style: { ...styles7.toolbarButton, ...styles7.toolbarButtonPrimary },
3183
- onClick: handleSave,
3184
- disabled: isSaving || !hasUnsavedChanges,
3185
- onMouseEnter: (e) => {
3186
- if (!isSaving && hasUnsavedChanges) {
3187
- e.currentTarget.style.backgroundColor = "#4f46e5";
3188
- }
3189
- },
3190
- onMouseLeave: (e) => {
3191
- e.currentTarget.style.backgroundColor = "#6366f1";
3192
- },
3193
- children: isSaving ? "Saving..." : "Save"
3194
- }
3195
- )
3196
- ] }) }),
3197
- /* @__PURE__ */ jsx(Panel, { position: "top-right", children: /* @__PURE__ */ jsxs("div", { style: styles7.statusPanel, children: [
3198
- /* @__PURE__ */ jsx("span", { style: styles7.statusBadge(validationResult.isValid), children: validationResult.isValid ? "Valid" : `${validationResult.errors.length} Error(s)` }),
3199
- /* @__PURE__ */ jsxs("span", { children: [
3200
- nodes.length,
3201
- " steps"
3202
- ] }),
3203
- isLoading && /* @__PURE__ */ jsx("span", { children: "Loading..." }),
3204
- error && /* @__PURE__ */ jsxs("span", { style: { color: "#dc2626" }, children: [
3205
- "Error: ",
3206
- error.message
3207
- ] })
3208
- ] }) })
3209
- ]
3210
- }
3211
- ),
3212
- showAddMenu && /* @__PURE__ */ jsx(
3213
- "div",
3214
- {
3215
- style: {
3216
- position: "fixed",
3217
- top: 0,
3218
- left: 0,
3219
- right: 0,
3220
- bottom: 0,
3221
- zIndex: 999
3222
- },
3223
- onClick: () => setShowAddMenu(false)
3224
- }
3225
- )
3226
- ] });
3227
- }
3228
- function PlusIcon() {
3229
- return /* @__PURE__ */ jsxs(
3230
- "svg",
3231
- {
3232
- width: "14",
3233
- height: "14",
3234
- viewBox: "0 0 24 24",
3235
- fill: "none",
3236
- stroke: "currentColor",
3237
- strokeWidth: "2",
3238
- children: [
3239
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
3240
- /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
3241
- ]
3242
- }
3243
- );
3244
- }
3245
- function PromptIcon() {
3246
- return /* @__PURE__ */ jsxs(
3247
- "svg",
3248
- {
3249
- width: "14",
3250
- height: "14",
3251
- viewBox: "0 0 24 24",
3252
- fill: "none",
3253
- stroke: "currentColor",
3254
- strokeWidth: "2",
3255
- children: [
3256
- /* @__PURE__ */ jsx("path", { d: "M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z" }),
3257
- /* @__PURE__ */ jsx("path", { d: "M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z" })
3258
- ]
3259
- }
3260
- );
3261
- }
3262
- function GlobeIcon2() {
3263
- return /* @__PURE__ */ jsxs(
3264
- "svg",
3265
- {
3266
- width: "14",
3267
- height: "14",
3268
- viewBox: "0 0 24 24",
3269
- fill: "none",
3270
- stroke: "currentColor",
3271
- strokeWidth: "2",
3272
- children: [
3273
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
3274
- /* @__PURE__ */ jsx("path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }),
3275
- /* @__PURE__ */ jsx("path", { d: "M2 12h20" })
3276
- ]
3277
- }
3278
- );
3279
- }
3280
- function CodeIcon2() {
3281
- return /* @__PURE__ */ jsxs(
3282
- "svg",
3283
- {
3284
- width: "14",
3285
- height: "14",
3286
- viewBox: "0 0 24 24",
3287
- fill: "none",
3288
- stroke: "currentColor",
3289
- strokeWidth: "2",
3290
- children: [
3291
- /* @__PURE__ */ jsx("polyline", { points: "16 18 22 12 16 6" }),
3292
- /* @__PURE__ */ jsx("polyline", { points: "8 6 2 12 8 18" })
3293
- ]
3294
- }
3295
- );
3296
- }
3297
- function BranchIcon() {
3298
- return /* @__PURE__ */ jsxs(
3299
- "svg",
3300
- {
3301
- width: "14",
3302
- height: "14",
3303
- viewBox: "0 0 24 24",
3304
- fill: "none",
3305
- stroke: "currentColor",
3306
- strokeWidth: "2",
3307
- children: [
3308
- /* @__PURE__ */ jsx("line", { x1: "6", y1: "3", x2: "6", y2: "15" }),
3309
- /* @__PURE__ */ jsx("circle", { cx: "18", cy: "6", r: "3" }),
3310
- /* @__PURE__ */ jsx("circle", { cx: "6", cy: "18", r: "3" }),
3311
- /* @__PURE__ */ jsx("path", { d: "M18 9a9 9 0 0 1-9 9" })
3312
- ]
3313
- }
3314
- );
3315
- }
3316
- function MailIcon2() {
3317
- return /* @__PURE__ */ jsxs(
3318
- "svg",
3319
- {
3320
- width: "14",
3321
- height: "14",
3322
- viewBox: "0 0 24 24",
3323
- fill: "none",
3324
- stroke: "currentColor",
3325
- strokeWidth: "2",
3326
- children: [
3327
- /* @__PURE__ */ jsx("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }),
3328
- /* @__PURE__ */ jsx("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })
3329
- ]
3330
- }
3331
- );
3332
- }
3333
-
3334
- export { BaseNode, CodeNode, ConditionalNode, FetchUrlNode, PromptNode, RuntypeFlowEditor, SUPPORTED_NODE_TYPES, SendEmailNode, autoLayout, centerNodes, cloneStep, createDefaultStep, createEdgesFromNodes, flowStepsToNodes, generateStepId, getDefaultStepName, getNodesBoundingBox, isSupportedNodeType, nodesToFlowSteps, snapToGrid, useFlowValidation, useRuntypeFlow };