@burdenoff/fluidgrids-fe-sdk 2026.703.2 → 2026.706.1
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/{WorkflowBuilder-BWB3552Z.js → WorkflowBuilder-QVM6P76K.js} +3 -3
- package/dist/{WorkflowBuilder-BWB3552Z.js.map → WorkflowBuilder-QVM6P76K.js.map} +1 -1
- package/dist/{chunk-5GIC24CM.js → chunk-DPD5ILMD.js} +1114 -300
- package/dist/chunk-DPD5ILMD.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-5GIC24CM.js.map +0 -1
|
@@ -9,17 +9,17 @@ import { config, getFluidGridsConfig, validateTrustedOrigin, setFluidGridsConfig
|
|
|
9
9
|
import { deepClone, applyTemplateInputs } from './chunk-XQP33UJR.js';
|
|
10
10
|
import { cn as cn$1, Badge as Badge$1, Button as Button$1 } from './chunk-Z54K22LP.js';
|
|
11
11
|
import { ThemeProvider as ThemeProvider$1 } from '@burdenoff/fe-libs/shared/providers/shell';
|
|
12
|
-
import {
|
|
12
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
13
13
|
import { useParams, useNavigate } from 'react-router-dom';
|
|
14
14
|
import { useShallow, shallow } from 'zustand/shallow';
|
|
15
|
-
import * as
|
|
16
|
-
import
|
|
17
|
-
import { Handle, Position, getBezierPath, MarkerType, useStore, useReactFlow, getConnectedEdges, useNodeId, ReactFlowProvider, ReactFlow, Background, useOnSelectionChange, MiniMap, EdgeLabelRenderer, getOutgoers, useNodes, useNodesState, useEdgesState, addEdge, Controls, Panel } from '@xyflow/react';
|
|
15
|
+
import * as React from 'react';
|
|
16
|
+
import React__default, { forwardRef, useState, useImperativeHandle, useRef, useEffect, useMemo, createContext, lazy, memo, useCallback, useContext, useLayoutEffect, Suspense, useDeferredValue } from 'react';
|
|
17
|
+
import { Handle, Position, getBezierPath, MarkerType, useStore, useReactFlow, getConnectedEdges, useUpdateNodeInternals, useNodeId, ReactFlowProvider, ReactFlow, Background, useOnSelectionChange, MiniMap, EdgeLabelRenderer, getOutgoers, useNodes, useNodesState, useEdgesState, addEdge, Controls, Panel } from '@xyflow/react';
|
|
18
18
|
import { produce } from 'immer';
|
|
19
19
|
import { nanoid } from 'nanoid/non-secure';
|
|
20
|
+
import { Icon } from '@iconify/react';
|
|
20
21
|
import { cn } from '@burdenoff/fe-libs/utils';
|
|
21
22
|
import { Textarea, Input, Button, Card, Badge, CardContent as CardContent$1, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator, Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, Popover, PopoverTrigger, PopoverContent, Toaster, Tabs, TabsList, TabsTrigger, TabsContent, CardHeader as CardHeader$1, CardTitle as CardTitle$1, CardDescription as CardDescription$1, ScrollArea, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@burdenoff/fe-libs/ui';
|
|
22
|
-
import { Icon } from '@iconify/react';
|
|
23
23
|
import * as AdaptiveCards from 'adaptivecards';
|
|
24
24
|
import { formatDistanceToNow } from 'date-fns';
|
|
25
25
|
import { gql } from '@apollo/client';
|
|
@@ -64,6 +64,255 @@ function useDeleteNode() {
|
|
|
64
64
|
[deleteElements, getEdges, getNode, deleteNode, deleteEdge]
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
|
+
var BRAND_ACCENTS = [
|
|
68
|
+
[/gmail|google/, "#ea4335"],
|
|
69
|
+
[/slack/, "#611f69"],
|
|
70
|
+
[/github/, "#334155"],
|
|
71
|
+
[/gitlab/, "#fc6d26"],
|
|
72
|
+
[/stripe/, "#635bff"],
|
|
73
|
+
[/discord/, "#5865f2"],
|
|
74
|
+
[/notion/, "#111827"],
|
|
75
|
+
[/telegram/, "#2aabee"],
|
|
76
|
+
[/whatsapp/, "#25d366"],
|
|
77
|
+
[/openai/, "#10a37f"],
|
|
78
|
+
[/anthropic|claude/, "#d97757"],
|
|
79
|
+
[/twilio/, "#f22f46"],
|
|
80
|
+
[/sheet|excel/, "#21a366"],
|
|
81
|
+
[/http|api|webhook|rest/, "#6366f1"],
|
|
82
|
+
[/db|sql|postgres|mysql|mongo/, "#0ea5e9"]
|
|
83
|
+
];
|
|
84
|
+
var HASH_PALETTE = [
|
|
85
|
+
"#6366f1",
|
|
86
|
+
"#0ea5e9",
|
|
87
|
+
"#10b981",
|
|
88
|
+
"#f59e0b",
|
|
89
|
+
"#ef4444",
|
|
90
|
+
"#a855f7",
|
|
91
|
+
"#ec4899",
|
|
92
|
+
"#14b8a6",
|
|
93
|
+
"#f97316",
|
|
94
|
+
"#8b5cf6"
|
|
95
|
+
];
|
|
96
|
+
function nodeAccent(key) {
|
|
97
|
+
const k = (key || "").toLowerCase();
|
|
98
|
+
for (const [re, hex] of BRAND_ACCENTS) if (re.test(k)) return hex;
|
|
99
|
+
let h = 0;
|
|
100
|
+
for (let i = 0; i < k.length; i++) h = h * 31 + k.charCodeAt(i) >>> 0;
|
|
101
|
+
return HASH_PALETTE[h % HASH_PALETTE.length];
|
|
102
|
+
}
|
|
103
|
+
function tint(hex, pct = 14) {
|
|
104
|
+
return `color-mix(in srgb, ${hex} ${pct}%, transparent)`;
|
|
105
|
+
}
|
|
106
|
+
var NodeCard = React.forwardRef(
|
|
107
|
+
({
|
|
108
|
+
className,
|
|
109
|
+
selected = false,
|
|
110
|
+
executionStatus = "idle",
|
|
111
|
+
itemCount,
|
|
112
|
+
isTrigger = false,
|
|
113
|
+
accent = "#3b82f6",
|
|
114
|
+
onSettings,
|
|
115
|
+
onExecute,
|
|
116
|
+
onDelete,
|
|
117
|
+
isExecuting = false,
|
|
118
|
+
infoButton,
|
|
119
|
+
children,
|
|
120
|
+
...props
|
|
121
|
+
}, ref) => {
|
|
122
|
+
const [hovered, setHovered] = React.useState(false);
|
|
123
|
+
const statusRing = executionStatus === "running" ? "ring-2 ring-[var(--color-status-success-border)] animate-pulse-border" : executionStatus === "success" ? "ring-2 ring-[var(--color-status-success-border)]" : executionStatus === "error" ? "ring-2 ring-[var(--color-status-error-border)]" : "";
|
|
124
|
+
return /* @__PURE__ */ jsxs(
|
|
125
|
+
"div",
|
|
126
|
+
{
|
|
127
|
+
className: "group/node relative",
|
|
128
|
+
onMouseEnter: () => setHovered(true),
|
|
129
|
+
onMouseLeave: () => setHovered(false),
|
|
130
|
+
children: [
|
|
131
|
+
itemCount !== void 0 && itemCount > 0 && /* @__PURE__ */ jsx("div", { className: "absolute -top-7 left-1/2 -translate-x-1/2 z-10", children: /* @__PURE__ */ jsxs("div", { className: "rounded-full border border-border bg-card px-2 py-0.5 text-[10px] font-medium text-muted-foreground shadow-sm", children: [
|
|
132
|
+
itemCount,
|
|
133
|
+
" item",
|
|
134
|
+
itemCount !== 1 ? "s" : ""
|
|
135
|
+
] }) }),
|
|
136
|
+
(onSettings || onExecute || onDelete || infoButton) && /* @__PURE__ */ jsxs(
|
|
137
|
+
"div",
|
|
138
|
+
{
|
|
139
|
+
className: cn(
|
|
140
|
+
"absolute right-1 z-20 flex items-center gap-0.5 rounded-lg border border-border bg-card p-0.5 shadow-md transition-all duration-150",
|
|
141
|
+
hovered ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
|
|
142
|
+
),
|
|
143
|
+
style: {
|
|
144
|
+
// Inline offset (not a `-top-*` class) so it survives the host
|
|
145
|
+
// app's Tailwind scan of fe-sdk source, which drops some spacing
|
|
146
|
+
// utilities. The toolbar is ~30px tall; top:-15px centers it on
|
|
147
|
+
// the card's top edge (half outside, half over the card).
|
|
148
|
+
top: -15,
|
|
149
|
+
transform: hovered ? "translateY(0)" : "translateY(4px)"
|
|
150
|
+
},
|
|
151
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
152
|
+
children: [
|
|
153
|
+
onSettings && /* @__PURE__ */ jsx(ToolbarButton, { title: "Configure", onClick: onSettings, children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:sliders-horizontal", className: "size-4" }) }),
|
|
154
|
+
onExecute && /* @__PURE__ */ jsx(
|
|
155
|
+
ToolbarButton,
|
|
156
|
+
{
|
|
157
|
+
title: "Execute step",
|
|
158
|
+
onClick: onExecute,
|
|
159
|
+
disabled: isExecuting,
|
|
160
|
+
children: isExecuting ? /* @__PURE__ */ jsx(
|
|
161
|
+
Icon,
|
|
162
|
+
{
|
|
163
|
+
icon: "svg-spinners:ring-resize",
|
|
164
|
+
className: "size-4 text-[var(--color-status-success-text)]"
|
|
165
|
+
}
|
|
166
|
+
) : /* @__PURE__ */ jsx(
|
|
167
|
+
Icon,
|
|
168
|
+
{
|
|
169
|
+
icon: "mdi:play",
|
|
170
|
+
className: "size-4 text-[var(--color-status-success-text)]"
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
),
|
|
175
|
+
infoButton,
|
|
176
|
+
onDelete && /* @__PURE__ */ jsx(ToolbarButton, { title: "Delete", onClick: onDelete, children: /* @__PURE__ */ jsx(
|
|
177
|
+
Icon,
|
|
178
|
+
{
|
|
179
|
+
icon: "mynaui:trash",
|
|
180
|
+
className: "size-4 text-[var(--color-status-error-text)]"
|
|
181
|
+
}
|
|
182
|
+
) })
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
),
|
|
186
|
+
/* @__PURE__ */ jsxs(
|
|
187
|
+
"div",
|
|
188
|
+
{
|
|
189
|
+
ref,
|
|
190
|
+
"data-selected": selected,
|
|
191
|
+
className: cn(
|
|
192
|
+
"relative w-72 rounded-xl border border-border bg-card shadow-sm will-change-transform",
|
|
193
|
+
statusRing,
|
|
194
|
+
executionStatus === "success" && "animate-success-glow",
|
|
195
|
+
className
|
|
196
|
+
),
|
|
197
|
+
style: {
|
|
198
|
+
borderTop: `3px solid ${accent}`,
|
|
199
|
+
transition: "transform 0.15s ease, box-shadow 0.15s ease",
|
|
200
|
+
transform: hovered ? "translateY(-2px)" : "none",
|
|
201
|
+
boxShadow: hovered ? "0 2px 4px rgba(16,24,40,0.06), 0 16px 34px -12px rgba(16,24,40,0.24)" : void 0
|
|
202
|
+
},
|
|
203
|
+
...props,
|
|
204
|
+
children: [
|
|
205
|
+
/* @__PURE__ */ jsx(
|
|
206
|
+
"div",
|
|
207
|
+
{
|
|
208
|
+
className: "pointer-events-none absolute -inset-0.5 transition-opacity duration-150",
|
|
209
|
+
style: {
|
|
210
|
+
borderRadius: 14,
|
|
211
|
+
opacity: selected || hovered ? 1 : 0,
|
|
212
|
+
boxShadow: selected ? `0 0 0 2px ${accent}, 0 0 0 5px ${tint(accent, 18)}` : `0 0 0 2px ${accent}`
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
),
|
|
216
|
+
isTrigger && /* @__PURE__ */ jsx(
|
|
217
|
+
"div",
|
|
218
|
+
{
|
|
219
|
+
className: "absolute -top-2 -left-2 z-10 flex size-5 items-center justify-center rounded-full shadow-md ring-2 ring-card",
|
|
220
|
+
style: { backgroundColor: "var(--color-status-success-text)" },
|
|
221
|
+
children: /* @__PURE__ */ jsx(
|
|
222
|
+
Icon,
|
|
223
|
+
{
|
|
224
|
+
icon: "mdi:lightning-bolt",
|
|
225
|
+
className: "size-3",
|
|
226
|
+
style: { color: "var(--color-status-success-text-inverse)" }
|
|
227
|
+
}
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
),
|
|
231
|
+
children
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
),
|
|
235
|
+
executionStatus === "success" && /* @__PURE__ */ jsx(StatusCorner, { icon: "mdi:check", tone: "success" }),
|
|
236
|
+
executionStatus === "error" && /* @__PURE__ */ jsx(StatusCorner, { icon: "mdi:close", tone: "error" }),
|
|
237
|
+
executionStatus === "running" && /* @__PURE__ */ jsx(StatusCorner, { icon: "svg-spinners:ring-resize", tone: "success" })
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
NodeCard.displayName = "NodeCard";
|
|
244
|
+
function ToolbarButton({
|
|
245
|
+
title,
|
|
246
|
+
onClick,
|
|
247
|
+
disabled,
|
|
248
|
+
children
|
|
249
|
+
}) {
|
|
250
|
+
return /* @__PURE__ */ jsx(
|
|
251
|
+
"button",
|
|
252
|
+
{
|
|
253
|
+
type: "button",
|
|
254
|
+
title,
|
|
255
|
+
disabled,
|
|
256
|
+
onClick: (e) => {
|
|
257
|
+
e.stopPropagation();
|
|
258
|
+
onClick?.();
|
|
259
|
+
},
|
|
260
|
+
className: "flex size-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50",
|
|
261
|
+
children
|
|
262
|
+
}
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
function StatusCorner({
|
|
266
|
+
icon,
|
|
267
|
+
tone
|
|
268
|
+
}) {
|
|
269
|
+
const bg = tone === "success" ? "var(--color-status-success-bg)" : "var(--color-status-error-bg)";
|
|
270
|
+
const fg = tone === "success" ? "var(--color-status-success-text-inverse)" : "var(--color-status-error-text-inverse)";
|
|
271
|
+
return /* @__PURE__ */ jsx("div", { className: "absolute -bottom-1.5 -right-1.5 z-10", children: /* @__PURE__ */ jsx(
|
|
272
|
+
"div",
|
|
273
|
+
{
|
|
274
|
+
className: "rounded-full p-0.5 shadow-md animate-in zoom-in duration-200",
|
|
275
|
+
style: { backgroundColor: bg },
|
|
276
|
+
children: /* @__PURE__ */ jsx(Icon, { icon, className: "size-3", style: { color: fg } })
|
|
277
|
+
}
|
|
278
|
+
) });
|
|
279
|
+
}
|
|
280
|
+
var NodeCardHeader = React.forwardRef(
|
|
281
|
+
({ icon, appName, accentKey }, ref) => {
|
|
282
|
+
const accent = nodeAccent(accentKey);
|
|
283
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "flex items-center gap-2.5 px-3 pb-3 pt-4", children: [
|
|
284
|
+
/* @__PURE__ */ jsx(
|
|
285
|
+
"div",
|
|
286
|
+
{
|
|
287
|
+
className: "flex size-8 shrink-0 items-center justify-center rounded-lg",
|
|
288
|
+
style: {
|
|
289
|
+
backgroundColor: tint(accent, 13),
|
|
290
|
+
color: accent,
|
|
291
|
+
border: `1px solid ${tint(accent, 26)}`
|
|
292
|
+
},
|
|
293
|
+
children: /* @__PURE__ */ jsx(Icon, { icon, className: "size-[18px]" })
|
|
294
|
+
}
|
|
295
|
+
),
|
|
296
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: appName })
|
|
297
|
+
] });
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
NodeCardHeader.displayName = "NodeCardHeader";
|
|
301
|
+
var NodeCardBody = React.forwardRef(
|
|
302
|
+
({ operationName, description }, ref) => /* @__PURE__ */ jsxs(
|
|
303
|
+
"div",
|
|
304
|
+
{
|
|
305
|
+
ref,
|
|
306
|
+
className: "rounded-b-xl border-t border-border/60 px-3 pb-3 pt-2.5",
|
|
307
|
+
children: [
|
|
308
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Operation" }),
|
|
309
|
+
/* @__PURE__ */ jsx("div", { className: "mt-0.5 truncate font-mono text-[13px] font-bold text-card-foreground", children: operationName }),
|
|
310
|
+
description ? /* @__PURE__ */ jsx("p", { className: "mt-1 line-clamp-2 text-xs leading-snug text-muted-foreground", children: description }) : null
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
);
|
|
315
|
+
NodeCardBody.displayName = "NodeCardBody";
|
|
67
316
|
function CustomHandle({
|
|
68
317
|
className,
|
|
69
318
|
isConnectable,
|
|
@@ -105,7 +354,259 @@ function CustomHandle({
|
|
|
105
354
|
} : void 0,
|
|
106
355
|
...props
|
|
107
356
|
}
|
|
108
|
-
) });
|
|
357
|
+
) });
|
|
358
|
+
}
|
|
359
|
+
var TONE_COLORS = {
|
|
360
|
+
success: "var(--color-status-success-text)",
|
|
361
|
+
error: "var(--color-status-error-text)",
|
|
362
|
+
warning: "var(--color-status-warning-text)",
|
|
363
|
+
info: "#3b82f6",
|
|
364
|
+
neutral: "var(--muted-foreground, #6b7280)"
|
|
365
|
+
};
|
|
366
|
+
function isDynamicSpec(spec) {
|
|
367
|
+
return !!spec && !Array.isArray(spec) && typeof spec.fromStateRecord === "string";
|
|
368
|
+
}
|
|
369
|
+
var DEFAULT_HANDLES = [{ id: "source", label: "" }];
|
|
370
|
+
function resolveOutputHandles(data) {
|
|
371
|
+
const nodeData = data?.nodeData;
|
|
372
|
+
const spec = nodeData?.outputHandles ?? nodeData?.operations?.outputHandles;
|
|
373
|
+
if (!spec) return DEFAULT_HANDLES;
|
|
374
|
+
if (isDynamicSpec(spec)) {
|
|
375
|
+
const args = data?.args;
|
|
376
|
+
const record = args?.state?.[spec.fromStateRecord] ?? data?.[spec.fromStateRecord] ?? {};
|
|
377
|
+
const dynamic = Object.entries(record).filter(([, handleId]) => typeof handleId === "string" && handleId).map(([label, handleId]) => ({ id: handleId, label }));
|
|
378
|
+
return [...dynamic, ...spec.extra ?? []];
|
|
379
|
+
}
|
|
380
|
+
if (spec.length === 0) return DEFAULT_HANDLES;
|
|
381
|
+
return spec;
|
|
382
|
+
}
|
|
383
|
+
function OutputHandles({
|
|
384
|
+
nodeId,
|
|
385
|
+
handles,
|
|
386
|
+
accent,
|
|
387
|
+
isConnectable
|
|
388
|
+
}) {
|
|
389
|
+
const updateNodeInternals = useUpdateNodeInternals();
|
|
390
|
+
const signature = useMemo(
|
|
391
|
+
() => handles.map((h) => h.id).join("|"),
|
|
392
|
+
[handles]
|
|
393
|
+
);
|
|
394
|
+
useEffect(() => {
|
|
395
|
+
updateNodeInternals(nodeId);
|
|
396
|
+
}, [nodeId, signature, updateNodeInternals]);
|
|
397
|
+
if (handles.length === 1) {
|
|
398
|
+
const handle = handles[0];
|
|
399
|
+
return /* @__PURE__ */ jsx(
|
|
400
|
+
CustomHandle,
|
|
401
|
+
{
|
|
402
|
+
type: "source",
|
|
403
|
+
id: handle.id,
|
|
404
|
+
position: Position.Right,
|
|
405
|
+
isConnectable,
|
|
406
|
+
accent: handle.tone ? TONE_COLORS[handle.tone] : accent
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
const total = handles.length;
|
|
411
|
+
return /* @__PURE__ */ jsx(Fragment, { children: handles.map((handle, index) => {
|
|
412
|
+
const top = `${(index + 1) / (total + 1) * 100}%`;
|
|
413
|
+
const color = handle.tone ? TONE_COLORS[handle.tone] : accent;
|
|
414
|
+
return /* @__PURE__ */ jsxs(
|
|
415
|
+
"div",
|
|
416
|
+
{
|
|
417
|
+
className: "absolute right-0",
|
|
418
|
+
style: { top, transform: "translateY(-50%)" },
|
|
419
|
+
children: [
|
|
420
|
+
/* @__PURE__ */ jsx(
|
|
421
|
+
CustomHandle,
|
|
422
|
+
{
|
|
423
|
+
type: "source",
|
|
424
|
+
id: handle.id,
|
|
425
|
+
position: Position.Right,
|
|
426
|
+
isConnectable,
|
|
427
|
+
accent: color
|
|
428
|
+
}
|
|
429
|
+
),
|
|
430
|
+
handle.label && /* @__PURE__ */ jsx(
|
|
431
|
+
"span",
|
|
432
|
+
{
|
|
433
|
+
className: "pointer-events-none absolute whitespace-nowrap text-[10px] font-medium leading-none",
|
|
434
|
+
style: {
|
|
435
|
+
color,
|
|
436
|
+
left: "100%",
|
|
437
|
+
marginLeft: 16,
|
|
438
|
+
top: "50%",
|
|
439
|
+
transform: "translateY(-50%)"
|
|
440
|
+
},
|
|
441
|
+
title: handle.label,
|
|
442
|
+
children: handle.label
|
|
443
|
+
}
|
|
444
|
+
)
|
|
445
|
+
]
|
|
446
|
+
},
|
|
447
|
+
handle.id
|
|
448
|
+
);
|
|
449
|
+
}) });
|
|
450
|
+
}
|
|
451
|
+
var DEFAULT_INPUT_HANDLES = [{ id: "target", label: "" }];
|
|
452
|
+
function resolveInputHandles(data) {
|
|
453
|
+
const nodeData = data?.nodeData;
|
|
454
|
+
const spec = nodeData?.inputHandles ?? nodeData?.operations?.inputHandles;
|
|
455
|
+
if (!Array.isArray(spec) || spec.length === 0) return DEFAULT_INPUT_HANDLES;
|
|
456
|
+
return spec;
|
|
457
|
+
}
|
|
458
|
+
function InputHandles({
|
|
459
|
+
nodeId,
|
|
460
|
+
handles,
|
|
461
|
+
accent,
|
|
462
|
+
isConnectable
|
|
463
|
+
}) {
|
|
464
|
+
const updateNodeInternals = useUpdateNodeInternals();
|
|
465
|
+
const signature = useMemo(
|
|
466
|
+
() => handles.map((h) => h.id).join("|"),
|
|
467
|
+
[handles]
|
|
468
|
+
);
|
|
469
|
+
useEffect(() => {
|
|
470
|
+
updateNodeInternals(nodeId);
|
|
471
|
+
}, [nodeId, signature, updateNodeInternals]);
|
|
472
|
+
if (handles.length === 1) {
|
|
473
|
+
const handle = handles[0];
|
|
474
|
+
return /* @__PURE__ */ jsx(
|
|
475
|
+
CustomHandle,
|
|
476
|
+
{
|
|
477
|
+
type: "target",
|
|
478
|
+
id: handle.id,
|
|
479
|
+
position: Position.Left,
|
|
480
|
+
isConnectable,
|
|
481
|
+
accent: handle.tone ? TONE_COLORS[handle.tone] : accent
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
const total = handles.length;
|
|
486
|
+
return /* @__PURE__ */ jsx(Fragment, { children: handles.map((handle, index) => {
|
|
487
|
+
const top = `${(index + 1) / (total + 1) * 100}%`;
|
|
488
|
+
const color = handle.tone ? TONE_COLORS[handle.tone] : accent;
|
|
489
|
+
return /* @__PURE__ */ jsxs(
|
|
490
|
+
"div",
|
|
491
|
+
{
|
|
492
|
+
className: "absolute left-0",
|
|
493
|
+
style: { top, transform: "translateY(-50%)" },
|
|
494
|
+
children: [
|
|
495
|
+
/* @__PURE__ */ jsx(
|
|
496
|
+
CustomHandle,
|
|
497
|
+
{
|
|
498
|
+
type: "target",
|
|
499
|
+
id: handle.id,
|
|
500
|
+
position: Position.Left,
|
|
501
|
+
isConnectable,
|
|
502
|
+
accent: color
|
|
503
|
+
}
|
|
504
|
+
),
|
|
505
|
+
handle.label && /* @__PURE__ */ jsx(
|
|
506
|
+
"span",
|
|
507
|
+
{
|
|
508
|
+
className: "pointer-events-none absolute whitespace-nowrap text-[10px] font-medium leading-none",
|
|
509
|
+
style: {
|
|
510
|
+
color,
|
|
511
|
+
right: "100%",
|
|
512
|
+
marginRight: 16,
|
|
513
|
+
top: "50%",
|
|
514
|
+
transform: "translateY(-50%)"
|
|
515
|
+
},
|
|
516
|
+
title: handle.label,
|
|
517
|
+
children: handle.label
|
|
518
|
+
}
|
|
519
|
+
)
|
|
520
|
+
]
|
|
521
|
+
},
|
|
522
|
+
handle.id
|
|
523
|
+
);
|
|
524
|
+
}) });
|
|
525
|
+
}
|
|
526
|
+
function outputHandlesSpacerHeight(count2) {
|
|
527
|
+
return count2 > 2 ? (count2 - 2) * 26 : 0;
|
|
528
|
+
}
|
|
529
|
+
function LogicNodeCard({
|
|
530
|
+
title,
|
|
531
|
+
subtitle,
|
|
532
|
+
icon,
|
|
533
|
+
accent,
|
|
534
|
+
selected,
|
|
535
|
+
executionStatus,
|
|
536
|
+
itemCount,
|
|
537
|
+
isTrigger,
|
|
538
|
+
isExecuting,
|
|
539
|
+
nodeId,
|
|
540
|
+
inputHandles,
|
|
541
|
+
outputHandles,
|
|
542
|
+
isConnectable,
|
|
543
|
+
onDoubleClick,
|
|
544
|
+
onSettings,
|
|
545
|
+
onExecute,
|
|
546
|
+
onDelete,
|
|
547
|
+
infoButton
|
|
548
|
+
}) {
|
|
549
|
+
const minHeight = Math.max(
|
|
550
|
+
64,
|
|
551
|
+
Math.max(outputHandles.length, inputHandles.length) * 30 + 24
|
|
552
|
+
);
|
|
553
|
+
return /* @__PURE__ */ jsxs(
|
|
554
|
+
NodeCard,
|
|
555
|
+
{
|
|
556
|
+
className: "w-48",
|
|
557
|
+
"data-selected": selected,
|
|
558
|
+
selected,
|
|
559
|
+
onDoubleClick,
|
|
560
|
+
executionStatus,
|
|
561
|
+
itemCount,
|
|
562
|
+
isTrigger,
|
|
563
|
+
accent,
|
|
564
|
+
isExecuting,
|
|
565
|
+
onSettings,
|
|
566
|
+
onExecute,
|
|
567
|
+
onDelete,
|
|
568
|
+
infoButton,
|
|
569
|
+
children: [
|
|
570
|
+
/* @__PURE__ */ jsxs(
|
|
571
|
+
"div",
|
|
572
|
+
{
|
|
573
|
+
className: "flex flex-col items-center justify-center gap-1 px-3 py-3 text-center",
|
|
574
|
+
style: { minHeight },
|
|
575
|
+
children: [
|
|
576
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-9 items-center justify-center rounded-lg bg-muted", children: /* @__PURE__ */ jsx(Icon, { icon, className: "size-5", style: { color: accent } }) }),
|
|
577
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-full truncate text-sm font-semibold leading-tight", children: title }),
|
|
578
|
+
subtitle && /* @__PURE__ */ jsx(
|
|
579
|
+
"span",
|
|
580
|
+
{
|
|
581
|
+
className: "max-w-full truncate font-mono text-[10px] text-muted-foreground",
|
|
582
|
+
title: subtitle,
|
|
583
|
+
children: subtitle
|
|
584
|
+
}
|
|
585
|
+
)
|
|
586
|
+
]
|
|
587
|
+
}
|
|
588
|
+
),
|
|
589
|
+
/* @__PURE__ */ jsx(
|
|
590
|
+
InputHandles,
|
|
591
|
+
{
|
|
592
|
+
nodeId,
|
|
593
|
+
handles: inputHandles,
|
|
594
|
+
accent,
|
|
595
|
+
isConnectable
|
|
596
|
+
}
|
|
597
|
+
),
|
|
598
|
+
/* @__PURE__ */ jsx(
|
|
599
|
+
OutputHandles,
|
|
600
|
+
{
|
|
601
|
+
nodeId,
|
|
602
|
+
handles: outputHandles,
|
|
603
|
+
accent,
|
|
604
|
+
isConnectable
|
|
605
|
+
}
|
|
606
|
+
)
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
);
|
|
109
610
|
}
|
|
110
611
|
|
|
111
612
|
// src/modules/ui-blocks/registry.ts
|
|
@@ -173,27 +674,27 @@ function ExpressionEditor({
|
|
|
173
674
|
"button",
|
|
174
675
|
{
|
|
175
676
|
type: "button",
|
|
176
|
-
onClick: () => insertTemplate("{
|
|
677
|
+
onClick: () => insertTemplate("${TriggerInput.}"),
|
|
177
678
|
className: "text-xs px-2 py-0.5 rounded bg-primary/10 text-primary hover:bg-primary/20 transition-colors",
|
|
178
|
-
children: "{
|
|
679
|
+
children: "${TriggerInput}"
|
|
179
680
|
}
|
|
180
681
|
),
|
|
181
682
|
/* @__PURE__ */ jsx(
|
|
182
683
|
"button",
|
|
183
684
|
{
|
|
184
685
|
type: "button",
|
|
185
|
-
onClick: () => insertTemplate("{
|
|
686
|
+
onClick: () => insertTemplate("${output.}"),
|
|
186
687
|
className: "text-xs px-2 py-0.5 rounded bg-primary/10 text-primary hover:bg-primary/20 transition-colors",
|
|
187
|
-
children: "{
|
|
688
|
+
children: "${output}"
|
|
188
689
|
}
|
|
189
690
|
),
|
|
190
691
|
/* @__PURE__ */ jsx(
|
|
191
692
|
"button",
|
|
192
693
|
{
|
|
193
694
|
type: "button",
|
|
194
|
-
onClick: () => insertTemplate("{
|
|
695
|
+
onClick: () => insertTemplate("${WorkflowState[''].output}"),
|
|
195
696
|
className: "text-xs px-2 py-0.5 rounded bg-primary/10 text-primary hover:bg-primary/20 transition-colors",
|
|
196
|
-
children: "{
|
|
697
|
+
children: "${WorkflowState}"
|
|
197
698
|
}
|
|
198
699
|
)
|
|
199
700
|
] }),
|
|
@@ -7752,271 +8253,22 @@ function NodePropertyPanel({
|
|
|
7752
8253
|
/* @__PURE__ */ jsx("div", { className: "font-medium text-card-foreground", children: "Connection handled automatically" }),
|
|
7753
8254
|
/* @__PURE__ */ jsx("div", { children: "This node uses the workspace BigConsole app connection at run time. You only need to configure the DataSink target below." })
|
|
7754
8255
|
] })
|
|
7755
|
-
] }),
|
|
7756
|
-
/* @__PURE__ */ jsxs("div", { className: "flex pt-5 flex-col", children: [
|
|
7757
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/60 font-semibold", children: "Properties" }),
|
|
7758
|
-
resolvedUi ? /* @__PURE__ */ jsx(
|
|
7759
|
-
BlocksRenderer,
|
|
7760
|
-
{
|
|
7761
|
-
spec: resolvedUi.spec,
|
|
7762
|
-
synthesized: resolvedUi.synthesized,
|
|
7763
|
-
state: sampleData2,
|
|
7764
|
-
onApply: submittedData
|
|
7765
|
-
},
|
|
7766
|
-
`${id}:${data?.operation_name ?? ""}`
|
|
7767
|
-
) : /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground py-2", children: "No Properties" })
|
|
7768
|
-
] })
|
|
7769
|
-
] });
|
|
7770
|
-
}
|
|
7771
|
-
var BRAND_ACCENTS = [
|
|
7772
|
-
[/gmail|google/, "#ea4335"],
|
|
7773
|
-
[/slack/, "#611f69"],
|
|
7774
|
-
[/github/, "#334155"],
|
|
7775
|
-
[/gitlab/, "#fc6d26"],
|
|
7776
|
-
[/stripe/, "#635bff"],
|
|
7777
|
-
[/discord/, "#5865f2"],
|
|
7778
|
-
[/notion/, "#111827"],
|
|
7779
|
-
[/telegram/, "#2aabee"],
|
|
7780
|
-
[/whatsapp/, "#25d366"],
|
|
7781
|
-
[/openai/, "#10a37f"],
|
|
7782
|
-
[/anthropic|claude/, "#d97757"],
|
|
7783
|
-
[/twilio/, "#f22f46"],
|
|
7784
|
-
[/sheet|excel/, "#21a366"],
|
|
7785
|
-
[/http|api|webhook|rest/, "#6366f1"],
|
|
7786
|
-
[/db|sql|postgres|mysql|mongo/, "#0ea5e9"]
|
|
7787
|
-
];
|
|
7788
|
-
var HASH_PALETTE = [
|
|
7789
|
-
"#6366f1",
|
|
7790
|
-
"#0ea5e9",
|
|
7791
|
-
"#10b981",
|
|
7792
|
-
"#f59e0b",
|
|
7793
|
-
"#ef4444",
|
|
7794
|
-
"#a855f7",
|
|
7795
|
-
"#ec4899",
|
|
7796
|
-
"#14b8a6",
|
|
7797
|
-
"#f97316",
|
|
7798
|
-
"#8b5cf6"
|
|
7799
|
-
];
|
|
7800
|
-
function nodeAccent(key) {
|
|
7801
|
-
const k = (key || "").toLowerCase();
|
|
7802
|
-
for (const [re, hex] of BRAND_ACCENTS) if (re.test(k)) return hex;
|
|
7803
|
-
let h = 0;
|
|
7804
|
-
for (let i = 0; i < k.length; i++) h = h * 31 + k.charCodeAt(i) >>> 0;
|
|
7805
|
-
return HASH_PALETTE[h % HASH_PALETTE.length];
|
|
7806
|
-
}
|
|
7807
|
-
function tint(hex, pct = 14) {
|
|
7808
|
-
return `color-mix(in srgb, ${hex} ${pct}%, transparent)`;
|
|
7809
|
-
}
|
|
7810
|
-
var NodeCard = React2.forwardRef(
|
|
7811
|
-
({
|
|
7812
|
-
className,
|
|
7813
|
-
selected = false,
|
|
7814
|
-
executionStatus = "idle",
|
|
7815
|
-
itemCount,
|
|
7816
|
-
isTrigger = false,
|
|
7817
|
-
accent = "#3b82f6",
|
|
7818
|
-
onSettings,
|
|
7819
|
-
onExecute,
|
|
7820
|
-
onDelete,
|
|
7821
|
-
isExecuting = false,
|
|
7822
|
-
infoButton,
|
|
7823
|
-
children,
|
|
7824
|
-
...props
|
|
7825
|
-
}, ref) => {
|
|
7826
|
-
const [hovered, setHovered] = React2.useState(false);
|
|
7827
|
-
const statusRing = executionStatus === "running" ? "ring-2 ring-[var(--color-status-success-border)] animate-pulse-border" : executionStatus === "success" ? "ring-2 ring-[var(--color-status-success-border)]" : executionStatus === "error" ? "ring-2 ring-[var(--color-status-error-border)]" : "";
|
|
7828
|
-
return /* @__PURE__ */ jsxs(
|
|
7829
|
-
"div",
|
|
7830
|
-
{
|
|
7831
|
-
className: "group/node relative",
|
|
7832
|
-
onMouseEnter: () => setHovered(true),
|
|
7833
|
-
onMouseLeave: () => setHovered(false),
|
|
7834
|
-
children: [
|
|
7835
|
-
itemCount !== void 0 && itemCount > 0 && /* @__PURE__ */ jsx("div", { className: "absolute -top-7 left-1/2 -translate-x-1/2 z-10", children: /* @__PURE__ */ jsxs("div", { className: "rounded-full border border-border bg-card px-2 py-0.5 text-[10px] font-medium text-muted-foreground shadow-sm", children: [
|
|
7836
|
-
itemCount,
|
|
7837
|
-
" item",
|
|
7838
|
-
itemCount !== 1 ? "s" : ""
|
|
7839
|
-
] }) }),
|
|
7840
|
-
(onSettings || onExecute || onDelete || infoButton) && /* @__PURE__ */ jsxs(
|
|
7841
|
-
"div",
|
|
7842
|
-
{
|
|
7843
|
-
className: cn(
|
|
7844
|
-
"absolute right-1 z-20 flex items-center gap-0.5 rounded-lg border border-border bg-card p-0.5 shadow-md transition-all duration-150",
|
|
7845
|
-
hovered ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
|
|
7846
|
-
),
|
|
7847
|
-
style: {
|
|
7848
|
-
// Inline offset (not a `-top-*` class) so it survives the host
|
|
7849
|
-
// app's Tailwind scan of fe-sdk source, which drops some spacing
|
|
7850
|
-
// utilities. The toolbar is ~30px tall; top:-15px centers it on
|
|
7851
|
-
// the card's top edge (half outside, half over the card).
|
|
7852
|
-
top: -15,
|
|
7853
|
-
transform: hovered ? "translateY(0)" : "translateY(4px)"
|
|
7854
|
-
},
|
|
7855
|
-
onDoubleClick: (e) => e.stopPropagation(),
|
|
7856
|
-
children: [
|
|
7857
|
-
onSettings && /* @__PURE__ */ jsx(ToolbarButton, { title: "Configure", onClick: onSettings, children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:sliders-horizontal", className: "size-4" }) }),
|
|
7858
|
-
onExecute && /* @__PURE__ */ jsx(
|
|
7859
|
-
ToolbarButton,
|
|
7860
|
-
{
|
|
7861
|
-
title: "Execute step",
|
|
7862
|
-
onClick: onExecute,
|
|
7863
|
-
disabled: isExecuting,
|
|
7864
|
-
children: isExecuting ? /* @__PURE__ */ jsx(
|
|
7865
|
-
Icon,
|
|
7866
|
-
{
|
|
7867
|
-
icon: "svg-spinners:ring-resize",
|
|
7868
|
-
className: "size-4 text-[var(--color-status-success-text)]"
|
|
7869
|
-
}
|
|
7870
|
-
) : /* @__PURE__ */ jsx(
|
|
7871
|
-
Icon,
|
|
7872
|
-
{
|
|
7873
|
-
icon: "mdi:play",
|
|
7874
|
-
className: "size-4 text-[var(--color-status-success-text)]"
|
|
7875
|
-
}
|
|
7876
|
-
)
|
|
7877
|
-
}
|
|
7878
|
-
),
|
|
7879
|
-
infoButton,
|
|
7880
|
-
onDelete && /* @__PURE__ */ jsx(ToolbarButton, { title: "Delete", onClick: onDelete, children: /* @__PURE__ */ jsx(
|
|
7881
|
-
Icon,
|
|
7882
|
-
{
|
|
7883
|
-
icon: "mynaui:trash",
|
|
7884
|
-
className: "size-4 text-[var(--color-status-error-text)]"
|
|
7885
|
-
}
|
|
7886
|
-
) })
|
|
7887
|
-
]
|
|
7888
|
-
}
|
|
7889
|
-
),
|
|
7890
|
-
/* @__PURE__ */ jsxs(
|
|
7891
|
-
"div",
|
|
7892
|
-
{
|
|
7893
|
-
ref,
|
|
7894
|
-
"data-selected": selected,
|
|
7895
|
-
className: cn(
|
|
7896
|
-
"relative w-72 rounded-xl border border-border bg-card shadow-sm will-change-transform",
|
|
7897
|
-
statusRing,
|
|
7898
|
-
executionStatus === "success" && "animate-success-glow",
|
|
7899
|
-
className
|
|
7900
|
-
),
|
|
7901
|
-
style: {
|
|
7902
|
-
borderTop: `3px solid ${accent}`,
|
|
7903
|
-
transition: "transform 0.15s ease, box-shadow 0.15s ease",
|
|
7904
|
-
transform: hovered ? "translateY(-2px)" : "none",
|
|
7905
|
-
boxShadow: hovered ? "0 2px 4px rgba(16,24,40,0.06), 0 16px 34px -12px rgba(16,24,40,0.24)" : void 0
|
|
7906
|
-
},
|
|
7907
|
-
...props,
|
|
7908
|
-
children: [
|
|
7909
|
-
/* @__PURE__ */ jsx(
|
|
7910
|
-
"div",
|
|
7911
|
-
{
|
|
7912
|
-
className: "pointer-events-none absolute -inset-0.5 transition-opacity duration-150",
|
|
7913
|
-
style: {
|
|
7914
|
-
borderRadius: 14,
|
|
7915
|
-
opacity: selected || hovered ? 1 : 0,
|
|
7916
|
-
boxShadow: selected ? `0 0 0 2px ${accent}, 0 0 0 5px ${tint(accent, 18)}` : `0 0 0 2px ${accent}`
|
|
7917
|
-
}
|
|
7918
|
-
}
|
|
7919
|
-
),
|
|
7920
|
-
isTrigger && /* @__PURE__ */ jsx(
|
|
7921
|
-
"div",
|
|
7922
|
-
{
|
|
7923
|
-
className: "absolute -top-2 -left-2 z-10 flex size-5 items-center justify-center rounded-full shadow-md ring-2 ring-card",
|
|
7924
|
-
style: { backgroundColor: "var(--color-status-success-text)" },
|
|
7925
|
-
children: /* @__PURE__ */ jsx(
|
|
7926
|
-
Icon,
|
|
7927
|
-
{
|
|
7928
|
-
icon: "mdi:lightning-bolt",
|
|
7929
|
-
className: "size-3",
|
|
7930
|
-
style: { color: "var(--color-status-success-text-inverse)" }
|
|
7931
|
-
}
|
|
7932
|
-
)
|
|
7933
|
-
}
|
|
7934
|
-
),
|
|
7935
|
-
children
|
|
7936
|
-
]
|
|
7937
|
-
}
|
|
7938
|
-
),
|
|
7939
|
-
executionStatus === "success" && /* @__PURE__ */ jsx(StatusCorner, { icon: "mdi:check", tone: "success" }),
|
|
7940
|
-
executionStatus === "error" && /* @__PURE__ */ jsx(StatusCorner, { icon: "mdi:close", tone: "error" }),
|
|
7941
|
-
executionStatus === "running" && /* @__PURE__ */ jsx(StatusCorner, { icon: "svg-spinners:ring-resize", tone: "success" })
|
|
7942
|
-
]
|
|
7943
|
-
}
|
|
7944
|
-
);
|
|
7945
|
-
}
|
|
7946
|
-
);
|
|
7947
|
-
NodeCard.displayName = "NodeCard";
|
|
7948
|
-
function ToolbarButton({
|
|
7949
|
-
title,
|
|
7950
|
-
onClick,
|
|
7951
|
-
disabled,
|
|
7952
|
-
children
|
|
7953
|
-
}) {
|
|
7954
|
-
return /* @__PURE__ */ jsx(
|
|
7955
|
-
"button",
|
|
7956
|
-
{
|
|
7957
|
-
type: "button",
|
|
7958
|
-
title,
|
|
7959
|
-
disabled,
|
|
7960
|
-
onClick: (e) => {
|
|
7961
|
-
e.stopPropagation();
|
|
7962
|
-
onClick?.();
|
|
7963
|
-
},
|
|
7964
|
-
className: "flex size-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50",
|
|
7965
|
-
children
|
|
7966
|
-
}
|
|
7967
|
-
);
|
|
7968
|
-
}
|
|
7969
|
-
function StatusCorner({
|
|
7970
|
-
icon,
|
|
7971
|
-
tone
|
|
7972
|
-
}) {
|
|
7973
|
-
const bg = tone === "success" ? "var(--color-status-success-bg)" : "var(--color-status-error-bg)";
|
|
7974
|
-
const fg = tone === "success" ? "var(--color-status-success-text-inverse)" : "var(--color-status-error-text-inverse)";
|
|
7975
|
-
return /* @__PURE__ */ jsx("div", { className: "absolute -bottom-1.5 -right-1.5 z-10", children: /* @__PURE__ */ jsx(
|
|
7976
|
-
"div",
|
|
7977
|
-
{
|
|
7978
|
-
className: "rounded-full p-0.5 shadow-md animate-in zoom-in duration-200",
|
|
7979
|
-
style: { backgroundColor: bg },
|
|
7980
|
-
children: /* @__PURE__ */ jsx(Icon, { icon, className: "size-3", style: { color: fg } })
|
|
7981
|
-
}
|
|
7982
|
-
) });
|
|
7983
|
-
}
|
|
7984
|
-
var NodeCardHeader = React2.forwardRef(
|
|
7985
|
-
({ icon, appName, accentKey }, ref) => {
|
|
7986
|
-
const accent = nodeAccent(accentKey);
|
|
7987
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: "flex items-center gap-2.5 px-3 pb-3 pt-4", children: [
|
|
7988
|
-
/* @__PURE__ */ jsx(
|
|
7989
|
-
"div",
|
|
8256
|
+
] }),
|
|
8257
|
+
/* @__PURE__ */ jsxs("div", { className: "flex pt-5 flex-col", children: [
|
|
8258
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/60 font-semibold", children: "Properties" }),
|
|
8259
|
+
resolvedUi ? /* @__PURE__ */ jsx(
|
|
8260
|
+
BlocksRenderer,
|
|
7990
8261
|
{
|
|
7991
|
-
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
] });
|
|
8002
|
-
}
|
|
8003
|
-
);
|
|
8004
|
-
NodeCardHeader.displayName = "NodeCardHeader";
|
|
8005
|
-
var NodeCardBody = React2.forwardRef(
|
|
8006
|
-
({ operationName, description }, ref) => /* @__PURE__ */ jsxs(
|
|
8007
|
-
"div",
|
|
8008
|
-
{
|
|
8009
|
-
ref,
|
|
8010
|
-
className: "rounded-b-xl border-t border-border/60 px-3 pb-3 pt-2.5",
|
|
8011
|
-
children: [
|
|
8012
|
-
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Operation" }),
|
|
8013
|
-
/* @__PURE__ */ jsx("div", { className: "mt-0.5 truncate font-mono text-[13px] font-bold text-card-foreground", children: operationName }),
|
|
8014
|
-
description ? /* @__PURE__ */ jsx("p", { className: "mt-1 line-clamp-2 text-xs leading-snug text-muted-foreground", children: description }) : null
|
|
8015
|
-
]
|
|
8016
|
-
}
|
|
8017
|
-
)
|
|
8018
|
-
);
|
|
8019
|
-
NodeCardBody.displayName = "NodeCardBody";
|
|
8262
|
+
spec: resolvedUi.spec,
|
|
8263
|
+
synthesized: resolvedUi.synthesized,
|
|
8264
|
+
state: sampleData2,
|
|
8265
|
+
onApply: submittedData
|
|
8266
|
+
},
|
|
8267
|
+
`${id}:${data?.operation_name ?? ""}`
|
|
8268
|
+
) : /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground py-2", children: "No Properties" })
|
|
8269
|
+
] })
|
|
8270
|
+
] });
|
|
8271
|
+
}
|
|
8020
8272
|
var nodeDetails = {
|
|
8021
8273
|
node_type: "gmail_reader",
|
|
8022
8274
|
version: "1.0.0",
|
|
@@ -8873,7 +9125,12 @@ var getNodeMetadata = (value) => {
|
|
|
8873
9125
|
const nodeStatus = nodeStatuses[id] || "idle";
|
|
8874
9126
|
const executionStatus = nodeStatus === "success" ? "success" : nodeStatus === "error" ? "error" : nodeStatus === "running" ? "running" : "idle";
|
|
8875
9127
|
const itemCount = nodeItemCounts[id];
|
|
8876
|
-
const
|
|
9128
|
+
const nodeKinds = data?.nodeData?.kind;
|
|
9129
|
+
const pinnedOpType = (data?.operation_type || "").toLowerCase();
|
|
9130
|
+
const isTrigger = pinnedOpType === "trigger" || (value?.type || "").toLowerCase().includes("trigger") || // Kind-based detection only when NO operation is pinned: dual-role
|
|
9131
|
+
// nodes (e.g. Gmail: trigger kind + action operations) must follow
|
|
9132
|
+
// their pinned operation's role, not the manifest kind.
|
|
9133
|
+
Array.isArray(nodeKinds) && nodeKinds.includes("trigger") && pinnedOpType === "";
|
|
8877
9134
|
const appName = (meta.title || nodeType || "Node").split(/\s+/)[0].toUpperCase();
|
|
8878
9135
|
const operationDisplay = nodeType === "integration/channel" ? (() => {
|
|
8879
9136
|
const explicitRole = data.args?.state?.role;
|
|
@@ -8885,6 +9142,65 @@ var getNodeMetadata = (value) => {
|
|
|
8885
9142
|
(value?.type || "").toLowerCase()
|
|
8886
9143
|
);
|
|
8887
9144
|
const roleAccent = isTrigger ? "#10b981" : isLogicNode ? "#f59e0b" : "#3b82f6";
|
|
9145
|
+
const outputHandles = resolveOutputHandles(
|
|
9146
|
+
data
|
|
9147
|
+
);
|
|
9148
|
+
const inputHandles = resolveInputHandles(
|
|
9149
|
+
data
|
|
9150
|
+
);
|
|
9151
|
+
const handleSpacer = outputHandlesSpacerHeight(
|
|
9152
|
+
Math.max(outputHandles.length, inputHandles.length)
|
|
9153
|
+
);
|
|
9154
|
+
const manifestKind = data?.nodeData?.kind;
|
|
9155
|
+
const isControlFlowNode = (value?.type || "").startsWith("internal:") && (Array.isArray(manifestKind) ? manifestKind.includes("control") : isLogicNode);
|
|
9156
|
+
if (isControlFlowNode) {
|
|
9157
|
+
const argsState = data?.args?.state;
|
|
9158
|
+
const rules = argsState?.rules;
|
|
9159
|
+
const mode = argsState?.mode;
|
|
9160
|
+
const logicSubtitle = Array.isArray(rules) ? `${rules.length} rule${rules.length === 1 ? "" : "s"}` : typeof mode === "string" ? mode : void 0;
|
|
9161
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
9162
|
+
/* @__PURE__ */ jsx(
|
|
9163
|
+
LogicNodeCard,
|
|
9164
|
+
{
|
|
9165
|
+
nodeId: id,
|
|
9166
|
+
title: data?.label || meta.title,
|
|
9167
|
+
subtitle: logicSubtitle,
|
|
9168
|
+
icon: meta.icon,
|
|
9169
|
+
accent: roleAccent,
|
|
9170
|
+
selected: !!selected,
|
|
9171
|
+
executionStatus,
|
|
9172
|
+
itemCount,
|
|
9173
|
+
isTrigger,
|
|
9174
|
+
isExecuting: isThisNodeExecuting,
|
|
9175
|
+
inputHandles,
|
|
9176
|
+
outputHandles,
|
|
9177
|
+
isConnectable: typeof isConnectable === "boolean" ? isConnectable : void 0,
|
|
9178
|
+
onDoubleClick: handleOpenNdv,
|
|
9179
|
+
onSettings: handleShowNodeProperties,
|
|
9180
|
+
onExecute: handleExecuteStep,
|
|
9181
|
+
onDelete: handleDeleteNode,
|
|
9182
|
+
infoButton: /* @__PURE__ */ jsx(
|
|
9183
|
+
NodeInfoButtonWithModal,
|
|
9184
|
+
{
|
|
9185
|
+
metadata: {
|
|
9186
|
+
icon: meta.icon,
|
|
9187
|
+
title: meta.title,
|
|
9188
|
+
description: nodeDescription,
|
|
9189
|
+
gradientColor: meta.gradientColor
|
|
9190
|
+
}
|
|
9191
|
+
}
|
|
9192
|
+
)
|
|
9193
|
+
}
|
|
9194
|
+
),
|
|
9195
|
+
/* @__PURE__ */ jsx(
|
|
9196
|
+
AdapterConnectors,
|
|
9197
|
+
{
|
|
9198
|
+
nodeId: id,
|
|
9199
|
+
adapters: data?.nodeData?.nodeAdapters
|
|
9200
|
+
}
|
|
9201
|
+
)
|
|
9202
|
+
] });
|
|
9203
|
+
}
|
|
8888
9204
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
8889
9205
|
/* @__PURE__ */ jsxs(
|
|
8890
9206
|
NodeCard,
|
|
@@ -8920,31 +9236,35 @@ var getNodeMetadata = (value) => {
|
|
|
8920
9236
|
accentKey: value?.type || meta.title
|
|
8921
9237
|
}
|
|
8922
9238
|
),
|
|
8923
|
-
|
|
9239
|
+
operationDisplay === "execute" && (value?.type || "").startsWith("internal:") || isTrigger ? (
|
|
9240
|
+
// Internal single-op nodes ('execute') and triggers: the operation
|
|
9241
|
+
// name is an implementation detail, not a user choice — show only
|
|
9242
|
+
// the description (n8n-style).
|
|
9243
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-b-xl border-t border-border/60 px-3 pb-3 pt-2.5", children: /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-xs leading-snug text-muted-foreground", children: nodeDescription }) })
|
|
9244
|
+
) : /* @__PURE__ */ jsx(
|
|
8924
9245
|
NodeCardBody,
|
|
8925
9246
|
{
|
|
8926
9247
|
operationName: operationDisplay,
|
|
8927
9248
|
description: nodeDescription
|
|
8928
9249
|
}
|
|
8929
9250
|
),
|
|
8930
|
-
/* @__PURE__ */ jsx(
|
|
8931
|
-
|
|
9251
|
+
handleSpacer > 0 && /* @__PURE__ */ jsx("div", { style: { height: handleSpacer } }),
|
|
9252
|
+
!isTrigger && /* @__PURE__ */ jsx(
|
|
9253
|
+
InputHandles,
|
|
8932
9254
|
{
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
isConnectable
|
|
8937
|
-
accent: roleAccent
|
|
9255
|
+
nodeId: id,
|
|
9256
|
+
handles: inputHandles,
|
|
9257
|
+
accent: roleAccent,
|
|
9258
|
+
isConnectable: typeof isConnectable === "boolean" ? isConnectable : void 0
|
|
8938
9259
|
}
|
|
8939
9260
|
),
|
|
8940
9261
|
/* @__PURE__ */ jsx(
|
|
8941
|
-
|
|
9262
|
+
OutputHandles,
|
|
8942
9263
|
{
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
isConnectable
|
|
8947
|
-
accent: roleAccent
|
|
9264
|
+
nodeId: id,
|
|
9265
|
+
handles: outputHandles,
|
|
9266
|
+
accent: roleAccent,
|
|
9267
|
+
isConnectable: typeof isConnectable === "boolean" ? isConnectable : void 0
|
|
8948
9268
|
}
|
|
8949
9269
|
)
|
|
8950
9270
|
]
|
|
@@ -12490,7 +12810,7 @@ function TemplateCard({
|
|
|
12490
12810
|
onClick,
|
|
12491
12811
|
onUseTemplate
|
|
12492
12812
|
}) {
|
|
12493
|
-
const [imageError, setImageError] =
|
|
12813
|
+
const [imageError, setImageError] = React__default.useState(false);
|
|
12494
12814
|
const previewImage = template.screenshots?.[0] || template.icon || void 0;
|
|
12495
12815
|
const hasPreview = Boolean(previewImage) && !imageError;
|
|
12496
12816
|
const handleUseTemplate = (e) => {
|
|
@@ -13350,7 +13670,7 @@ function ThemeProvider2({
|
|
|
13350
13670
|
defaultTheme = "system",
|
|
13351
13671
|
storageKey = "vite-ui-theme"
|
|
13352
13672
|
}) {
|
|
13353
|
-
|
|
13673
|
+
React.useEffect(() => {
|
|
13354
13674
|
if (typeof window !== "undefined") {
|
|
13355
13675
|
try {
|
|
13356
13676
|
localStorage.removeItem(storageKey);
|
|
@@ -14270,8 +14590,8 @@ function toast5({ ...props }) {
|
|
|
14270
14590
|
};
|
|
14271
14591
|
}
|
|
14272
14592
|
function useToast() {
|
|
14273
|
-
const [state, setState] =
|
|
14274
|
-
|
|
14593
|
+
const [state, setState] = React.useState(memoryState);
|
|
14594
|
+
React.useEffect(() => {
|
|
14275
14595
|
listeners.push(setState);
|
|
14276
14596
|
return () => {
|
|
14277
14597
|
const index = listeners.indexOf(setState);
|
|
@@ -19290,6 +19610,9 @@ function buildOperationSeed(type, operationName, existingData) {
|
|
|
19290
19610
|
if (!op) return null;
|
|
19291
19611
|
const manifest = config2.defaultData?.nodeData;
|
|
19292
19612
|
const prevArgs = existingData.args ?? {};
|
|
19613
|
+
const manifestOps = manifest?.operations;
|
|
19614
|
+
const outputHandles = manifest?.outputHandles ?? manifestOps?.outputHandles;
|
|
19615
|
+
const inputHandles = manifest?.inputHandles ?? manifestOps?.inputHandles;
|
|
19293
19616
|
return {
|
|
19294
19617
|
...existingData,
|
|
19295
19618
|
operation_name: op.name,
|
|
@@ -19300,7 +19623,12 @@ function buildOperationSeed(type, operationName, existingData) {
|
|
|
19300
19623
|
state: { ...op.adaptive_card?.defaultValue ?? {} }
|
|
19301
19624
|
},
|
|
19302
19625
|
// Slim manifest: keep node-level metadata but only the pinned operation.
|
|
19303
|
-
nodeData: {
|
|
19626
|
+
nodeData: {
|
|
19627
|
+
...manifest ?? {},
|
|
19628
|
+
...outputHandles !== void 0 ? { outputHandles } : {},
|
|
19629
|
+
...inputHandles !== void 0 ? { inputHandles } : {},
|
|
19630
|
+
operations: [op]
|
|
19631
|
+
}
|
|
19304
19632
|
};
|
|
19305
19633
|
}
|
|
19306
19634
|
function useInsertNode() {
|
|
@@ -19320,10 +19648,18 @@ function useInsertNode() {
|
|
|
19320
19648
|
position: _pos,
|
|
19321
19649
|
selected: true
|
|
19322
19650
|
});
|
|
19323
|
-
|
|
19651
|
+
let pinTo = operationName;
|
|
19652
|
+
if (!pinTo) {
|
|
19653
|
+
const config2 = NODE_CONFIGS.find((c) => c.type === type);
|
|
19654
|
+
const ops = config2?.operations ?? [];
|
|
19655
|
+
if (ops.length === 1 && ops[0]?.name) {
|
|
19656
|
+
pinTo = ops[0].name;
|
|
19657
|
+
}
|
|
19658
|
+
}
|
|
19659
|
+
if (pinTo) {
|
|
19324
19660
|
const seeded = buildOperationSeed(
|
|
19325
19661
|
type,
|
|
19326
|
-
|
|
19662
|
+
pinTo,
|
|
19327
19663
|
newNode.data ?? {}
|
|
19328
19664
|
);
|
|
19329
19665
|
if (seeded) newNode.data = seeded;
|
|
@@ -20907,6 +21243,449 @@ function FieldTree({
|
|
|
20907
21243
|
field.path
|
|
20908
21244
|
)) });
|
|
20909
21245
|
}
|
|
21246
|
+
function emptyGroup() {
|
|
21247
|
+
return { type: "group", combinator: "AND", children: [] };
|
|
21248
|
+
}
|
|
21249
|
+
function emptyRule(field = "") {
|
|
21250
|
+
return { type: "rule", field, operator: "==", value: "" };
|
|
21251
|
+
}
|
|
21252
|
+
var OPERATORS2 = {
|
|
21253
|
+
string: [
|
|
21254
|
+
{ value: "==", label: "equals", needsValue: true },
|
|
21255
|
+
{ value: "!=", label: "not equals", needsValue: true },
|
|
21256
|
+
{ value: "contains", label: "contains", needsValue: true },
|
|
21257
|
+
{ value: "notContains", label: "does not contain", needsValue: true },
|
|
21258
|
+
{ value: "startsWith", label: "starts with", needsValue: true },
|
|
21259
|
+
{ value: "endsWith", label: "ends with", needsValue: true },
|
|
21260
|
+
{ value: "regex", label: "matches regex", needsValue: true },
|
|
21261
|
+
{ value: "isEmpty", label: "is empty", needsValue: false },
|
|
21262
|
+
{ value: "isNotEmpty", label: "is not empty", needsValue: false },
|
|
21263
|
+
{ value: "isNull", label: "is null", needsValue: false },
|
|
21264
|
+
{ value: "isNotNull", label: "is not null", needsValue: false }
|
|
21265
|
+
],
|
|
21266
|
+
number: [
|
|
21267
|
+
{ value: "==", label: "equals", needsValue: true },
|
|
21268
|
+
{ value: "!=", label: "not equals", needsValue: true },
|
|
21269
|
+
{ value: ">", label: "greater than", needsValue: true },
|
|
21270
|
+
{ value: ">=", label: "greater or equal", needsValue: true },
|
|
21271
|
+
{ value: "<", label: "less than", needsValue: true },
|
|
21272
|
+
{ value: "<=", label: "less or equal", needsValue: true },
|
|
21273
|
+
{ value: "isNull", label: "is null", needsValue: false },
|
|
21274
|
+
{ value: "isNotNull", label: "is not null", needsValue: false }
|
|
21275
|
+
],
|
|
21276
|
+
boolean: [
|
|
21277
|
+
{ value: "isTrue", label: "is true", needsValue: false },
|
|
21278
|
+
{ value: "isFalse", label: "is false", needsValue: false },
|
|
21279
|
+
{ value: "isNull", label: "is null", needsValue: false },
|
|
21280
|
+
{ value: "isNotNull", label: "is not null", needsValue: false }
|
|
21281
|
+
],
|
|
21282
|
+
array: [
|
|
21283
|
+
{ value: "contains", label: "contains", needsValue: true },
|
|
21284
|
+
{ value: "notContains", label: "does not contain", needsValue: true },
|
|
21285
|
+
{ value: "isEmpty", label: "is empty", needsValue: false },
|
|
21286
|
+
{ value: "isNotEmpty", label: "is not empty", needsValue: false },
|
|
21287
|
+
{ value: "isNull", label: "is null", needsValue: false },
|
|
21288
|
+
{ value: "isNotNull", label: "is not null", needsValue: false }
|
|
21289
|
+
],
|
|
21290
|
+
object: [
|
|
21291
|
+
{ value: "hasProperty", label: "has property", needsValue: true },
|
|
21292
|
+
{ value: "isEmpty", label: "is empty", needsValue: false },
|
|
21293
|
+
{ value: "isNotEmpty", label: "is not empty", needsValue: false },
|
|
21294
|
+
{ value: "isNull", label: "is null", needsValue: false },
|
|
21295
|
+
{ value: "isNotNull", label: "is not null", needsValue: false }
|
|
21296
|
+
],
|
|
21297
|
+
any: [
|
|
21298
|
+
{ value: "==", label: "equals", needsValue: true },
|
|
21299
|
+
{ value: "!=", label: "not equals", needsValue: true },
|
|
21300
|
+
{ value: ">", label: "greater than", needsValue: true },
|
|
21301
|
+
{ value: "<", label: "less than", needsValue: true },
|
|
21302
|
+
{ value: "contains", label: "contains", needsValue: true },
|
|
21303
|
+
{ value: "isEmpty", label: "is empty", needsValue: false },
|
|
21304
|
+
{ value: "isNotEmpty", label: "is not empty", needsValue: false },
|
|
21305
|
+
{ value: "isNull", label: "is null", needsValue: false },
|
|
21306
|
+
{ value: "isNotNull", label: "is not null", needsValue: false }
|
|
21307
|
+
]
|
|
21308
|
+
};
|
|
21309
|
+
function operatorsFor(type) {
|
|
21310
|
+
return OPERATORS2[type ?? "any"] ?? OPERATORS2.any;
|
|
21311
|
+
}
|
|
21312
|
+
function flattenFields(nodes) {
|
|
21313
|
+
const out = [];
|
|
21314
|
+
const walk = (list) => {
|
|
21315
|
+
for (const node of list) {
|
|
21316
|
+
if (node.path) out.push({ path: node.path, type: node.type ?? "any" });
|
|
21317
|
+
if (Array.isArray(node.children)) walk(node.children);
|
|
21318
|
+
}
|
|
21319
|
+
};
|
|
21320
|
+
walk(nodes);
|
|
21321
|
+
return out.sort((a, b) => a.path.localeCompare(b.path));
|
|
21322
|
+
}
|
|
21323
|
+
var rowInput = "rounded-md border border-input bg-background px-2 py-1 text-xs outline-none focus:border-primary";
|
|
21324
|
+
function RuleRow({
|
|
21325
|
+
rule,
|
|
21326
|
+
fields,
|
|
21327
|
+
onChange,
|
|
21328
|
+
onRemove
|
|
21329
|
+
}) {
|
|
21330
|
+
const fieldType = fields.find((f) => f.path === rule.field)?.type ?? "any";
|
|
21331
|
+
const ops = operatorsFor(fieldType);
|
|
21332
|
+
const currentOp = ops.find((o) => o.value === rule.operator) ?? ops[0];
|
|
21333
|
+
const knownField = fields.some((f) => f.path === rule.field);
|
|
21334
|
+
return /* @__PURE__ */ jsxs(
|
|
21335
|
+
"div",
|
|
21336
|
+
{
|
|
21337
|
+
className: "flex flex-wrap items-center gap-1.5",
|
|
21338
|
+
"data-testid": "condition-rule",
|
|
21339
|
+
children: [
|
|
21340
|
+
fields.length > 0 && (knownField || rule.field === "") ? /* @__PURE__ */ jsxs(
|
|
21341
|
+
"select",
|
|
21342
|
+
{
|
|
21343
|
+
value: rule.field,
|
|
21344
|
+
onChange: (e) => {
|
|
21345
|
+
const nextField = e.target.value;
|
|
21346
|
+
const nextType = fields.find((f) => f.path === nextField)?.type ?? "any";
|
|
21347
|
+
const nextOps = operatorsFor(nextType);
|
|
21348
|
+
const operator = nextOps.some((o) => o.value === rule.operator) ? rule.operator : nextOps[0].value;
|
|
21349
|
+
onChange({ ...rule, field: nextField, operator });
|
|
21350
|
+
},
|
|
21351
|
+
className: cn(rowInput, "max-w-[180px] flex-1"),
|
|
21352
|
+
"data-testid": "condition-field",
|
|
21353
|
+
children: [
|
|
21354
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Select field\u2026" }),
|
|
21355
|
+
fields.map((f) => /* @__PURE__ */ jsxs("option", { value: f.path, children: [
|
|
21356
|
+
f.path,
|
|
21357
|
+
" (",
|
|
21358
|
+
f.type,
|
|
21359
|
+
")"
|
|
21360
|
+
] }, f.path)),
|
|
21361
|
+
/* @__PURE__ */ jsx("option", { value: "__custom__", children: "Custom path\u2026" })
|
|
21362
|
+
]
|
|
21363
|
+
}
|
|
21364
|
+
) : /* @__PURE__ */ jsx(
|
|
21365
|
+
"input",
|
|
21366
|
+
{
|
|
21367
|
+
type: "text",
|
|
21368
|
+
value: rule.field === "__custom__" ? "" : rule.field,
|
|
21369
|
+
placeholder: "field.path",
|
|
21370
|
+
onChange: (e) => onChange({ ...rule, field: e.target.value }),
|
|
21371
|
+
className: cn(rowInput, "max-w-[180px] flex-1 font-mono"),
|
|
21372
|
+
"data-testid": "condition-field"
|
|
21373
|
+
}
|
|
21374
|
+
),
|
|
21375
|
+
/* @__PURE__ */ jsx(
|
|
21376
|
+
"select",
|
|
21377
|
+
{
|
|
21378
|
+
value: currentOp.value,
|
|
21379
|
+
onChange: (e) => onChange({ ...rule, operator: e.target.value }),
|
|
21380
|
+
className: rowInput,
|
|
21381
|
+
"data-testid": "condition-operator",
|
|
21382
|
+
children: ops.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
21383
|
+
}
|
|
21384
|
+
),
|
|
21385
|
+
currentOp.needsValue && /* @__PURE__ */ jsx(
|
|
21386
|
+
"input",
|
|
21387
|
+
{
|
|
21388
|
+
type: fieldType === "number" ? "number" : "text",
|
|
21389
|
+
value: rule.value === null || rule.value === void 0 ? "" : String(rule.value),
|
|
21390
|
+
placeholder: "value",
|
|
21391
|
+
onChange: (e) => {
|
|
21392
|
+
const raw = e.target.value;
|
|
21393
|
+
const value = fieldType === "number" && raw.trim() !== "" && !Number.isNaN(Number(raw)) ? Number(raw) : raw;
|
|
21394
|
+
onChange({ ...rule, value });
|
|
21395
|
+
},
|
|
21396
|
+
className: cn(rowInput, "min-w-[90px] flex-1"),
|
|
21397
|
+
"data-testid": "condition-value"
|
|
21398
|
+
}
|
|
21399
|
+
),
|
|
21400
|
+
/* @__PURE__ */ jsx(
|
|
21401
|
+
"button",
|
|
21402
|
+
{
|
|
21403
|
+
type: "button",
|
|
21404
|
+
onClick: onRemove,
|
|
21405
|
+
title: "Remove condition",
|
|
21406
|
+
className: "rounded p-1 text-muted-foreground hover:text-[var(--color-status-error-text)]",
|
|
21407
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:trash", className: "size-3.5" })
|
|
21408
|
+
}
|
|
21409
|
+
)
|
|
21410
|
+
]
|
|
21411
|
+
}
|
|
21412
|
+
);
|
|
21413
|
+
}
|
|
21414
|
+
function GroupEditor({
|
|
21415
|
+
group,
|
|
21416
|
+
fields,
|
|
21417
|
+
depth,
|
|
21418
|
+
onChange,
|
|
21419
|
+
onRemove
|
|
21420
|
+
}) {
|
|
21421
|
+
const setChild = (index, child) => {
|
|
21422
|
+
const children = group.children.slice();
|
|
21423
|
+
children[index] = child;
|
|
21424
|
+
onChange({ ...group, children });
|
|
21425
|
+
};
|
|
21426
|
+
const removeChild = (index) => {
|
|
21427
|
+
onChange({
|
|
21428
|
+
...group,
|
|
21429
|
+
children: group.children.filter((_, i) => i !== index)
|
|
21430
|
+
});
|
|
21431
|
+
};
|
|
21432
|
+
return /* @__PURE__ */ jsxs(
|
|
21433
|
+
"div",
|
|
21434
|
+
{
|
|
21435
|
+
className: cn(
|
|
21436
|
+
"flex flex-col gap-1.5 rounded-md",
|
|
21437
|
+
depth > 0 && "border border-border/70 bg-muted/20 p-2"
|
|
21438
|
+
),
|
|
21439
|
+
"data-testid": `condition-group-depth-${depth}`,
|
|
21440
|
+
children: [
|
|
21441
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
21442
|
+
/* @__PURE__ */ jsx("div", { className: "flex overflow-hidden rounded-md border border-input text-[10px] font-semibold", children: ["AND", "OR"].map((c) => /* @__PURE__ */ jsx(
|
|
21443
|
+
"button",
|
|
21444
|
+
{
|
|
21445
|
+
type: "button",
|
|
21446
|
+
onClick: () => onChange({ ...group, combinator: c }),
|
|
21447
|
+
className: cn(
|
|
21448
|
+
"px-2 py-0.5",
|
|
21449
|
+
group.combinator === c ? "bg-primary text-primary-foreground" : "bg-background text-muted-foreground hover:text-foreground"
|
|
21450
|
+
),
|
|
21451
|
+
"data-testid": `combinator-${c}`,
|
|
21452
|
+
children: c
|
|
21453
|
+
},
|
|
21454
|
+
c
|
|
21455
|
+
)) }),
|
|
21456
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: group.combinator === "AND" ? "all conditions must match" : "any condition may match" }),
|
|
21457
|
+
onRemove && /* @__PURE__ */ jsx(
|
|
21458
|
+
"button",
|
|
21459
|
+
{
|
|
21460
|
+
type: "button",
|
|
21461
|
+
onClick: onRemove,
|
|
21462
|
+
title: "Remove group",
|
|
21463
|
+
className: "ml-auto rounded p-1 text-muted-foreground hover:text-[var(--color-status-error-text)]",
|
|
21464
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:trash", className: "size-3.5" })
|
|
21465
|
+
}
|
|
21466
|
+
)
|
|
21467
|
+
] }),
|
|
21468
|
+
group.children.map(
|
|
21469
|
+
(child, index) => child.type === "rule" ? /* @__PURE__ */ jsx(
|
|
21470
|
+
RuleRow,
|
|
21471
|
+
{
|
|
21472
|
+
rule: child,
|
|
21473
|
+
fields,
|
|
21474
|
+
onChange: (next) => setChild(index, next),
|
|
21475
|
+
onRemove: () => removeChild(index)
|
|
21476
|
+
},
|
|
21477
|
+
index
|
|
21478
|
+
) : /* @__PURE__ */ jsx(
|
|
21479
|
+
GroupEditor,
|
|
21480
|
+
{
|
|
21481
|
+
group: child,
|
|
21482
|
+
fields,
|
|
21483
|
+
depth: depth + 1,
|
|
21484
|
+
onChange: (next) => setChild(index, next),
|
|
21485
|
+
onRemove: () => removeChild(index)
|
|
21486
|
+
},
|
|
21487
|
+
index
|
|
21488
|
+
)
|
|
21489
|
+
),
|
|
21490
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
21491
|
+
/* @__PURE__ */ jsxs(
|
|
21492
|
+
"button",
|
|
21493
|
+
{
|
|
21494
|
+
type: "button",
|
|
21495
|
+
onClick: () => onChange({
|
|
21496
|
+
...group,
|
|
21497
|
+
children: [...group.children, emptyRule(fields[0]?.path ?? "")]
|
|
21498
|
+
}),
|
|
21499
|
+
className: "flex items-center gap-1 text-[11px] font-medium text-primary hover:underline",
|
|
21500
|
+
"data-testid": "add-condition",
|
|
21501
|
+
children: [
|
|
21502
|
+
/* @__PURE__ */ jsx(Icon, { icon: "basil:add-solid", className: "size-3.5" }),
|
|
21503
|
+
" Add condition"
|
|
21504
|
+
]
|
|
21505
|
+
}
|
|
21506
|
+
),
|
|
21507
|
+
depth < 2 && /* @__PURE__ */ jsxs(
|
|
21508
|
+
"button",
|
|
21509
|
+
{
|
|
21510
|
+
type: "button",
|
|
21511
|
+
onClick: () => onChange({
|
|
21512
|
+
...group,
|
|
21513
|
+
children: [...group.children, emptyGroup()]
|
|
21514
|
+
}),
|
|
21515
|
+
className: "flex items-center gap-1 text-[11px] font-medium text-muted-foreground hover:text-foreground",
|
|
21516
|
+
"data-testid": "add-group",
|
|
21517
|
+
children: [
|
|
21518
|
+
/* @__PURE__ */ jsx(Icon, { icon: "basil:add-solid", className: "size-3.5" }),
|
|
21519
|
+
" Add group"
|
|
21520
|
+
]
|
|
21521
|
+
}
|
|
21522
|
+
)
|
|
21523
|
+
] })
|
|
21524
|
+
]
|
|
21525
|
+
}
|
|
21526
|
+
);
|
|
21527
|
+
}
|
|
21528
|
+
function ConditionTreeBuilder({
|
|
21529
|
+
value,
|
|
21530
|
+
fields,
|
|
21531
|
+
onChange
|
|
21532
|
+
}) {
|
|
21533
|
+
const tree = value && typeof value === "object" && value.type === "group" ? value : emptyGroup();
|
|
21534
|
+
return /* @__PURE__ */ jsx("div", { "data-testid": "condition-tree-builder", children: /* @__PURE__ */ jsx(
|
|
21535
|
+
GroupEditor,
|
|
21536
|
+
{
|
|
21537
|
+
group: tree,
|
|
21538
|
+
fields,
|
|
21539
|
+
depth: 0,
|
|
21540
|
+
onChange: (next) => onChange(next.children.length === 0 ? void 0 : next)
|
|
21541
|
+
}
|
|
21542
|
+
) });
|
|
21543
|
+
}
|
|
21544
|
+
function newRuleHandle(existing) {
|
|
21545
|
+
let n = existing.length;
|
|
21546
|
+
const taken = new Set(existing.map((r) => r.handle));
|
|
21547
|
+
let handle = `rule-${n}`;
|
|
21548
|
+
while (taken.has(handle)) handle = `rule-${++n}`;
|
|
21549
|
+
return handle;
|
|
21550
|
+
}
|
|
21551
|
+
function casesFromRules(rules) {
|
|
21552
|
+
const cases = {};
|
|
21553
|
+
rules.forEach((rule, index) => {
|
|
21554
|
+
cases[rule.name || `Rule ${index + 1}`] = rule.handle;
|
|
21555
|
+
});
|
|
21556
|
+
return cases;
|
|
21557
|
+
}
|
|
21558
|
+
function SwitchRulesEditor({
|
|
21559
|
+
rules,
|
|
21560
|
+
fallbackHandle,
|
|
21561
|
+
fields,
|
|
21562
|
+
onChange
|
|
21563
|
+
}) {
|
|
21564
|
+
const setRule = (index, rule) => {
|
|
21565
|
+
const next = rules.slice();
|
|
21566
|
+
next[index] = rule;
|
|
21567
|
+
onChange({ rules: next, fallbackHandle });
|
|
21568
|
+
};
|
|
21569
|
+
const move = (index, dir) => {
|
|
21570
|
+
const target = index + dir;
|
|
21571
|
+
if (target < 0 || target >= rules.length) return;
|
|
21572
|
+
const next = rules.slice();
|
|
21573
|
+
const tmp = next[index];
|
|
21574
|
+
next[index] = next[target];
|
|
21575
|
+
next[target] = tmp;
|
|
21576
|
+
onChange({ rules: next, fallbackHandle });
|
|
21577
|
+
};
|
|
21578
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", "data-testid": "switch-rules-editor", children: [
|
|
21579
|
+
rules.map((rule, index) => /* @__PURE__ */ jsxs(
|
|
21580
|
+
"div",
|
|
21581
|
+
{
|
|
21582
|
+
className: "rounded-md border border-border/70 bg-muted/10 p-2",
|
|
21583
|
+
"data-testid": `switch-rule-${index}`,
|
|
21584
|
+
children: [
|
|
21585
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-1.5 flex items-center gap-1.5", children: [
|
|
21586
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[10px] font-semibold text-muted-foreground", children: [
|
|
21587
|
+
index + 1,
|
|
21588
|
+
"."
|
|
21589
|
+
] }),
|
|
21590
|
+
/* @__PURE__ */ jsx(
|
|
21591
|
+
"input",
|
|
21592
|
+
{
|
|
21593
|
+
type: "text",
|
|
21594
|
+
value: rule.name,
|
|
21595
|
+
placeholder: `Rule ${index + 1}`,
|
|
21596
|
+
onChange: (e) => setRule(index, { ...rule, name: e.target.value }),
|
|
21597
|
+
className: cn(rowInput, "flex-1 font-medium"),
|
|
21598
|
+
"data-testid": "switch-rule-name"
|
|
21599
|
+
}
|
|
21600
|
+
),
|
|
21601
|
+
/* @__PURE__ */ jsx(
|
|
21602
|
+
"button",
|
|
21603
|
+
{
|
|
21604
|
+
type: "button",
|
|
21605
|
+
onClick: () => move(index, -1),
|
|
21606
|
+
disabled: index === 0,
|
|
21607
|
+
title: "Move up",
|
|
21608
|
+
className: "rounded p-0.5 text-muted-foreground hover:text-foreground disabled:opacity-30",
|
|
21609
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: "mdi:chevron-up", className: "size-4" })
|
|
21610
|
+
}
|
|
21611
|
+
),
|
|
21612
|
+
/* @__PURE__ */ jsx(
|
|
21613
|
+
"button",
|
|
21614
|
+
{
|
|
21615
|
+
type: "button",
|
|
21616
|
+
onClick: () => move(index, 1),
|
|
21617
|
+
disabled: index === rules.length - 1,
|
|
21618
|
+
title: "Move down",
|
|
21619
|
+
className: "rounded p-0.5 text-muted-foreground hover:text-foreground disabled:opacity-30",
|
|
21620
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: "mdi:chevron-down", className: "size-4" })
|
|
21621
|
+
}
|
|
21622
|
+
),
|
|
21623
|
+
/* @__PURE__ */ jsx(
|
|
21624
|
+
"button",
|
|
21625
|
+
{
|
|
21626
|
+
type: "button",
|
|
21627
|
+
onClick: () => onChange({
|
|
21628
|
+
rules: rules.filter((_, i) => i !== index),
|
|
21629
|
+
fallbackHandle
|
|
21630
|
+
}),
|
|
21631
|
+
title: "Remove rule",
|
|
21632
|
+
className: "rounded p-0.5 text-muted-foreground hover:text-[var(--color-status-error-text)]",
|
|
21633
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:trash", className: "size-3.5" })
|
|
21634
|
+
}
|
|
21635
|
+
)
|
|
21636
|
+
] }),
|
|
21637
|
+
/* @__PURE__ */ jsx(
|
|
21638
|
+
ConditionTreeBuilder,
|
|
21639
|
+
{
|
|
21640
|
+
value: rule.conditionTree,
|
|
21641
|
+
fields,
|
|
21642
|
+
onChange: (tree) => setRule(index, { ...rule, conditionTree: tree ?? emptyGroup() })
|
|
21643
|
+
}
|
|
21644
|
+
)
|
|
21645
|
+
]
|
|
21646
|
+
},
|
|
21647
|
+
rule.handle
|
|
21648
|
+
)),
|
|
21649
|
+
/* @__PURE__ */ jsxs(
|
|
21650
|
+
"button",
|
|
21651
|
+
{
|
|
21652
|
+
type: "button",
|
|
21653
|
+
onClick: () => onChange({
|
|
21654
|
+
rules: [
|
|
21655
|
+
...rules,
|
|
21656
|
+
{
|
|
21657
|
+
name: `Rule ${rules.length + 1}`,
|
|
21658
|
+
handle: newRuleHandle(rules),
|
|
21659
|
+
conditionTree: emptyGroup()
|
|
21660
|
+
}
|
|
21661
|
+
],
|
|
21662
|
+
fallbackHandle
|
|
21663
|
+
}),
|
|
21664
|
+
className: "flex w-fit items-center gap-1 text-[11px] font-medium text-primary hover:underline",
|
|
21665
|
+
"data-testid": "add-switch-rule",
|
|
21666
|
+
children: [
|
|
21667
|
+
/* @__PURE__ */ jsx(Icon, { icon: "basil:add-solid", className: "size-3.5" }),
|
|
21668
|
+
" Add rule"
|
|
21669
|
+
]
|
|
21670
|
+
}
|
|
21671
|
+
),
|
|
21672
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
|
|
21673
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: "Fallback output (no rule matches):" }),
|
|
21674
|
+
/* @__PURE__ */ jsx(
|
|
21675
|
+
"input",
|
|
21676
|
+
{
|
|
21677
|
+
type: "text",
|
|
21678
|
+
value: fallbackHandle,
|
|
21679
|
+
placeholder: "default",
|
|
21680
|
+
onChange: (e) => onChange({ rules, fallbackHandle: e.target.value }),
|
|
21681
|
+
className: cn(rowInput, "w-28"),
|
|
21682
|
+
"data-testid": "switch-fallback"
|
|
21683
|
+
}
|
|
21684
|
+
)
|
|
21685
|
+
] }),
|
|
21686
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] leading-snug text-muted-foreground", children: "Rules are checked top-down; the first matching rule routes the item to its output. Each rule renders as an output handle on the node." })
|
|
21687
|
+
] });
|
|
21688
|
+
}
|
|
20910
21689
|
function coerceNumber(type, raw) {
|
|
20911
21690
|
if (raw.trim() === "") return void 0;
|
|
20912
21691
|
const n = type === "integer" ? parseInt(raw, 10) : parseFloat(raw);
|
|
@@ -21036,6 +21815,7 @@ function NodeDetailView() {
|
|
|
21036
21815
|
[currentOp]
|
|
21037
21816
|
);
|
|
21038
21817
|
const params = useMemo(() => paramsFromOperation(currentOp), [currentOp]);
|
|
21818
|
+
const pickerFields = useMemo(() => flattenFields(inputFields), [inputFields]);
|
|
21039
21819
|
const mapping = currentEdge?.mapping?.definition ?? {};
|
|
21040
21820
|
const argsState = useMemo(() => {
|
|
21041
21821
|
const data = asRecord(node?.data);
|
|
@@ -21284,6 +22064,40 @@ function NodeDetailView() {
|
|
|
21284
22064
|
] }),
|
|
21285
22065
|
!currentEdge && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-dashed border-border bg-muted/40 px-3 py-2 text-xs text-muted-foreground", children: "No upstream node connected \u2014 set fixed values below, or connect a node to map fields with expressions." }),
|
|
21286
22066
|
params.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-xs text-muted-foreground", children: "This operation has no input parameters." }) : params.map((p) => {
|
|
22067
|
+
if (p.type === "condition") {
|
|
22068
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
22069
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-foreground", children: p.name === "conditionTree" ? "Conditions" : p.name }),
|
|
22070
|
+
/* @__PURE__ */ jsx(
|
|
22071
|
+
ConditionTreeBuilder,
|
|
22072
|
+
{
|
|
22073
|
+
value: argsState[p.name],
|
|
22074
|
+
fields: pickerFields,
|
|
22075
|
+
onChange: (tree) => writeFixed(p.name, tree)
|
|
22076
|
+
}
|
|
22077
|
+
),
|
|
22078
|
+
p.description && /* @__PURE__ */ jsx("span", { className: "text-[11px] leading-snug text-muted-foreground", children: p.description })
|
|
22079
|
+
] }, p.name);
|
|
22080
|
+
}
|
|
22081
|
+
if (p.type === "switch-rules") {
|
|
22082
|
+
const rules = Array.isArray(argsState[p.name]) ? argsState[p.name] : [];
|
|
22083
|
+
const fallbackHandle = typeof argsState.fallbackHandle === "string" ? argsState.fallbackHandle : "default";
|
|
22084
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
22085
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-foreground", children: "Routing rules" }),
|
|
22086
|
+
/* @__PURE__ */ jsx(
|
|
22087
|
+
SwitchRulesEditor,
|
|
22088
|
+
{
|
|
22089
|
+
rules,
|
|
22090
|
+
fallbackHandle,
|
|
22091
|
+
fields: pickerFields,
|
|
22092
|
+
onChange: (next) => {
|
|
22093
|
+
writeFixed(p.name, next.rules);
|
|
22094
|
+
writeFixed("cases", casesFromRules(next.rules));
|
|
22095
|
+
writeFixed("fallbackHandle", next.fallbackHandle);
|
|
22096
|
+
}
|
|
22097
|
+
}
|
|
22098
|
+
)
|
|
22099
|
+
] }, p.name);
|
|
22100
|
+
}
|
|
21287
22101
|
const mode = modeByField[p.name] ?? (mapping[p.name] !== void 0 ? "expression" : "fixed");
|
|
21288
22102
|
const exprValue = mapping[p.name] ?? "";
|
|
21289
22103
|
const fixedValue = argsState[p.name];
|
|
@@ -22221,5 +23035,5 @@ function WorkflowBuilder() {
|
|
|
22221
23035
|
}
|
|
22222
23036
|
|
|
22223
23037
|
export { Card2 as Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ConfigSchemaForm, ConnectionFormDialog, ConnectionSelector, FluidGridsProvider, ProviderPicker, TemplateCard, WorkflowBuilder, getProviderForm, listCustomBlocks, refetchStoreNodes, registerCustomBlock, resolveUiSpec, stripSubmitActions, useConnection, useConnectionDialog, useConnections, useConnectionsByProvider, useCreateConnection, useFluidGridsContext, useImportWorkflowTemplate, useInitiateOAuth, useNodeExecution, useProviderByKey, useProviderCatalog, useProviders, useWorkflowTemplates };
|
|
22224
|
-
//# sourceMappingURL=chunk-
|
|
22225
|
-
//# sourceMappingURL=chunk-
|
|
23038
|
+
//# sourceMappingURL=chunk-DPD5ILMD.js.map
|
|
23039
|
+
//# sourceMappingURL=chunk-DPD5ILMD.js.map
|