@burdenoff/fluidgrids-fe-sdk 2026.1111.16 → 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.
Files changed (119) hide show
  1. package/README.md +41 -0
  2. package/dist/AiStudioPage-BHVEU4Wp.js +774 -0
  3. package/dist/ApprovalInboxPage-dbBDSJ-f.js +558 -0
  4. package/dist/DataSinkDashboardPage-1h2QsMzH.js +270 -0
  5. package/dist/DataTablesPage-BZy2z0LB.js +1690 -0
  6. package/dist/EntityTagPicker-BqRNsLCQ.js +135 -0
  7. package/dist/{ExecutionDetailPage-D-0_POAf.js → ExecutionDetailPage-BdcZmLT4.js} +799 -4420
  8. package/dist/ExecutionDetailPage-DvQ667OE.d.ts +10 -0
  9. package/dist/ExecutionsListPage-BCUJoAIE.js +2742 -0
  10. package/dist/{FailureTriagePanel-BHiduL7A.js → FailureTriagePanel-B9hDQymi.js} +4 -97
  11. package/dist/{FluidGridsProvider-DmvFADFa.js → FluidGridsProvider-dvZSNtSW.js} +10 -350
  12. package/dist/HistoryPage-BLoRpJ1R.d.ts +6 -0
  13. package/dist/{HistoryPage-BbUgxx1I.js → HistoryPage-U0tqupBN.js} +6 -4
  14. package/dist/HumanRequestCard-D-ooVPDn.js +439 -0
  15. package/dist/{InsightsPage-s6f5bU-8.js → InsightsPage-CALo16eB.js} +17 -328
  16. package/dist/ManagedAiPolicyAuthority-BxwJ3ptd.js +40 -0
  17. package/dist/{ManagedAiPolicyAuthority-CGux_DaV.d.ts → ManagedAiPolicyAuthority-DM3t3wNr.d.ts} +1 -5
  18. package/dist/ManagedAiPolicyAuthorityContext-CNkxIOZ1.js +10 -0
  19. package/dist/{MissingNodesInstallModal-B-9gHy2K.js → MissingNodesInstallModal-CMybsI8h.js} +3 -2
  20. package/dist/{NodesPage-ClvhUfbh.js → NodesPage-Bf5PhfBK.js} +7 -3
  21. package/dist/NodesPage-DEbnz9iU.d.ts +6 -0
  22. package/dist/{PublishCustomNodeAction-D2F7oN0S.js → PublishCustomNodeAction-5XXnSA3H.js} +3 -45
  23. package/dist/QuotaExhaustedDialog-7IFSaLyi.js +54 -0
  24. package/dist/RunnerStatusPill-Ctg4TJcP.js +187 -0
  25. package/dist/RunnersPage-CLCOCclc.js +467 -0
  26. package/dist/{ManagedAiPolicyAuthority-DsSaz-vg.js → SettingsPage-CJLZvv4J.js} +743 -773
  27. package/dist/SettingsPage-DMHQFj5-.d.ts +9 -0
  28. package/dist/TagFilterSelect-DCBOH6Ou.js +41 -0
  29. package/dist/TaskQueuesPage-9VgSnLdL.js +951 -0
  30. package/dist/TemplateCard-DsC0KNH1.js +1416 -0
  31. package/dist/{TemplateConfigurationModal-D_Mvgxqa.js → TemplateConfigurationModal-BhGWIzpm.js} +3 -2
  32. package/dist/{TemplateDetailPanel-DfFfUcOe.js → TemplateDetailPanel-D4cUVr-m.js} +3 -3
  33. package/dist/TemplatePreview-FayF6jxh.js +231 -0
  34. package/dist/TemplatesPage-BG3H-6v6.d.ts +10 -0
  35. package/dist/{TemplatesPage-Cku13bav.js → TemplatesPage-CsDNT54N.js} +11 -228
  36. package/dist/VariablesPage-67WR_lVE.js +949 -0
  37. package/dist/{VersionDiffDialog-Dq2xlPFI.js → VersionDiffDialog-DSN0mU0f.js} +2 -1
  38. package/dist/WorkflowBuilder-CPnXEL5J.js +555 -0
  39. package/dist/{WorkflowSearchRedirect-CaoOOpEl.js → WorkflowBuilder-YXRysvZc.js} +19 -585
  40. package/dist/{WorkflowProposalCard-8Vr56kQa.js → WorkflowProposalCard-qrEeNyYG.js} +4 -405
  41. package/dist/WorkflowSearchRedirect-DwDNZ_q5.js +36 -0
  42. package/dist/WorkflowShareDialog-mbIwRQUY.js +168 -0
  43. package/dist/WorkflowsList-CcNDQge5.d.ts +6 -0
  44. package/dist/{WorkflowsList-B2j1Pehb.js → WorkflowsList-DiiGyZkT.js} +12 -6
  45. package/dist/agent-form-Bfvm32j1.js +83 -0
  46. package/dist/{agentTools-DJ5o2ekg.js → agentTools-8s_25Q_F.js} +3 -2
  47. package/dist/{ai-usage-D5p7ZeRR.js → ai-usage-glCwHyQz.js} +1 -1
  48. package/dist/api-BrCHB5oA.js +224 -0
  49. package/dist/api-C8e0iV-Q.js +55 -0
  50. package/dist/button-DG7y_FVJ.js +48 -0
  51. package/dist/{canvasNoteTools-D3zUdEeg.js → canvasNoteTools-B6pYARgU.js} +2 -2
  52. package/dist/client-C9XSzSXr.js +1147 -0
  53. package/dist/code-editor-field-9-GdVE_8.js +111 -0
  54. package/dist/{codec-client-DstqyzTN.js → codec-client-CJ95Rmqo.js} +1 -1
  55. package/dist/constants-B2lhWNoN.js +202 -0
  56. package/dist/constants-XdvUxeWK.d.ts +162 -0
  57. package/dist/dialog-Cjb4lB4D.js +105 -0
  58. package/dist/executions.d.ts +1 -1
  59. package/dist/executions.js +2 -1
  60. package/dist/feature-flags-DM5myWaD.js +296 -0
  61. package/dist/flags.d.ts +3 -0
  62. package/dist/flags.js +4 -0
  63. package/dist/{flow-builder-DEzT8TQu.js → flow-builder-CZDKRc6f.js} +662 -10716
  64. package/dist/{node-endpoint-configs-DHFGA5MQ.js → graphql-operation-types-kX-MMjgW.js} +1 -1194
  65. package/dist/{graphql-types-XcDLtFwU.js → graphql-types-CDKVWH2R.js} +2 -202
  66. package/dist/history.d.ts +1 -1
  67. package/dist/history.js +1 -1
  68. package/dist/{index-DRf25-D3.d.ts → index-6JR2vD9J.d.ts} +33 -215
  69. package/dist/index-72XFgvbn.d.ts +132 -0
  70. package/dist/index-BcdtKBM-.d.ts +56 -0
  71. package/dist/{index-B3BWqafN.d.ts → index-DjiFgEQl.d.ts} +5 -131
  72. package/dist/index.d.ts +13 -9
  73. package/dist/index.js +52 -5300
  74. package/dist/{node-detail-view-LNqeIqN-.js → node-detail-view-CV4ZRwqh.js} +13 -8
  75. package/dist/node-editor-tab-body-DU-dh35X.js +174 -0
  76. package/dist/node-endpoint-configs-B5bjNMDW.js +37 -0
  77. package/dist/node-registry-refresh-Dy0uRg9f.js +84 -0
  78. package/dist/nodes.d.ts +1 -1
  79. package/dist/nodes.js +1 -1
  80. package/dist/observability.d.ts +1 -1
  81. package/dist/observability.js +2 -1
  82. package/dist/popover-BJHvrFGR.js +472 -0
  83. package/dist/{quick-config-panel-D3ogsaFL.js → quick-config-panel-ws3pLvbt.js} +3 -2
  84. package/dist/rolldown-runtime-hDbaFkMy.js +18 -0
  85. package/dist/run-display-BycKYSU0.js +46 -0
  86. package/dist/run-list-links-ByYC0OlV.js +98 -0
  87. package/dist/schedule-panel-C0mfGQSD.js +7542 -0
  88. package/dist/settings.d.ts +2 -1
  89. package/dist/settings.js +2 -1
  90. package/dist/shared-CMfn30xT.js +196 -0
  91. package/dist/sidebar-node-editor-CR1PiZO-.js +177 -0
  92. package/dist/templates.d.ts +1 -1
  93. package/dist/templates.js +2 -1
  94. package/dist/theme-provider-B3mIuz2d.js +11 -0
  95. package/dist/{useAgentDefinitions-NFtLytDR.js → useAgentDefinitions-B0dam3_o.js} +3 -397
  96. package/dist/useConnections-Cs7LCWEM.js +401 -0
  97. package/dist/useDurableParity-CzUQMFJ3.js +415 -0
  98. package/dist/useEntityTags-DhnsZcTl.js +236 -0
  99. package/dist/{useExecutions-DAzeWHS6.js → useExecutions-9aLuOt1c.js} +4 -3
  100. package/dist/{useObservability-COCZ0hUS.js → useObservability-CfEw3ZFD.js} +2 -2
  101. package/dist/{useRunHistory-CsYUbouO.js → useRunHistory-B1xJDwl1.js} +4 -3
  102. package/dist/{WorkflowShareDialog-6RRDe-_v.js → useWorkflowCodeExport-Bu2QYJzA.js} +7 -210
  103. package/dist/{useWorkflows-w4Dx2fF2.js → useWorkflows-BlVVu8NM.js} +3 -2
  104. package/dist/utils-uaL5UVxb.js +65 -0
  105. package/dist/workflow-builder.d.ts +1 -1
  106. package/dist/workflow-builder.js +4 -2
  107. package/dist/workflow-host.d.ts +6 -0
  108. package/dist/workflow-host.js +9 -0
  109. package/dist/workflow-pages.d.ts +55 -0
  110. package/dist/workflow-pages.js +113 -0
  111. package/dist/workflows-list.d.ts +1 -1
  112. package/dist/workflows-list.js +1 -1
  113. package/package.json +13 -1
  114. package/dist/ExecutionDetailPage-MvsnOnE1.d.ts +0 -4
  115. package/dist/HistoryPage-BqUizaFv.d.ts +0 -3
  116. package/dist/NodesPage-C97-9K2Y.d.ts +0 -3
  117. package/dist/TemplatesPage-D0qnXzHh.d.ts +0 -4
  118. package/dist/WorkflowsList-0d5GSKdh.d.ts +0 -3
  119. package/dist/agent-form-BvMWhQ42.js +0 -496
@@ -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
- import { G as nodeSubtitle, K as nodeTitle, Kn as getNodeDetail, X as useNodeConfig, rn as useNodeExecution } from "./FluidGridsProvider-DmvFADFa.js";
4
- import { H as NodeEditorTabBody, V as NodeExecutionActions, dt as NodeInputFields, lt as NodeEditorTabs, ot as useNodeEditorTab } from "./flow-builder-DEzT8TQu.js";
3
+ import { G as nodeSubtitle, K as nodeTitle, Mn as getNodeDetail, X as useNodeConfig, rn as useNodeExecution } from "./FluidGridsProvider-dvZSNtSW.js";
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";
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ // \0rolldown/runtime.js
3
+ var __defProp = Object.defineProperty;
4
+ var __exportAll = (all, flags) => {
5
+ let target = Object.setPrototypeOf({}, null);
6
+ for (var name in all) {
7
+ __defProp(target, name, {
8
+ get: all[name],
9
+ enumerable: true
10
+ });
11
+ }
12
+ if (!(flags & 1)) {
13
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
14
+ }
15
+ return flags & 2 ? target : Object.preventExtensions(target);
16
+ };
17
+
18
+ export { __exportAll as t };
@@ -0,0 +1,46 @@
1
+ "use client";
2
+ // src/modules/executions/utils/run-display.ts
3
+ /**
4
+ * Versions are stored as "v1"/"v2" (legacy: "1.0.0"). Render without
5
+ * double-prefixing: "v1" stays "v1", "1.0.0" becomes "v1.0.0".
6
+ */
7
+ function formatRunVersion(version) {
8
+ if (!version) return "";
9
+ return version.startsWith("v") ? version : `v${version}`;
10
+ }
11
+ function asString(value) {
12
+ return typeof value === "string" && value.trim() ? value : void 0;
13
+ }
14
+ /**
15
+ * Build a nodeId → display mapping from a workflow definitionJson.
16
+ * Label priority: user-set node label → manifest name → node type.
17
+ * Returns an empty map for missing/malformed definitions (e.g. runs of
18
+ * deleted workflows) — callers fall back to the raw nodeId.
19
+ */
20
+ function buildNodeDisplayMap(definitionJson) {
21
+ const map = {};
22
+ const nodes = definitionJson?.data?.nodes;
23
+ if (!Array.isArray(nodes)) return map;
24
+ for (const node of nodes) {
25
+ const id = asString(node?.id);
26
+ if (!id) continue;
27
+ const label = asString(node?.data?.label) ?? asString(node?.data?.nodeData?.name) ?? asString(node?.type);
28
+ if (!label) continue;
29
+ const operation = asString(node?.data?.operation_name);
30
+ map[id] = {
31
+ label,
32
+ operation: operation === "execute" ? void 0 : operation
33
+ };
34
+ }
35
+ return map;
36
+ }
37
+ /**
38
+ * "GitHub · searchIssues" title for a node, falling back to the raw nodeId
39
+ * when the definition doesn't know this node.
40
+ */
41
+ function nodeDisplayTitle(display, fallback) {
42
+ if (!display) return fallback;
43
+ return display.operation ? `${display.label} · ${display.operation}` : display.label;
44
+ }
45
+
46
+ export { formatRunVersion as n, nodeDisplayTitle as r, buildNodeDisplayMap as t };
@@ -0,0 +1,98 @@
1
+ "use client";
2
+ import { $u as ErrorType } from "./graphql-types-CDKVWH2R.js";
3
+
4
+ // src/modules/executions/utils/run-list-links.ts
5
+ /**
6
+ * Links into the Runs list that carry its filters in the query string
7
+ * (BOFF-9974), and the reading of them on the list.
8
+ *
9
+ * Insights' error panel links each failing node, error type, workflow and day
10
+ * to "the failed runs behind it". The two halves live together so a link and
11
+ * the filter it opens cannot drift apart.
12
+ *
13
+ * ../runs?status=FAILED&failedNodeType=internal%3Ahttp&from=…&to=…
14
+ *
15
+ * `from` / `to` are ISO instants (the list's custom date range); `workflowKey`
16
+ * is read by the list on its own, as it always was.
17
+ */
18
+ /** The filters a link may set; `workflowKey` stays with the list's own sync. */
19
+ const RUN_LIST_LINK_PARAMS = [
20
+ "status",
21
+ "errorType",
22
+ "failedNodeType",
23
+ "from",
24
+ "to"
25
+ ];
26
+ const RUN_STATUSES = [
27
+ "PENDING",
28
+ "RUNNING",
29
+ "COMPLETED",
30
+ "FAILED",
31
+ "CANCELLED",
32
+ "WAITING",
33
+ "TERMINATED"
34
+ ];
35
+ function isRunStatus(value) {
36
+ return RUN_STATUSES.some((status) => status === value);
37
+ }
38
+ /** A classification the service knows (its ErrorType enum). */
39
+ function isErrorType(value) {
40
+ return Object.values(ErrorType).some((type) => type === value);
41
+ }
42
+ function validDate(value) {
43
+ return value instanceof Date && Number.isFinite(value.getTime());
44
+ }
45
+ /** The Runs list with `link`'s filters, relative to an SDK page route. */
46
+ function runListPath(link) {
47
+ const params = new URLSearchParams();
48
+ if (link.workflowKey) params.set("workflowKey", link.workflowKey);
49
+ if (link.status) params.set("status", link.status);
50
+ if (link.errorType) params.set("errorType", link.errorType);
51
+ if (link.failedNodeType) params.set("failedNodeType", link.failedNodeType);
52
+ if (validDate(link.from)) params.set("from", link.from.toISOString());
53
+ if (validDate(link.to)) params.set("to", link.to.toISOString());
54
+ const query = params.toString();
55
+ return query ? `../runs?${query}` : "../runs";
56
+ }
57
+ function parseDate(value) {
58
+ if (!value) return null;
59
+ const date = new Date(value);
60
+ return Number.isFinite(date.getTime()) ? date : null;
61
+ }
62
+ /**
63
+ * The list filters a link's query string sets, or null when it carries none.
64
+ * Unknown values are ignored rather than trusted (the URL is user input); a
65
+ * reversed range is dropped, like the custom range inputs do.
66
+ */
67
+ function runListFilterFromSearch(params) {
68
+ const filter = {};
69
+ const status = params.get("status")?.trim().toUpperCase() ?? "";
70
+ if (isRunStatus(status)) filter.status = status;
71
+ const errorType = params.get("errorType")?.trim().toUpperCase() ?? "";
72
+ if (isErrorType(errorType)) filter.errorType = errorType;
73
+ const failedNodeType = params.get("failedNodeType")?.trim() ?? "";
74
+ if (failedNodeType) filter.failedNodeType = failedNodeType;
75
+ const from = parseDate(params.get("from"));
76
+ const to = parseDate(params.get("to"));
77
+ if ((from || to) && !(from && to && from.getTime() > to.getTime())) filter.dateRange = {
78
+ start: from,
79
+ end: to,
80
+ preset: "custom"
81
+ };
82
+ return Object.keys(filter).length > 0 ? filter : null;
83
+ }
84
+ /** A stable key of the link parameters in `params`, to apply each link once. */
85
+ function runListLinkKey(params) {
86
+ return RUN_LIST_LINK_PARAMS.map((name) => params.get(name) ?? "").join("|");
87
+ }
88
+ /** The UTC day [00:00, 24:00) of an ISO calendar date such as "2026-11-10". */
89
+ function utcDay(date) {
90
+ const from = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
91
+ if (!Number.isFinite(from.getTime())) return null;
92
+ return {
93
+ from,
94
+ to: /* @__PURE__ */ new Date(from.getTime() + 864e5 - 1)
95
+ };
96
+ }
97
+
98
+ export { utcDay as i, runListLinkKey as n, runListPath as r, runListFilterFromSearch as t };