@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.
- package/README.md +41 -0
- package/dist/AiStudioPage-BHVEU4Wp.js +774 -0
- package/dist/ApprovalInboxPage-dbBDSJ-f.js +558 -0
- package/dist/DataSinkDashboardPage-1h2QsMzH.js +270 -0
- package/dist/DataTablesPage-BZy2z0LB.js +1690 -0
- package/dist/EntityTagPicker-BqRNsLCQ.js +135 -0
- package/dist/{ExecutionDetailPage-D-0_POAf.js → ExecutionDetailPage-BdcZmLT4.js} +799 -4420
- package/dist/ExecutionDetailPage-DvQ667OE.d.ts +10 -0
- package/dist/ExecutionsListPage-BCUJoAIE.js +2742 -0
- package/dist/{FailureTriagePanel-BHiduL7A.js → FailureTriagePanel-B9hDQymi.js} +4 -97
- package/dist/{FluidGridsProvider-DmvFADFa.js → FluidGridsProvider-dvZSNtSW.js} +10 -350
- package/dist/HistoryPage-BLoRpJ1R.d.ts +6 -0
- package/dist/{HistoryPage-BbUgxx1I.js → HistoryPage-U0tqupBN.js} +6 -4
- package/dist/HumanRequestCard-D-ooVPDn.js +439 -0
- package/dist/{InsightsPage-s6f5bU-8.js → InsightsPage-CALo16eB.js} +17 -328
- package/dist/ManagedAiPolicyAuthority-BxwJ3ptd.js +40 -0
- package/dist/{ManagedAiPolicyAuthority-CGux_DaV.d.ts → ManagedAiPolicyAuthority-DM3t3wNr.d.ts} +1 -5
- package/dist/ManagedAiPolicyAuthorityContext-CNkxIOZ1.js +10 -0
- package/dist/{MissingNodesInstallModal-B-9gHy2K.js → MissingNodesInstallModal-CMybsI8h.js} +3 -2
- package/dist/{NodesPage-ClvhUfbh.js → NodesPage-Bf5PhfBK.js} +7 -3
- package/dist/NodesPage-DEbnz9iU.d.ts +6 -0
- package/dist/{PublishCustomNodeAction-D2F7oN0S.js → PublishCustomNodeAction-5XXnSA3H.js} +3 -45
- package/dist/QuotaExhaustedDialog-7IFSaLyi.js +54 -0
- package/dist/RunnerStatusPill-Ctg4TJcP.js +187 -0
- package/dist/RunnersPage-CLCOCclc.js +467 -0
- package/dist/{ManagedAiPolicyAuthority-DsSaz-vg.js → SettingsPage-CJLZvv4J.js} +743 -773
- package/dist/SettingsPage-DMHQFj5-.d.ts +9 -0
- package/dist/TagFilterSelect-DCBOH6Ou.js +41 -0
- package/dist/TaskQueuesPage-9VgSnLdL.js +951 -0
- package/dist/TemplateCard-DsC0KNH1.js +1416 -0
- package/dist/{TemplateConfigurationModal-D_Mvgxqa.js → TemplateConfigurationModal-BhGWIzpm.js} +3 -2
- package/dist/{TemplateDetailPanel-DfFfUcOe.js → TemplateDetailPanel-D4cUVr-m.js} +3 -3
- package/dist/TemplatePreview-FayF6jxh.js +231 -0
- package/dist/TemplatesPage-BG3H-6v6.d.ts +10 -0
- package/dist/{TemplatesPage-Cku13bav.js → TemplatesPage-CsDNT54N.js} +11 -228
- package/dist/VariablesPage-67WR_lVE.js +949 -0
- package/dist/{VersionDiffDialog-Dq2xlPFI.js → VersionDiffDialog-DSN0mU0f.js} +2 -1
- package/dist/WorkflowBuilder-CPnXEL5J.js +555 -0
- package/dist/{WorkflowSearchRedirect-CaoOOpEl.js → WorkflowBuilder-YXRysvZc.js} +19 -585
- package/dist/{WorkflowProposalCard-8Vr56kQa.js → WorkflowProposalCard-qrEeNyYG.js} +4 -405
- package/dist/WorkflowSearchRedirect-DwDNZ_q5.js +36 -0
- package/dist/WorkflowShareDialog-mbIwRQUY.js +168 -0
- package/dist/WorkflowsList-CcNDQge5.d.ts +6 -0
- package/dist/{WorkflowsList-B2j1Pehb.js → WorkflowsList-DiiGyZkT.js} +12 -6
- package/dist/agent-form-Bfvm32j1.js +83 -0
- package/dist/{agentTools-DJ5o2ekg.js → agentTools-8s_25Q_F.js} +3 -2
- package/dist/{ai-usage-D5p7ZeRR.js → ai-usage-glCwHyQz.js} +1 -1
- package/dist/api-BrCHB5oA.js +224 -0
- package/dist/api-C8e0iV-Q.js +55 -0
- package/dist/button-DG7y_FVJ.js +48 -0
- package/dist/{canvasNoteTools-D3zUdEeg.js → canvasNoteTools-B6pYARgU.js} +2 -2
- package/dist/client-C9XSzSXr.js +1147 -0
- package/dist/code-editor-field-9-GdVE_8.js +111 -0
- package/dist/{codec-client-DstqyzTN.js → codec-client-CJ95Rmqo.js} +1 -1
- package/dist/constants-B2lhWNoN.js +202 -0
- package/dist/constants-XdvUxeWK.d.ts +162 -0
- package/dist/dialog-Cjb4lB4D.js +105 -0
- package/dist/executions.d.ts +1 -1
- package/dist/executions.js +2 -1
- package/dist/feature-flags-DM5myWaD.js +296 -0
- package/dist/flags.d.ts +3 -0
- package/dist/flags.js +4 -0
- package/dist/{flow-builder-DEzT8TQu.js → flow-builder-CZDKRc6f.js} +662 -10716
- package/dist/{node-endpoint-configs-DHFGA5MQ.js → graphql-operation-types-kX-MMjgW.js} +1 -1194
- package/dist/{graphql-types-XcDLtFwU.js → graphql-types-CDKVWH2R.js} +2 -202
- package/dist/history.d.ts +1 -1
- package/dist/history.js +1 -1
- package/dist/{index-DRf25-D3.d.ts → index-6JR2vD9J.d.ts} +33 -215
- package/dist/index-72XFgvbn.d.ts +132 -0
- package/dist/index-BcdtKBM-.d.ts +56 -0
- package/dist/{index-B3BWqafN.d.ts → index-DjiFgEQl.d.ts} +5 -131
- package/dist/index.d.ts +13 -9
- package/dist/index.js +52 -5300
- package/dist/{node-detail-view-LNqeIqN-.js → node-detail-view-CV4ZRwqh.js} +13 -8
- package/dist/node-editor-tab-body-DU-dh35X.js +174 -0
- package/dist/node-endpoint-configs-B5bjNMDW.js +37 -0
- package/dist/node-registry-refresh-Dy0uRg9f.js +84 -0
- package/dist/nodes.d.ts +1 -1
- package/dist/nodes.js +1 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +2 -1
- package/dist/popover-BJHvrFGR.js +472 -0
- package/dist/{quick-config-panel-D3ogsaFL.js → quick-config-panel-ws3pLvbt.js} +3 -2
- package/dist/rolldown-runtime-hDbaFkMy.js +18 -0
- package/dist/run-display-BycKYSU0.js +46 -0
- package/dist/run-list-links-ByYC0OlV.js +98 -0
- package/dist/schedule-panel-C0mfGQSD.js +7542 -0
- package/dist/settings.d.ts +2 -1
- package/dist/settings.js +2 -1
- package/dist/shared-CMfn30xT.js +196 -0
- package/dist/sidebar-node-editor-CR1PiZO-.js +177 -0
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +2 -1
- package/dist/theme-provider-B3mIuz2d.js +11 -0
- package/dist/{useAgentDefinitions-NFtLytDR.js → useAgentDefinitions-B0dam3_o.js} +3 -397
- package/dist/useConnections-Cs7LCWEM.js +401 -0
- package/dist/useDurableParity-CzUQMFJ3.js +415 -0
- package/dist/useEntityTags-DhnsZcTl.js +236 -0
- package/dist/{useExecutions-DAzeWHS6.js → useExecutions-9aLuOt1c.js} +4 -3
- package/dist/{useObservability-COCZ0hUS.js → useObservability-CfEw3ZFD.js} +2 -2
- package/dist/{useRunHistory-CsYUbouO.js → useRunHistory-B1xJDwl1.js} +4 -3
- package/dist/{WorkflowShareDialog-6RRDe-_v.js → useWorkflowCodeExport-Bu2QYJzA.js} +7 -210
- package/dist/{useWorkflows-w4Dx2fF2.js → useWorkflows-BlVVu8NM.js} +3 -2
- package/dist/utils-uaL5UVxb.js +65 -0
- package/dist/workflow-builder.d.ts +1 -1
- package/dist/workflow-builder.js +4 -2
- package/dist/workflow-host.d.ts +6 -0
- package/dist/workflow-host.js +9 -0
- package/dist/workflow-pages.d.ts +55 -0
- package/dist/workflow-pages.js +113 -0
- package/dist/workflows-list.d.ts +1 -1
- package/dist/workflows-list.js +1 -1
- package/package.json +13 -1
- package/dist/ExecutionDetailPage-MvsnOnE1.d.ts +0 -4
- package/dist/HistoryPage-BqUizaFv.d.ts +0 -3
- package/dist/NodesPage-C97-9K2Y.d.ts +0 -3
- package/dist/TemplatesPage-D0qnXzHh.d.ts +0 -4
- package/dist/WorkflowsList-0d5GSKdh.d.ts +0 -3
- 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,
|
|
4
|
-
import {
|
|
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 };
|