@burdenoff/fluidgrids-fe-sdk 2026.616.1 → 2026.616.2

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 (27) hide show
  1. package/dist/{TemplateConfigurationModal-UJAGRE7X.js → TemplateConfigurationModal-FPQR7W4M.js} +3 -3
  2. package/dist/{TemplateConfigurationModal-UJAGRE7X.js.map → TemplateConfigurationModal-FPQR7W4M.js.map} +1 -1
  3. package/dist/{WorkflowBuilder-TIT4KURD.js → WorkflowBuilder-BIAKKNKM.js} +6 -6
  4. package/dist/{WorkflowBuilder-TIT4KURD.js.map → WorkflowBuilder-BIAKKNKM.js.map} +1 -1
  5. package/dist/WorkflowsList-J33J7EIF.js +8 -0
  6. package/dist/{WorkflowsList-CLI32VRE.js.map → WorkflowsList-J33J7EIF.js.map} +1 -1
  7. package/dist/{chunk-NDJSUC4W.js → chunk-7VEOUEIN.js} +21 -21
  8. package/dist/chunk-7VEOUEIN.js.map +1 -0
  9. package/dist/{chunk-6FP5I5EG.js → chunk-C5VIFUNU.js} +3 -3
  10. package/dist/{chunk-6FP5I5EG.js.map → chunk-C5VIFUNU.js.map} +1 -1
  11. package/dist/{chunk-GSS5PHRL.js → chunk-M2KBI2FX.js} +3 -3
  12. package/dist/{chunk-GSS5PHRL.js.map → chunk-M2KBI2FX.js.map} +1 -1
  13. package/dist/{chunk-XVHQN2UK.js → chunk-TYOU6RYA.js} +781 -866
  14. package/dist/chunk-TYOU6RYA.js.map +1 -0
  15. package/dist/{chunk-CGKBAJMM.js → chunk-Z2ZEVYDE.js} +2 -2
  16. package/dist/chunk-Z2ZEVYDE.js.map +1 -0
  17. package/dist/index.d.ts +3 -3
  18. package/dist/index.js +12 -12
  19. package/dist/index.js.map +1 -1
  20. package/dist/useImportWorkflowTemplate-P62I2ADG.js +11 -0
  21. package/dist/{useImportWorkflowTemplate-RCPS4OTA.js.map → useImportWorkflowTemplate-P62I2ADG.js.map} +1 -1
  22. package/package.json +1 -1
  23. package/dist/WorkflowsList-CLI32VRE.js +0 -8
  24. package/dist/chunk-CGKBAJMM.js.map +0 -1
  25. package/dist/chunk-NDJSUC4W.js.map +0 -1
  26. package/dist/chunk-XVHQN2UK.js.map +0 -1
  27. package/dist/useImportWorkflowTemplate-RCPS4OTA.js +0 -11
@@ -1,7 +1,7 @@
1
- import { registerWorkflowNodeTypes, ensureNodeConfigsLoaded, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, useNodeExecution, AVAILABLE_NODES, createNodeWithDefaultData, NODES_METADATA, HeaderWithIcon, isNodeConfigsInitialized, useInstalledNodes, getNodeDetail, NODES, NodePropertyPanel, useInstallNode, useRefreshAvailableNodes, NODE_CONFIGS, ConnectionSelector } from './chunk-6FP5I5EG.js';
2
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, Input as Input$1 } from './chunk-NDJSUC4W.js';
1
+ import { registerWorkflowNodeTypes, ensureNodeConfigsLoaded, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, useNodeExecution, AVAILABLE_NODES, createNodeWithDefaultData, NODES_METADATA, isNodeConfigsInitialized, HeaderWithIcon, useInstalledNodes, useInstallNode, useRefreshAvailableNodes, getNodeDetail, NODES, NodePropertyPanel, NODE_CONFIGS, ConnectionSelector } from './chunk-C5VIFUNU.js';
2
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, Input as Input$1 } from './chunk-7VEOUEIN.js';
3
3
  import { cn, Badge as Badge$1, Button } from './chunk-Z54K22LP.js';
4
- import { useFlowStore } from './chunk-CGKBAJMM.js';
4
+ import { useFlowStore } from './chunk-Z2ZEVYDE.js';
5
5
  import { useLazyWorkflowDefinition, useCreateWorkflow, useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeactivateWorkflow } from './chunk-4FFPGQD3.js';
6
6
  import { NodeSchemaIntrospectionDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-FGYVIXQ7.js';
7
7
  import { BrowseWorkflowTemplatesDocument, BrowseWorkflowNodesDocument, UninstallWorkflowNodeDocument, CreateStoreOrderDocument } from './chunk-LUGJJ7LL.js';
@@ -15,15 +15,15 @@ import { useShallow, shallow } from 'zustand/shallow';
15
15
  import * as React3 from 'react';
16
16
  import React3__default, { forwardRef, lazy, memo, createContext, useContext, useMemo, useState, useRef, useEffect, useLayoutEffect, useCallback, Suspense, useDeferredValue } from 'react';
17
17
  import { Handle, Position, getBezierPath, MarkerType, ReactFlowProvider, useReactFlow, ReactFlow, Background, useOnSelectionChange, useStore, MiniMap, getSmoothStepPath, EdgeLabelRenderer, getOutgoers, getConnectedEdges, useNodes, useNodesState, useEdgesState, addEdge, Controls, Panel } from '@xyflow/react';
18
- import { cn as cn$1 } from '@burdenoff/fe-libs/utils';
19
- import { Icon } from '@iconify/react';
20
18
  import { produce } from 'immer';
19
+ import { cn as cn$1 } from '@burdenoff/fe-libs/utils';
21
20
  import { Card as Card$1, Badge, CardContent as CardContent$1, Button as Button$1, Input, Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, Popover, PopoverTrigger, PopoverContent, Toaster, Tabs, TabsList, TabsTrigger, TabsContent, CardHeader as CardHeader$1, CardTitle as CardTitle$1, CardDescription as CardDescription$1, ScrollArea, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, Label, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Textarea } from '@burdenoff/fe-libs/ui';
22
21
  import { isEmpty } from 'radash';
22
+ import { Icon } from '@iconify/react';
23
23
  import { gql } from '@apollo/client';
24
- import { Sparkles, Star, Download, Eye, History, Loader2, RotateCcw, Maximize2, LayoutGrid, Plus, Trash2, GitBranch, Store, AlertCircle, Search, RefreshCw, CheckCircle2, Package, Info, Copy, List, CheckCircle, XCircle, ArrowUpCircle, PlusCircle, ChevronDown, Type, Code, Hash, Braces, Workflow, ChevronRight, Layers, Check, DollarSign, X, AlertTriangle } from 'lucide-react';
25
24
  import { useQuery, useMutation } from '@apollo/client/react';
26
25
  import { gql as gql$1 } from '@apollo/client/core';
26
+ import { Sparkles, Star, Download, Eye, History, Loader2, RotateCcw, Maximize2, LayoutGrid, Plus, Trash2, GitBranch, AlertCircle, Search, RefreshCw, CheckCircle2, Package, Info, Copy, BadgeCheck, DollarSign, PlusCircle, ChevronDown, Type, Code, Hash, List, Braces, Workflow, ChevronRight, Layers, X, AlertTriangle } from 'lucide-react';
27
27
  import { toast } from 'sonner';
28
28
  import { animate, easeOut } from 'popmotion';
29
29
  import { createPortal } from 'react-dom';
@@ -36,28 +36,19 @@ import { ErrorBoundary } from '@burdenoff/fe-libs/shared/components';
36
36
  function ThemeProvider({ children }) {
37
37
  return /* @__PURE__ */ jsx(ThemeProvider$1, { children });
38
38
  }
39
- function useInsertNode() {
40
- const { addNodes, screenToFlowPosition, getNodes, updateNode } = useReactFlow();
41
- return useCallback(
42
- (type, pos) => {
43
- const _pos = pos || screenToFlowPosition({
44
- x: window.innerWidth / 2,
45
- y: window.innerHeight / 2
46
- });
47
- getNodes().forEach((node) => {
48
- if (node.selected) {
49
- updateNode(node.id, { selected: false });
50
- }
51
- });
52
- const newNode = createNodeWithDefaultData(type, {
53
- position: _pos,
54
- selected: true
55
- });
56
- addNodes(newNode);
57
- return newNode;
58
- },
59
- [screenToFlowPosition, getNodes, addNodes, updateNode]
60
- );
39
+ function useNodeList(nodes) {
40
+ return useMemo(() => {
41
+ return nodes.slice().sort((a, b) => {
42
+ if (a.type === "trigger:api" /* TRIGGER */) return -1;
43
+ if (b.type === "trigger:api" /* TRIGGER */) return 1;
44
+ if (a.type === "end" /* END */) return 1;
45
+ if (b.type === "end" /* END */) return -1;
46
+ return 0;
47
+ }).map((n) => ({
48
+ ...n,
49
+ detail: getNodeDetail(n.type)
50
+ }));
51
+ }, [nodes]);
61
52
  }
62
53
  function SidebarPanelWrapper({
63
54
  children,
@@ -73,244 +64,6 @@ function SidebarPanelWrapper({
73
64
  }
74
65
  );
75
66
  }
76
-
77
- // src/builder/contants/symbols.ts
78
- var NODE_TYPE_DRAG_DATA_FORMAT = "application/flow-builder.node-type";
79
- function NodePreviewDraggable({
80
- icon,
81
- title,
82
- description,
83
- type,
84
- setActivePanel,
85
- insertNode
86
- }) {
87
- const onDragStart = useCallback((e, type2) => {
88
- e.dataTransfer.setData(NODE_TYPE_DRAG_DATA_FORMAT, type2);
89
- e.dataTransfer.effectAllowed = "move";
90
- }, []);
91
- const onClick = useCallback(() => {
92
- insertNode(type);
93
- setActivePanel("none");
94
- }, [insertNode, setActivePanel, type]);
95
- return /* @__PURE__ */ jsxs(
96
- "div",
97
- {
98
- className: "flex cursor-grab select-none gap-2 border border-card-foreground/10 rounded-xl bg-card p-2.5 shadow-sm transition hover:ring-2 hover:ring-primary/50",
99
- onClick,
100
- onDragStart: (e) => onDragStart(e, type),
101
- draggable: true,
102
- "data-vaul-no-drag": true,
103
- children: [
104
- /* @__PURE__ */ jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsx("div", { className: "size-10 flex items-center justify-center border border-card-foreground/10 rounded-xl bg-card", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { icon, className: "size-6 text-card-foreground/80" }) : icon }) }),
105
- /* @__PURE__ */ jsxs("div", { className: "ml-1 flex grow flex-col", children: [
106
- /* @__PURE__ */ jsx("div", { className: "mt-px text-sm font-medium leading-normal", children: title }),
107
- /* @__PURE__ */ jsx("div", { className: "line-clamp-3 mt-1 text-xs text-card-foreground/60 leading-normal", children: description })
108
- ] })
109
- ]
110
- }
111
- );
112
- }
113
- function AvailableNodesPanel() {
114
- const [setActivePanel] = useFlowStore(
115
- useShallow((s) => [s.actions.sidebar.setActivePanel])
116
- );
117
- const [triggersExpanded, setTriggersExpanded] = useState(true);
118
- const [builtInExpanded, setBuiltInExpanded] = useState(true);
119
- const [storeExpanded, setStoreExpanded] = useState(true);
120
- const [nodesLoaded, setNodesLoaded] = useState(isNodeConfigsInitialized());
121
- const insertNode = useInsertNode();
122
- useEffect(() => {
123
- if (!nodesLoaded) {
124
- ensureNodeConfigsLoaded().then(() => {
125
- setNodesLoaded(true);
126
- });
127
- }
128
- }, [nodesLoaded]);
129
- const isTriggerType = (type) => {
130
- return type === "trigger" || type === "trigger:api" || type.startsWith("trigger:") || type.startsWith("internal:schedule") || type.startsWith("internal:webhook") || type.startsWith("internal:api") || type.startsWith("internal:form") || type.startsWith("internal:mcp") || type.endsWith("_trigger") || type.endsWith("Trigger") || type.endsWith("-trigger") || type === "integration/channel";
131
- };
132
- const triggerNodes = AVAILABLE_NODES.filter((node) => {
133
- return isTriggerType(node.type) && (node.publishType === "BUILTIN" || node.publishType === void 0 || node.publishType === null);
134
- });
135
- const builtInNodes = AVAILABLE_NODES.filter((node) => {
136
- return !isTriggerType(node.type) && (node.publishType === "BUILTIN" || node.publishType === void 0 || node.publishType === null);
137
- });
138
- const storeNodes = AVAILABLE_NODES.filter((node) => {
139
- return node.publishType === "STORE";
140
- });
141
- const storeTriggerNodes = storeNodes.filter(
142
- (node) => isTriggerType(node.type)
143
- );
144
- const storeActionNodes = storeNodes.filter(
145
- (node) => !isTriggerType(node.type)
146
- );
147
- return /* @__PURE__ */ jsxs(SidebarPanelWrapper, { children: [
148
- /* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-col items-center p-4 text-center", children: [
149
- /* @__PURE__ */ jsx("div", { className: "size-12 flex items-center justify-center rounded-full bg-primary", children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:grid", className: "size-6 text-white" }) }),
150
- /* @__PURE__ */ jsx("div", { className: "mt-4 text-balance font-medium", children: "Available Nodes" }),
151
- /* @__PURE__ */ jsx("div", { className: "mt-1 w-2/3 text-xs text-light-50/40 font-medium leading-normal", children: "Drag and drop nodes to build your workflow" })
152
- ] }),
153
- !nodesLoaded && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-8", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
154
- /* @__PURE__ */ jsx(
155
- Icon,
156
- {
157
- icon: "mynaui:spinner",
158
- className: "size-6 text-primary animate-spin"
159
- }
160
- ),
161
- /* @__PURE__ */ jsx("span", { className: "text-sm text-foreground/60", children: "Loading nodes..." })
162
- ] }) }),
163
- nodesLoaded && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4 overflow-y-auto max-h-[calc(100vh-200px)] scrollbar-thin scrollbar-track-transparent hover:scrollbar-thumb-gray-300/50 scrollbar-thumb-gray-300/30 scrollbar-w-[3px]", children: [
164
- (triggerNodes.length > 0 || storeTriggerNodes.length > 0) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
165
- /* @__PURE__ */ jsxs(
166
- "button",
167
- {
168
- onClick: () => setTriggersExpanded(!triggersExpanded),
169
- className: "flex items-center justify-between px-2 py-1.5 text-sm font-medium text-foreground/80 hover:text-foreground transition-colors",
170
- children: [
171
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
172
- /* @__PURE__ */ jsx(
173
- Icon,
174
- {
175
- icon: triggersExpanded ? "mynaui:chevron-down" : "mynaui:chevron-right",
176
- className: "size-4"
177
- }
178
- ),
179
- /* @__PURE__ */ jsx(
180
- Icon,
181
- {
182
- icon: "solar:play-bold",
183
- className: "size-3.5 text-primary"
184
- }
185
- ),
186
- "Triggers"
187
- ] }),
188
- /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground/50", children: triggerNodes.length + storeTriggerNodes.length })
189
- ]
190
- }
191
- ),
192
- triggersExpanded && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 pl-2", children: [
193
- triggerNodes.map((node) => /* @__PURE__ */ jsx(
194
- NodePreviewDraggable,
195
- {
196
- type: node.type,
197
- icon: node.icon,
198
- title: node.title,
199
- description: node.description ?? "",
200
- setActivePanel,
201
- insertNode
202
- },
203
- node.type
204
- )),
205
- storeTriggerNodes.map((node) => /* @__PURE__ */ jsx(
206
- NodePreviewDraggable,
207
- {
208
- type: node.type,
209
- icon: node.icon,
210
- title: node.title,
211
- description: node.description ?? "",
212
- setActivePanel,
213
- insertNode
214
- },
215
- node.type
216
- ))
217
- ] })
218
- ] }),
219
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
220
- /* @__PURE__ */ jsxs(
221
- "button",
222
- {
223
- onClick: () => setBuiltInExpanded(!builtInExpanded),
224
- className: "flex items-center justify-between px-2 py-1.5 text-sm font-medium text-foreground/80 hover:text-foreground transition-colors",
225
- children: [
226
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
227
- /* @__PURE__ */ jsx(
228
- Icon,
229
- {
230
- icon: builtInExpanded ? "mynaui:chevron-down" : "mynaui:chevron-right",
231
- className: "size-4"
232
- }
233
- ),
234
- "Built-in Nodes"
235
- ] }),
236
- /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground/50", children: builtInNodes.length })
237
- ]
238
- }
239
- ),
240
- builtInExpanded && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 pl-2", children: builtInNodes.map((node) => /* @__PURE__ */ jsx(
241
- NodePreviewDraggable,
242
- {
243
- type: node.type,
244
- icon: node.icon,
245
- title: node.title,
246
- description: node.description ?? "",
247
- setActivePanel,
248
- insertNode
249
- },
250
- node.type
251
- )) })
252
- ] }),
253
- storeActionNodes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
254
- /* @__PURE__ */ jsxs(
255
- "button",
256
- {
257
- onClick: () => setStoreExpanded(!storeExpanded),
258
- className: "flex items-center justify-between px-2 py-1.5 text-sm font-medium text-foreground/80 hover:text-foreground transition-colors",
259
- children: [
260
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
261
- /* @__PURE__ */ jsx(
262
- Icon,
263
- {
264
- icon: storeExpanded ? "mynaui:chevron-down" : "mynaui:chevron-right",
265
- className: "size-4"
266
- }
267
- ),
268
- "Store Nodes",
269
- /* @__PURE__ */ jsx(
270
- Icon,
271
- {
272
- icon: "mynaui:shopping-bag",
273
- className: "size-3.5 text-primary"
274
- }
275
- )
276
- ] }),
277
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-foreground/50", children: [
278
- storeActionNodes.length,
279
- " installed"
280
- ] })
281
- ]
282
- }
283
- ),
284
- storeExpanded && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 pl-2", children: storeActionNodes.map((node) => /* @__PURE__ */ jsx(
285
- NodePreviewDraggable,
286
- {
287
- type: node.type,
288
- icon: node.icon,
289
- title: node.title,
290
- description: node.description ?? "",
291
- setActivePanel,
292
- insertNode
293
- },
294
- node.type
295
- )) })
296
- ] })
297
- ] })
298
- ] });
299
- }
300
- function useNodeList(nodes) {
301
- return useMemo(() => {
302
- return nodes.slice().sort((a, b) => {
303
- if (a.type === "trigger:api" /* TRIGGER */) return -1;
304
- if (b.type === "trigger:api" /* TRIGGER */) return 1;
305
- if (a.type === "end" /* END */) return 1;
306
- if (b.type === "end" /* END */) return -1;
307
- return 0;
308
- }).map((n) => ({
309
- ...n,
310
- detail: getNodeDetail(n.type)
311
- }));
312
- }, [nodes]);
313
- }
314
67
  function SidebarPanelHeading({
315
68
  children,
316
69
  className,
@@ -1309,37 +1062,51 @@ function NodePropertiesPanel() {
1309
1062
  ] });
1310
1063
  }
1311
1064
 
1312
- // src/builder/components/flow-builder/components/blocks/sidebar/constants/panels.tsx
1313
- var PANEL_COMPONENTS = {
1314
- "available-nodes": AvailableNodesPanel,
1315
- "node-properties": NodePropertiesPanel,
1316
- none: () => null
1317
- };
1318
- function SwitchSidebarPanel({ active }) {
1319
- const PanelComponent = PANEL_COMPONENTS[active];
1320
- return PanelComponent ? /* @__PURE__ */ jsx(PanelComponent, {}) : null;
1321
- }
1322
- function SidebarButtonItem({
1323
- children,
1324
- className,
1325
- active,
1326
- ...props
1327
- }) {
1328
- return /* @__PURE__ */ jsx(
1329
- Button$1,
1330
- {
1331
- size: "icon",
1332
- type: "button",
1333
- variant: active ? "default" : "ghost",
1334
- className: cn$1(
1335
- "size-8 flex items-center justify-center",
1336
- className
1337
- ),
1338
- ...props,
1339
- children
1340
- }
1341
- );
1342
- }
1065
+ // src/builder/components/flow-builder/components/blocks/sidebar/panels/store-browse/store-categories.ts
1066
+ var STORE_CATEGORIES = [
1067
+ {
1068
+ key: "ai",
1069
+ label: "AI & Automation",
1070
+ description: "AI models, agents, and intelligent automation",
1071
+ icon: "mynaui:brain"
1072
+ },
1073
+ {
1074
+ key: "integration",
1075
+ label: "Action in an App",
1076
+ description: "Connect with apps like Slack, Notion, Google Sheets",
1077
+ icon: "mynaui:puzzle"
1078
+ },
1079
+ {
1080
+ key: "data",
1081
+ label: "Data & Transform",
1082
+ description: "Manipulate, filter, or convert data",
1083
+ icon: "mynaui:database"
1084
+ },
1085
+ {
1086
+ key: "flow",
1087
+ label: "Flow & Logic",
1088
+ description: "Branch, merge, or loop the flow",
1089
+ icon: "mynaui:git-branch"
1090
+ },
1091
+ {
1092
+ key: "core",
1093
+ label: "Core",
1094
+ description: "HTTP requests, code, webhooks, and more",
1095
+ icon: "mynaui:cog"
1096
+ },
1097
+ {
1098
+ key: "communication",
1099
+ label: "Communication",
1100
+ description: "Email, messaging, and notifications",
1101
+ icon: "mynaui:message-dots"
1102
+ },
1103
+ {
1104
+ key: "trigger",
1105
+ label: "Triggers",
1106
+ description: "Start your workflow automatically",
1107
+ icon: "mynaui:bolt"
1108
+ }
1109
+ ];
1343
1110
  function useStoreNodes(options = {}) {
1344
1111
  const client = useGlobalStoreClient();
1345
1112
  const context = useContext(FluidGridsContext);
@@ -1720,159 +1487,318 @@ gql$1`
1720
1487
  }
1721
1488
  }
1722
1489
  `;
1723
- function TabButton({
1724
- icon: Icon19,
1725
- label,
1726
- count: count2,
1727
- active,
1490
+
1491
+ // src/builder/contants/symbols.ts
1492
+ var NODE_TYPE_DRAG_DATA_FORMAT = "application/flow-builder.node-type";
1493
+ function StoreNodeListItem({
1494
+ name,
1495
+ description,
1496
+ icon,
1497
+ isInstalled,
1498
+ hasUpdate,
1499
+ nodeType,
1500
+ isDraggable,
1728
1501
  onClick
1729
1502
  }) {
1503
+ const handleDragStart = useCallback(
1504
+ (e) => {
1505
+ if (!isDraggable || !nodeType) return;
1506
+ e.dataTransfer.setData(NODE_TYPE_DRAG_DATA_FORMAT, nodeType);
1507
+ e.dataTransfer.effectAllowed = "move";
1508
+ },
1509
+ [isDraggable, nodeType]
1510
+ );
1730
1511
  return /* @__PURE__ */ jsxs(
1731
- Button,
1512
+ "button",
1732
1513
  {
1733
- variant: "ghost",
1734
- size: "sm",
1735
- className: cn(
1736
- "w-full justify-start gap-2 px-3",
1737
- active && "bg-accent text-accent-foreground"
1738
- ),
1739
1514
  onClick,
1515
+ draggable: isDraggable && !!nodeType,
1516
+ onDragStart: handleDragStart,
1517
+ title: isDraggable ? `${name} \u2014 drag to add to canvas` : name,
1518
+ className: "w-full flex items-center gap-3 px-2 py-2.5 rounded-md hover:bg-muted/60 transition-colors text-left group",
1519
+ style: isDraggable ? { cursor: "grab" } : void 0,
1740
1520
  children: [
1741
- /* @__PURE__ */ jsx(Icon19, { className: "size-4 shrink-0" }),
1742
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-left text-sm", children: label }),
1743
- count2 !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: count2 })
1744
- ]
1745
- }
1746
- );
1747
- }
1748
- function StoreNodesSidebar({
1749
- activeTab,
1750
- onTabChange,
1751
- searchTerm,
1752
- onSearchChange
1753
- }) {
1754
- const { totalCount: installedCount } = useInstalledNodes();
1755
- return /* @__PURE__ */ jsxs("div", { className: "w-64 shrink-0 border-r bg-muted/30 p-4 space-y-3 overflow-y-auto", children: [
1756
- /* @__PURE__ */ jsx(
1757
- Input$1,
1758
- {
1759
- placeholder: "Search nodes...",
1760
- value: searchTerm,
1761
- onChange: (e) => onSearchChange(e.target.value),
1762
- className: "h-9"
1763
- }
1764
- ),
1765
- /* @__PURE__ */ jsxs("nav", { className: "space-y-1", children: [
1766
- /* @__PURE__ */ jsx(
1767
- TabButton,
1768
- {
1769
- icon: List,
1770
- label: "All",
1771
- active: activeTab === "all",
1772
- onClick: () => onTabChange("all")
1773
- }
1774
- ),
1775
- /* @__PURE__ */ jsx(
1776
- TabButton,
1777
- {
1778
- icon: CheckCircle,
1779
- label: "Installed",
1780
- count: installedCount,
1781
- active: activeTab === "installed",
1782
- onClick: () => onTabChange("installed")
1783
- }
1784
- ),
1785
- /* @__PURE__ */ jsx(
1786
- TabButton,
1787
- {
1788
- icon: AlertCircle,
1789
- label: "In Workflow",
1790
- active: activeTab === "in-workflow",
1791
- onClick: () => onTabChange("in-workflow")
1792
- }
1793
- ),
1521
+ /* @__PURE__ */ jsx("div", { className: "size-9 shrink-0 rounded-lg bg-muted flex items-center justify-center overflow-hidden", children: icon ? /* @__PURE__ */ jsx("img", { src: icon, alt: name, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-muted-foreground", children: name.charAt(0).toUpperCase() }) }),
1522
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1523
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
1524
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors truncate", children: name }),
1525
+ hasUpdate && /* @__PURE__ */ jsx(
1526
+ "span",
1527
+ {
1528
+ className: "shrink-0 inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold",
1529
+ style: {
1530
+ background: "var(--color-status-warning-bgSubtle)",
1531
+ color: "var(--color-status-warning-text)"
1532
+ },
1533
+ children: "Update"
1534
+ }
1535
+ ),
1536
+ isInstalled && !hasUpdate && /* @__PURE__ */ jsxs(
1537
+ "span",
1538
+ {
1539
+ className: "shrink-0 inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] font-semibold",
1540
+ style: {
1541
+ background: "var(--color-status-success-bgSubtle)",
1542
+ color: "var(--color-status-success-text)"
1543
+ },
1544
+ children: [
1545
+ /* @__PURE__ */ jsx(
1546
+ "span",
1547
+ {
1548
+ className: "size-1.5 rounded-full inline-block",
1549
+ style: { background: "var(--color-status-success-bg)" }
1550
+ }
1551
+ ),
1552
+ "Installed"
1553
+ ]
1554
+ }
1555
+ )
1556
+ ] }),
1557
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate mt-0.5 leading-snug", children: description })
1558
+ ] }),
1559
+ isDraggable ? /* @__PURE__ */ jsx(
1560
+ Icon,
1561
+ {
1562
+ icon: "mynaui:drag-dots-vertical",
1563
+ className: "size-4 shrink-0 text-foreground/40 group-hover:text-primary transition-colors"
1564
+ }
1565
+ ) : /* @__PURE__ */ jsx(
1566
+ Icon,
1567
+ {
1568
+ icon: "mynaui:chevron-right",
1569
+ className: "size-4 shrink-0 text-foreground/40"
1570
+ }
1571
+ )
1572
+ ]
1573
+ }
1574
+ );
1575
+ }
1576
+ function StoreCategoryList({
1577
+ searchTerm,
1578
+ onSearchChange,
1579
+ onSelectCategory,
1580
+ onSelectNode
1581
+ }) {
1582
+ const isSearching = searchTerm.trim().length > 0;
1583
+ const { products, loading, hasMore, fetchMore } = useStoreNodes({
1584
+ filter: {
1585
+ type: "NODE",
1586
+ compatibleWith: "fluidgrids",
1587
+ search: isSearching ? searchTerm.trim() : void 0
1588
+ }
1589
+ });
1590
+ const { installedAppIds, installationsMap } = useInstalledNodes();
1591
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [
1592
+ /* @__PURE__ */ jsx("div", { className: "px-3 pt-3 pb-2 shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1794
1593
  /* @__PURE__ */ jsx(
1795
- TabButton,
1594
+ Icon,
1796
1595
  {
1797
- icon: XCircle,
1798
- label: "Missing",
1799
- active: activeTab === "missing",
1800
- onClick: () => onTabChange("missing")
1596
+ icon: "mynaui:search",
1597
+ className: "absolute left-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground pointer-events-none"
1801
1598
  }
1802
1599
  ),
1803
1600
  /* @__PURE__ */ jsx(
1804
- TabButton,
1601
+ Input$1,
1602
+ {
1603
+ value: searchTerm,
1604
+ onChange: (e) => onSearchChange(e.target.value),
1605
+ placeholder: "Search nodes...",
1606
+ className: "pl-8 text-sm h-9"
1607
+ }
1608
+ ),
1609
+ searchTerm && /* @__PURE__ */ jsx(
1610
+ "button",
1805
1611
  {
1806
- icon: ArrowUpCircle,
1807
- label: "Update Available",
1808
- active: activeTab === "update-available",
1809
- onClick: () => onTabChange("update-available")
1612
+ onClick: () => onSearchChange(""),
1613
+ className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors",
1614
+ children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:x", className: "size-3.5" })
1810
1615
  }
1811
1616
  )
1812
- ] })
1617
+ ] }) }),
1618
+ isSearching ? (
1619
+ /* Search results */
1620
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-2 pb-2", children: loading && products.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-10", children: /* @__PURE__ */ jsx(
1621
+ Icon,
1622
+ {
1623
+ icon: "mynaui:spinner",
1624
+ className: "size-5 text-primary animate-spin"
1625
+ }
1626
+ ) }) : products.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center py-10 px-4", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
1627
+ "No nodes found for \u201C",
1628
+ searchTerm,
1629
+ "\u201D"
1630
+ ] }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1631
+ /* @__PURE__ */ jsxs("p", { className: "px-2 py-1.5 text-xs text-muted-foreground font-medium", children: [
1632
+ products.length,
1633
+ " result",
1634
+ products.length !== 1 ? "s" : ""
1635
+ ] }),
1636
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: products.map((node) => {
1637
+ const installation = installationsMap.get(node.id);
1638
+ const isInstalled = installedAppIds.has(node.id);
1639
+ const hasUpdate = isInstalled && !!installation?.installedVersion && !!node.manifestVersion && installation.installedVersion !== node.manifestVersion;
1640
+ const manifestNodeType = node.manifest?.nodeType;
1641
+ const nodeType = manifestNodeType ?? (isInstalled ? `store/${node.slug}` : void 0);
1642
+ const isDraggable = !!nodeType && (isInstalled || AVAILABLE_NODES.some((n) => n.type === nodeType));
1643
+ return /* @__PURE__ */ jsx(
1644
+ StoreNodeListItem,
1645
+ {
1646
+ name: node.name,
1647
+ description: node.description,
1648
+ icon: node.icon,
1649
+ isInstalled,
1650
+ hasUpdate,
1651
+ nodeType,
1652
+ isDraggable,
1653
+ onClick: () => onSelectNode(node)
1654
+ },
1655
+ node.id
1656
+ );
1657
+ }) }),
1658
+ hasMore && /* @__PURE__ */ jsx(
1659
+ "button",
1660
+ {
1661
+ onClick: fetchMore,
1662
+ className: "w-full mt-2 py-2 text-xs text-primary hover:text-primary/80 font-medium transition-colors",
1663
+ children: "Load more"
1664
+ }
1665
+ )
1666
+ ] }) })
1667
+ ) : (
1668
+ /* Category list */
1669
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-2 pb-2", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5 pt-1", children: STORE_CATEGORIES.map((cat) => /* @__PURE__ */ jsxs(
1670
+ "button",
1671
+ {
1672
+ onClick: () => onSelectCategory(cat),
1673
+ className: "w-full flex items-center gap-3 px-2 py-3 rounded-md hover:bg-muted/60 transition-colors text-left group",
1674
+ children: [
1675
+ /* @__PURE__ */ jsx("div", { className: "size-9 shrink-0 rounded-lg bg-muted flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { icon: cat.icon, className: "size-5 text-primary" }) }),
1676
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1677
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors", children: cat.label }),
1678
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate mt-0.5", children: cat.description })
1679
+ ] }),
1680
+ /* @__PURE__ */ jsx(
1681
+ Icon,
1682
+ {
1683
+ icon: "mynaui:chevron-right",
1684
+ className: "size-4 shrink-0 text-foreground/40"
1685
+ }
1686
+ )
1687
+ ]
1688
+ },
1689
+ cat.key
1690
+ )) }) })
1691
+ )
1813
1692
  ] });
1814
1693
  }
1815
- var Card = forwardRef(
1816
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1817
- "div",
1818
- {
1819
- ref,
1820
- className: cn(
1821
- "rounded-lg border bg-card text-card-foreground shadow-sm transition-all duration-200 ease-out hover:shadow-md",
1822
- className
1823
- ),
1824
- ...props
1825
- }
1826
- )
1827
- );
1828
- Card.displayName = "Card";
1829
- var CardHeader = forwardRef(
1830
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1831
- "div",
1832
- {
1833
- ref,
1834
- className: cn("flex flex-col space-y-1.5 p-6", className),
1835
- ...props
1836
- }
1837
- )
1838
- );
1839
- CardHeader.displayName = "CardHeader";
1840
- var CardTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1841
- "h3",
1842
- {
1843
- ref,
1844
- className: cn(
1845
- "text-2xl font-semibold leading-none tracking-tight",
1846
- className
1847
- ),
1848
- ...props
1849
- }
1850
- ));
1851
- CardTitle.displayName = "CardTitle";
1852
- var CardDescription = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1853
- "p",
1854
- {
1855
- ref,
1856
- className: cn("text-sm text-muted-foreground", className),
1857
- ...props
1858
- }
1859
- ));
1860
- CardDescription.displayName = "CardDescription";
1861
- var CardContent = forwardRef(
1862
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props })
1863
- );
1864
- CardContent.displayName = "CardContent";
1865
- var CardFooter = forwardRef(
1866
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1867
- "div",
1868
- {
1869
- ref,
1870
- className: cn("flex items-center p-6 pt-0", className),
1871
- ...props
1694
+ function StoreCategoryNodes({
1695
+ category,
1696
+ onBack,
1697
+ onSelectNode
1698
+ }) {
1699
+ const [searchTerm, setSearchTerm] = useState("");
1700
+ const { products, loading, hasMore, fetchMore } = useStoreNodes({
1701
+ filter: {
1702
+ type: "NODE",
1703
+ compatibleWith: "fluidgrids",
1704
+ category: category.key || void 0,
1705
+ search: searchTerm.trim() || void 0
1872
1706
  }
1873
- )
1874
- );
1875
- CardFooter.displayName = "CardFooter";
1707
+ });
1708
+ const { installedAppIds, installationsMap } = useInstalledNodes();
1709
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [
1710
+ /* @__PURE__ */ jsxs("div", { className: "px-3 pt-3 pb-2 shrink-0", children: [
1711
+ /* @__PURE__ */ jsxs(
1712
+ "button",
1713
+ {
1714
+ onClick: onBack,
1715
+ className: "flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground mb-3 transition-colors",
1716
+ children: [
1717
+ /* @__PURE__ */ jsx(Icon, { icon: "mynaui:chevron-left", className: "size-3.5" }),
1718
+ "Back"
1719
+ ]
1720
+ }
1721
+ ),
1722
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 mb-3", children: [
1723
+ /* @__PURE__ */ jsx("div", { className: "size-8 shrink-0 rounded-lg bg-muted flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { icon: category.icon, className: "size-4 text-primary" }) }),
1724
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
1725
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-foreground leading-tight", children: category.label }),
1726
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: category.description })
1727
+ ] })
1728
+ ] }),
1729
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1730
+ /* @__PURE__ */ jsx(
1731
+ Icon,
1732
+ {
1733
+ icon: "mynaui:search",
1734
+ className: "absolute left-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground pointer-events-none"
1735
+ }
1736
+ ),
1737
+ /* @__PURE__ */ jsx(
1738
+ Input$1,
1739
+ {
1740
+ value: searchTerm,
1741
+ onChange: (e) => setSearchTerm(e.target.value),
1742
+ placeholder: `Search in ${category.label}...`,
1743
+ className: "pl-8 text-sm h-9"
1744
+ }
1745
+ ),
1746
+ searchTerm && /* @__PURE__ */ jsx(
1747
+ "button",
1748
+ {
1749
+ onClick: () => setSearchTerm(""),
1750
+ className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors",
1751
+ children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:x", className: "size-3.5" })
1752
+ }
1753
+ )
1754
+ ] })
1755
+ ] }),
1756
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-2 pb-2", children: loading && products.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-10", children: /* @__PURE__ */ jsx(
1757
+ Icon,
1758
+ {
1759
+ icon: "mynaui:spinner",
1760
+ className: "size-5 text-primary animate-spin"
1761
+ }
1762
+ ) }) : products.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center py-10 px-4", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: searchTerm ? `No nodes found for "${searchTerm}"` : "No nodes in this category yet" }) }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
1763
+ /* @__PURE__ */ jsxs("p", { className: "px-2 py-1.5 text-xs text-muted-foreground font-medium", children: [
1764
+ products.length,
1765
+ " node",
1766
+ products.length !== 1 ? "s" : "",
1767
+ searchTerm ? ` matching "${searchTerm}"` : ""
1768
+ ] }),
1769
+ products.map((node) => {
1770
+ const installation = installationsMap.get(node.id);
1771
+ const isInstalled = installedAppIds.has(node.id);
1772
+ const hasUpdate = isInstalled && !!installation?.installedVersion && !!node.manifestVersion && installation.installedVersion !== node.manifestVersion;
1773
+ const manifestNodeType = node.manifest?.nodeType;
1774
+ const nodeType = manifestNodeType ?? (isInstalled ? `store/${node.slug}` : void 0);
1775
+ const isDraggable = !!nodeType && (isInstalled || AVAILABLE_NODES.some((n) => n.type === nodeType));
1776
+ return /* @__PURE__ */ jsx(
1777
+ StoreNodeListItem,
1778
+ {
1779
+ name: node.name,
1780
+ description: node.description,
1781
+ icon: node.icon,
1782
+ isInstalled,
1783
+ hasUpdate,
1784
+ nodeType,
1785
+ isDraggable,
1786
+ onClick: () => onSelectNode(node)
1787
+ },
1788
+ node.id
1789
+ );
1790
+ }),
1791
+ hasMore && /* @__PURE__ */ jsx(
1792
+ "button",
1793
+ {
1794
+ onClick: fetchMore,
1795
+ className: "w-full mt-2 py-2 text-xs text-primary hover:text-primary/80 font-medium transition-colors",
1796
+ children: "Load more"
1797
+ }
1798
+ )
1799
+ ] }) })
1800
+ ] });
1801
+ }
1876
1802
  var UninstallNodeDialog = ({
1877
1803
  nodeName,
1878
1804
  nodeType,
@@ -1964,28 +1890,22 @@ var UninstallNodeDialog = ({
1964
1890
  ] }) });
1965
1891
  };
1966
1892
  function formatDownloads(count2) {
1967
- if (count2 >= 1e6) {
1968
- return `${(count2 / 1e6).toFixed(1)}M`;
1969
- }
1970
- if (count2 >= 1e3) {
1971
- return `${(count2 / 1e3).toFixed(1)}k`;
1972
- }
1893
+ if (count2 >= 1e6) return `${(count2 / 1e6).toFixed(1)}M`;
1894
+ if (count2 >= 1e3) return `${(count2 / 1e3).toFixed(1)}k`;
1973
1895
  return count2.toString();
1974
1896
  }
1975
- function StoreNodeCard({
1976
- node,
1977
- isInstalled,
1978
- installedVersion,
1979
- installationId,
1980
- onClick
1981
- }) {
1897
+ function StoreNodeDetail({ node, onBack }) {
1982
1898
  const { installNode, installing } = useInstallNode();
1983
1899
  const { updateNode, updating } = useUpdateNode();
1984
1900
  const { uninstallNode, loading: uninstalling } = useUninstallNode();
1985
- const { checkNodeUsage} = useNodeUsageInWorkflows();
1901
+ const { checkNodeUsage } = useNodeUsageInWorkflows();
1986
1902
  const { removeNodeFromWorkflows } = useRemoveNodeFromWorkflows();
1987
1903
  const { createOrder, creating: creatingOrder } = useCreateOrder();
1988
- const { refetch: refetchInstalledNodes } = useInstalledNodes();
1904
+ const {
1905
+ installedAppIds,
1906
+ installationsMap,
1907
+ refetch: refetchInstalledNodes
1908
+ } = useInstalledNodes();
1989
1909
  const { refreshAvailableNodes } = useRefreshAvailableNodes();
1990
1910
  const [showUninstallDialog, setShowUninstallDialog] = useState(false);
1991
1911
  const [checkingNodeUsage, setCheckingNodeUsage] = useState(false);
@@ -1993,490 +1913,474 @@ function StoreNodeCard({
1993
1913
  const [nodeUsage, setNodeUsage] = useState({ isUsed: false, workflows: [] });
1994
1914
  const context = useContext(FluidGridsContext);
1995
1915
  const workspaceId = context?.workspaceId ?? getFluidGridsConfig().workspaceId;
1996
- context?.organizationId;
1916
+ const isInstalled = installedAppIds.has(node.id);
1917
+ const installation = installationsMap.get(node.id);
1918
+ const installedVersion = installation?.installedVersion;
1919
+ const installationId = installation?.installationId;
1997
1920
  const latestVersion = node.manifestVersion;
1998
- const hasUpdate = isInstalled && installedVersion && latestVersion && installedVersion !== latestVersion;
1999
- const handleInstall = async (e) => {
2000
- e.stopPropagation();
1921
+ const hasUpdate = isInstalled && !!installedVersion && !!latestVersion && installedVersion !== latestVersion;
1922
+ const isFree = node.pricingModel === "FREE";
1923
+ const isPurchased = node.isPurchased === true;
1924
+ const canInstall = isFree || isPurchased;
1925
+ const isInstalling = installing === node.id;
1926
+ const isUpdating = updating === node.id;
1927
+ const handleInstall = async () => {
2001
1928
  const result = await installNode(node);
2002
1929
  if (result.success) {
2003
- toast.success("Node installed successfully!", {
1930
+ toast.success("Node installed!", {
2004
1931
  description: `${node.name} is now available in your workflow builder.`
2005
1932
  });
2006
- console.log(
2007
- "[StoreNodeCard] Refreshing available nodes after install..."
2008
- );
2009
1933
  await refreshAvailableNodes();
2010
- console.log("[StoreNodeCard] Refetching installed nodes list...");
2011
1934
  await refetchInstalledNodes();
2012
- console.log("[StoreNodeCard] Refresh complete!");
2013
1935
  } else {
2014
1936
  toast.error("Installation failed", {
2015
- description: result.error || "Failed to install node. Please try again."
1937
+ description: result.error || "Please try again."
2016
1938
  });
2017
1939
  }
2018
1940
  };
2019
- const handleUpdate = async (e) => {
2020
- e.stopPropagation();
1941
+ const handleUpdate = async () => {
2021
1942
  if (!installationId) {
2022
1943
  toast.error("Cannot update node", {
2023
- description: "Installation ID not found. Please reinstall the node."
1944
+ description: "Installation ID not found. Please reinstall."
2024
1945
  });
2025
1946
  return;
2026
1947
  }
2027
1948
  const result = await updateNode(node, installationId);
2028
1949
  if (result.success) {
2029
- toast.success("Node updated successfully!", {
2030
- description: `${node.name} has been updated to v${latestVersion}.`
1950
+ toast.success("Node updated!", {
1951
+ description: `${node.name} updated to v${latestVersion}.`
2031
1952
  });
2032
- console.log("[StoreNodeCard] Refreshing available nodes after update...");
2033
1953
  await refreshAvailableNodes();
2034
- console.log("[StoreNodeCard] Refetching installed nodes list...");
2035
1954
  await refetchInstalledNodes();
2036
- console.log("[StoreNodeCard] Refresh complete!");
2037
1955
  } else {
2038
1956
  toast.error("Update failed", {
2039
- description: result.error || "Failed to update node. Please try again."
2040
- });
2041
- }
2042
- };
2043
- const handlePurchase = async (e) => {
2044
- e.stopPropagation();
2045
- try {
2046
- toast.info("Creating order", {
2047
- description: `Preparing checkout for ${node.name}...`
2048
- });
2049
- const unitPrice = node.price || 0;
2050
- const quantity = 1;
2051
- const subtotal = unitPrice * quantity;
2052
- const lineItem = {
2053
- productId: node.id,
2054
- name: node.name,
2055
- // Required: product name at time of purchase
2056
- quantity,
2057
- unitPrice,
2058
- // Required: unit price for one item
2059
- subtotal,
2060
- // Required: subtotal (unitPrice * quantity)
2061
- itemType: "DIGITAL",
2062
- // Optional: type of item
2063
- pricingModel: node.pricingModel || "PAID_ONETIME",
2064
- // Optional: pricing model
2065
- version: node.manifestVersion || void 0
2066
- // Optional: product version
2067
- };
2068
- const orderInput = {
2069
- total: subtotal,
2070
- lineItems: [lineItem],
2071
- billingAccountId: ""
2072
- // Will be set on billing page
2073
- };
2074
- const result = await createOrder(orderInput);
2075
- if (result.success && result.order?.id) {
2076
- console.log("[StoreNodeCard] Order created:", result.order.id);
2077
- const checkoutUrl = `/billing/checkout/store/${result.order.id}`;
2078
- console.log("[StoreNodeCard] Navigating to checkout:", checkoutUrl);
2079
- window.location.href = checkoutUrl;
2080
- } else {
2081
- throw new Error(result.error || "Failed to create order");
2082
- }
2083
- } catch (error) {
2084
- console.error("[StoreNodeCard] Purchase flow error:", error);
2085
- toast.error("Failed to start checkout", {
2086
- description: error instanceof Error ? error.message : "Please try again."
1957
+ description: result.error || "Please try again."
2087
1958
  });
2088
1959
  }
2089
1960
  };
2090
- const handleUninstallClick = async (e) => {
2091
- e.stopPropagation();
2092
- if (!installationId) {
2093
- toast.error("Cannot uninstall node", {
2094
- description: "Installation ID not found."
2095
- });
2096
- return;
2097
- }
2098
- if (!workspaceId) {
2099
- toast.error("Workspace not found", {
2100
- description: "Unable to check node usage without workspace context."
2101
- });
2102
- return;
2103
- }
1961
+ const handleUninstallClick = async () => {
1962
+ if (!installationId || !workspaceId) return;
2104
1963
  try {
2105
1964
  setCheckingNodeUsage(true);
2106
- const nodeVersion = installedVersion || latestVersion || "1.0.0";
2107
1965
  const usage = await checkNodeUsage(
2108
1966
  workspaceId,
2109
1967
  node.name,
2110
- // Use node name as identifier
2111
- nodeVersion
1968
+ installedVersion || latestVersion || "1.0.0"
2112
1969
  );
2113
1970
  setNodeUsage(usage);
2114
1971
  setShowUninstallDialog(true);
2115
- } catch (error) {
2116
- console.error("[StoreNodeCard] Failed to check node usage:", error);
2117
- toast.error("Failed to check node usage", {
2118
- description: "Please try again."
2119
- });
1972
+ } catch {
1973
+ toast.error("Failed to check node usage. Please try again.");
2120
1974
  } finally {
2121
1975
  setCheckingNodeUsage(false);
2122
1976
  }
2123
1977
  };
2124
1978
  const handleConfirmUninstall = async () => {
2125
- if (!workspaceId) {
2126
- toast.error("Workspace not found", {
2127
- description: "Unable to uninstall without workspace context."
2128
- });
2129
- return;
2130
- }
1979
+ if (!workspaceId) return;
2131
1980
  try {
2132
1981
  if (nodeUsage.isUsed && nodeUsage.workflows.length > 0) {
2133
1982
  setRemovingFromWorkflows(true);
2134
- const nodeVersion = installedVersion || latestVersion || "1.0.0";
2135
- const workflowIds = nodeUsage.workflows.map((wf) => wf.id);
2136
- console.log(
2137
- `[StoreNodeCard] Removing node ${node.name} (v${nodeVersion}) from ${workflowIds.length} workflows...`
2138
- );
2139
1983
  const removeResult = await removeNodeFromWorkflows(
2140
1984
  node.name,
2141
- nodeVersion,
2142
- workflowIds
1985
+ installedVersion || latestVersion || "1.0.0",
1986
+ nodeUsage.workflows.map((wf) => wf.id)
2143
1987
  );
2144
1988
  if (!removeResult.success) {
2145
1989
  throw new Error("Failed to remove node from workflows");
2146
1990
  }
2147
- console.log(
2148
- `[StoreNodeCard] Node removed from ${removeResult.removedFromWorkflows.length} workflows, ${removeResult.deactivatedWorkflows.length} workflows deactivated`
2149
- );
2150
- toast.info("Node removed from workflows", {
2151
- description: `Removed from ${removeResult.removedFromWorkflows.length} workflow(s) and deactivated ${removeResult.deactivatedWorkflows.length} workflow(s).`
2152
- });
2153
1991
  setRemovingFromWorkflows(false);
2154
1992
  }
2155
- const result = await uninstallNode({
2156
- productId: node.id,
2157
- workspaceId
2158
- });
1993
+ const result = await uninstallNode({ productId: node.id, workspaceId });
2159
1994
  if (result) {
2160
- toast.success("Node uninstalled successfully!", {
1995
+ toast.success("Node uninstalled", {
2161
1996
  description: `${node.name} has been removed from your workspace.`
2162
1997
  });
2163
1998
  setShowUninstallDialog(false);
2164
- console.log(
2165
- "[StoreNodeCard] Refreshing available nodes after uninstall..."
2166
- );
2167
1999
  await refreshAvailableNodes();
2168
- console.log("[StoreNodeCard] Refetching installed nodes list...");
2169
2000
  await refetchInstalledNodes();
2170
- console.log("[StoreNodeCard] Refresh complete!");
2171
2001
  } else {
2172
2002
  throw new Error("Uninstall failed");
2173
2003
  }
2174
- } catch (error) {
2004
+ } catch (err) {
2175
2005
  toast.error("Uninstall failed", {
2176
- description: error instanceof Error ? error.message : "Failed to uninstall node."
2006
+ description: err instanceof Error ? err.message : "Please try again."
2177
2007
  });
2178
2008
  } finally {
2179
2009
  setRemovingFromWorkflows(false);
2180
2010
  }
2181
2011
  };
2182
- const handleCancelUninstall = () => {
2183
- setShowUninstallDialog(false);
2012
+ const handlePurchase = async () => {
2013
+ try {
2014
+ toast.info("Creating order", {
2015
+ description: `Preparing checkout for ${node.name}...`
2016
+ });
2017
+ const unitPrice = node.price || 0;
2018
+ const result = await createOrder({
2019
+ total: unitPrice,
2020
+ lineItems: [
2021
+ {
2022
+ productId: node.id,
2023
+ name: node.name,
2024
+ quantity: 1,
2025
+ unitPrice,
2026
+ subtotal: unitPrice,
2027
+ itemType: "DIGITAL",
2028
+ pricingModel: node.pricingModel || "PAID_ONETIME",
2029
+ version: node.manifestVersion || void 0
2030
+ }
2031
+ ],
2032
+ billingAccountId: ""
2033
+ });
2034
+ if (result.success && result.order?.id) {
2035
+ window.location.href = `/billing/checkout/store/${result.order.id}`;
2036
+ } else {
2037
+ throw new Error(result.error || "Failed to create order");
2038
+ }
2039
+ } catch (err) {
2040
+ toast.error("Failed to start checkout", {
2041
+ description: err instanceof Error ? err.message : "Please try again."
2042
+ });
2043
+ }
2184
2044
  };
2185
- const isFree = node.pricingModel === "FREE";
2186
- const isPurchased = node.isPurchased === true;
2187
- const isInstalling = installing === node.id;
2188
- const isUpdating = updating === node.id;
2189
- const canInstall = isFree || isPurchased;
2190
- return /* @__PURE__ */ jsxs(
2191
- Card,
2192
- {
2193
- className: cn(
2194
- "p-4 hover:shadow-lg transition-all cursor-pointer group",
2195
- "border-2 hover:border-primary/50"
2196
- ),
2197
- onClick,
2198
- children: [
2199
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center space-y-2", children: [
2200
- /* @__PURE__ */ jsx("div", { className: "w-20 h-20 rounded-lg bg-muted flex items-center justify-center overflow-hidden", children: node.icon ? /* @__PURE__ */ jsx(
2201
- "img",
2202
- {
2203
- src: node.icon,
2204
- alt: node.name,
2205
- className: "w-full h-full object-cover"
2206
- }
2207
- ) : /* @__PURE__ */ jsx("div", { className: "text-3xl font-bold text-muted-foreground", children: node.name.charAt(0).toUpperCase() }) }),
2208
- /* @__PURE__ */ jsx("h4", { className: "font-semibold text-sm truncate w-full group-hover:text-primary transition-colors", children: node.name }),
2209
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground truncate w-full", children: [
2210
- "by ",
2211
- node.authorName || node.publisher?.name || "Unknown"
2212
- ] }),
2213
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs", children: [
2214
- /* @__PURE__ */ jsx(Star, { className: "size-3 fill-yellow-400 text-yellow-400" }),
2215
- /* @__PURE__ */ jsx("span", { children: node.rating?.toFixed(1) || "N/A" }),
2216
- /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
2217
- "(",
2218
- node.reviewCount || 0,
2219
- ")"
2220
- ] })
2221
- ] }),
2222
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
2223
- formatDownloads(node.downloads || 0),
2224
- " downloads"
2225
- ] }),
2226
- node.featured && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "text-xs", children: "Featured" }),
2227
- /* @__PURE__ */ jsxs("div", { className: "w-full pt-2 space-y-2", children: [
2228
- hasUpdate && /* @__PURE__ */ jsx(
2229
- Button,
2230
- {
2231
- size: "sm",
2232
- variant: "outline",
2233
- className: "w-full",
2234
- onClick: handleUpdate,
2235
- disabled: isUpdating,
2236
- children: isUpdating ? /* @__PURE__ */ jsxs(Fragment, { children: [
2237
- /* @__PURE__ */ jsx(Loader2, { className: "size-3 mr-1 animate-spin" }),
2238
- "Updating..."
2239
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2240
- /* @__PURE__ */ jsx(RefreshCw, { className: "size-3 mr-1" }),
2241
- "Update to v",
2242
- latestVersion
2243
- ] })
2244
- }
2245
- ),
2246
- isInstalled ? /* @__PURE__ */ jsxs(Fragment, { children: [
2247
- /* @__PURE__ */ jsxs(Badge$1, { variant: "secondary", className: "w-full justify-center py-2", children: [
2248
- /* @__PURE__ */ jsx(Check, { className: "size-3 mr-1" }),
2249
- "Installed ",
2250
- installedVersion && `(v${installedVersion})`
2251
- ] }),
2045
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [
2046
+ /* @__PURE__ */ jsx("div", { className: "px-3 pt-3 pb-1 shrink-0", children: /* @__PURE__ */ jsxs(
2047
+ "button",
2048
+ {
2049
+ onClick: onBack,
2050
+ className: "flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors",
2051
+ children: [
2052
+ /* @__PURE__ */ jsx(Icon, { icon: "mynaui:chevron-left", className: "size-3.5" }),
2053
+ "Back"
2054
+ ]
2055
+ }
2056
+ ) }),
2057
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-3 pb-2", children: [
2058
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center py-4", children: [
2059
+ /* @__PURE__ */ jsx("div", { className: "size-16 rounded-xl bg-muted flex items-center justify-center overflow-hidden mb-3", children: node.icon ? /* @__PURE__ */ jsx(
2060
+ "img",
2061
+ {
2062
+ src: node.icon,
2063
+ alt: node.name,
2064
+ className: "w-full h-full object-cover"
2065
+ }
2066
+ ) : /* @__PURE__ */ jsx("span", { className: "text-2xl font-bold text-muted-foreground", children: node.name.charAt(0).toUpperCase() }) }),
2067
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-foreground leading-tight", children: node.name }),
2068
+ (node.authorName || node.publisher?.name) && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-1 flex items-center gap-1", children: [
2069
+ "by ",
2070
+ node.authorName || node.publisher?.name,
2071
+ node.publisher?.isVerified && /* @__PURE__ */ jsx(BadgeCheck, { className: "size-3.5 text-primary" })
2072
+ ] })
2073
+ ] }),
2074
+ (isInstalled || hasUpdate || node.featured) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2 mb-4 flex-wrap", children: [
2075
+ hasUpdate && /* @__PURE__ */ jsxs(
2076
+ "span",
2077
+ {
2078
+ className: "inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-semibold",
2079
+ style: {
2080
+ background: "var(--color-status-warning-bgSubtle)",
2081
+ color: "var(--color-status-warning-text)"
2082
+ },
2083
+ children: [
2084
+ /* @__PURE__ */ jsx(Icon, { icon: "mynaui:refresh", className: "size-3" }),
2085
+ "Update available \u2014 v",
2086
+ latestVersion
2087
+ ]
2088
+ }
2089
+ ),
2090
+ isInstalled && !hasUpdate && /* @__PURE__ */ jsxs(
2091
+ "span",
2092
+ {
2093
+ className: "inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-semibold",
2094
+ style: {
2095
+ background: "var(--color-status-success-bgSubtle)",
2096
+ color: "var(--color-status-success-text)"
2097
+ },
2098
+ children: [
2252
2099
  /* @__PURE__ */ jsx(
2253
- Button,
2100
+ "span",
2254
2101
  {
2255
- size: "sm",
2256
- variant: "destructive",
2257
- className: "w-full",
2258
- onClick: handleUninstallClick,
2259
- disabled: uninstalling || checkingNodeUsage || removingFromWorkflows,
2260
- children: uninstalling ? /* @__PURE__ */ jsxs(Fragment, { children: [
2261
- /* @__PURE__ */ jsx(Loader2, { className: "size-3 mr-1 animate-spin" }),
2262
- "Uninstalling..."
2263
- ] }) : checkingNodeUsage ? /* @__PURE__ */ jsxs(Fragment, { children: [
2264
- /* @__PURE__ */ jsx(Loader2, { className: "size-3 mr-1 animate-spin" }),
2265
- "Checking..."
2266
- ] }) : removingFromWorkflows ? /* @__PURE__ */ jsxs(Fragment, { children: [
2267
- /* @__PURE__ */ jsx(Loader2, { className: "size-3 mr-1 animate-spin" }),
2268
- "Removing..."
2269
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2270
- /* @__PURE__ */ jsx(Trash2, { className: "size-3 mr-1" }),
2271
- "Uninstall"
2272
- ] })
2102
+ className: "size-1.5 rounded-full",
2103
+ style: { background: "var(--color-status-success-bg)" }
2273
2104
  }
2274
- )
2275
- ] }) : canInstall ? /* @__PURE__ */ jsx(
2276
- Button,
2277
- {
2278
- size: "sm",
2279
- className: "w-full",
2280
- onClick: handleInstall,
2281
- disabled: isInstalling,
2282
- children: isInstalling ? /* @__PURE__ */ jsxs(Fragment, { children: [
2283
- /* @__PURE__ */ jsx(Loader2, { className: "size-3 mr-1 animate-spin" }),
2284
- "Installing..."
2285
- ] }) : "Install"
2286
- }
2287
- ) : /* @__PURE__ */ jsx(
2288
- Badge$1,
2289
- {
2290
- className: "w-full justify-center py-2 cursor-pointer hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
2291
- onClick: handlePurchase,
2292
- children: creatingOrder ? /* @__PURE__ */ jsxs(Fragment, { children: [
2293
- /* @__PURE__ */ jsx(Loader2, { className: "size-3 mr-1 animate-spin" }),
2294
- "Creating order..."
2295
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2296
- /* @__PURE__ */ jsx(DollarSign, { className: "size-3 mr-1" }),
2297
- "$",
2298
- node.price?.toFixed(2) || "0.00"
2299
- ] })
2300
- }
2301
- )
2105
+ ),
2106
+ "Installed",
2107
+ installedVersion ? ` v${installedVersion}` : ""
2108
+ ]
2109
+ }
2110
+ ),
2111
+ node.featured && !isInstalled && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-semibold bg-primary/10 text-primary", children: "Featured" })
2112
+ ] }),
2113
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-4 text-xs text-muted-foreground mb-4", children: [
2114
+ node.rating != null && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
2115
+ /* @__PURE__ */ jsx(Star, { className: "size-3 fill-yellow-400 text-yellow-400" }),
2116
+ node.rating.toFixed(1),
2117
+ /* @__PURE__ */ jsxs("span", { className: "opacity-60", children: [
2118
+ "(",
2119
+ node.reviewCount ?? 0,
2120
+ ")"
2302
2121
  ] })
2303
2122
  ] }),
2304
- showUninstallDialog && /* @__PURE__ */ jsx(
2305
- UninstallNodeDialog,
2123
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
2124
+ /* @__PURE__ */ jsx(Download, { className: "size-3" }),
2125
+ formatDownloads(node.downloads ?? 0)
2126
+ ] }),
2127
+ latestVersion && /* @__PURE__ */ jsxs("span", { className: "opacity-80", children: [
2128
+ "v",
2129
+ latestVersion
2130
+ ] })
2131
+ ] }),
2132
+ node.description && /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground/80 leading-relaxed mb-4", children: node.description }),
2133
+ node.publisher && /* @__PURE__ */ jsxs("div", { className: "mb-4 p-2.5 rounded-lg bg-muted/50 flex items-center gap-2", children: [
2134
+ /* @__PURE__ */ jsx("div", { className: "size-6 rounded bg-muted flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-bold text-muted-foreground", children: node.publisher.name.charAt(0) }) }),
2135
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground font-medium flex-1 min-w-0 truncate", children: node.publisher.name }),
2136
+ node.publisher.isVerified && /* @__PURE__ */ jsx(BadgeCheck, { className: "size-4 text-primary shrink-0" })
2137
+ ] }),
2138
+ node.license && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mb-4", children: [
2139
+ "License:",
2140
+ " ",
2141
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground/70", children: node.license })
2142
+ ] }),
2143
+ node.compatibleProducts && node.compatibleProducts.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
2144
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mb-1.5", children: "Compatible with" }),
2145
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: node.compatibleProducts.map((p) => /* @__PURE__ */ jsx(
2146
+ "span",
2306
2147
  {
2307
- nodeName: node.name,
2308
- nodeType: node.name,
2309
- isUsed: nodeUsage.isUsed,
2310
- workflows: nodeUsage.workflows,
2311
- loading: uninstalling || removingFromWorkflows,
2312
- onConfirm: handleConfirmUninstall,
2313
- onCancel: handleCancelUninstall
2314
- }
2315
- )
2316
- ]
2317
- }
2318
- );
2319
- }
2320
- function StoreNodesGrid({
2321
- filterTab,
2322
- searchTerm,
2323
- onNodeClick
2324
- }) {
2325
- const { products, loading, hasMore, fetchMore, error } = useStoreNodes({
2326
- filter: {
2327
- search: searchTerm || void 0,
2328
- type: "NODE",
2329
- compatibleWith: "fluidgrids"
2330
- },
2331
- sortBy: "DOWNLOADS",
2332
- limit: 20
2333
- });
2334
- const { installedAppIds, installationsMap } = useInstalledNodes();
2335
- console.log("[StoreNodesGrid] Debug:", {
2336
- products,
2337
- productsLength: products?.length,
2338
- loading,
2339
- error,
2340
- filterTab,
2341
- searchTerm
2342
- });
2343
- const filteredProducts = useMemo(() => {
2344
- if (!products) return [];
2345
- switch (filterTab) {
2346
- case "installed":
2347
- return products.filter((p) => installedAppIds.has(p.id));
2348
- case "all":
2349
- default:
2350
- return products;
2351
- }
2352
- }, [products, filterTab, installedAppIds]);
2353
- if (loading && filteredProducts.length === 0) {
2354
- return /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader2, { className: "size-8 animate-spin text-muted-foreground" }) });
2355
- }
2356
- if (error) {
2357
- return /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center p-8 text-center", children: [
2358
- /* @__PURE__ */ jsx("p", { className: "text-lg font-medium text-destructive", children: "Error loading nodes" }),
2359
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: error.message || "Failed to fetch nodes from store" }),
2360
- /* @__PURE__ */ jsx(
2148
+ className: "px-2 py-0.5 rounded-full text-xs bg-muted text-muted-foreground",
2149
+ children: p
2150
+ },
2151
+ p
2152
+ )) })
2153
+ ] })
2154
+ ] }),
2155
+ /* @__PURE__ */ jsxs("div", { className: "shrink-0 px-3 pb-3 pt-2 border-t border-border/50 flex flex-col gap-2", children: [
2156
+ hasUpdate && /* @__PURE__ */ jsx(
2361
2157
  Button,
2362
2158
  {
2159
+ size: "sm",
2363
2160
  variant: "outline",
2364
- className: "mt-4",
2365
- onClick: () => window.location.reload(),
2366
- children: "Retry"
2161
+ className: "w-full",
2162
+ onClick: handleUpdate,
2163
+ disabled: isUpdating,
2164
+ children: isUpdating ? /* @__PURE__ */ jsxs(Fragment, { children: [
2165
+ /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 mr-1.5 animate-spin" }),
2166
+ "Updating..."
2167
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2168
+ /* @__PURE__ */ jsx(RefreshCw, { className: "size-3.5 mr-1.5" }),
2169
+ "Update to v",
2170
+ latestVersion
2171
+ ] })
2367
2172
  }
2368
- )
2369
- ] });
2370
- }
2371
- if (!loading && filteredProducts.length === 0) {
2372
- return /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center p-8 text-center space-y-4", children: [
2373
- /* @__PURE__ */ jsx("p", { className: "text-lg font-medium text-muted-foreground", children: "No nodes found" }),
2374
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Try adjusting your search or filters" }),
2375
- /* @__PURE__ */ jsxs("div", { className: "mt-4 p-4 bg-muted rounded-lg text-left text-xs font-mono max-w-md", children: [
2376
- /* @__PURE__ */ jsx("div", { className: "font-bold mb-2", children: "Debug Info:" }),
2377
- /* @__PURE__ */ jsxs("div", { children: [
2378
- "Total products: ",
2379
- products?.length || 0
2380
- ] }),
2381
- /* @__PURE__ */ jsxs("div", { children: [
2382
- "Filter tab: ",
2383
- filterTab
2384
- ] }),
2385
- /* @__PURE__ */ jsxs("div", { children: [
2386
- 'Search term: "',
2387
- searchTerm,
2388
- '"'
2389
- ] }),
2390
- /* @__PURE__ */ jsxs("div", { children: [
2391
- "Loading: ",
2392
- loading ? "yes" : "no"
2393
- ] }),
2394
- /* @__PURE__ */ jsx("div", { children: "Error: none" }),
2395
- /* @__PURE__ */ jsxs("div", { children: [
2396
- "Installed count: ",
2397
- installedAppIds.size
2398
- ] })
2399
- ] })
2400
- ] });
2401
- }
2402
- return /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto bg-background", children: [
2403
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 p-6", children: filteredProducts.map((node) => {
2404
- const installation = installationsMap.get(node.id);
2405
- return /* @__PURE__ */ jsx(
2406
- StoreNodeCard,
2173
+ ),
2174
+ isInstalled ? /* @__PURE__ */ jsx(
2175
+ Button,
2407
2176
  {
2408
- node,
2409
- isInstalled: installedAppIds.has(node.id),
2410
- installedVersion: installation?.installedVersion,
2411
- installationId: installation?.installationId,
2412
- onClick: () => onNodeClick(node)
2413
- },
2414
- node.id
2415
- );
2416
- }) }),
2417
- hasMore && /* @__PURE__ */ jsx("div", { className: "p-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: fetchMore, disabled: loading, children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
2418
- /* @__PURE__ */ jsx(Loader2, { className: "size-4 mr-2 animate-spin" }),
2419
- "Loading..."
2420
- ] }) : "Load More" }) })
2177
+ size: "sm",
2178
+ variant: "destructive",
2179
+ className: "w-full",
2180
+ onClick: handleUninstallClick,
2181
+ disabled: uninstalling || checkingNodeUsage || removingFromWorkflows,
2182
+ children: uninstalling || removingFromWorkflows ? /* @__PURE__ */ jsxs(Fragment, { children: [
2183
+ /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 mr-1.5 animate-spin" }),
2184
+ "Uninstalling..."
2185
+ ] }) : checkingNodeUsage ? /* @__PURE__ */ jsxs(Fragment, { children: [
2186
+ /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 mr-1.5 animate-spin" }),
2187
+ "Checking usage..."
2188
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2189
+ /* @__PURE__ */ jsx(Trash2, { className: "size-3.5 mr-1.5" }),
2190
+ "Uninstall"
2191
+ ] })
2192
+ }
2193
+ ) : canInstall ? /* @__PURE__ */ jsx(
2194
+ Button,
2195
+ {
2196
+ size: "sm",
2197
+ className: "w-full",
2198
+ onClick: handleInstall,
2199
+ disabled: isInstalling,
2200
+ children: isInstalling ? /* @__PURE__ */ jsxs(Fragment, { children: [
2201
+ /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 mr-1.5 animate-spin" }),
2202
+ "Installing..."
2203
+ ] }) : "Install"
2204
+ }
2205
+ ) : /* @__PURE__ */ jsx(
2206
+ Button,
2207
+ {
2208
+ size: "sm",
2209
+ className: "w-full",
2210
+ onClick: handlePurchase,
2211
+ disabled: creatingOrder,
2212
+ children: creatingOrder ? /* @__PURE__ */ jsxs(Fragment, { children: [
2213
+ /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 mr-1.5 animate-spin" }),
2214
+ "Creating order..."
2215
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2216
+ /* @__PURE__ */ jsx(DollarSign, { className: "size-3.5 mr-1.5" }),
2217
+ "$",
2218
+ node.price?.toFixed(2) ?? "0.00"
2219
+ ] })
2220
+ }
2221
+ )
2222
+ ] }),
2223
+ showUninstallDialog && /* @__PURE__ */ jsx(
2224
+ UninstallNodeDialog,
2225
+ {
2226
+ nodeName: node.name,
2227
+ nodeType: node.name,
2228
+ isUsed: nodeUsage.isUsed,
2229
+ workflows: nodeUsage.workflows,
2230
+ loading: uninstalling || removingFromWorkflows,
2231
+ onConfirm: handleConfirmUninstall,
2232
+ onCancel: () => setShowUninstallDialog(false)
2233
+ }
2234
+ )
2421
2235
  ] });
2422
2236
  }
2423
- function StoreNodesContent() {
2424
- const [activeTab, setActiveTab] = useState("all");
2425
- const [searchTerm, setSearchTerm] = useState("");
2426
- const [selectedNode, setSelectedNode] = useState(
2427
- null
2428
- );
2429
- const { refetch: refetchStoreNodes } = useStoreNodes({
2430
- filter: {
2431
- type: "NODE",
2432
- compatibleWith: "fluidgrids"
2433
- }
2434
- });
2435
- const { refetch: refetchInstalledNodes } = useInstalledNodes();
2237
+ function StoreBrowsePanel() {
2238
+ const [view, setView] = useState({ type: "categories" });
2239
+ const [globalSearch, setGlobalSearch] = useState("");
2240
+ const [, setNodesReady] = useState(isNodeConfigsInitialized);
2436
2241
  useEffect(() => {
2437
- console.log("[StoreNodesContent] Modal opened, refetching data...");
2438
- Promise.all([refetchStoreNodes(), refetchInstalledNodes()]).then(() => {
2439
- console.log("[StoreNodesContent] Data refreshed successfully");
2440
- }).catch((error) => {
2441
- console.error("[StoreNodesContent] Failed to refresh data:", error);
2242
+ void ensureNodeConfigsLoaded().then(() => setNodesReady(true));
2243
+ }, []);
2244
+ const openCategory = useCallback((category) => {
2245
+ setView({ type: "category-nodes", category });
2246
+ setGlobalSearch("");
2247
+ }, []);
2248
+ const openNodeDetail = useCallback((node) => {
2249
+ setView((prev) => ({
2250
+ type: "node-detail",
2251
+ node,
2252
+ from: prev.type === "node-detail" ? prev.from : prev
2253
+ }));
2254
+ }, []);
2255
+ const goBack = useCallback(() => {
2256
+ setView((prev) => {
2257
+ if (prev.type === "node-detail") return prev.from;
2258
+ return { type: "categories" };
2442
2259
  });
2443
2260
  }, []);
2444
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-row flex-1 overflow-hidden", children: [
2445
- /* @__PURE__ */ jsx(
2446
- StoreNodesSidebar,
2447
- {
2448
- activeTab,
2449
- onTabChange: setActiveTab,
2450
- searchTerm,
2451
- onSearchChange: setSearchTerm
2452
- }
2453
- ),
2454
- /* @__PURE__ */ jsx(
2455
- StoreNodesGrid,
2456
- {
2457
- filterTab: activeTab,
2458
- searchTerm,
2459
- onNodeClick: setSelectedNode
2460
- }
2461
- )
2261
+ return /* @__PURE__ */ jsxs(SidebarPanelWrapper, { children: [
2262
+ view.type === "categories" && /* @__PURE__ */ jsxs("div", { className: "px-4 pt-4 pb-2 shrink-0 flex items-center gap-2", children: [
2263
+ /* @__PURE__ */ jsx("div", { className: "size-7 flex items-center justify-center rounded-lg bg-primary", children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:store", className: "size-4 text-white" }) }),
2264
+ /* @__PURE__ */ jsxs("div", { children: [
2265
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground leading-tight", children: "Node Store" }),
2266
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Browse & install workflow nodes" })
2267
+ ] })
2268
+ ] }),
2269
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-hidden flex flex-col", children: [
2270
+ view.type === "categories" && /* @__PURE__ */ jsx(
2271
+ StoreCategoryList,
2272
+ {
2273
+ searchTerm: globalSearch,
2274
+ onSearchChange: setGlobalSearch,
2275
+ onSelectCategory: openCategory,
2276
+ onSelectNode: openNodeDetail
2277
+ }
2278
+ ),
2279
+ view.type === "category-nodes" && /* @__PURE__ */ jsx(
2280
+ StoreCategoryNodes,
2281
+ {
2282
+ category: view.category,
2283
+ onBack: goBack,
2284
+ onSelectNode: openNodeDetail
2285
+ }
2286
+ ),
2287
+ view.type === "node-detail" && /* @__PURE__ */ jsx(StoreNodeDetail, { node: view.node, onBack: goBack })
2288
+ ] })
2462
2289
  ] });
2463
2290
  }
2464
- function StoreNodesModal({ open, onOpenChange }) {
2465
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
2466
- DialogContent,
2291
+
2292
+ // src/builder/components/flow-builder/components/blocks/sidebar/constants/panels.tsx
2293
+ var PANEL_COMPONENTS = {
2294
+ "node-properties": NodePropertiesPanel,
2295
+ "store-browse": StoreBrowsePanel,
2296
+ none: () => null
2297
+ };
2298
+ function SwitchSidebarPanel({ active }) {
2299
+ const PanelComponent = PANEL_COMPONENTS[active];
2300
+ return PanelComponent ? /* @__PURE__ */ jsx(PanelComponent, {}) : null;
2301
+ }
2302
+ function SidebarButtonItem({
2303
+ children,
2304
+ className,
2305
+ active,
2306
+ ...props
2307
+ }) {
2308
+ return /* @__PURE__ */ jsx(
2309
+ Button$1,
2467
2310
  {
2468
- size: "xl",
2469
- className: "!flex !flex-col !h-[75vh] !max-h-[75vh] min-h-[500px] p-0 gap-0 overflow-hidden",
2470
- children: [
2471
- /* @__PURE__ */ jsxs(DialogHeader, { className: "px-6 pt-6 pb-4 border-b shrink-0", children: [
2472
- /* @__PURE__ */ jsx(DialogTitle, { className: "text-xl font-semibold", children: "Discover Custom Workflow Nodes" }),
2473
- /* @__PURE__ */ jsx(DialogDescription, { className: "text-sm", children: "Browse and install community-made nodes, integrations, and extensions for your workflows" })
2474
- ] }),
2475
- open && /* @__PURE__ */ jsx(StoreNodesContent, {})
2476
- ]
2311
+ size: "icon",
2312
+ type: "button",
2313
+ variant: active ? "default" : "ghost",
2314
+ className: cn$1(
2315
+ "size-8 flex items-center justify-center",
2316
+ className
2317
+ ),
2318
+ ...props,
2319
+ children
2477
2320
  }
2478
- ) });
2321
+ );
2479
2322
  }
2323
+ var Card = forwardRef(
2324
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2325
+ "div",
2326
+ {
2327
+ ref,
2328
+ className: cn(
2329
+ "rounded-lg border bg-card text-card-foreground shadow-sm transition-all duration-200 ease-out hover:shadow-md",
2330
+ className
2331
+ ),
2332
+ ...props
2333
+ }
2334
+ )
2335
+ );
2336
+ Card.displayName = "Card";
2337
+ var CardHeader = forwardRef(
2338
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2339
+ "div",
2340
+ {
2341
+ ref,
2342
+ className: cn("flex flex-col space-y-1.5 p-6", className),
2343
+ ...props
2344
+ }
2345
+ )
2346
+ );
2347
+ CardHeader.displayName = "CardHeader";
2348
+ var CardTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2349
+ "h3",
2350
+ {
2351
+ ref,
2352
+ className: cn(
2353
+ "text-2xl font-semibold leading-none tracking-tight",
2354
+ className
2355
+ ),
2356
+ ...props
2357
+ }
2358
+ ));
2359
+ CardTitle.displayName = "CardTitle";
2360
+ var CardDescription = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2361
+ "p",
2362
+ {
2363
+ ref,
2364
+ className: cn("text-sm text-muted-foreground", className),
2365
+ ...props
2366
+ }
2367
+ ));
2368
+ CardDescription.displayName = "CardDescription";
2369
+ var CardContent = forwardRef(
2370
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props })
2371
+ );
2372
+ CardContent.displayName = "CardContent";
2373
+ var CardFooter = forwardRef(
2374
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2375
+ "div",
2376
+ {
2377
+ ref,
2378
+ className: cn("flex items-center p-6 pt-0", className),
2379
+ ...props
2380
+ }
2381
+ )
2382
+ );
2383
+ CardFooter.displayName = "CardFooter";
2480
2384
  function formatNumber(count2) {
2481
2385
  if (count2 >= 1e6) {
2482
2386
  return `${(count2 / 1e6).toFixed(1)}M`;
@@ -2768,7 +2672,7 @@ function TemplatesModal({
2768
2672
  ) });
2769
2673
  }
2770
2674
  var LazyTemplateConfigurationModal = lazy(
2771
- () => import('./TemplateConfigurationModal-UJAGRE7X.js').then((m) => ({
2675
+ () => import('./TemplateConfigurationModal-FPQR7W4M.js').then((m) => ({
2772
2676
  default: m.TemplateConfigurationModal
2773
2677
  }))
2774
2678
  );
@@ -2776,7 +2680,6 @@ function DesktopSidebarFragment({
2776
2680
  activePanel,
2777
2681
  setActivePanel
2778
2682
  }) {
2779
- const [storeModalOpen, setStoreModalOpen] = useState(false);
2780
2683
  const [templatesModalOpen, setTemplatesModalOpen] = useState(false);
2781
2684
  const [configModalOpen, setConfigModalOpen] = useState(false);
2782
2685
  const [configTemplate, setConfigTemplate] = useState(
@@ -2789,7 +2692,7 @@ function DesktopSidebarFragment({
2789
2692
  const handleUseTemplate = useCallback(
2790
2693
  async (template) => {
2791
2694
  try {
2792
- const { useImportWorkflowTemplate: useImportWorkflowTemplate2 } = await import('./useImportWorkflowTemplate-RCPS4OTA.js');
2695
+ const { useImportWorkflowTemplate: useImportWorkflowTemplate2 } = await import('./useImportWorkflowTemplate-P62I2ADG.js');
2793
2696
  const { useTemplateDetail: useTemplateDetail2 } = await import('./useTemplateDetail-NK63V3PC.js');
2794
2697
  toast.loading("Loading template...", { id: "template-load" });
2795
2698
  const { getGlobalStoreClient } = await import('./global-client-OW43ZRDR.js');
@@ -3011,18 +2914,6 @@ function DesktopSidebarFragment({
3011
2914
  return /* @__PURE__ */ jsxs("div", { className: "relative max-w-sm w-fit flex shrink-0 divide-x divide-card-foreground/10", children: [
3012
2915
  activePanel !== "none" && /* @__PURE__ */ jsx("div", { className: "min-w-xs grow bg-card", children: /* @__PURE__ */ jsx(SwitchSidebarPanel, { active: activePanel }) }),
3013
2916
  /* @__PURE__ */ jsx("div", { className: "shrink-0 bg-card p-1.5", children: /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col gap-2", children: [
3014
- /* @__PURE__ */ jsx(
3015
- SidebarButtonItem,
3016
- {
3017
- active: activePanel === "available-nodes",
3018
- onClick: () => setActivePanel(
3019
- activePanel === "available-nodes" ? "none" : "available-nodes"
3020
- ),
3021
- title: "Available Nodes",
3022
- children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:grid", className: "size-5" })
3023
- }
3024
- ),
3025
- /* @__PURE__ */ jsx("div", { className: "mx-auto h-px w-4 bg-card-foreground/10" }),
3026
2917
  /* @__PURE__ */ jsx(
3027
2918
  SidebarButtonItem,
3028
2919
  {
@@ -3038,10 +2929,12 @@ function DesktopSidebarFragment({
3038
2929
  /* @__PURE__ */ jsx(
3039
2930
  SidebarButtonItem,
3040
2931
  {
3041
- active: storeModalOpen,
3042
- onClick: () => setStoreModalOpen(true),
2932
+ active: activePanel === "store-browse",
2933
+ onClick: () => setActivePanel(
2934
+ activePanel === "store-browse" ? "none" : "store-browse"
2935
+ ),
3043
2936
  title: "Browse custom nodes from the store",
3044
- children: /* @__PURE__ */ jsx(Store, { className: "size-5" })
2937
+ children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:store", className: "size-5" })
3045
2938
  }
3046
2939
  ),
3047
2940
  /* @__PURE__ */ jsx(
@@ -3054,7 +2947,6 @@ function DesktopSidebarFragment({
3054
2947
  }
3055
2948
  )
3056
2949
  ] }) }),
3057
- /* @__PURE__ */ jsx(StoreNodesModal, { open: storeModalOpen, onOpenChange: setStoreModalOpen }),
3058
2950
  /* @__PURE__ */ jsx(
3059
2951
  TemplatesModal,
3060
2952
  {
@@ -9215,6 +9107,29 @@ var useAddNodeOnEdgeDropStore = create()(
9215
9107
  }
9216
9108
  })
9217
9109
  );
9110
+ function useInsertNode() {
9111
+ const { addNodes, screenToFlowPosition, getNodes, updateNode } = useReactFlow();
9112
+ return useCallback(
9113
+ (type, pos) => {
9114
+ const _pos = pos || screenToFlowPosition({
9115
+ x: window.innerWidth / 2,
9116
+ y: window.innerHeight / 2
9117
+ });
9118
+ getNodes().forEach((node) => {
9119
+ if (node.selected) {
9120
+ updateNode(node.id, { selected: false });
9121
+ }
9122
+ });
9123
+ const newNode = createNodeWithDefaultData(type, {
9124
+ position: _pos,
9125
+ selected: true
9126
+ });
9127
+ addNodes(newNode);
9128
+ return newNode;
9129
+ },
9130
+ [screenToFlowPosition, getNodes, addNodes, updateNode]
9131
+ );
9132
+ }
9218
9133
  function useAddNodeOnEdgeDrop() {
9219
9134
  const [
9220
9135
  dropPosition,
@@ -11344,7 +11259,7 @@ function WorkflowItem({
11344
11259
  edges: [],
11345
11260
  nodes: [],
11346
11261
  sidebar: {
11347
- active: "available-nodes",
11262
+ active: "store-browse",
11348
11263
  panels: {
11349
11264
  nodeProperties: {
11350
11265
  selectedNode: null
@@ -11490,5 +11405,5 @@ function WorkflowBuilder() {
11490
11405
  }
11491
11406
 
11492
11407
  export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, TemplateCard, WorkflowBuilder, useWorkflowTemplates };
11493
- //# sourceMappingURL=chunk-XVHQN2UK.js.map
11494
- //# sourceMappingURL=chunk-XVHQN2UK.js.map
11408
+ //# sourceMappingURL=chunk-TYOU6RYA.js.map
11409
+ //# sourceMappingURL=chunk-TYOU6RYA.js.map