@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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
3
|
-
import {
|
|
3
|
+
import { _ as throwIfResultError, m as describeOperationError, n as getFluidGridsClient } from "./client-C9XSzSXr.js";
|
|
4
|
+
import { Er as WorkflowDefinitionDocument, yi as WorkflowVersionDiffDocument } from "./graphql-operation-types-kX-MMjgW.js";
|
|
4
5
|
import { t as canvasFromDefinition } from "./definition-canvas--3MPHoP-.js";
|
|
5
6
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
6
7
|
import { Background, Controls, Handle, MiniMap, Position, ReactFlow, ReactFlowProvider } from "@xyflow/react";
|
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { hn as useCanvasEdges, n as FluidGridsProvider } from "./FluidGridsProvider-dvZSNtSW.js";
|
|
3
|
+
import { H as useFlowStore } from "./node-operation-selection--oy-yEq_.js";
|
|
4
|
+
import { t as Button } from "./button-DG7y_FVJ.js";
|
|
5
|
+
import { d as Input } from "./dialog-Cjb4lB4D.js";
|
|
6
|
+
import { b as Card } from "./TemplateCard-DsC0KNH1.js";
|
|
7
|
+
import { t as cn } from "./cn-QqidFIgr.js";
|
|
8
|
+
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
9
|
+
import { S as FluidGridsMark, x as useNodeSelectedEvent } from "./flow-builder-CZDKRc6f.js";
|
|
10
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
|
+
import { Background, Controls, Handle, MarkerType, MiniMap, Position, ReactFlow, ReactFlowProvider, useReactFlow } from "@xyflow/react";
|
|
12
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { Toaster } from "sonner";
|
|
14
|
+
import { edgeColor, nodeCategoryColor } from "@burdenoff/fe-libs/shared/utils";
|
|
15
|
+
import { useShallow } from "zustand/shallow";
|
|
16
|
+
import { ThemeProvider } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
17
|
+
import { useTheme, useThemeOrNull } from "@burdenoff/fe-libs/shared/hooks/shell";
|
|
18
|
+
import "@xyflow/react/dist/style.css";
|
|
19
|
+
import { ArrowLeft, Play, Save, Trash2 } from "lucide-react";
|
|
20
|
+
|
|
21
|
+
// src/theme/EnsureThemeProvider.tsx
|
|
22
|
+
/**
|
|
23
|
+
* Give the SDK's components a fe-libs theme context when the host has none.
|
|
24
|
+
*
|
|
25
|
+
* Several SDK components (the toast host, theme toggles, editors) read the
|
|
26
|
+
* theme through fe-libs `useTheme`, which throws outside a `ThemeProvider`.
|
|
27
|
+
* The Burdenoff app shells always mount one, but a third-party page that
|
|
28
|
+
* renders `<WorkflowBuilder>` or `<FluidGridsRoot>` directly does not. This
|
|
29
|
+
* wrapper mounts the SDK's own provider only in that case: when the host
|
|
30
|
+
* already has a provider, its children render inside the host's context
|
|
31
|
+
* unchanged, so there is never a second provider fighting over the
|
|
32
|
+
* document's theme attributes.
|
|
33
|
+
*/
|
|
34
|
+
function EnsureThemeProvider({ children }) {
|
|
35
|
+
if (useThemeOrNull()) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
36
|
+
return /* @__PURE__ */ jsx(ThemeProvider, { children });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/builder/components/ui/sonner.tsx
|
|
40
|
+
const Toaster$1 = ({ ...props }) => {
|
|
41
|
+
const { resolvedTheme = "light" } = useTheme();
|
|
42
|
+
return /* @__PURE__ */ jsx(Toaster, {
|
|
43
|
+
theme: resolvedTheme,
|
|
44
|
+
className: "toaster group",
|
|
45
|
+
toastOptions: { classNames: {
|
|
46
|
+
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
|
47
|
+
description: "group-[.toast]:text-muted-foreground",
|
|
48
|
+
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
|
49
|
+
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground"
|
|
50
|
+
} },
|
|
51
|
+
...props
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/components/WorkflowBuilderCore.tsx
|
|
56
|
+
const defaultEdgeOptions = {
|
|
57
|
+
type: "smoothstep",
|
|
58
|
+
markerEnd: {
|
|
59
|
+
type: MarkerType.ArrowClosed,
|
|
60
|
+
width: 21,
|
|
61
|
+
height: 21
|
|
62
|
+
},
|
|
63
|
+
style: { stroke: edgeColor("default") }
|
|
64
|
+
};
|
|
65
|
+
const handleStyle = {
|
|
66
|
+
width: 10,
|
|
67
|
+
height: 10,
|
|
68
|
+
background: "var(--color-node-handle-connected)",
|
|
69
|
+
border: "2px solid var(--color-node-bg)"
|
|
70
|
+
};
|
|
71
|
+
const baseNodeStyle = {
|
|
72
|
+
padding: "8px 16px",
|
|
73
|
+
borderRadius: "8px",
|
|
74
|
+
fontWeight: 500,
|
|
75
|
+
boxShadow: "var(--shadow-elevation-2)",
|
|
76
|
+
position: "relative",
|
|
77
|
+
color: "var(--color-action-primary-text)"
|
|
78
|
+
};
|
|
79
|
+
const NODE_CATEGORY_BY_TYPE = {
|
|
80
|
+
"trigger:api": "trigger",
|
|
81
|
+
end: "end",
|
|
82
|
+
"internal:if": "logic",
|
|
83
|
+
"internal:switch": "logic",
|
|
84
|
+
"internal:loop": "loop",
|
|
85
|
+
"internal:merge": "utility",
|
|
86
|
+
"internal:set": "data",
|
|
87
|
+
"internal:filter": "data",
|
|
88
|
+
"internal:aggregate": "data",
|
|
89
|
+
"internal:wait": "utility",
|
|
90
|
+
"internal:noop": "utility",
|
|
91
|
+
"internal:http": "integration"
|
|
92
|
+
};
|
|
93
|
+
function getNodeColor(type) {
|
|
94
|
+
return nodeCategoryColor(NODE_CATEGORY_BY_TYPE[type] ?? "default");
|
|
95
|
+
}
|
|
96
|
+
function TriggerNode({ data }) {
|
|
97
|
+
const tr = useTr();
|
|
98
|
+
const label = data.label;
|
|
99
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
100
|
+
style: {
|
|
101
|
+
...baseNodeStyle,
|
|
102
|
+
background: getNodeColor("trigger:api")
|
|
103
|
+
},
|
|
104
|
+
children: [label || tr("fluidgrids.components.workflowBuilderCore.triggerNodeLabel", "API Trigger"), /* @__PURE__ */ jsx(Handle, {
|
|
105
|
+
type: "source",
|
|
106
|
+
position: Position.Bottom,
|
|
107
|
+
style: handleStyle
|
|
108
|
+
})]
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function EndNode({ data }) {
|
|
112
|
+
const tr = useTr();
|
|
113
|
+
const label = data.label;
|
|
114
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
115
|
+
style: {
|
|
116
|
+
...baseNodeStyle,
|
|
117
|
+
background: getNodeColor("end")
|
|
118
|
+
},
|
|
119
|
+
children: [/* @__PURE__ */ jsx(Handle, {
|
|
120
|
+
type: "target",
|
|
121
|
+
position: Position.Top,
|
|
122
|
+
style: handleStyle
|
|
123
|
+
}), label || tr("fluidgrids.components.workflowBuilderCore.endNodeLabel", "End")]
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function ActionNode({ data, type }) {
|
|
127
|
+
const tr = useTr();
|
|
128
|
+
const label = data.label;
|
|
129
|
+
const color = getNodeColor(type || "default");
|
|
130
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
131
|
+
style: {
|
|
132
|
+
...baseNodeStyle,
|
|
133
|
+
background: color,
|
|
134
|
+
minWidth: 120,
|
|
135
|
+
textAlign: "center"
|
|
136
|
+
},
|
|
137
|
+
children: [
|
|
138
|
+
/* @__PURE__ */ jsx(Handle, {
|
|
139
|
+
type: "target",
|
|
140
|
+
position: Position.Top,
|
|
141
|
+
style: handleStyle
|
|
142
|
+
}),
|
|
143
|
+
label || tr("fluidgrids.components.workflowBuilderCore.actionNodeLabel", "Action"),
|
|
144
|
+
/* @__PURE__ */ jsx(Handle, {
|
|
145
|
+
type: "source",
|
|
146
|
+
position: Position.Bottom,
|
|
147
|
+
style: handleStyle
|
|
148
|
+
})
|
|
149
|
+
]
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const NODE_TYPES = {
|
|
153
|
+
"trigger:api": TriggerNode,
|
|
154
|
+
end: EndNode,
|
|
155
|
+
"internal:if": ActionNode,
|
|
156
|
+
"internal:switch": ActionNode,
|
|
157
|
+
"internal:loop": ActionNode,
|
|
158
|
+
"internal:merge": ActionNode,
|
|
159
|
+
"internal:set": ActionNode,
|
|
160
|
+
"internal:filter": ActionNode,
|
|
161
|
+
"internal:aggregate": ActionNode,
|
|
162
|
+
"internal:wait": ActionNode,
|
|
163
|
+
"internal:noop": ActionNode,
|
|
164
|
+
"internal:http": ActionNode,
|
|
165
|
+
"internal:subworkflow": ActionNode,
|
|
166
|
+
default: ActionNode
|
|
167
|
+
};
|
|
168
|
+
let nodeIdCounter = 0;
|
|
169
|
+
function FlowBuilderInner({ workflow, readonly = false, hideHeader = false, hideSidebar = false, hideLogsPanel = false, onSave, onExecute, onNodeClick, onBack, className }) {
|
|
170
|
+
const reactFlowInstance = useReactFlow();
|
|
171
|
+
const tr = useTr();
|
|
172
|
+
useNodeSelectedEvent();
|
|
173
|
+
const setWorkflow = useFlowStore((s) => s.actions.setWorkflow);
|
|
174
|
+
const resetWorkflow = useFlowStore((s) => s.actions.resetWorkflow);
|
|
175
|
+
const deleteNode = useFlowStore((s) => s.actions.nodes.deleteNode);
|
|
176
|
+
const setNodes = useFlowStore((s) => s.actions.nodes.setNodes);
|
|
177
|
+
const [nodes, edges, onNodesChange, onEdgesChange, onConnect] = useFlowStore(useShallow((s) => [
|
|
178
|
+
s.workflow.nodes,
|
|
179
|
+
s.workflow.edges,
|
|
180
|
+
s.actions.nodes.onNodesChange,
|
|
181
|
+
s.actions.edges.onEdgesChange,
|
|
182
|
+
s.actions.edges.onConnect
|
|
183
|
+
]));
|
|
184
|
+
const canvasEdges = useCanvasEdges(nodes, edges);
|
|
185
|
+
const [workflowName, setWorkflowName] = useState(workflow?.name || "Untitled Workflow");
|
|
186
|
+
const [selectedNodeId, setSelectedNodeId] = useState(null);
|
|
187
|
+
const reactFlowWrapper = useRef(null);
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
resetWorkflow();
|
|
190
|
+
if (workflow) {
|
|
191
|
+
setWorkflow(workflow);
|
|
192
|
+
setWorkflowName(workflow.name || "Untitled Workflow");
|
|
193
|
+
}
|
|
194
|
+
}, [
|
|
195
|
+
workflow,
|
|
196
|
+
resetWorkflow,
|
|
197
|
+
setWorkflow
|
|
198
|
+
]);
|
|
199
|
+
const handleNameChange = (e) => {
|
|
200
|
+
setWorkflowName(e.target.value);
|
|
201
|
+
setWorkflow({ name: e.target.value });
|
|
202
|
+
};
|
|
203
|
+
const handleSave = () => {
|
|
204
|
+
const savedWorkflow = {
|
|
205
|
+
id: workflow?.id || "",
|
|
206
|
+
workflowKey: workflow?.workflowKey || "",
|
|
207
|
+
name: workflowName,
|
|
208
|
+
version: workflow?.version || "1",
|
|
209
|
+
alias: workflow?.alias,
|
|
210
|
+
nodes,
|
|
211
|
+
edges,
|
|
212
|
+
sidebar: {
|
|
213
|
+
active: "none",
|
|
214
|
+
panels: { nodeProperties: { selectedNode: null } }
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
onSave?.(savedWorkflow);
|
|
218
|
+
};
|
|
219
|
+
const handleExecute = () => {
|
|
220
|
+
const runId = `run-${Date.now()}`;
|
|
221
|
+
onExecute?.(runId);
|
|
222
|
+
};
|
|
223
|
+
const handleNodeClick = useCallback((_event, node) => {
|
|
224
|
+
setSelectedNodeId(node.id);
|
|
225
|
+
onNodeClick?.(node);
|
|
226
|
+
}, [onNodeClick]);
|
|
227
|
+
const handlePaneClick = useCallback(() => {
|
|
228
|
+
setSelectedNodeId(null);
|
|
229
|
+
}, []);
|
|
230
|
+
const handleDragOver = useCallback((event) => {
|
|
231
|
+
event.preventDefault();
|
|
232
|
+
event.dataTransfer.dropEffect = "copy";
|
|
233
|
+
}, []);
|
|
234
|
+
const handleDrop = useCallback((event) => {
|
|
235
|
+
event.preventDefault();
|
|
236
|
+
const raw = event.dataTransfer.getData("application/json");
|
|
237
|
+
if (!raw) return;
|
|
238
|
+
let payload;
|
|
239
|
+
try {
|
|
240
|
+
payload = JSON.parse(raw);
|
|
241
|
+
} catch {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const nodeType = payload.type || payload.id || "default";
|
|
245
|
+
const label = payload.label || nodeType;
|
|
246
|
+
const bounds = reactFlowWrapper.current?.getBoundingClientRect();
|
|
247
|
+
if (!bounds) return;
|
|
248
|
+
const position = reactFlowInstance.screenToFlowPosition({
|
|
249
|
+
x: event.clientX - bounds.left,
|
|
250
|
+
y: event.clientY - bounds.top
|
|
251
|
+
});
|
|
252
|
+
nodeIdCounter += 1;
|
|
253
|
+
const newNode = {
|
|
254
|
+
id: `${nodeType}-${Date.now()}-${nodeIdCounter}`,
|
|
255
|
+
type: nodeType,
|
|
256
|
+
position,
|
|
257
|
+
data: { label }
|
|
258
|
+
};
|
|
259
|
+
const currentNodes = useFlowStore.getState().workflow.nodes;
|
|
260
|
+
setNodes([...currentNodes, newNode]);
|
|
261
|
+
}, [reactFlowInstance, setNodes]);
|
|
262
|
+
const selectedNode = selectedNodeId ? nodes.find((n) => n.id === selectedNodeId) : null;
|
|
263
|
+
const handleSelectedNodeLabelChange = useCallback((newLabel) => {
|
|
264
|
+
if (!selectedNodeId) return;
|
|
265
|
+
const updated = useFlowStore.getState().workflow.nodes.map((n) => n.id === selectedNodeId ? {
|
|
266
|
+
...n,
|
|
267
|
+
data: {
|
|
268
|
+
...n.data,
|
|
269
|
+
label: newLabel
|
|
270
|
+
}
|
|
271
|
+
} : n);
|
|
272
|
+
setNodes(updated);
|
|
273
|
+
}, [selectedNodeId, setNodes]);
|
|
274
|
+
const handleDeleteSelectedNode = useCallback(() => {
|
|
275
|
+
if (!selectedNode) return;
|
|
276
|
+
if (selectedNode.deletable === false) return;
|
|
277
|
+
deleteNode(selectedNode);
|
|
278
|
+
setSelectedNodeId(null);
|
|
279
|
+
}, [selectedNode, deleteNode]);
|
|
280
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
281
|
+
className: cn("flex flex-col flex-1 h-full w-full min-h-0", className),
|
|
282
|
+
children: [
|
|
283
|
+
!hideHeader && /* @__PURE__ */ jsxs(Card, {
|
|
284
|
+
className: "h-14 shrink-0 border-0 rounded-none bg-gradient-to-r from-primary/20 to-transparent p-2 flex items-center justify-between border-b",
|
|
285
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
286
|
+
className: "flex items-center gap-2",
|
|
287
|
+
children: [onBack && /* @__PURE__ */ jsx(Button, {
|
|
288
|
+
variant: "ghost",
|
|
289
|
+
size: "icon",
|
|
290
|
+
onClick: onBack,
|
|
291
|
+
children: /* @__PURE__ */ jsx(ArrowLeft, { className: "size-5" })
|
|
292
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
293
|
+
className: "font-semibold max-w-[300px]",
|
|
294
|
+
value: workflowName,
|
|
295
|
+
onChange: handleNameChange,
|
|
296
|
+
placeholder: tr("fluidgrids.components.workflowBuilderCore.workflowNamePlaceholder", "Workflow Name"),
|
|
297
|
+
disabled: readonly
|
|
298
|
+
})]
|
|
299
|
+
}), !readonly && /* @__PURE__ */ jsxs("div", {
|
|
300
|
+
className: "flex items-center gap-2",
|
|
301
|
+
children: [/* @__PURE__ */ jsxs(Button, {
|
|
302
|
+
"data-agent": "confirm",
|
|
303
|
+
variant: "outline",
|
|
304
|
+
size: "sm",
|
|
305
|
+
onClick: handleSave,
|
|
306
|
+
children: [/* @__PURE__ */ jsx(Save, { className: "size-4 mr-1" }), tr("fluidgrids.components.workflowBuilderCore.save", "Save")]
|
|
307
|
+
}), /* @__PURE__ */ jsxs(Button, {
|
|
308
|
+
"data-agent": "confirm",
|
|
309
|
+
size: "sm",
|
|
310
|
+
onClick: handleExecute,
|
|
311
|
+
children: [/* @__PURE__ */ jsx(Play, { className: "size-4 mr-1" }), tr("fluidgrids.components.workflowBuilderCore.run", "Run")]
|
|
312
|
+
})]
|
|
313
|
+
})]
|
|
314
|
+
}),
|
|
315
|
+
/* @__PURE__ */ jsxs("div", {
|
|
316
|
+
className: "flex flex-1 min-h-0 overflow-hidden",
|
|
317
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
318
|
+
className: "flex-1 h-full relative",
|
|
319
|
+
ref: reactFlowWrapper,
|
|
320
|
+
children: [/* @__PURE__ */ jsxs(ReactFlow, {
|
|
321
|
+
nodes,
|
|
322
|
+
edges: canvasEdges,
|
|
323
|
+
onNodesChange: readonly ? void 0 : onNodesChange,
|
|
324
|
+
onEdgesChange: readonly ? void 0 : onEdgesChange,
|
|
325
|
+
onConnect: readonly ? void 0 : onConnect,
|
|
326
|
+
onNodeClick: readonly ? void 0 : handleNodeClick,
|
|
327
|
+
onPaneClick: handlePaneClick,
|
|
328
|
+
onDragOver: readonly ? void 0 : handleDragOver,
|
|
329
|
+
onDrop: readonly ? void 0 : handleDrop,
|
|
330
|
+
nodeTypes: NODE_TYPES,
|
|
331
|
+
defaultEdgeOptions,
|
|
332
|
+
fitView: true,
|
|
333
|
+
snapToGrid: true,
|
|
334
|
+
snapGrid: [16, 16],
|
|
335
|
+
proOptions: { hideAttribution: true },
|
|
336
|
+
deleteKeyCode: readonly ? null : "Backspace",
|
|
337
|
+
children: [
|
|
338
|
+
/* @__PURE__ */ jsx(Background, { gap: 24 }),
|
|
339
|
+
/* @__PURE__ */ jsx(Controls, {}),
|
|
340
|
+
/* @__PURE__ */ jsx(MiniMap, {})
|
|
341
|
+
]
|
|
342
|
+
}), /* @__PURE__ */ jsx(FluidGridsMark, {})]
|
|
343
|
+
}), !hideSidebar && !readonly && /* @__PURE__ */ jsxs("div", {
|
|
344
|
+
className: "w-60 shrink-0 border-l bg-card overflow-y-auto",
|
|
345
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
346
|
+
className: "p-4 border-b",
|
|
347
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
348
|
+
className: "text-sm font-semibold",
|
|
349
|
+
children: tr("fluidgrids.components.workflowBuilderCore.nodePropertiesHeading", "Node Properties")
|
|
350
|
+
})
|
|
351
|
+
}), selectedNode ? /* @__PURE__ */ jsxs("div", {
|
|
352
|
+
className: "p-4 space-y-4",
|
|
353
|
+
children: [
|
|
354
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("label", {
|
|
355
|
+
className: "block text-xs font-medium text-muted-foreground mb-1",
|
|
356
|
+
children: tr("fluidgrids.components.workflowBuilderCore.nodeIdLabel", "Node ID")
|
|
357
|
+
}), /* @__PURE__ */ jsx("code", {
|
|
358
|
+
className: "block text-xs bg-muted px-2 py-1 rounded font-mono break-all",
|
|
359
|
+
children: selectedNode.id
|
|
360
|
+
})] }),
|
|
361
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("label", {
|
|
362
|
+
className: "block text-xs font-medium text-muted-foreground mb-1",
|
|
363
|
+
children: tr("fluidgrids.components.workflowBuilderCore.nodeTypeLabel", "Type")
|
|
364
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
365
|
+
className: "flex items-center gap-2",
|
|
366
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
367
|
+
className: "inline-block w-3 h-3 rounded-full shrink-0",
|
|
368
|
+
style: { background: getNodeColor(selectedNode.type || "default") }
|
|
369
|
+
}), /* @__PURE__ */ jsx("code", {
|
|
370
|
+
className: "text-xs font-mono",
|
|
371
|
+
children: selectedNode.type
|
|
372
|
+
})]
|
|
373
|
+
})] }),
|
|
374
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("label", {
|
|
375
|
+
className: "block text-xs font-medium text-muted-foreground mb-1",
|
|
376
|
+
children: tr("fluidgrids.components.workflowBuilderCore.nodeLabelLabel", "Label")
|
|
377
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
378
|
+
value: selectedNode.data?.label ?? "",
|
|
379
|
+
onChange: (e) => handleSelectedNodeLabelChange(e.target.value),
|
|
380
|
+
className: "text-sm",
|
|
381
|
+
placeholder: tr("fluidgrids.components.workflowBuilderCore.nodeLabelPlaceholder", "Node label")
|
|
382
|
+
})] }),
|
|
383
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("label", {
|
|
384
|
+
className: "block text-xs font-medium text-muted-foreground mb-1",
|
|
385
|
+
children: tr("fluidgrids.components.workflowBuilderCore.positionLabel", "Position")
|
|
386
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
387
|
+
className: "grid grid-cols-2 gap-2 text-xs text-muted-foreground",
|
|
388
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [
|
|
389
|
+
"X:",
|
|
390
|
+
" ",
|
|
391
|
+
/* @__PURE__ */ jsx("span", {
|
|
392
|
+
className: "font-mono",
|
|
393
|
+
children: Math.round(selectedNode.position.x)
|
|
394
|
+
})
|
|
395
|
+
] }), /* @__PURE__ */ jsxs("div", { children: [
|
|
396
|
+
"Y:",
|
|
397
|
+
" ",
|
|
398
|
+
/* @__PURE__ */ jsx("span", {
|
|
399
|
+
className: "font-mono",
|
|
400
|
+
children: Math.round(selectedNode.position.y)
|
|
401
|
+
})
|
|
402
|
+
] })]
|
|
403
|
+
})] }),
|
|
404
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("label", {
|
|
405
|
+
className: "block text-xs font-medium text-muted-foreground mb-1",
|
|
406
|
+
children: tr("fluidgrids.components.workflowBuilderCore.connectionsLabel", "Connections")
|
|
407
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
408
|
+
className: "text-xs text-muted-foreground",
|
|
409
|
+
children: (() => {
|
|
410
|
+
const inbound = edges.filter((e) => e.target === selectedNode.id);
|
|
411
|
+
const outbound = edges.filter((e) => e.source === selectedNode.id);
|
|
412
|
+
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
413
|
+
inbound.length,
|
|
414
|
+
" inbound, ",
|
|
415
|
+
outbound.length,
|
|
416
|
+
" outbound"
|
|
417
|
+
] }) });
|
|
418
|
+
})()
|
|
419
|
+
})] }),
|
|
420
|
+
selectedNode.deletable !== false && /* @__PURE__ */ jsx("div", {
|
|
421
|
+
className: "pt-2 border-t",
|
|
422
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
423
|
+
variant: "destructive",
|
|
424
|
+
size: "sm",
|
|
425
|
+
className: "w-full",
|
|
426
|
+
onClick: handleDeleteSelectedNode,
|
|
427
|
+
children: [/* @__PURE__ */ jsx(Trash2, { className: "size-4 mr-1" }), tr("fluidgrids.components.workflowBuilderCore.deleteNode", "Delete Node")]
|
|
428
|
+
})
|
|
429
|
+
})
|
|
430
|
+
]
|
|
431
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
432
|
+
className: "p-4",
|
|
433
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
434
|
+
className: "text-xs text-muted-foreground",
|
|
435
|
+
children: tr("fluidgrids.components.workflowBuilderCore.noSelectionHint", "Click a node on the canvas to view and edit its properties.")
|
|
436
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
437
|
+
className: "text-xs text-muted-foreground mt-2",
|
|
438
|
+
children: tr("fluidgrids.components.workflowBuilderCore.dragPaletteHint", "Drag nodes from the palette on the left to add them to the workflow.")
|
|
439
|
+
})]
|
|
440
|
+
})]
|
|
441
|
+
})]
|
|
442
|
+
}),
|
|
443
|
+
!hideLogsPanel && /* @__PURE__ */ jsxs("div", {
|
|
444
|
+
className: "h-32 border-t bg-card p-2",
|
|
445
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
446
|
+
className: "text-sm font-medium mb-2",
|
|
447
|
+
children: tr("fluidgrids.components.workflowBuilderCore.executionLogsHeading", "Execution Logs")
|
|
448
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
449
|
+
className: "text-xs text-muted-foreground",
|
|
450
|
+
children: tr("fluidgrids.components.workflowBuilderCore.executionLogsEmpty", "Execution logs will appear here when you run the workflow")
|
|
451
|
+
})]
|
|
452
|
+
})
|
|
453
|
+
]
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Lightweight, local-only workflow canvas.
|
|
458
|
+
*
|
|
459
|
+
* Host events (`FluidGridsEventMap`): reports `node:selected` exactly like the
|
|
460
|
+
* full builder canvas. Save and Run only hand data to `onSave` / `onExecute`
|
|
461
|
+
* and call no backend, so it emits no `workflow:saved`, `run:started` or
|
|
462
|
+
* `error` events: the host performs those actions and already knows their
|
|
463
|
+
* outcome. Works without a host `ThemeProvider`.
|
|
464
|
+
*/
|
|
465
|
+
function WorkflowBuilderCore(props) {
|
|
466
|
+
return /* @__PURE__ */ jsx(EnsureThemeProvider, { children: /* @__PURE__ */ jsxs(ReactFlowProvider, { children: [/* @__PURE__ */ jsx(FlowBuilderInner, { ...props }), /* @__PURE__ */ jsx(Toaster$1, {
|
|
467
|
+
richColors: true,
|
|
468
|
+
position: "bottom-center",
|
|
469
|
+
duration: 2e3
|
|
470
|
+
})] }) });
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/components/WorkflowBuilder.tsx
|
|
474
|
+
/**
|
|
475
|
+
* WorkflowBuilder - Standalone workflow builder component with Apollo client support
|
|
476
|
+
*
|
|
477
|
+
* Use this component when you want to embed the workflow builder in any React app.
|
|
478
|
+
* You can either:
|
|
479
|
+
* 1. Provide pre-configured Apollo clients (workspaceClient + globalClient) - Recommended
|
|
480
|
+
* 2. Provide URLs and let the component create clients internally
|
|
481
|
+
*
|
|
482
|
+
* It needs no host `ThemeProvider` (one is mounted only when the page has
|
|
483
|
+
* none). Host events: `onEvent` receives `node:selected`; Save and Run are
|
|
484
|
+
* local (they call `onSave` / `onExecute` and no backend), so they emit no
|
|
485
|
+
* `workflow:saved` / `run:started`. See `WorkflowBuilderCore`.
|
|
486
|
+
*
|
|
487
|
+
* @example Dual Client Injection (Recommended)
|
|
488
|
+
* ```tsx
|
|
489
|
+
* import { createFluidGridsClients } from '@fluidgrids/fe-sdk';
|
|
490
|
+
*
|
|
491
|
+
* const { workspaceClient, globalClient } = createFluidGridsClients({
|
|
492
|
+
* workspaceApiUrl: 'http://localhost:4000/workspaces/graphql',
|
|
493
|
+
* globalApiUrl: 'http://localhost:4000/global/graphql',
|
|
494
|
+
* authToken: token,
|
|
495
|
+
* workspaceId: 'ws-123',
|
|
496
|
+
* });
|
|
497
|
+
*
|
|
498
|
+
* <WorkflowBuilder
|
|
499
|
+
* workspaceClient={workspaceClient}
|
|
500
|
+
* globalClient={globalClient}
|
|
501
|
+
* workspaceId="ws-123"
|
|
502
|
+
* onSave={(workflow) => console.log(workflow)}
|
|
503
|
+
* />
|
|
504
|
+
* ```
|
|
505
|
+
*
|
|
506
|
+
* @example URL-based (Simpler, less flexible)
|
|
507
|
+
* ```tsx
|
|
508
|
+
* <WorkflowBuilder
|
|
509
|
+
* apiGatewayUrl="http://localhost:4000/workspaces/graphql"
|
|
510
|
+
* globalApiUrl="http://localhost:4000/global/graphql"
|
|
511
|
+
* authToken={token}
|
|
512
|
+
* workspaceId="ws-123"
|
|
513
|
+
* onSave={(workflow) => console.log(workflow)}
|
|
514
|
+
* />
|
|
515
|
+
* ```
|
|
516
|
+
*/
|
|
517
|
+
function WorkflowBuilder({ workflowId, workflowVersion, initialWorkflow, apiGatewayUrl, globalApiUrl, authToken, workspaceId, tenantId, productId, userId, workspaceToken, organizationId, workspaceClient, globalClient, theme, auth, onEvent, ...coreProps }) {
|
|
518
|
+
const workflow = initialWorkflow || createDefaultWorkflow(workflowId, workflowVersion);
|
|
519
|
+
return /* @__PURE__ */ jsx(FluidGridsProvider, {
|
|
520
|
+
apiGatewayUrl,
|
|
521
|
+
globalApiUrl,
|
|
522
|
+
authToken,
|
|
523
|
+
workspaceId,
|
|
524
|
+
tenantId,
|
|
525
|
+
productId,
|
|
526
|
+
userId,
|
|
527
|
+
workspaceToken,
|
|
528
|
+
organizationId,
|
|
529
|
+
workspaceClient,
|
|
530
|
+
globalClient,
|
|
531
|
+
theme,
|
|
532
|
+
auth,
|
|
533
|
+
onEvent,
|
|
534
|
+
children: /* @__PURE__ */ jsx(WorkflowBuilderCore, {
|
|
535
|
+
workflow,
|
|
536
|
+
...coreProps
|
|
537
|
+
})
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
function createDefaultWorkflow(id, version) {
|
|
541
|
+
return {
|
|
542
|
+
id: id || `workflow-${Date.now()}`,
|
|
543
|
+
workflowKey: id || `workflow-${Date.now()}`,
|
|
544
|
+
name: "Untitled Workflow",
|
|
545
|
+
version: version || "1",
|
|
546
|
+
nodes: [],
|
|
547
|
+
edges: [],
|
|
548
|
+
sidebar: {
|
|
549
|
+
active: "store-browse",
|
|
550
|
+
panels: { nodeProperties: { selectedNode: null } }
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
export { WorkflowBuilderCore as n, EnsureThemeProvider as r, WorkflowBuilder as t };
|