@burdenoff/fluidgrids-fe-sdk 2026.1111.17 → 2026.1111.18
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/{AiStudioPage-kJHSsIcj.js → AiStudioPage-BHVEU4Wp.js} +2 -2
- package/dist/{SettingsPage-CgkRlCM5.js → SettingsPage-CJLZvv4J.js} +1485 -1484
- package/dist/{TemplatePreview-GthzCOSo.js → TemplatePreview-FayF6jxh.js} +1 -1
- package/dist/{WorkflowBuilder-DEi_9YOb.js → WorkflowBuilder-CPnXEL5J.js} +1 -1
- package/dist/{WorkflowBuilder-iPqXgbYr.js → WorkflowBuilder-YXRysvZc.js} +2 -2
- package/dist/WorkflowShareDialog-mbIwRQUY.js +168 -0
- package/dist/{WorkflowsList-CA20dVIl.js → WorkflowsList-DiiGyZkT.js} +2 -1
- package/dist/{agentTools-CkRJB7r5.js → agentTools-8s_25Q_F.js} +1 -1
- package/dist/{canvasNoteTools-CQIc7Oxg.js → canvasNoteTools-B6pYARgU.js} +1 -1
- package/dist/code-editor-field-9-GdVE_8.js +111 -0
- package/dist/{flow-builder-y2Y1iG4Y.js → flow-builder-CZDKRc6f.js} +245 -8638
- package/dist/{index-W2o__Nm6.d.ts → index-6JR2vD9J.d.ts} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +13 -11
- package/dist/{node-detail-view-B91kXzIy.js → node-detail-view-CV4ZRwqh.js} +4 -2
- package/dist/node-editor-tab-body-DU-dh35X.js +174 -0
- package/dist/observability.d.ts +1 -1
- package/dist/popover-BJHvrFGR.js +472 -0
- package/dist/{quick-config-panel-DggPl1vY.js → quick-config-panel-ws3pLvbt.js} +2 -1
- package/dist/schedule-panel-C0mfGQSD.js +7542 -0
- package/dist/settings.js +1 -1
- package/dist/sidebar-node-editor-CR1PiZO-.js +177 -0
- package/dist/templates.js +1 -1
- package/dist/{useAgentDefinitions-Dpz0HDTq.js → useAgentDefinitions-B0dam3_o.js} +1 -396
- package/dist/useConnections-Cs7LCWEM.js +401 -0
- package/dist/{WorkflowShareDialog-B_gn968c.js → useWorkflowCodeExport-Bu2QYJzA.js} +4 -161
- package/dist/workflow-builder.js +2 -2
- package/dist/workflow-pages.d.ts +1 -1
- package/dist/workflow-pages.js +5 -5
- package/dist/workflows-list.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { An as newConnectionProviderKey, Dn as connectionsForAdapter, On as isOptionalAdapter, jn as replaceAdapterConnections, kn as matchesAdapterProvider } from "./FluidGridsProvider-dvZSNtSW.js";
|
|
3
|
+
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
4
|
+
import { r as useAgentsUsingConnection } from "./useAgentDefinitions-B0dam3_o.js";
|
|
5
|
+
import { t as cn } from "./cn-QqidFIgr.js";
|
|
6
|
+
import { o as ConnectionFormDialog } from "./flow-builder-CZDKRc6f.js";
|
|
7
|
+
import { a as SdkPermissionGate, t as FLUIDGRIDS_PERMISSIONS } from "./constants-B2lhWNoN.js";
|
|
8
|
+
import { n as useConnections } from "./useConnections-Cs7LCWEM.js";
|
|
9
|
+
import { a as useRunners, t as RunnerStatusPill } from "./RunnerStatusPill-Ctg4TJcP.js";
|
|
10
|
+
import * as React$1 from "react";
|
|
11
|
+
import { useCallback, useMemo, useState } from "react";
|
|
12
|
+
import { Icon } from "@iconify/react";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@burdenoff/fe-libs/ui";
|
|
15
|
+
import { ProviderIcon } from "@burdenoff/fe-libs/connections";
|
|
16
|
+
import { formatDistanceToNow } from "date-fns";
|
|
17
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
18
|
+
|
|
19
|
+
// src/modules/agent-definitions/components/ConnectionAgentUsage.tsx
|
|
20
|
+
/**
|
|
21
|
+
* A connection's "used by agents" list (BOFF-9962).
|
|
22
|
+
*
|
|
23
|
+
* Shows which agents may use a connection, so whoever edits or reuses it knows an agent can act
|
|
24
|
+
* with it. The list comes from `agentDefinitionsUsingConnection`; it renders nothing when no agent
|
|
25
|
+
* uses the connection or the viewer cannot read agent definitions.
|
|
26
|
+
*/
|
|
27
|
+
function ConnectionAgentUsage({ connectionId, connectionName }) {
|
|
28
|
+
const tr = useTr();
|
|
29
|
+
const agents = useAgentsUsingConnection(connectionId);
|
|
30
|
+
if (agents.length === 0) return null;
|
|
31
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
32
|
+
className: "flex items-start gap-1.5 text-xs text-muted-foreground",
|
|
33
|
+
"data-testid": `connection-agent-usage-${connectionId}`,
|
|
34
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
35
|
+
icon: "mdi:robot-outline",
|
|
36
|
+
className: "w-3.5 h-3.5 mt-0.5 shrink-0"
|
|
37
|
+
}), /* @__PURE__ */ jsxs("span", { children: [
|
|
38
|
+
connectionName ? tr("fluidgrids.agents.usedBy.namedLabel", "{{connection}} is used by agents:", { connection: connectionName }) : tr("fluidgrids.agents.usedBy.label", "Used by agents:"),
|
|
39
|
+
" ",
|
|
40
|
+
agents.map((agent) => agent.status === "ACTIVE" ? agent.name : tr("fluidgrids.agents.usedBy.disabled", "{{name}} (disabled)", { name: agent.name })).join(", ")
|
|
41
|
+
] })]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/modules/connections/components/ConnectionSelector.tsx
|
|
46
|
+
/**
|
|
47
|
+
* ConnectionSelector Component
|
|
48
|
+
*
|
|
49
|
+
* A dropdown selector for choosing integration connections in workflow nodes.
|
|
50
|
+
* Replaces the legacy CredentialSelector and queries the integrations service.
|
|
51
|
+
*
|
|
52
|
+
* This component:
|
|
53
|
+
* - Fetches connections from wspace-integrations-svc via the federated gateway
|
|
54
|
+
* - Filters connections by provider adapters defined in node manifests
|
|
55
|
+
* - Supports single and multiple selection modes
|
|
56
|
+
* - Opens an inline ConnectionFormDialog popup for creating new connections (n8n-style)
|
|
57
|
+
*/
|
|
58
|
+
function formatAge(dateString) {
|
|
59
|
+
try {
|
|
60
|
+
return formatDistanceToNow(new Date(dateString), { addSuffix: true });
|
|
61
|
+
} catch {
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function getStatusColor(status) {
|
|
66
|
+
switch (status) {
|
|
67
|
+
case "ACTIVE": return "text-[var(--color-status-success-text)]";
|
|
68
|
+
case "INACTIVE": return "text-text-secondary";
|
|
69
|
+
case "ERROR":
|
|
70
|
+
case "REVOKED": return "text-[var(--color-status-error-text)]";
|
|
71
|
+
case "EXPIRED":
|
|
72
|
+
case "PENDING_AUTH": return "text-[var(--color-status-warning-text)]";
|
|
73
|
+
default: return "text-text-secondary";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function getStatusIcon(status) {
|
|
77
|
+
switch (status) {
|
|
78
|
+
case "ACTIVE": return "mdi:check-circle";
|
|
79
|
+
case "INACTIVE": return "mdi:pause-circle";
|
|
80
|
+
case "ERROR":
|
|
81
|
+
case "REVOKED": return "mdi:alert-circle";
|
|
82
|
+
case "EXPIRED": return "mdi:clock-alert";
|
|
83
|
+
case "PENDING_AUTH": return "mdi:account-clock";
|
|
84
|
+
default: return "mdi:help-circle";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function ConnectionChip({ connection, connectionData, onRemove }) {
|
|
88
|
+
const tr = useTr();
|
|
89
|
+
const name = connectionData?.name || connection.connectionId;
|
|
90
|
+
const status = connectionData?.status;
|
|
91
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
92
|
+
className: "flex items-center gap-1.5 px-2 py-1 bg-accent/30 rounded-md text-sm group",
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsx(ProviderIcon, {
|
|
95
|
+
variant: "bare",
|
|
96
|
+
provider: connectionData?.provider ?? {
|
|
97
|
+
key: connection.adapter,
|
|
98
|
+
icon: void 0,
|
|
99
|
+
category: "CUSTOM"
|
|
100
|
+
},
|
|
101
|
+
size: 16
|
|
102
|
+
}),
|
|
103
|
+
/* @__PURE__ */ jsx("span", {
|
|
104
|
+
className: "truncate max-w-32",
|
|
105
|
+
children: name
|
|
106
|
+
}),
|
|
107
|
+
status && /* @__PURE__ */ jsx(Icon, {
|
|
108
|
+
icon: getStatusIcon(status),
|
|
109
|
+
className: `w-3.5 h-3.5 ${getStatusColor(status)}`
|
|
110
|
+
}),
|
|
111
|
+
/* @__PURE__ */ jsx("button", {
|
|
112
|
+
type: "button",
|
|
113
|
+
"aria-label": tr("fluidgrids.connections.connectionSelector.removeConnection", "Remove connection"),
|
|
114
|
+
onClick: (e) => {
|
|
115
|
+
e.stopPropagation();
|
|
116
|
+
onRemove();
|
|
117
|
+
},
|
|
118
|
+
className: "text-text-secondary hover:text-status-error-text opacity-0 group-hover:opacity-100 transition-opacity",
|
|
119
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
120
|
+
icon: "mdi:close",
|
|
121
|
+
className: "w-3.5 h-3.5"
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function ConnectionSelector(props) {
|
|
128
|
+
const connectionList = useConnections();
|
|
129
|
+
if (props.adapters.length <= 1) return /* @__PURE__ */ jsx(AdapterConnectionSelector, {
|
|
130
|
+
...props,
|
|
131
|
+
connectionList
|
|
132
|
+
});
|
|
133
|
+
return /* @__PURE__ */ jsx("div", {
|
|
134
|
+
className: props.compact ? "space-y-2" : "space-y-3",
|
|
135
|
+
children: props.adapters.map((adapter) => /* @__PURE__ */ jsxs("fieldset", {
|
|
136
|
+
className: "min-w-0 space-y-1.5",
|
|
137
|
+
children: [/* @__PURE__ */ jsx("legend", {
|
|
138
|
+
className: "text-xs font-medium text-text-secondary",
|
|
139
|
+
children: adapter.name
|
|
140
|
+
}), /* @__PURE__ */ jsx(AdapterConnectionSelector, {
|
|
141
|
+
...props,
|
|
142
|
+
adapters: [adapter],
|
|
143
|
+
selectedConnections: connectionsForAdapter(props.selectedConnections, adapter.name),
|
|
144
|
+
onChange: (connections) => props.onChange(replaceAdapterConnections(props.selectedConnections, adapter.name, connections.map((connection) => connection.connectionId))),
|
|
145
|
+
showRequired: false,
|
|
146
|
+
connectionList
|
|
147
|
+
})]
|
|
148
|
+
}, adapter.name))
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function AdapterConnectionSelector({ adapters, selectedConnections, onChange, multiple = false, showStatus = true, compact = false, showRequired = true, connectionList }) {
|
|
152
|
+
const tr = useTr();
|
|
153
|
+
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
|
154
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
155
|
+
const [dialogProviderKey, setDialogProviderKey] = useState();
|
|
156
|
+
const { connections, loading: connectionsLoading, refetch } = connectionList;
|
|
157
|
+
const availableConnections = useMemo(() => {
|
|
158
|
+
if (!adapters || adapters.length === 0) return [];
|
|
159
|
+
return connections.filter((connection) => connection.canUse !== false && adapters.some((adapter) => matchesAdapterProvider(adapter, connection.provider?.key ?? "")));
|
|
160
|
+
}, [connections, adapters]);
|
|
161
|
+
const mergedConnections = useMemo(() => {
|
|
162
|
+
const allConnections = [...availableConnections];
|
|
163
|
+
selectedConnections.forEach((selected) => {
|
|
164
|
+
if (!availableConnections.some((c) => c.id === selected.connectionId)) {
|
|
165
|
+
const fullConn = connections.find((c) => c.id === selected.connectionId);
|
|
166
|
+
if (fullConn && fullConn.canUse !== false) allConnections.push(fullConn);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return allConnections;
|
|
170
|
+
}, [
|
|
171
|
+
availableConnections,
|
|
172
|
+
selectedConnections,
|
|
173
|
+
connections
|
|
174
|
+
]);
|
|
175
|
+
const groupedConnections = useMemo(() => {
|
|
176
|
+
const groups = {};
|
|
177
|
+
mergedConnections.forEach((conn) => {
|
|
178
|
+
const providerName = conn.provider?.name || "Other";
|
|
179
|
+
if (!groups[providerName]) groups[providerName] = [];
|
|
180
|
+
groups[providerName].push(conn);
|
|
181
|
+
});
|
|
182
|
+
return groups;
|
|
183
|
+
}, [mergedConnections]);
|
|
184
|
+
const handleSelect = useCallback((connection) => {
|
|
185
|
+
const providerKey = connection.provider?.key || "";
|
|
186
|
+
const adapter = adapters.find((candidate) => matchesAdapterProvider(candidate, providerKey));
|
|
187
|
+
if (!adapter) return;
|
|
188
|
+
const newSelection = {
|
|
189
|
+
connectionId: connection.id,
|
|
190
|
+
adapter: adapter.name
|
|
191
|
+
};
|
|
192
|
+
if (multiple) {
|
|
193
|
+
if (selectedConnections.some((c) => c.connectionId === connection.id)) onChange(selectedConnections.filter((c) => c.connectionId !== connection.id));
|
|
194
|
+
else onChange([...selectedConnections, newSelection]);
|
|
195
|
+
} else {
|
|
196
|
+
onChange([newSelection]);
|
|
197
|
+
setIsDropdownOpen(false);
|
|
198
|
+
}
|
|
199
|
+
}, [
|
|
200
|
+
adapters,
|
|
201
|
+
selectedConnections,
|
|
202
|
+
onChange,
|
|
203
|
+
multiple
|
|
204
|
+
]);
|
|
205
|
+
const handleRemove = useCallback((connectionId) => {
|
|
206
|
+
onChange(selectedConnections.filter((c) => c.connectionId !== connectionId));
|
|
207
|
+
}, [selectedConnections, onChange]);
|
|
208
|
+
const handleNewConnection = useCallback((providerKey) => {
|
|
209
|
+
setDialogProviderKey(providerKey);
|
|
210
|
+
setDialogOpen(true);
|
|
211
|
+
setIsDropdownOpen(false);
|
|
212
|
+
}, []);
|
|
213
|
+
const handleConnectionCreated = useCallback((conn) => {
|
|
214
|
+
const providerKey = conn.provider?.key || "";
|
|
215
|
+
const adapter = adapters.find((candidate) => matchesAdapterProvider(candidate, providerKey));
|
|
216
|
+
if (adapter) {
|
|
217
|
+
const newSelection = {
|
|
218
|
+
connectionId: conn.id,
|
|
219
|
+
adapter: adapter.name
|
|
220
|
+
};
|
|
221
|
+
if (multiple) onChange([...selectedConnections, newSelection]);
|
|
222
|
+
else onChange([newSelection]);
|
|
223
|
+
}
|
|
224
|
+
setDialogOpen(false);
|
|
225
|
+
refetch();
|
|
226
|
+
}, [
|
|
227
|
+
adapters,
|
|
228
|
+
selectedConnections,
|
|
229
|
+
onChange,
|
|
230
|
+
multiple,
|
|
231
|
+
refetch
|
|
232
|
+
]);
|
|
233
|
+
const getConnectionData = useCallback((connectionId) => connections.find((c) => c.id === connectionId), [connections]);
|
|
234
|
+
if (!adapters || adapters.length === 0) return null;
|
|
235
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
236
|
+
className: compact ? "space-y-2" : "space-y-3",
|
|
237
|
+
children: [
|
|
238
|
+
selectedConnections.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
239
|
+
className: "flex flex-wrap gap-1.5",
|
|
240
|
+
children: selectedConnections.map((conn) => {
|
|
241
|
+
const connData = getConnectionData(conn.connectionId);
|
|
242
|
+
return /* @__PURE__ */ jsx(ConnectionChip, {
|
|
243
|
+
connection: conn,
|
|
244
|
+
connectionData: connData,
|
|
245
|
+
onRemove: () => handleRemove(conn.connectionId)
|
|
246
|
+
}, conn.connectionId);
|
|
247
|
+
})
|
|
248
|
+
}),
|
|
249
|
+
selectedConnections.map((conn) => /* @__PURE__ */ jsx(ConnectionAgentUsage, {
|
|
250
|
+
connectionId: conn.connectionId,
|
|
251
|
+
connectionName: selectedConnections.length > 1 ? getConnectionData(conn.connectionId)?.name : null
|
|
252
|
+
}, `agents-${conn.connectionId}`)),
|
|
253
|
+
/* @__PURE__ */ jsxs("div", {
|
|
254
|
+
className: "flex items-center gap-2",
|
|
255
|
+
children: [/* @__PURE__ */ jsxs(DropdownMenu, {
|
|
256
|
+
open: isDropdownOpen,
|
|
257
|
+
onOpenChange: setIsDropdownOpen,
|
|
258
|
+
children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
259
|
+
asChild: true,
|
|
260
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
261
|
+
variant: "outline",
|
|
262
|
+
size: compact ? "sm" : "default",
|
|
263
|
+
className: "justify-between min-w-[200px]",
|
|
264
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
265
|
+
className: "flex items-center gap-2",
|
|
266
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
267
|
+
icon: "mdi:link-variant",
|
|
268
|
+
className: "w-4 h-4 text-text-secondary"
|
|
269
|
+
}), selectedConnections.length === 0 ? tr("fluidgrids.connections.connectionSelector.selectConnection", "Select connection") : multiple ? `${selectedConnections.length} selected` : tr("fluidgrids.connections.connectionSelector.changeConnection", "Change connection")]
|
|
270
|
+
}), /* @__PURE__ */ jsx(Icon, {
|
|
271
|
+
icon: "mdi:chevron-down",
|
|
272
|
+
className: "w-4 h-4 text-text-secondary"
|
|
273
|
+
})]
|
|
274
|
+
})
|
|
275
|
+
}), /* @__PURE__ */ jsxs(DropdownMenuContent, {
|
|
276
|
+
align: "start",
|
|
277
|
+
style: { zIndex: 1100 },
|
|
278
|
+
className: "w-[280px] max-h-[400px] overflow-y-auto",
|
|
279
|
+
children: [connectionsLoading ? /* @__PURE__ */ jsxs("div", {
|
|
280
|
+
className: "p-4 text-center text-sm text-text-secondary",
|
|
281
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
282
|
+
icon: "mdi:loading",
|
|
283
|
+
className: "w-6 h-6 mx-auto mb-2 animate-spin"
|
|
284
|
+
}), /* @__PURE__ */ jsx("p", { children: tr("fluidgrids.connections.connectionSelector.loading", "Loading connections...") })]
|
|
285
|
+
}) : Object.keys(groupedConnections).length === 0 ? /* @__PURE__ */ jsxs("div", {
|
|
286
|
+
className: "p-4 text-center text-sm text-text-secondary",
|
|
287
|
+
children: [
|
|
288
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
289
|
+
icon: "mdi:link-off",
|
|
290
|
+
className: "w-8 h-8 mx-auto mb-2 opacity-50"
|
|
291
|
+
}),
|
|
292
|
+
/* @__PURE__ */ jsx("p", { children: tr("fluidgrids.connections.connectionSelector.emptyTitle", "No matching connections") }),
|
|
293
|
+
/* @__PURE__ */ jsx("p", {
|
|
294
|
+
className: "text-xs mt-1",
|
|
295
|
+
children: tr("fluidgrids.connections.connectionSelector.emptyHint", "Create one in Integrations")
|
|
296
|
+
})
|
|
297
|
+
]
|
|
298
|
+
}) : Object.entries(groupedConnections).map(([providerName, conns]) => /* @__PURE__ */ jsxs("div", { children: [
|
|
299
|
+
/* @__PURE__ */ jsxs(DropdownMenuLabel, {
|
|
300
|
+
className: "flex items-center gap-2 text-xs font-semibold text-text-secondary uppercase tracking-wide",
|
|
301
|
+
children: [/* @__PURE__ */ jsx(ProviderIcon, {
|
|
302
|
+
variant: "bare",
|
|
303
|
+
provider: conns[0]?.provider ?? {
|
|
304
|
+
key: "generic",
|
|
305
|
+
icon: void 0,
|
|
306
|
+
category: "CUSTOM"
|
|
307
|
+
},
|
|
308
|
+
size: 16
|
|
309
|
+
}), providerName]
|
|
310
|
+
}),
|
|
311
|
+
conns.map((conn) => {
|
|
312
|
+
const isSelected = selectedConnections.some((c) => c.connectionId === conn.id);
|
|
313
|
+
const isActive = conn.status === "ACTIVE";
|
|
314
|
+
return /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
315
|
+
onSelect: (event) => {
|
|
316
|
+
if (multiple) event.preventDefault();
|
|
317
|
+
handleSelect(conn);
|
|
318
|
+
},
|
|
319
|
+
className: `flex items-center justify-between cursor-pointer ${isSelected ? "bg-action-primary-bg/10" : ""} ${!isActive ? "opacity-60" : ""}`,
|
|
320
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
321
|
+
className: "flex flex-col min-w-0",
|
|
322
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
323
|
+
className: "font-medium truncate flex items-center gap-1.5",
|
|
324
|
+
children: [conn.name, showStatus && /* @__PURE__ */ jsx("span", {
|
|
325
|
+
title: conn.status,
|
|
326
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
327
|
+
icon: getStatusIcon(conn.status),
|
|
328
|
+
className: `w-3.5 h-3.5 ${getStatusColor(conn.status)}`
|
|
329
|
+
})
|
|
330
|
+
})]
|
|
331
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
332
|
+
className: "text-xs text-text-secondary",
|
|
333
|
+
children: conn.externalAccountEmail || conn.updatedAt && `Updated ${formatAge(conn.updatedAt)}`
|
|
334
|
+
})]
|
|
335
|
+
}), isSelected && /* @__PURE__ */ jsx(Icon, {
|
|
336
|
+
icon: "mdi:check",
|
|
337
|
+
className: "w-4 h-4 text-primary flex-shrink-0"
|
|
338
|
+
})]
|
|
339
|
+
}, conn.id);
|
|
340
|
+
}),
|
|
341
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {})
|
|
342
|
+
] }, providerName)), /* @__PURE__ */ jsx(SdkPermissionGate, {
|
|
343
|
+
permission: FLUIDGRIDS_PERMISSIONS.INTEGRATION_CONNECTION_CREATE,
|
|
344
|
+
children: /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
345
|
+
onClick: () => {
|
|
346
|
+
handleNewConnection(newConnectionProviderKey(adapters));
|
|
347
|
+
},
|
|
348
|
+
className: "text-primary cursor-pointer",
|
|
349
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
350
|
+
icon: "mdi:plus",
|
|
351
|
+
className: "w-4 h-4 mr-2"
|
|
352
|
+
}), tr("fluidgrids.connections.connectionSelector.newConnection", "New connection")]
|
|
353
|
+
})
|
|
354
|
+
})]
|
|
355
|
+
})]
|
|
356
|
+
}), selectedConnections.length === 0 && !compact && /* @__PURE__ */ jsx(SdkPermissionGate, {
|
|
357
|
+
permission: FLUIDGRIDS_PERMISSIONS.INTEGRATION_CONNECTION_CREATE,
|
|
358
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
359
|
+
variant: "ghost",
|
|
360
|
+
size: "sm",
|
|
361
|
+
onClick: () => handleNewConnection(newConnectionProviderKey(adapters)),
|
|
362
|
+
className: "text-primary hover:text-primary/80",
|
|
363
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
364
|
+
icon: "mdi:plus",
|
|
365
|
+
className: "w-4 h-4 mr-1"
|
|
366
|
+
}), tr("fluidgrids.connections.connectionSelector.new", "New")]
|
|
367
|
+
})
|
|
368
|
+
})]
|
|
369
|
+
}),
|
|
370
|
+
showStatus && showRequired && selectedConnections.length === 0 && adapters.some((adapter) => !isOptionalAdapter(adapter)) && /* @__PURE__ */ jsxs("div", {
|
|
371
|
+
className: "flex items-center gap-1.5 text-xs text-[var(--color-status-warning-text)]",
|
|
372
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
373
|
+
icon: "mdi:alert-circle",
|
|
374
|
+
className: "w-3.5 h-3.5"
|
|
375
|
+
}), /* @__PURE__ */ jsx("span", { children: tr("fluidgrids.connections.connectionSelector.connectionRequired", "Connection required for this node") })]
|
|
376
|
+
}),
|
|
377
|
+
/* @__PURE__ */ jsx(ConnectionFormDialog, {
|
|
378
|
+
open: dialogOpen,
|
|
379
|
+
onClose: () => setDialogOpen(false),
|
|
380
|
+
providerKey: dialogProviderKey,
|
|
381
|
+
onConnectionCreated: handleConnectionCreated
|
|
382
|
+
})
|
|
383
|
+
]
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/modules/runners/components/RunOnSection.tsx
|
|
388
|
+
/**
|
|
389
|
+
* NDV Settings → "Run on": FluidGrids Cloud (default) or one of the
|
|
390
|
+
* workspace's self-hosted runners.
|
|
391
|
+
*
|
|
392
|
+
* Persisted at `node.data.executionSettings.runOn = { kind: "runner", runnerId }`
|
|
393
|
+
* (absent = FluidGrids Cloud). fluidgrids-workers reads exactly that and the
|
|
394
|
+
* node then runs on the runner — or fails if it is offline; it never falls
|
|
395
|
+
* back to the cloud.
|
|
396
|
+
*/
|
|
397
|
+
const CLOUD = "__fluidgrids_cloud__";
|
|
398
|
+
function RunOnSection({ value, onChange, sectionLabelClassName }) {
|
|
399
|
+
const tr = useTr();
|
|
400
|
+
const { runners, loading } = useRunners({ pollMs: 15e3 });
|
|
401
|
+
const selected = value ? runners.find((r) => r.id === value.runnerId) : void 0;
|
|
402
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
403
|
+
className: "space-y-2",
|
|
404
|
+
"data-testid": "ndv-settings-run-on",
|
|
405
|
+
children: [
|
|
406
|
+
/* @__PURE__ */ jsx("div", {
|
|
407
|
+
className: sectionLabelClassName,
|
|
408
|
+
children: tr("fluidgrids.builder.nodeSettings.runOn", "Run on")
|
|
409
|
+
}),
|
|
410
|
+
/* @__PURE__ */ jsxs(Select, {
|
|
411
|
+
value: value?.runnerId ?? CLOUD,
|
|
412
|
+
onValueChange: (v) => onChange(v === CLOUD ? null : {
|
|
413
|
+
kind: "runner",
|
|
414
|
+
runnerId: v
|
|
415
|
+
}),
|
|
416
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
417
|
+
className: "w-full",
|
|
418
|
+
"data-testid": "ndv-settings-run-on-select",
|
|
419
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
420
|
+
}), /* @__PURE__ */ jsxs(SelectContent, {
|
|
421
|
+
style: { zIndex: 1100 },
|
|
422
|
+
"data-testid": "ndv-settings-run-on-options",
|
|
423
|
+
children: [
|
|
424
|
+
/* @__PURE__ */ jsx(SelectItem, {
|
|
425
|
+
value: CLOUD,
|
|
426
|
+
"data-testid": "run-on-cloud",
|
|
427
|
+
children: tr("fluidgrids.builder.nodeSettings.runOnCloud", "FluidGrids Cloud (default)")
|
|
428
|
+
}),
|
|
429
|
+
runners.map((runner) => /* @__PURE__ */ jsxs(SelectItem, {
|
|
430
|
+
value: runner.id,
|
|
431
|
+
"data-testid": "run-on-runner-option",
|
|
432
|
+
children: [runner.name, runner.status !== "ONLINE" ? ` (${runner.status === "OFFLINE" ? tr("fluidgrids.runners.offline", "Offline") : tr("fluidgrids.runners.neverConnected", "Not connected yet")})` : ""]
|
|
433
|
+
}, runner.id)),
|
|
434
|
+
value && !loading && !selected && /* @__PURE__ */ jsx(SelectItem, {
|
|
435
|
+
value: value.runnerId,
|
|
436
|
+
disabled: true,
|
|
437
|
+
children: tr("fluidgrids.builder.nodeSettings.runOnMissing", "Removed runner")
|
|
438
|
+
})
|
|
439
|
+
]
|
|
440
|
+
})]
|
|
441
|
+
}),
|
|
442
|
+
value ? /* @__PURE__ */ jsxs("div", {
|
|
443
|
+
className: "space-y-1 text-xs text-text-secondary",
|
|
444
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
445
|
+
className: "flex items-start gap-2",
|
|
446
|
+
children: [selected && /* @__PURE__ */ jsx(RunnerStatusPill, { status: selected.status }), /* @__PURE__ */ jsx("span", { children: tr("fluidgrids.builder.nodeSettings.runOnRunnerHint", "This node runs on your runner, in a local sandbox. If the runner is offline the node fails — it never falls back to FluidGrids Cloud. The node's input and the credentials it uses are sent to that machine.") })]
|
|
447
|
+
}), selected && /* @__PURE__ */ jsx("p", {
|
|
448
|
+
"data-testid": "run-on-private-network",
|
|
449
|
+
children: (selected.privateNetwork ?? []).length === 0 ? tr("fluidgrids.builder.nodeSettings.runOnPublicOnly", "On this runner, nodes reach the public internet only. Private destinations are opened on the runner machine (fluidgrids-runner network allow).") : tr("fluidgrids.builder.nodeSettings.runOnPrivateNetwork", "This runner opens {{count}} private destination(s) — see Runners for which nodes may use them.", { count: (selected.privateNetwork ?? []).length })
|
|
450
|
+
})]
|
|
451
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
452
|
+
className: "text-xs text-text-secondary",
|
|
453
|
+
children: runners.length === 0 && !loading ? tr("fluidgrids.builder.nodeSettings.runOnNoRunners", "Runs in FluidGrids Cloud. Add a runner under Workflows → Runners to run nodes on your own machine.") : tr("fluidgrids.builder.nodeSettings.runOnCloudHint", "Runs in FluidGrids Cloud.")
|
|
454
|
+
})
|
|
455
|
+
]
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// src/ui/popover.tsx
|
|
460
|
+
const Popover$1 = PopoverPrimitive.Root;
|
|
461
|
+
const PopoverTrigger$1 = PopoverPrimitive.Trigger;
|
|
462
|
+
const PopoverContent$1 = React$1.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(PopoverPrimitive.Content, {
|
|
463
|
+
ref,
|
|
464
|
+
"data-slot": "popover-content",
|
|
465
|
+
align,
|
|
466
|
+
sideOffset,
|
|
467
|
+
className: cn("z-50 w-72 rounded-card border border-border-subtle bg-bg-elevated p-4 text-text-primary shadow-elevation-3 outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className),
|
|
468
|
+
...props
|
|
469
|
+
}) }));
|
|
470
|
+
PopoverContent$1.displayName = PopoverPrimitive.Content.displayName;
|
|
471
|
+
|
|
472
|
+
export { ConnectionSelector as a, RunOnSection as i, PopoverContent$1 as n, PopoverTrigger$1 as r, Popover$1 as t };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { A as nodeAccent, H as useFlowStore, j as NodeTypeIcon } from "./node-operation-selection--oy-yEq_.js";
|
|
3
3
|
import { G as nodeSubtitle, K as nodeTitle, Mn as getNodeDetail, X as useNodeConfig, rn as useNodeExecution } from "./FluidGridsProvider-dvZSNtSW.js";
|
|
4
|
-
import {
|
|
4
|
+
import { i as NodeInputFields, n as useNodeEditorTab, r as NodeEditorTabs, t as NodeEditorTabBody } from "./node-editor-tab-body-DU-dh35X.js";
|
|
5
5
|
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
6
|
+
import { r as NodeExecutionActions } from "./schedule-panel-C0mfGQSD.js";
|
|
6
7
|
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
7
8
|
import { useReactFlow, useStore } from "@xyflow/react";
|
|
8
9
|
import { Icon } from "@iconify/react";
|