@burdenoff/fluidgrids-fe-sdk 2026.1113.1 → 2026.1113.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 (127) hide show
  1. package/dist/{AiStudioPage-D3MAk-bs.js → AiStudioPage-5KYZ8r8-.js} +464 -7
  2. package/dist/{ApprovalInboxPage-Bb8H9ruw.js → ApprovalInboxPage-BsJX4osU.js} +4 -3
  3. package/dist/{ConnectionFormDialog-Bg9_OdHX.js → ConnectionFormDialog-Dr1-CTan.js} +2 -1
  4. package/dist/CreateFluidgridsTagDocument-Dtp9KPLJ.js +1055 -0
  5. package/dist/{DataSinkDashboardPage-Dc2QuJbL.js → DataSinkDashboardPage-8ZDn85e2.js} +1 -1
  6. package/dist/{DataTablesPage-Cv4veaKK.js → DataTablesPage-BBvABuxE.js} +5 -4
  7. package/dist/{EntityTagPicker-D8ws706D.js → EntityTagPicker-BppBSEJk.js} +2 -2
  8. package/dist/{ExecutionDetailPage-CTVGE-d-.js → ExecutionDetailPage-BXDF2eoT.js} +1444 -18
  9. package/dist/ExecutionsListDocument-CzdLPpj5.js +1259 -0
  10. package/dist/{ExecutionsListPage-J0sJPuoM.js → ExecutionsListPage--4BthM8L.js} +285 -11
  11. package/dist/FailureTriagePanel-B5WCSRFo.js +1252 -0
  12. package/dist/{FluidGridsProvider-C4FVNz0n.js → FluidGridsProvider-Dc_Jhtch.js} +8666 -8734
  13. package/dist/{HistoryPage-B9XcTPrO.js → HistoryPage-BvFk2m1m.js} +4 -3
  14. package/dist/{InsightsPage-DFOltjyj.js → InsightsPage-Dwmb02F6.js} +2682 -5
  15. package/dist/{MissingNodesInstallModal-D8H-YNCJ.js → MissingNodesInstallModal-Cze674hp.js} +2 -2
  16. package/dist/{NodesPage-YQ-hP60x.js → NodesPage-C5Dq-ru-.js} +3 -2
  17. package/dist/{OpenTemplateAsCodeButton-hH26HQCk.js → OpenTemplateAsCodeButton-8MZHih6I.js} +2 -2
  18. package/dist/{PaidTemplateConfirm-DoKWMBtR.js → PaidTemplateConfirm-0G-gv29n.js} +1 -1
  19. package/dist/{PublishCustomNodeAction-5XXnSA3H.js → PublishCustomNodeAction-OOY35dUv.js} +1 -1
  20. package/dist/QuotaExhaustedDialog-wvu_-WJ-.js +55 -0
  21. package/dist/{RunnerStatusPill-Ctg4TJcP.js → RunnerStatusPill-Bh7mEsPh.js} +2 -1
  22. package/dist/{RunnersPage-CAt4YDhB.js → RunnersPage-DHeuUDil.js} +2 -2
  23. package/dist/{SettingsPage-DEKPCVVP.js → SettingsPage-CfjXiGpb.js} +694 -14
  24. package/dist/{TagFilterSelect-CwM2-DU6.js → TagFilterSelect-CAShgvbS.js} +1 -1
  25. package/dist/{TaskQueuesPage-Dhi6SIT4.js → TaskQueuesPage--Mmn36b-.js} +3 -3
  26. package/dist/{TemplateCard-DVSd_4zJ.js → TemplateCard-BA_9em22.js} +644 -352
  27. package/dist/{TemplateConfigurationModal-BKi1z7z7.js → TemplateConfigurationModal-BT3PaR0O.js} +4 -3
  28. package/dist/{TemplateDetailPanel-DK1gF7P5.js → TemplateDetailPanel-BxFNnlXm.js} +2 -1
  29. package/dist/{TemplatePreview-DuSX2Q7H.js → TemplatePreview-Bagja6WN.js} +7 -7
  30. package/dist/{TemplatesPage-CAWHh61l.js → TemplatesPage-CAajpJ5w.js} +711 -6
  31. package/dist/{VariablesPage-D7CoatWf.js → VariablesPage-CgUBKhAe.js} +3 -3
  32. package/dist/{VersionDiffDialog-DGwysiyE.js → VersionDiffDialog-D9W5Fm56.js} +233 -129
  33. package/dist/VersionLifecycleBar-DuphLOT0.js +131 -0
  34. package/dist/{WorkflowBuilder-DAeoQi5E.js → WorkflowBuilder-DMpSPElu.js} +16 -13
  35. package/dist/{WorkflowBuilder-BJgqDboZ.js → WorkflowBuilder-v8h8skwG.js} +5 -5
  36. package/dist/WorkflowDefinitionDocument-DZLbTPUZ.js +321 -0
  37. package/dist/WorkflowEditLeaseStatusDocument-Dp62med3.js +627 -0
  38. package/dist/WorkflowProposalCard-zCdUpCk8.js +249 -0
  39. package/dist/WorkflowProposalDocument-BdUbsrd0.js +620 -0
  40. package/dist/{WorkflowSearchRedirect-CMEvd_AR.js → WorkflowSearchRedirect-G78lINAE.js} +1 -1
  41. package/dist/{WorkflowShareDialog-BgHRsDP0.js → WorkflowShareDialog-B7VOgr4-.js} +304 -3
  42. package/dist/WorkflowVersionsDocument-CfPMloRW.js +3195 -0
  43. package/dist/{WorkflowsList-CcQPxWKL.js → WorkflowsList-CPYzfE4K.js} +11 -9
  44. package/dist/agent-form-D0uLvzx4.js +718 -0
  45. package/dist/{agentTools-DKpNKztf.js → agentTools-DTXUqtfu.js} +4 -4
  46. package/dist/api-BZVyX5d2.js +2286 -0
  47. package/dist/api-BqA-f-AD.js +8064 -0
  48. package/dist/app-BJUvugPM.js +3813 -0
  49. package/dist/assert-rules-CPNrO44K.js +318 -0
  50. package/dist/attach-node-helpers-CNsYtLOR.js +32 -0
  51. package/dist/badge-CXfPhoMH.js +26 -0
  52. package/dist/{canvasNoteTools-C_AN79m0.js → canvasNoteTools-DmfZwtnL.js} +3 -3
  53. package/dist/{channel-CZ70oI81.js → channel-DtF1n_ab.js} +1 -1
  54. package/dist/client-Ctl4jmY3.js +127 -0
  55. package/dist/code-editor-diagnostics-Zr0cIcx1.js +46 -0
  56. package/dist/{code-editor-field-Dt6KNWwN.js → code-editor-field-Cv907s3W.js} +2 -2
  57. package/dist/{codec-client-CJ95Rmqo.js → codec-client-CAYl6j46.js} +2 -1
  58. package/dist/conditionBuilder-D8aLGL1w.js +1134 -0
  59. package/dist/config-X97zrIvn.js +600 -0
  60. package/dist/{definition-canvas-Bshn_dSP.js → definition-canvas-DL25_6NH.js} +1 -1
  61. package/dist/{dialog-Cjb4lB4D.js → dialog-BVd152GS.js} +3 -14
  62. package/dist/durable-nodes-DXCCQYWD.js +81 -0
  63. package/dist/errors-xPZ-IbQd.js +142 -0
  64. package/dist/executions.js +2 -2
  65. package/dist/{flow-builder-D3Hl2AFk.js → flow-builder-Dv5fWJ6F.js} +9301 -8189
  66. package/dist/{node-registry-refresh-Dy0uRg9f.js → global-client-DP_Wxe5t.js} +2 -27
  67. package/dist/global-operations-7pvXw_j9.js +145 -0
  68. package/dist/history.js +1 -1
  69. package/dist/{index-CWcP-tG1.d.ts → index-DtMUtXNq.d.ts} +247 -247
  70. package/dist/index.d.ts +1 -1
  71. package/dist/index.js +4403 -46
  72. package/dist/input-ChT6Q-Pr.js +17 -0
  73. package/dist/logs-panel-DtG93ocy.js +342 -0
  74. package/dist/mapping-colors-BIX_YeCQ.js +48 -0
  75. package/dist/{node-detail-view-bVLeYarT.js → node-detail-view-BKI_2kM6.js} +12 -11
  76. package/dist/{node-editor-tab-body-JHHVtQgR.js → node-editor-tab-body-Cc1MWEFR.js} +3 -3
  77. package/dist/{node-operation-selection-DAbS6jSY.js → node-operation-selection-Czeeb2D4.js} +2 -139
  78. package/dist/node-registry-refresh-s3okf83X.js +27 -0
  79. package/dist/nodes.js +1 -1
  80. package/dist/notesKey-5EaREBGA.js +12 -0
  81. package/dist/observability.d.ts +1 -1
  82. package/dist/observability.js +2 -2
  83. package/dist/{popover-Xx3gN7vg.js → popover-DDv7J1Kl.js} +717 -6
  84. package/dist/{quick-config-panel-BvVQXuIL.js → quick-config-panel-BPCRfqWI.js} +4 -4
  85. package/dist/read-only-context-Dt9N9SIG.js +18 -0
  86. package/dist/{schedule-panel-DCb40TPN.js → schedule-panel-C1KwfLCE.js} +14 -12
  87. package/dist/settings.js +1 -1
  88. package/dist/{shared-CMfn30xT.js → shared-Ctl9ZHo1.js} +2 -1
  89. package/dist/{sidebar-node-editor-DxCWFZG2.js → sidebar-node-editor-d9Rlq5pU.js} +4 -4
  90. package/dist/sticky-notes-23j-wL6Q.js +96 -0
  91. package/dist/template-code-dqRunGOv.js +184 -0
  92. package/dist/template-preview-C01KV277.js +29 -0
  93. package/dist/templates.js +2 -2
  94. package/dist/token-refresh-link-BjN7H4qA.js +291 -0
  95. package/dist/useAgentDefinitions-ZKX2N9aP.js +3101 -0
  96. package/dist/useConnections-BlB0gbOB.js +931 -0
  97. package/dist/useDurableParity-BgLH_SCF.js +2088 -0
  98. package/dist/{useEntityTags-Db4Pc8_M.js → useEntityTags-4iW6UTly.js} +227 -3
  99. package/dist/{useExecutions-DOpG1pUQ.js → useExecutions-Bm7q_UwN.js} +6 -3
  100. package/dist/useGlobalStoreClient-DMTrywdX.js +24 -0
  101. package/dist/{useHumanRequests-ZiR0sSzS.js → useHumanRequests-DwG2tQ3f.js} +2 -1
  102. package/dist/{useObservability-rQmwhoZZ.js → useObservability-DPATdbw7.js} +4 -2
  103. package/dist/{useRunHistory-COn6dl7l.js → useRunHistory-CGfjCsJ3.js} +1122 -4
  104. package/dist/{useVariables-2ddyJX4a.js → useVariables-DFdZofLQ.js} +2 -1
  105. package/dist/{useWorkflowCodeExport-ZoUJKRSK.js → useWorkflowCodeExport-D_mCuhKP.js} +289 -4
  106. package/dist/useWorkflowOrganization-r5FWNBs6.js +1690 -0
  107. package/dist/useWorkflowProposal-Bh2_qjmM.js +7478 -0
  108. package/dist/{useWorkflows-jOW60YmD.js → useWorkflows-aqVD7kGa.js} +694 -4
  109. package/dist/workflow-builder.js +5 -5
  110. package/dist/{workflow-code-transfer-l9wO34S0.js → workflow-code-transfer-5C0HUzae.js} +1 -53
  111. package/dist/workflow-host.js +4 -2
  112. package/dist/workflow-pages.d.ts +1 -1
  113. package/dist/workflow-pages.js +19 -19
  114. package/dist/workflow-preview.js +3 -2
  115. package/dist/workflows-list.js +1 -1
  116. package/package.json +1 -1
  117. package/dist/FailureTriagePanel-BbYFYeV_.js +0 -311
  118. package/dist/WorkflowProposalCard-DGMdZC4R.js +0 -1432
  119. package/dist/agent-form-Bfvm32j1.js +0 -83
  120. package/dist/api-DQtHXbIg.js +0 -224
  121. package/dist/api-MeAm6g7E.js +0 -55
  122. package/dist/client-C9XSzSXr.js +0 -1147
  123. package/dist/graphql-operation-types-C9qbvRa8.js +0 -53122
  124. package/dist/useAgentDefinitions-_hgNCK1A.js +0 -550
  125. package/dist/useConnections-Cs7LCWEM.js +0 -401
  126. package/dist/useDurableParity-CcLeCDfv.js +0 -504
  127. package/dist/useWorkflowOrganization-QxVePSkk.js +0 -282
@@ -0,0 +1,3813 @@
1
+ "use client";
2
+ import { a as mappingTypeColor, i as compatibilityColor, n as MAPPING_FALLBACK_COLOR, r as MAPPING_TYPE_COLORS, t as MAPPING_COMPATIBILITY_COLORS } from "./mapping-colors-BIX_YeCQ.js";
3
+ import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
4
+ import * as React$1 from "react";
5
+ import { createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
6
+ import { Background, Controls, Handle, MiniMap, Panel, Position, ReactFlow, ReactFlowProvider, addEdge, getBezierPath, useEdgesState, useNodesState } from "@xyflow/react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster } from "@burdenoff/fe-libs/ui";
9
+ import { ThemeProvider } from "@burdenoff/fe-libs/shared/providers/shell";
10
+ import "@xyflow/react/dist/style.css";
11
+ import { AlertCircle, Braces, CheckCircle2, ChevronDown, ChevronRight, Code, Hash, List, PlusCircle, Type, Workflow, X } from "lucide-react";
12
+ import { createPortal } from "react-dom";
13
+ import { GraphQLEnumType, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLUnionType, buildSchema } from "graphql";
14
+
15
+ // src/builder/components/mapper/theme-provider.tsx
16
+ function ThemeProvider$1({ children, defaultTheme = "system", storageKey = "vite-ui-theme" }) {
17
+ React$1.useEffect(() => {
18
+ if (typeof window !== "undefined") try {
19
+ localStorage.removeItem(storageKey);
20
+ } catch (err) {
21
+ console.warn("Failed to clean up legacy theme storage:", err);
22
+ }
23
+ }, [storageKey]);
24
+ return /* @__PURE__ */ jsx(ThemeProvider, {
25
+ defaultMode: defaultTheme,
26
+ children
27
+ });
28
+ }
29
+
30
+ // src/builder/components/mapper/config/data.ts
31
+ let parsedSchemas = {};
32
+ let nodeTypes$1 = null;
33
+ let typeCompatibility = null;
34
+ let sampleData = null;
35
+ let nodeStyles = null;
36
+ let currentConfig = null;
37
+ function initializeConfig(schemas, dataConfig) {
38
+ parsedSchemas = schemas;
39
+ currentConfig = dataConfig;
40
+ generateNodeTypes(dataConfig);
41
+ generateTypeCompatibilityFunc(dataConfig);
42
+ generateSampleDataFunc(dataConfig);
43
+ generateVisualStylesFunc(dataConfig);
44
+ }
45
+ function generateNodeTypes(dataConfig) {
46
+ const newNodeTypes = {
47
+ sourceNodes: {},
48
+ targetNodes: {}
49
+ };
50
+ Object.entries(dataConfig.nodes).forEach(([nodeKey, nodeInfo]) => {
51
+ const category = nodeInfo.category;
52
+ if (category === "source" || category === "both") newNodeTypes.sourceNodes[nodeKey] = {
53
+ displayName: nodeInfo.displayName,
54
+ schema: nodeKey,
55
+ inputTypes: [],
56
+ operations: []
57
+ };
58
+ if (category === "target" || category === "both") newNodeTypes.targetNodes[nodeKey] = {
59
+ displayName: nodeInfo.displayName,
60
+ schema: nodeKey,
61
+ inputTypes: [],
62
+ operations: []
63
+ };
64
+ if (!parsedSchemas[nodeKey]) {}
65
+ const schema = parsedSchemas[nodeKey];
66
+ if (schema) {
67
+ const operations = findOperationsWithStateArgs(schema);
68
+ const inputTypes = operations.map((op) => op.stateType).filter((type) => type !== null);
69
+ if (category === "both") {
70
+ newNodeTypes.sourceNodes[nodeKey].inputTypes = [...new Set(inputTypes)];
71
+ newNodeTypes.sourceNodes[nodeKey].operations = operations;
72
+ newNodeTypes.targetNodes[nodeKey].inputTypes = [...new Set(inputTypes)];
73
+ newNodeTypes.targetNodes[nodeKey].operations = operations;
74
+ } else if (category === "source") {
75
+ newNodeTypes.sourceNodes[nodeKey].inputTypes = [...new Set(inputTypes)];
76
+ newNodeTypes.sourceNodes[nodeKey].operations = operations;
77
+ } else if (category === "target") {
78
+ newNodeTypes.targetNodes[nodeKey].inputTypes = [...new Set(inputTypes)];
79
+ newNodeTypes.targetNodes[nodeKey].operations = operations;
80
+ }
81
+ }
82
+ });
83
+ nodeTypes$1 = newNodeTypes;
84
+ }
85
+ function findOperationsWithStateArgs(schema) {
86
+ const operations = [];
87
+ if (schema.queryType) {
88
+ const queryType = schema.types[schema.queryType];
89
+ if (queryType && queryType.fields) for (const fieldName in queryType.fields) {
90
+ const field = queryType.fields[fieldName];
91
+ if (fieldName === "__schema" || fieldName === "__type") continue;
92
+ const stateArg = field.args && field.args.find((arg) => arg.name === "state");
93
+ const contextArg = field.args && field.args.find((arg) => arg.name === "context");
94
+ if (!!stateArg && !!contextArg) operations.push({
95
+ name: fieldName,
96
+ type: "query",
97
+ returnType: field.type,
98
+ stateType: stateArg.type,
99
+ inputType: stateArg.type
100
+ });
101
+ else if (field.args && field.args.length > 0) {
102
+ const firstArg = field.args[0];
103
+ operations.push({
104
+ name: fieldName,
105
+ type: "query",
106
+ returnType: field.type,
107
+ stateType: firstArg.type,
108
+ inputType: firstArg.type
109
+ });
110
+ } else operations.push({
111
+ name: fieldName,
112
+ type: "query",
113
+ returnType: field.type,
114
+ stateType: null,
115
+ inputType: null
116
+ });
117
+ }
118
+ else console.warn(`Query type ${schema.queryType} not found or has no fields`);
119
+ }
120
+ if (schema.mutationType) {
121
+ const mutationType = schema.types[schema.mutationType];
122
+ if (mutationType && mutationType.fields) for (const fieldName in mutationType.fields) {
123
+ const field = mutationType.fields[fieldName];
124
+ const stateArg = field.args && field.args.find((arg) => arg.name === "state");
125
+ const contextArg = field.args && field.args.find((arg) => arg.name === "context");
126
+ if (!!stateArg && !!contextArg) operations.push({
127
+ name: fieldName,
128
+ type: "mutation",
129
+ returnType: field.type,
130
+ stateType: stateArg.type,
131
+ inputType: stateArg.type
132
+ });
133
+ else if (field.args && field.args.length > 0) {
134
+ const firstArg = field.args[0];
135
+ operations.push({
136
+ name: fieldName,
137
+ type: "mutation",
138
+ returnType: field.type,
139
+ stateType: firstArg.type,
140
+ inputType: firstArg.type
141
+ });
142
+ } else operations.push({
143
+ name: fieldName,
144
+ type: "mutation",
145
+ returnType: field.type,
146
+ stateType: null,
147
+ inputType: null
148
+ });
149
+ }
150
+ else console.warn(`Mutation type ${schema.mutationType} not found or has no fields`);
151
+ }
152
+ return operations;
153
+ }
154
+ function generateTypeCompatibilityFunc(dataConfig) {
155
+ typeCompatibility = dataConfig.typeCompatibility;
156
+ }
157
+ function generateSampleDataFunc(dataConfig) {
158
+ sampleData = dataConfig.sampleData;
159
+ }
160
+ function generateVisualStylesFunc(dataConfig) {
161
+ const newNodeStyles = {};
162
+ Object.entries(dataConfig.nodes).forEach(([nodeKey, nodeInfo]) => {
163
+ newNodeStyles[nodeKey] = nodeInfo.style || {};
164
+ });
165
+ nodeStyles = newNodeStyles;
166
+ }
167
+ function getEdgeColor(mappingType, compatible = true) {
168
+ const colorConfig = currentConfig?.mappingTypes[mappingType]?.color;
169
+ if (!colorConfig) return null;
170
+ return typeof colorConfig === "string" ? colorConfig : compatible ? colorConfig.compatible : colorConfig.incompatible;
171
+ }
172
+ function getReturnTypeForOperation(nodeType, operationName) {
173
+ return ((nodeTypes$1?.targetNodes[nodeType] || nodeTypes$1?.sourceNodes[nodeType])?.operations?.find((op) => op.name === operationName))?.returnType;
174
+ }
175
+ function getNodeStyle(nodeType, side) {
176
+ if (!nodeStyles || !nodeStyles[nodeType]) return "";
177
+ const styles = nodeStyles[nodeType];
178
+ if (side) return (side === "source" ? styles.source : styles.target) || "";
179
+ return styles;
180
+ }
181
+ function getInputTypeForOperation(nodeType, operationName) {
182
+ return ((nodeTypes$1?.targetNodes[nodeType] || nodeTypes$1?.sourceNodes[nodeType])?.operations?.find((op) => op.name === operationName))?.inputType;
183
+ }
184
+ function getTypeCompatibility() {
185
+ return typeCompatibility || {};
186
+ }
187
+
188
+ // src/builder/components/lib/type-utils.ts
189
+ function areTypesCompatible(sourceType, targetType) {
190
+ const cleanSourceType = sourceType.replace(/!$/, "").replace(/^\[/, "").replace(/\]!?$/, "");
191
+ const cleanTargetType = targetType.replace(/!$/, "").replace(/\]!?$/, "");
192
+ if (cleanSourceType === cleanTargetType) return true;
193
+ return getTypeCompatibility()[cleanSourceType]?.includes(cleanTargetType) || false;
194
+ }
195
+ function getReadableTypeName(type) {
196
+ const isNonNull = type.endsWith("!");
197
+ const isList = type.includes("[");
198
+ let result = type.replace(/!$/, "").replace(/^\[/, "").replace(/\]!?$/, "");
199
+ if (isList) result = `Array of ${result}`;
200
+ if (isNonNull) result = `${result} (Required)`;
201
+ return result;
202
+ }
203
+
204
+ // src/builder/components/mapper/schema-node.tsx
205
+ const SchemaNode = memo(({ data, isConnectable }) => {
206
+ const { label, type, side, isRequired, isNested, isArray, nodeType, category } = data;
207
+ const readableType = getReadableTypeName(type);
208
+ const borderColor = getNodeStyle(nodeType || "", side);
209
+ const bgColor = side === "source" ? "bg-surface hover:bg-[var(--color-bg-accent)]/10 transition-colors duration-200" : "bg-surface hover:bg-[var(--color-status-success-bg-subtle)] transition-colors duration-200";
210
+ const categoryColor = getCategoryColor(category);
211
+ return /* @__PURE__ */ jsxs(Card, {
212
+ className: `w-56 shadow-sm ${borderColor} ${bgColor} transition-colors duration-200`,
213
+ children: [
214
+ /* @__PURE__ */ jsxs("div", {
215
+ className: `flex items-center px-2 py-1 border-b ${categoryColor}`,
216
+ children: [/* @__PURE__ */ jsx("div", {
217
+ className: "flex-1 font-medium text-xs truncate",
218
+ title: label,
219
+ children: label
220
+ }), /* @__PURE__ */ jsxs("div", {
221
+ className: "flex gap-1 flex-shrink-0",
222
+ children: [
223
+ isRequired && /* @__PURE__ */ jsx(Badge, {
224
+ variant: "destructive",
225
+ className: "text-[10px] px-1 py-0",
226
+ children: "Req"
227
+ }),
228
+ isArray && /* @__PURE__ */ jsx(Badge, {
229
+ variant: "secondary",
230
+ className: "text-[10px] px-1 py-0",
231
+ children: "Array"
232
+ }),
233
+ isNested && /* @__PURE__ */ jsx(Badge, {
234
+ variant: "outline",
235
+ className: "text-[10px] px-1 py-0",
236
+ children: "Obj"
237
+ })
238
+ ]
239
+ })]
240
+ }),
241
+ /* @__PURE__ */ jsx(CardContent, {
242
+ className: "p-1 text-[10px] text-muted-foreground",
243
+ children: /* @__PURE__ */ jsxs("div", {
244
+ className: "flex justify-between items-center",
245
+ children: [/* @__PURE__ */ jsx("span", {
246
+ title: readableType,
247
+ children: readableType
248
+ }), category && /* @__PURE__ */ jsx(Badge, {
249
+ variant: "outline",
250
+ className: "text-[10px] px-1 py-0",
251
+ style: { backgroundColor: getCategoryBgColor(category) },
252
+ children: category
253
+ })]
254
+ })
255
+ }),
256
+ side === "source" ? /* @__PURE__ */ jsx(Handle, {
257
+ type: "source",
258
+ position: Position.Right,
259
+ isConnectable,
260
+ className: "w-2 h-2 bg-accent transition-transform hover:scale-125"
261
+ }) : /* @__PURE__ */ jsx(Handle, {
262
+ type: "target",
263
+ position: Position.Left,
264
+ isConnectable,
265
+ className: "w-2 h-2 bg-[var(--color-status-success-bg)] transition-transform hover:scale-125"
266
+ })
267
+ ]
268
+ });
269
+ });
270
+ function getCategoryColor(category) {
271
+ if (!category) return "";
272
+ switch (category.toLowerCase()) {
273
+ case "input": return "border-[var(--color-border-accent)]/50 bg-[var(--color-bg-accent)]/10";
274
+ case "metadata": return "border-[var(--color-status-warning-border)]/50 bg-[var(--color-status-warning-bg-subtle)]";
275
+ case "context": return "border-[var(--color-status-success-border)]/50 bg-[var(--color-status-success-bg-subtle)]";
276
+ case "output": return "border-[var(--color-border-accent)]/30 bg-[var(--color-bg-accent)]/5";
277
+ case "config": return "border-[var(--color-status-error-border)]/50 bg-[var(--color-status-error-bg-subtle)]";
278
+ default: return "border-default";
279
+ }
280
+ }
281
+ /** Translucent category tint for the field badge (semantic tokens, light + dark). */
282
+ function getCategoryBgColor(category) {
283
+ switch (category.toLowerCase()) {
284
+ case "input": return "var(--color-node-integration-subtle)";
285
+ case "metadata": return "var(--color-status-warning-bgSubtle)";
286
+ case "context": return "var(--color-status-success-bgSubtle)";
287
+ case "output": return "var(--color-status-info-bgSubtle)";
288
+ case "config": return "var(--color-status-error-bgSubtle)";
289
+ default: return "var(--color-bg-sunken)";
290
+ }
291
+ }
292
+ SchemaNode.displayName = "SchemaNode";
293
+
294
+ // src/builder/components/mapper/mapping-edge.tsx
295
+ const MappingEdge = memo(({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, style = {}, markerEnd }) => {
296
+ const [edgePath, labelX, labelY] = getBezierPath({
297
+ sourceX,
298
+ sourceY,
299
+ sourcePosition,
300
+ targetX,
301
+ targetY,
302
+ targetPosition
303
+ });
304
+ const mappingType = data?.mappingType || "direct";
305
+ const isCompatible = data?.isCompatible !== false;
306
+ let mappingLabel = "";
307
+ const mappingColor = getEdgeColor(mappingType, isCompatible) || MAPPING_FALLBACK_COLOR;
308
+ switch (mappingType) {
309
+ case "direct":
310
+ mappingLabel = "Direct";
311
+ break;
312
+ case "expression":
313
+ mappingLabel = "Expression";
314
+ break;
315
+ case "transform":
316
+ mappingLabel = data?.mappingData?.function ? `Transform: ${data.mappingData.function}` : "Transform";
317
+ break;
318
+ case "loop":
319
+ mappingLabel = "Loop";
320
+ break;
321
+ case "cast": mappingLabel = data?.mappingData?.type ? `Cast: ${data.mappingData.type}` : "Cast";
322
+ }
323
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("path", {
324
+ id,
325
+ style: {
326
+ ...style,
327
+ stroke: mappingColor,
328
+ strokeWidth: 2
329
+ },
330
+ className: "react-flow__edge-path",
331
+ d: edgePath,
332
+ markerEnd
333
+ }), /* @__PURE__ */ jsx("foreignObject", {
334
+ width: 120,
335
+ height: 40,
336
+ x: labelX - 60,
337
+ y: labelY - 20,
338
+ className: "overflow-visible",
339
+ children: /* @__PURE__ */ jsx("div", {
340
+ className: "flex items-center justify-center bg-surface border border-default rounded-md shadow-sm px-2 py-1",
341
+ children: /* @__PURE__ */ jsxs("span", {
342
+ className: "text-xs font-medium",
343
+ style: { color: mappingColor },
344
+ children: [mappingLabel, !isCompatible && mappingType === "direct" && " ⚠️"]
345
+ })
346
+ })
347
+ })] });
348
+ });
349
+ MappingEdge.displayName = "MappingEdge";
350
+
351
+ // src/builder/components/mapper/node-group.tsx
352
+ const NodeGroup = memo(({ data, children }) => {
353
+ const { label, nodeType, side } = data;
354
+ const bgColor = side === "source" ? "bg-[var(--color-bg-accent)]/10" : "bg-[var(--color-status-success-bg-subtle)]";
355
+ const borderColor = side === "source" ? "border-[var(--color-border-accent)]" : "border-[var(--color-status-success-border)]";
356
+ const textColor = side === "source" ? "text-accent" : "text-[var(--color-status-success-text)]";
357
+ return /* @__PURE__ */ jsxs("div", {
358
+ className: `px-4 pt-12 pb-4 rounded-lg border-2 ${borderColor} ${bgColor} min-w-[400px] min-h-[600px] shadow-md relative overflow-visible bg-gradient-to-b ${side === "source" ? "from-[var(--color-bg-accent)]/20 to-transparent" : "from-[var(--color-status-success-bg-subtle)]/50 to-transparent"}`,
359
+ style: { minHeight: "600px" },
360
+ children: [/* @__PURE__ */ jsx("div", {
361
+ className: `absolute top-0 left-0 right-0 ${textColor} font-semibold p-2 border-b ${borderColor} text-center bg-surface/70 backdrop-blur-sm rounded-t-lg flex items-center justify-center`,
362
+ children: /* @__PURE__ */ jsxs("div", {
363
+ className: "text-sm",
364
+ children: [
365
+ label,
366
+ " ",
367
+ /* @__PURE__ */ jsxs("span", {
368
+ className: "text-xs opacity-75",
369
+ children: [
370
+ "(",
371
+ nodeType,
372
+ ")"
373
+ ]
374
+ })
375
+ ]
376
+ })
377
+ }), /* @__PURE__ */ jsx("div", {
378
+ className: "relative w-full h-full overflow-visible",
379
+ children
380
+ })]
381
+ });
382
+ });
383
+ NodeGroup.displayName = "NodeGroup";
384
+
385
+ // src/builder/components/lib/node-generator.ts
386
+ /**
387
+ * Find the return type for an operation directly from the schema
388
+ */
389
+ function findReturnTypeFromSchema(schema, operationName) {
390
+ if (schema.queryType && schema.types[schema.queryType]?.fields[operationName]) return schema.types[schema.queryType].fields[operationName].type;
391
+ if (schema.mutationType && schema.types[schema.mutationType]?.fields[operationName]) return schema.types[schema.mutationType].fields[operationName].type;
392
+ return null;
393
+ }
394
+ function findInputTypeFromSchema(schema, operationName) {
395
+ let field = null;
396
+ if (schema.queryType && schema.types[schema.queryType]?.fields[operationName]) field = schema.types[schema.queryType].fields[operationName];
397
+ if (!field && schema.mutationType && schema.types[schema.mutationType]?.fields[operationName]) field = schema.types[schema.mutationType].fields[operationName];
398
+ if (!field) return {
399
+ typeName: null,
400
+ useArgsDirectly: false,
401
+ field: null
402
+ };
403
+ const stateArg = field.args?.find((a) => a.name === "state" || a.name === "input");
404
+ if (stateArg) {
405
+ const inputType = schema.types[stateArg.type];
406
+ if (inputType && (inputType.inputFields || inputType.fields)) return {
407
+ typeName: stateArg.type,
408
+ useArgsDirectly: false,
409
+ field
410
+ };
411
+ }
412
+ if (field.args && field.args.length > 0) {
413
+ const firstArg = field.args[0];
414
+ const firstArgType = schema.types[firstArg.type];
415
+ if (firstArgType && firstArgType.kind === "input" && (firstArgType.inputFields || firstArgType.fields)) return {
416
+ typeName: firstArg.type,
417
+ useArgsDirectly: false,
418
+ field
419
+ };
420
+ }
421
+ if (field.args && field.args.length > 0) return {
422
+ typeName: null,
423
+ useArgsDirectly: true,
424
+ field
425
+ };
426
+ return {
427
+ typeName: null,
428
+ useArgsDirectly: false,
429
+ field: null
430
+ };
431
+ }
432
+ /**
433
+ * Generate schema nodes for visual mapping
434
+ */
435
+ function generateSchemaNodes(sourceSchema, sourceNode, sourceOperation, targetSchema, targetNode, targetOperation) {
436
+ const nodes = [];
437
+ const edges = [];
438
+ if (targetSchema?.mutationType && targetSchema?.types[targetSchema.mutationType]) {
439
+ const mutationField = targetSchema.types[targetSchema.mutationType].fields?.[targetOperation];
440
+ if (mutationField?.args) {
441
+ for (const arg of mutationField.args) if (targetSchema.types[arg.type]?.inputFields) {}
442
+ }
443
+ }
444
+ let sourceOutputType = null;
445
+ const sourceReturnTypeName = findReturnTypeFromSchema(sourceSchema, sourceOperation);
446
+ if (sourceReturnTypeName) sourceOutputType = sourceSchema.types[sourceReturnTypeName];
447
+ if (!sourceOutputType) for (const typeName of Object.keys(sourceSchema.types)) {
448
+ const type = sourceSchema.types[typeName];
449
+ if (type.kind === "type" && type.fields && Object.keys(type.fields).length > 0) {
450
+ if (typeName === sourceSchema.queryType || typeName === sourceSchema.mutationType || typeName === sourceSchema.subscriptionType) continue;
451
+ sourceOutputType = type;
452
+ break;
453
+ }
454
+ }
455
+ let targetInputType = null;
456
+ let useArgsDirectlyForTarget = false;
457
+ let targetOperationField = null;
458
+ const targetInputResult = findInputTypeFromSchema(targetSchema, targetOperation);
459
+ if (targetInputResult.typeName) targetInputType = targetSchema.types[targetInputResult.typeName];
460
+ else if (targetInputResult.useArgsDirectly && targetInputResult.field) {
461
+ useArgsDirectlyForTarget = true;
462
+ targetOperationField = targetInputResult.field;
463
+ }
464
+ if (!targetInputType && !useArgsDirectlyForTarget) for (const typeName of Object.keys(targetSchema.types)) {
465
+ const type = targetSchema.types[typeName];
466
+ if (type.kind === "input" && (type.inputFields || type.fields)) {
467
+ targetInputType = type;
468
+ break;
469
+ }
470
+ }
471
+ const sourceGroupNode = {
472
+ id: "source-group",
473
+ type: "nodeGroup",
474
+ position: {
475
+ x: 50,
476
+ y: 50
477
+ },
478
+ style: {
479
+ width: 450,
480
+ height: 800
481
+ },
482
+ data: {
483
+ label: `Source: ${sourceOperation}`,
484
+ nodeType: sourceNode,
485
+ side: "source"
486
+ }
487
+ };
488
+ const targetGroupNode = {
489
+ id: "target-group",
490
+ type: "nodeGroup",
491
+ position: {
492
+ x: 650,
493
+ y: 50
494
+ },
495
+ style: {
496
+ width: 450,
497
+ height: 800
498
+ },
499
+ data: {
500
+ label: `Target: ${targetOperation}`,
501
+ nodeType: targetNode,
502
+ side: "target"
503
+ }
504
+ };
505
+ nodes.push(sourceGroupNode, targetGroupNode);
506
+ const yPos = 70;
507
+ const sourceFields = sourceOutputType?.fields || {};
508
+ if (Object.keys(sourceFields).length === 0) {
509
+ console.warn("No source fields found for", sourceNode, sourceOperation);
510
+ nodes.push({
511
+ id: `source-placeholder`,
512
+ position: {
513
+ x: 100,
514
+ y: 70
515
+ },
516
+ data: {
517
+ label: "No fields available",
518
+ type: "String",
519
+ path: "placeholder",
520
+ side: "source",
521
+ isRequired: false,
522
+ isNested: false,
523
+ isArray: false,
524
+ nodeType: sourceNode
525
+ },
526
+ type: "schemaNode",
527
+ parentId: "source-group",
528
+ extent: "parent"
529
+ });
530
+ }
531
+ const generateFieldNodes = (fields, parentPath = "", xPos, startYPos, side, parentNodeType, schema) => {
532
+ let currentYPos = startYPos;
533
+ const generatedNodes = [];
534
+ const xOffset = 100;
535
+ const categorizedFields = {
536
+ input: {},
537
+ metadata: {},
538
+ context: {},
539
+ output: {},
540
+ config: {},
541
+ other: {}
542
+ };
543
+ for (const fieldName in fields) {
544
+ const field = fields[fieldName];
545
+ if (fieldName.toLowerCase().includes("input") || fieldName.toLowerCase().includes("request")) categorizedFields.input[fieldName] = field;
546
+ else if (fieldName.toLowerCase().includes("metadata") || fieldName.toLowerCase().includes("meta")) categorizedFields.metadata[fieldName] = field;
547
+ else if (fieldName.toLowerCase().includes("context") || fieldName.toLowerCase().includes("ctx")) categorizedFields.context[fieldName] = field;
548
+ else if (fieldName.toLowerCase().includes("output") || fieldName.toLowerCase().includes("response") || fieldName.toLowerCase().includes("result")) categorizedFields.output[fieldName] = field;
549
+ else if (fieldName.toLowerCase().includes("config") || fieldName.toLowerCase().includes("setting") || fieldName.toLowerCase().includes("option")) categorizedFields.config[fieldName] = field;
550
+ else categorizedFields.other[fieldName] = field;
551
+ }
552
+ const categories = Object.keys(categorizedFields);
553
+ for (const category of categories) {
554
+ const categoryFields = categorizedFields[category];
555
+ if (Object.keys(categoryFields).length === 0) continue;
556
+ if (generatedNodes.length > 0) currentYPos += 20;
557
+ for (const fieldName in categoryFields) {
558
+ const field = categoryFields[fieldName];
559
+ const fullPath = parentPath ? `${parentPath}.${fieldName}` : fieldName;
560
+ const node = {
561
+ id: `${side}-${fullPath}`,
562
+ position: {
563
+ x: xOffset,
564
+ y: currentYPos
565
+ },
566
+ data: {
567
+ label: fieldName,
568
+ type: field.type,
569
+ path: fullPath,
570
+ side,
571
+ isRequired: field.isNonNull,
572
+ isNested: isComplexType(schema, field.type),
573
+ isArray: field.isList,
574
+ nodeType: parentNodeType,
575
+ category: category !== "other" ? category : void 0
576
+ },
577
+ type: "schemaNode",
578
+ parentId: side === "source" ? "source-group" : "target-group",
579
+ extent: "parent"
580
+ };
581
+ generatedNodes.push(node);
582
+ currentYPos += 70;
583
+ if (isComplexType(schema, field.type) && schema.types[field.type]) {
584
+ const nestedFields = schema.types[field.type].fields || {};
585
+ if (Object.keys(nestedFields).length > 0) {
586
+ const nestedNodes = generateFieldNodes(nestedFields, fullPath, xPos + (side === "source" ? 150 : -150), currentYPos - 20, side, parentNodeType, schema);
587
+ generatedNodes.push(...nestedNodes);
588
+ currentYPos += nestedNodes.length * 60 + 30;
589
+ }
590
+ }
591
+ }
592
+ }
593
+ return generatedNodes;
594
+ };
595
+ const sourceNodes = generateFieldNodes(sourceFields, "", 100, yPos, "source", sourceNode, sourceSchema);
596
+ nodes.push(...sourceNodes);
597
+ const targetFields = {};
598
+ if (useArgsDirectlyForTarget && targetOperationField?.args) for (const arg of targetOperationField.args) targetFields[arg.name] = {
599
+ name: arg.name,
600
+ type: arg.type,
601
+ isNonNull: arg.isNonNull || false,
602
+ isList: arg.isList || false,
603
+ args: []
604
+ };
605
+ else if (targetInputType) {
606
+ const inputFieldsSource = targetInputType.inputFields || targetInputType.fields || {};
607
+ for (const fieldName of Object.keys(inputFieldsSource)) {
608
+ const field = inputFieldsSource[fieldName];
609
+ targetFields[fieldName] = {
610
+ name: field.name,
611
+ type: field.type,
612
+ isNonNull: field.isNonNull,
613
+ isList: field.isList,
614
+ args: field.args || []
615
+ };
616
+ }
617
+ }
618
+ if (Object.keys(targetFields).length === 0) {
619
+ const processOperationArgs = (operationField) => {
620
+ if (!operationField?.args || operationField.args.length === 0) return false;
621
+ const inputArg = operationField.args.find((a) => a.name === "input" || a.name === "state");
622
+ if (inputArg) {
623
+ const inputType = targetSchema.types[inputArg.type];
624
+ if (inputType && inputType.kind === "input" && inputType.inputFields) {
625
+ for (const fieldName of Object.keys(inputType.inputFields)) {
626
+ const field = inputType.inputFields[fieldName];
627
+ targetFields[fieldName] = {
628
+ name: field.name || fieldName,
629
+ type: field.type,
630
+ isNonNull: field.isNonNull || false,
631
+ isList: field.isList || false,
632
+ args: []
633
+ };
634
+ }
635
+ return true;
636
+ }
637
+ }
638
+ if (operationField.args.length > 0) {
639
+ const firstArg = operationField.args[0];
640
+ const firstArgType = targetSchema.types[firstArg.type];
641
+ if (firstArgType && firstArgType.kind === "input" && firstArgType.inputFields) {
642
+ for (const fieldName of Object.keys(firstArgType.inputFields)) {
643
+ const field = firstArgType.inputFields[fieldName];
644
+ targetFields[fieldName] = {
645
+ name: field.name || fieldName,
646
+ type: field.type,
647
+ isNonNull: field.isNonNull || false,
648
+ isList: field.isList || false,
649
+ args: []
650
+ };
651
+ }
652
+ return true;
653
+ }
654
+ }
655
+ for (const arg of operationField.args) targetFields[arg.name] = {
656
+ name: arg.name,
657
+ type: arg.type,
658
+ isNonNull: arg.isNonNull || false,
659
+ isList: arg.isList || false,
660
+ args: []
661
+ };
662
+ return true;
663
+ };
664
+ if (targetSchema.mutationType && targetSchema.types[targetSchema.mutationType]) {
665
+ const mutationField = targetSchema.types[targetSchema.mutationType].fields?.[targetOperation];
666
+ if (mutationField) processOperationArgs(mutationField);
667
+ }
668
+ if (Object.keys(targetFields).length === 0 && targetSchema.queryType && targetSchema.types[targetSchema.queryType]) {
669
+ const queryField = targetSchema.types[targetSchema.queryType].fields?.[targetOperation];
670
+ if (queryField) processOperationArgs(queryField);
671
+ }
672
+ }
673
+ if (Object.keys(targetFields).length === 0) {
674
+ console.warn("No target fields found for", targetNode, targetOperation);
675
+ nodes.push({
676
+ id: `target-placeholder`,
677
+ position: {
678
+ x: 100,
679
+ y: 70
680
+ },
681
+ data: {
682
+ label: "No fields available",
683
+ type: "String",
684
+ path: "placeholder",
685
+ side: "target",
686
+ isRequired: false,
687
+ isNested: false,
688
+ isArray: false,
689
+ nodeType: targetNode
690
+ },
691
+ type: "schemaNode",
692
+ parentId: "target-group",
693
+ extent: "parent"
694
+ });
695
+ }
696
+ const targetNodes = generateFieldNodes(targetFields, "", 100, yPos, "target", targetNode, targetSchema);
697
+ nodes.push(...targetNodes);
698
+ if (sourceNodes.length > 0) {
699
+ const maxSourceY = Math.max(...sourceNodes.map((node) => {
700
+ return node.position.y;
701
+ })) + 150;
702
+ if (sourceGroupNode.style) sourceGroupNode.style.height = Math.max(maxSourceY, 600);
703
+ const maxSourceX = Math.max(...sourceNodes.map((node) => node.position.x + 300));
704
+ if (sourceGroupNode.style) sourceGroupNode.style.width = Math.max(maxSourceX, 400);
705
+ }
706
+ if (targetNodes.length > 0) {
707
+ const maxTargetY = Math.max(...targetNodes.map((node) => {
708
+ return node.position.y;
709
+ })) + 150;
710
+ if (targetGroupNode.style) targetGroupNode.style.height = Math.max(maxTargetY, 600);
711
+ const maxTargetX = Math.max(...targetNodes.map((node) => node.position.x + 300));
712
+ if (targetGroupNode.style) targetGroupNode.style.width = Math.max(maxTargetX, 400);
713
+ }
714
+ return {
715
+ nodes,
716
+ edges
717
+ };
718
+ }
719
+ function isComplexType(schema, typeName) {
720
+ const type = schema.types[typeName];
721
+ if (!type) return false;
722
+ return type.kind === "type" || type.kind === "input";
723
+ }
724
+
725
+ // src/builder/components/hooks/use-toast.ts
726
+ const TOAST_LIMIT = 5;
727
+ const TOAST_REMOVE_DELAY = 1e6;
728
+ const actionTypes = {
729
+ ADD_TOAST: "ADD_TOAST",
730
+ UPDATE_TOAST: "UPDATE_TOAST",
731
+ DISMISS_TOAST: "DISMISS_TOAST",
732
+ REMOVE_TOAST: "REMOVE_TOAST"
733
+ };
734
+ let count = 0;
735
+ function genId() {
736
+ count = (count + 1) % Number.MAX_VALUE;
737
+ return count.toString();
738
+ }
739
+ const toastTimeouts = /* @__PURE__ */ new Map();
740
+ const reducer = (state, action) => {
741
+ switch (action.type) {
742
+ case actionTypes.ADD_TOAST: return {
743
+ ...state,
744
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT)
745
+ };
746
+ case actionTypes.UPDATE_TOAST: return {
747
+ ...state,
748
+ toasts: state.toasts.map((t) => t.id === action.toast.id ? {
749
+ ...t,
750
+ ...action.toast
751
+ } : t)
752
+ };
753
+ case actionTypes.DISMISS_TOAST: {
754
+ const { toastId } = action;
755
+ if (toastId) addToRemoveQueue(toastId);
756
+ else state.toasts.forEach((toast) => {
757
+ addToRemoveQueue(toast.id);
758
+ });
759
+ return {
760
+ ...state,
761
+ toasts: state.toasts.map((t) => t.id === toastId || toastId === void 0 ? {
762
+ ...t,
763
+ open: false
764
+ } : t)
765
+ };
766
+ }
767
+ case actionTypes.REMOVE_TOAST:
768
+ if (action.toastId === void 0) return {
769
+ ...state,
770
+ toasts: []
771
+ };
772
+ return {
773
+ ...state,
774
+ toasts: state.toasts.filter((t) => t.id !== action.toastId)
775
+ };
776
+ }
777
+ };
778
+ const listeners = [];
779
+ let memoryState = { toasts: [] };
780
+ function dispatch(action) {
781
+ memoryState = reducer(memoryState, action);
782
+ listeners.forEach((listener) => {
783
+ listener(memoryState);
784
+ });
785
+ }
786
+ function toast({ ...props }) {
787
+ const id = genId();
788
+ const update = (props) => dispatch({
789
+ type: actionTypes.UPDATE_TOAST,
790
+ toast: {
791
+ ...props,
792
+ id
793
+ }
794
+ });
795
+ const dismiss = () => dispatch({
796
+ type: actionTypes.DISMISS_TOAST,
797
+ toastId: id
798
+ });
799
+ dispatch({
800
+ type: actionTypes.ADD_TOAST,
801
+ toast: {
802
+ ...props,
803
+ id,
804
+ open: true,
805
+ onOpenChange: (open) => {
806
+ if (!open) dismiss();
807
+ }
808
+ }
809
+ });
810
+ return {
811
+ id,
812
+ dismiss,
813
+ update
814
+ };
815
+ }
816
+ function useToast() {
817
+ const [state, setState] = React$1.useState(memoryState);
818
+ React$1.useEffect(() => {
819
+ listeners.push(setState);
820
+ return () => {
821
+ const index = listeners.indexOf(setState);
822
+ if (index > -1) listeners.splice(index, 1);
823
+ };
824
+ }, [state]);
825
+ return {
826
+ ...state,
827
+ toast,
828
+ dismiss: (toastId) => dispatch({
829
+ type: actionTypes.DISMISS_TOAST,
830
+ toastId
831
+ })
832
+ };
833
+ }
834
+ function addToRemoveQueue(toastId) {
835
+ if (toastTimeouts.has(toastId)) return;
836
+ const timeout = setTimeout(() => {
837
+ toastTimeouts.delete(toastId);
838
+ dispatch({
839
+ type: actionTypes.REMOVE_TOAST,
840
+ toastId
841
+ });
842
+ }, TOAST_REMOVE_DELAY);
843
+ toastTimeouts.set(toastId, timeout);
844
+ }
845
+
846
+ // src/builder/components/mapper/config/data-config-context.tsx
847
+ const DataConfigContext = createContext(null);
848
+ function DataConfigProvider({ children, config }) {
849
+ return /* @__PURE__ */ jsx(DataConfigContext.Provider, {
850
+ value: config,
851
+ children
852
+ });
853
+ }
854
+ function useDataConfig() {
855
+ const context = useContext(DataConfigContext);
856
+ if (!context) {
857
+ console.warn("useDataConfig: No DataConfigProvider found, using empty config");
858
+ return {
859
+ nodes: {},
860
+ mappingTypes: {},
861
+ typeCompatibility: {},
862
+ sampleData: {}
863
+ };
864
+ }
865
+ return context;
866
+ }
867
+
868
+ // src/builder/components/mapper/mapping-dialog.tsx
869
+ function MappingDialog(props) {
870
+ if (!props.open) return null;
871
+ const dialogKey = `${props.mappingType}-${props.sourceField || ""}-${props.targetField || ""}`;
872
+ return /* @__PURE__ */ jsx(MappingDialogContent, { ...props }, dialogKey);
873
+ }
874
+ function MappingDialogContent({ open, onOpenChange, onSave, mappingType, sourceField, targetField, sourceSchema, sourceOperation, targetSchema, targetOperation }) {
875
+ const [expression, setExpression] = useState(() => sourceField ? `\${output.${sourceField}}` : "");
876
+ const [selectedExample, setSelectedExample] = useState("");
877
+ const [activeTab, setActiveTab] = useState(() => mappingType === "array" || mappingType === "object" ? "builder" : "examples");
878
+ const [targetFieldName, setTargetFieldName] = useState(() => targetField || "");
879
+ const [selectedSourceArray, setSelectedSourceArray] = useState("");
880
+ const [itemExpression, setItemExpression] = useState("");
881
+ const dataConfig = useDataConfig();
882
+ const tr = useTr();
883
+ const sourceFields = useMemo(() => {
884
+ if (!sourceSchema) return [];
885
+ const fields = [];
886
+ const extractFields = (typeName, parentPath = "", depth = 0) => {
887
+ if (depth > 3) return [];
888
+ const typeInfo = sourceSchema.types[typeName];
889
+ if (!typeInfo || !typeInfo.fields) return [];
890
+ const result = [];
891
+ for (const fieldName in typeInfo.fields) {
892
+ const field = typeInfo.fields[fieldName];
893
+ const fieldPath = parentPath ? `${parentPath}.${fieldName}` : fieldName;
894
+ const fieldInfo = {
895
+ path: fieldPath,
896
+ name: fieldName,
897
+ type: field.type,
898
+ isList: field.isList || false,
899
+ isNonNull: field.isNonNull || false
900
+ };
901
+ if (sourceSchema.types[field.type] && sourceSchema.types[field.type].kind === "type") fieldInfo.children = extractFields(field.type, fieldPath, depth + 1);
902
+ result.push(fieldInfo);
903
+ }
904
+ return result;
905
+ };
906
+ const queryType = sourceSchema.types[sourceSchema.queryType || "Query"];
907
+ if (queryType && queryType.fields && sourceOperation) {
908
+ const operationField = queryType.fields[sourceOperation];
909
+ if (operationField) {
910
+ const returnType = operationField.type;
911
+ if (sourceSchema.types[returnType]) return extractFields(returnType, sourceOperation);
912
+ }
913
+ }
914
+ for (const typeName in sourceSchema.types) if (sourceSchema.types[typeName].kind === "type" && !typeName.startsWith("_") && typeName !== "Query" && typeName !== "Mutation") fields.push(...extractFields(typeName, ""));
915
+ return fields;
916
+ }, [sourceSchema, sourceOperation]);
917
+ const arrayFields = useMemo(() => {
918
+ const arrays = [];
919
+ const collectArrays = (fields, prefix = "") => {
920
+ for (const field of fields) {
921
+ if (field.isList) arrays.push({
922
+ ...field,
923
+ path: prefix ? `${prefix}.${field.path}` : field.path
924
+ });
925
+ if (field.children) collectArrays(field.children, prefix);
926
+ }
927
+ };
928
+ collectArrays(sourceFields);
929
+ return arrays;
930
+ }, [sourceFields]);
931
+ const arrayItemFields = useMemo(() => {
932
+ if (!selectedSourceArray || !sourceSchema) return [];
933
+ const findField = (fields, path) => {
934
+ for (const field of fields) {
935
+ if (field.path === path) return field;
936
+ if (field.children) {
937
+ const found = findField(field.children, path);
938
+ if (found) return found;
939
+ }
940
+ }
941
+ return null;
942
+ };
943
+ const arrayField = findField(sourceFields, selectedSourceArray);
944
+ if (!arrayField) return [];
945
+ const itemType = sourceSchema.types[arrayField.type];
946
+ if (!itemType || !itemType.fields) return [];
947
+ const result = [];
948
+ const extractNestedFields = (typeName, parentPath = "", currentDepth = 0) => {
949
+ if (currentDepth > 2) return;
950
+ const type = sourceSchema?.types[typeName];
951
+ if (!type || !type.fields) return;
952
+ for (const fieldName in type.fields) {
953
+ const field = type.fields[fieldName];
954
+ const fullPath = parentPath ? `${parentPath}.${fieldName}` : fieldName;
955
+ result.push({
956
+ name: fieldName,
957
+ type: field.type,
958
+ path: fullPath,
959
+ isNested: currentDepth > 0
960
+ });
961
+ const fieldType = sourceSchema?.types[field.type];
962
+ if (fieldType && fieldType.kind === "type" && !field.isList) extractNestedFields(field.type, fullPath, currentDepth + 1);
963
+ }
964
+ };
965
+ extractNestedFields(arrayField.type);
966
+ return result;
967
+ }, [
968
+ selectedSourceArray,
969
+ sourceFields,
970
+ sourceSchema
971
+ ]);
972
+ const targetFields = useMemo(() => {
973
+ if (!targetSchema) return [];
974
+ const fields = [];
975
+ const extractFields = (typeName, parentPath = "", depth = 0) => {
976
+ if (depth > 3) return [];
977
+ const typeInfo = targetSchema.types[typeName];
978
+ if (!typeInfo) return [];
979
+ const fieldsObj = typeInfo.inputFields || typeInfo.fields;
980
+ if (!fieldsObj) return [];
981
+ const result = [];
982
+ for (const fieldName in fieldsObj) {
983
+ const field = fieldsObj[fieldName];
984
+ const fieldPath = parentPath ? `${parentPath}.${fieldName}` : fieldName;
985
+ const fieldInfo = {
986
+ path: fieldPath,
987
+ name: fieldName,
988
+ type: field.type,
989
+ isList: field.isList || false,
990
+ isNonNull: field.isNonNull || false
991
+ };
992
+ if (targetSchema.types[field.type]) {
993
+ const nestedType = targetSchema.types[field.type];
994
+ if (nestedType.kind === "type" || nestedType.kind === "input") fieldInfo.children = extractFields(field.type, fieldPath, depth + 1);
995
+ }
996
+ result.push(fieldInfo);
997
+ }
998
+ return result;
999
+ };
1000
+ const mutationType = targetSchema.types[targetSchema.mutationType || "Mutation"];
1001
+ const queryType = targetSchema.types[targetSchema.queryType || "Query"];
1002
+ if (targetOperation) {
1003
+ if (mutationType?.fields?.[targetOperation]) {
1004
+ const operationField = mutationType.fields[targetOperation];
1005
+ if (operationField.args && operationField.args.length > 0) for (const arg of operationField.args) if (targetSchema.types[arg.type]) fields.push(...extractFields(arg.type, ""));
1006
+ else fields.push({
1007
+ path: arg.name,
1008
+ name: arg.name,
1009
+ type: arg.type,
1010
+ isList: arg.isList || false,
1011
+ isNonNull: arg.isNonNull || false
1012
+ });
1013
+ }
1014
+ if (queryType?.fields?.[targetOperation]) {
1015
+ const operationField = queryType.fields[targetOperation];
1016
+ if (operationField.args && operationField.args.length > 0) for (const arg of operationField.args) if (targetSchema.types[arg.type]) fields.push(...extractFields(arg.type, ""));
1017
+ else fields.push({
1018
+ path: arg.name,
1019
+ name: arg.name,
1020
+ type: arg.type,
1021
+ isList: arg.isList || false,
1022
+ isNonNull: arg.isNonNull || false
1023
+ });
1024
+ }
1025
+ }
1026
+ return fields;
1027
+ }, [targetSchema, targetOperation]);
1028
+ const handleSourceArrayChange = (value) => {
1029
+ setSelectedSourceArray(value);
1030
+ if (mappingType === "array" && value && itemExpression) setExpression(`\${output.${value}.map(item => item.${itemExpression})}`);
1031
+ };
1032
+ const handleItemExpressionChange = (value) => {
1033
+ setItemExpression(value);
1034
+ if (mappingType === "array" && selectedSourceArray && value) setExpression(`\${output.${selectedSourceArray}.map(item => item.${value})}`);
1035
+ };
1036
+ const getMappingTypeConfig = () => {
1037
+ return dataConfig?.mappingTypes?.[mappingType] || {};
1038
+ };
1039
+ const mappingTypeConfig = getMappingTypeConfig();
1040
+ const examples = mappingTypeConfig.examples || [];
1041
+ const safeBuiltins = mappingTypeConfig.safeBuiltins || [];
1042
+ const isFormValid = useMemo(() => {
1043
+ if (!targetFieldName.trim()) return false;
1044
+ if (!expression.trim()) return false;
1045
+ return true;
1046
+ }, [targetFieldName, expression]);
1047
+ const getValidationMessage = () => {
1048
+ const missing = [];
1049
+ if (!targetFieldName.trim()) missing.push(tr("fluidgrids.builder.mappingDialog.missingTargetFieldName", "target field name"));
1050
+ if (!expression.trim()) missing.push(tr("fluidgrids.builder.mappingDialog.missingExpression", "expression"));
1051
+ if (missing.length === 0) return null;
1052
+ return `${tr("fluidgrids.builder.mappingDialog.validationPrefix", "Please provide:")} ${missing.join(", ")}`;
1053
+ };
1054
+ const handleExampleChange = (exampleName) => {
1055
+ setSelectedExample(exampleName);
1056
+ if (exampleName && exampleName !== "choose") {
1057
+ const example = examples.find((ex) => ex.name === exampleName);
1058
+ if (example && example.expression) setExpression(example.expression);
1059
+ }
1060
+ };
1061
+ const handleSave = () => {
1062
+ onSave(expression, targetFieldName || void 0);
1063
+ onOpenChange(false);
1064
+ };
1065
+ const getDialogTitle = () => {
1066
+ switch (mappingType) {
1067
+ case "direct": return tr("fluidgrids.builder.mappingDialog.titleDirect", "Direct Field Mapping");
1068
+ case "expression": return tr("fluidgrids.builder.mappingDialog.titleExpression", "Expression Mapping");
1069
+ case "transform": return tr("fluidgrids.builder.mappingDialog.titleTransform", "Transform Mapping");
1070
+ case "cast": return tr("fluidgrids.builder.mappingDialog.titleCast", "Type Cast Mapping");
1071
+ case "array": return tr("fluidgrids.builder.mappingDialog.titleArray", "Array Mapping");
1072
+ case "object": return tr("fluidgrids.builder.mappingDialog.titleObject", "Object Mapping");
1073
+ case "context": return tr("fluidgrids.builder.mappingDialog.titleContext", "Workflow Context");
1074
+ default: return tr("fluidgrids.builder.mappingDialog.titleDefault", "Data Mapping");
1075
+ }
1076
+ };
1077
+ const getDialogDescription = () => {
1078
+ return mappingTypeConfig.description || tr("fluidgrids.builder.mappingDialog.defaultDescription", "Create a mapping using JavaScript template literal syntax");
1079
+ };
1080
+ const getPlaceholder = () => {
1081
+ switch (mappingType) {
1082
+ case "direct": return "${output.fieldName}";
1083
+ case "expression": return "${output.firstName + ' ' + output.lastName}";
1084
+ case "transform": return "${output.field.toUpperCase()}";
1085
+ case "cast": return "${parseInt(output.numberString)}";
1086
+ case "array": return "${output.items.map(item => item.id)}";
1087
+ case "object": return "${({ id: output.user.id, email: output.user.email })}";
1088
+ case "context": return "${TriggerInput.userId}";
1089
+ default: return "${output.field}";
1090
+ }
1091
+ };
1092
+ const getQuickInserts = () => {
1093
+ switch (mappingType) {
1094
+ case "direct": return [
1095
+ {
1096
+ label: "output.",
1097
+ snippet: "output."
1098
+ },
1099
+ {
1100
+ label: "?.",
1101
+ snippet: "?."
1102
+ },
1103
+ {
1104
+ label: "|| ''",
1105
+ snippet: " || ''"
1106
+ },
1107
+ {
1108
+ label: "?? null",
1109
+ snippet: " ?? null"
1110
+ }
1111
+ ];
1112
+ case "expression": return [
1113
+ {
1114
+ label: "output.",
1115
+ snippet: "output."
1116
+ },
1117
+ {
1118
+ label: "? :",
1119
+ snippet: " ? '' : ''"
1120
+ },
1121
+ {
1122
+ label: "&&",
1123
+ snippet: " && "
1124
+ },
1125
+ {
1126
+ label: "||",
1127
+ snippet: " || "
1128
+ },
1129
+ {
1130
+ label: "??",
1131
+ snippet: " ?? "
1132
+ }
1133
+ ];
1134
+ case "transform": return [
1135
+ {
1136
+ label: ".toUpperCase()",
1137
+ snippet: ".toUpperCase()"
1138
+ },
1139
+ {
1140
+ label: ".toLowerCase()",
1141
+ snippet: ".toLowerCase()"
1142
+ },
1143
+ {
1144
+ label: ".trim()",
1145
+ snippet: ".trim()"
1146
+ },
1147
+ {
1148
+ label: ".split(',')",
1149
+ snippet: ".split(',')"
1150
+ },
1151
+ {
1152
+ label: ".join(', ')",
1153
+ snippet: ".join(', ')"
1154
+ },
1155
+ {
1156
+ label: ".replace()",
1157
+ snippet: ".replace('old', 'new')"
1158
+ }
1159
+ ];
1160
+ case "cast": return [
1161
+ {
1162
+ label: "parseInt()",
1163
+ snippet: "parseInt("
1164
+ },
1165
+ {
1166
+ label: "parseFloat()",
1167
+ snippet: "parseFloat("
1168
+ },
1169
+ {
1170
+ label: "String()",
1171
+ snippet: "String("
1172
+ },
1173
+ {
1174
+ label: "Boolean()",
1175
+ snippet: "Boolean("
1176
+ },
1177
+ {
1178
+ label: "Number()",
1179
+ snippet: "Number("
1180
+ }
1181
+ ];
1182
+ case "array": return [
1183
+ {
1184
+ label: ".map()",
1185
+ snippet: ".map(item => item)"
1186
+ },
1187
+ {
1188
+ label: ".filter()",
1189
+ snippet: ".filter(item => item)"
1190
+ },
1191
+ {
1192
+ label: ".reduce()",
1193
+ snippet: ".reduce((acc, item) => acc, 0)"
1194
+ },
1195
+ {
1196
+ label: ".find()",
1197
+ snippet: ".find(item => item)"
1198
+ },
1199
+ {
1200
+ label: ".some()",
1201
+ snippet: ".some(item => item)"
1202
+ },
1203
+ {
1204
+ label: ".every()",
1205
+ snippet: ".every(item => item)"
1206
+ },
1207
+ {
1208
+ label: ".flat()",
1209
+ snippet: ".flat()"
1210
+ },
1211
+ {
1212
+ label: ".slice()",
1213
+ snippet: ".slice(0, 5)"
1214
+ },
1215
+ {
1216
+ label: ".sort()",
1217
+ snippet: ".sort((a, b) => a - b)"
1218
+ }
1219
+ ];
1220
+ case "object": return [
1221
+ {
1222
+ label: "Object.keys()",
1223
+ snippet: "Object.keys("
1224
+ },
1225
+ {
1226
+ label: "Object.values()",
1227
+ snippet: "Object.values("
1228
+ },
1229
+ {
1230
+ label: "Object.entries()",
1231
+ snippet: "Object.entries("
1232
+ },
1233
+ {
1234
+ label: "Object.assign()",
1235
+ snippet: "Object.assign({}, "
1236
+ },
1237
+ {
1238
+ label: "{ ...obj }",
1239
+ snippet: "{ ..."
1240
+ }
1241
+ ];
1242
+ case "context": return [
1243
+ {
1244
+ label: "TriggerInput.",
1245
+ snippet: "TriggerInput."
1246
+ },
1247
+ {
1248
+ label: "WorkflowState.",
1249
+ snippet: "WorkflowState."
1250
+ },
1251
+ {
1252
+ label: "RunContext.",
1253
+ snippet: "RunContext."
1254
+ },
1255
+ {
1256
+ label: ".output.",
1257
+ snippet: ".output."
1258
+ },
1259
+ {
1260
+ label: ".status",
1261
+ snippet: ".status"
1262
+ }
1263
+ ];
1264
+ default: return [];
1265
+ }
1266
+ };
1267
+ const insertSnippet = (snippet) => {
1268
+ const textarea = document.getElementById("expression-input");
1269
+ if (textarea) {
1270
+ const start = textarea.selectionStart;
1271
+ const end = textarea.selectionEnd;
1272
+ const newValue = expression.slice(0, start) + snippet + expression.slice(end);
1273
+ setExpression(newValue);
1274
+ setTimeout(() => {
1275
+ textarea.focus();
1276
+ textarea.setSelectionRange(start + snippet.length, start + snippet.length);
1277
+ }, 0);
1278
+ } else setExpression(expression + snippet);
1279
+ };
1280
+ if (!open) return null;
1281
+ return createPortal(/* @__PURE__ */ jsx("div", {
1282
+ className: "fixed inset-0 bg-bg-overlay z-[100001] flex items-center justify-center",
1283
+ onClick: () => onOpenChange(false),
1284
+ children: /* @__PURE__ */ jsxs("div", {
1285
+ className: "bg-surface dark:bg-surface z-[100002] flex flex-col w-[700px] max-w-[95vw] max-h-[90vh] rounded-lg overflow-hidden pointer-events-auto shadow-xl",
1286
+ onClick: (e) => e.stopPropagation(),
1287
+ children: [
1288
+ /* @__PURE__ */ jsxs("div", {
1289
+ className: "flex justify-between items-start p-6 border-b",
1290
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
1291
+ className: "text-lg font-semibold",
1292
+ children: getDialogTitle()
1293
+ }), /* @__PURE__ */ jsx("p", {
1294
+ className: "text-sm text-muted-foreground mt-1",
1295
+ children: getDialogDescription()
1296
+ })] }), /* @__PURE__ */ jsx("button", {
1297
+ onClick: () => onOpenChange(false),
1298
+ className: "rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
1299
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
1300
+ })]
1301
+ }),
1302
+ /* @__PURE__ */ jsxs("div", {
1303
+ className: "flex-1 overflow-y-auto p-6",
1304
+ children: [/* @__PURE__ */ jsxs("div", {
1305
+ className: "mb-4 p-3 bg-[var(--color-bg-accent)]/10 rounded-md border border-[var(--color-border-accent)]",
1306
+ children: [/* @__PURE__ */ jsxs(Label, {
1307
+ htmlFor: "target-field-name",
1308
+ className: "text-sm font-medium",
1309
+ children: [
1310
+ tr("fluidgrids.builder.mappingDialog.targetFieldNameLabel", "Target Field Name"),
1311
+ " ",
1312
+ /* @__PURE__ */ jsx("span", {
1313
+ className: "text-muted-foreground",
1314
+ children: tr("fluidgrids.builder.mappingDialog.targetFieldNameHint", "(where the result will be stored)")
1315
+ })
1316
+ ]
1317
+ }), targetFields.length > 0 ? /* @__PURE__ */ jsxs("div", {
1318
+ className: "mt-2 space-y-2",
1319
+ children: [
1320
+ /* @__PURE__ */ jsxs(Select, {
1321
+ value: targetFieldName,
1322
+ onValueChange: setTargetFieldName,
1323
+ children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: tr("fluidgrids.builder.mappingDialog.selectTargetFieldPlaceholder", "Select target field...") }) }), /* @__PURE__ */ jsx(SelectContent, {
1324
+ className: "z-[100003]",
1325
+ children: targetFields.map((field) => /* @__PURE__ */ jsx(SelectItem, {
1326
+ value: field.path,
1327
+ children: /* @__PURE__ */ jsxs("div", {
1328
+ className: "flex items-center gap-2",
1329
+ children: [
1330
+ /* @__PURE__ */ jsx("span", {
1331
+ className: "font-mono",
1332
+ children: field.path
1333
+ }),
1334
+ /* @__PURE__ */ jsx(Badge, {
1335
+ variant: "outline",
1336
+ className: "text-xs",
1337
+ children: field.isList ? `[${field.type}]` : field.type
1338
+ }),
1339
+ field.isNonNull && /* @__PURE__ */ jsx("span", {
1340
+ className: "text-[var(--color-status-error-text)] text-xs",
1341
+ children: "*"
1342
+ })
1343
+ ]
1344
+ })
1345
+ }, field.path))
1346
+ })]
1347
+ }),
1348
+ /* @__PURE__ */ jsx("p", {
1349
+ className: "text-xs text-muted-foreground",
1350
+ children: tr("fluidgrids.builder.mappingDialog.orCustomFieldName", "Or enter a custom field name:")
1351
+ }),
1352
+ /* @__PURE__ */ jsx(Input, {
1353
+ id: "target-field-name",
1354
+ placeholder: tr("fluidgrids.builder.mappingDialog.targetFieldNamePlaceholder", "e.g., messageIds, userNames, totalPrice"),
1355
+ value: targetFieldName,
1356
+ onChange: (e) => setTargetFieldName(e.target.value),
1357
+ className: "font-mono"
1358
+ })
1359
+ ]
1360
+ }) : /* @__PURE__ */ jsx(Input, {
1361
+ id: "target-field-name",
1362
+ placeholder: tr("fluidgrids.builder.mappingDialog.targetFieldNamePlaceholder", "e.g., messageIds, userNames, totalPrice"),
1363
+ value: targetFieldName,
1364
+ onChange: (e) => setTargetFieldName(e.target.value),
1365
+ className: "mt-2"
1366
+ })]
1367
+ }), /* @__PURE__ */ jsxs(Tabs, {
1368
+ value: activeTab,
1369
+ onValueChange: setActiveTab,
1370
+ className: "w-full",
1371
+ children: [
1372
+ /* @__PURE__ */ jsxs(TabsList, {
1373
+ className: "grid w-full grid-cols-4",
1374
+ children: [
1375
+ /* @__PURE__ */ jsx(TabsTrigger, {
1376
+ value: "builder",
1377
+ children: tr("fluidgrids.builder.mappingDialog.tabBuilder", "Builder")
1378
+ }),
1379
+ /* @__PURE__ */ jsx(TabsTrigger, {
1380
+ value: "examples",
1381
+ children: tr("fluidgrids.builder.mappingDialog.tabExamples", "Examples")
1382
+ }),
1383
+ /* @__PURE__ */ jsx(TabsTrigger, {
1384
+ value: "editor",
1385
+ children: tr("fluidgrids.builder.mappingDialog.tabEditor", "Editor")
1386
+ }),
1387
+ /* @__PURE__ */ jsx(TabsTrigger, {
1388
+ value: "help",
1389
+ children: tr("fluidgrids.builder.mappingDialog.tabHelp", "Help")
1390
+ })
1391
+ ]
1392
+ }),
1393
+ /* @__PURE__ */ jsxs(TabsContent, {
1394
+ value: "builder",
1395
+ className: "space-y-4 mt-4",
1396
+ children: [
1397
+ mappingType === "array" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
1398
+ /* @__PURE__ */ jsxs("div", {
1399
+ className: "grid gap-2",
1400
+ children: [/* @__PURE__ */ jsx(Label, { children: tr("fluidgrids.builder.mappingDialog.stepSelectSourceArray", "1. Select Source Array") }), arrayFields.length > 0 ? /* @__PURE__ */ jsxs(Select, {
1401
+ value: selectedSourceArray,
1402
+ onValueChange: handleSourceArrayChange,
1403
+ children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: tr("fluidgrids.builder.mappingDialog.chooseArrayFieldPlaceholder", "Choose an array field...") }) }), /* @__PURE__ */ jsx(SelectContent, {
1404
+ className: "z-[100003]",
1405
+ children: arrayFields.map((field) => /* @__PURE__ */ jsx(SelectItem, {
1406
+ value: field.path,
1407
+ children: /* @__PURE__ */ jsxs("div", {
1408
+ className: "flex items-center gap-2",
1409
+ children: [/* @__PURE__ */ jsx("span", {
1410
+ className: "font-mono",
1411
+ children: field.path
1412
+ }), /* @__PURE__ */ jsxs(Badge, {
1413
+ variant: "outline",
1414
+ className: "text-xs",
1415
+ children: [
1416
+ "[",
1417
+ field.type,
1418
+ "]"
1419
+ ]
1420
+ })]
1421
+ })
1422
+ }, field.path))
1423
+ })]
1424
+ }) : /* @__PURE__ */ jsxs("div", {
1425
+ className: "p-3 border border-default rounded-md bg-muted",
1426
+ children: [/* @__PURE__ */ jsx("p", {
1427
+ className: "text-sm text-muted-foreground",
1428
+ children: tr("fluidgrids.builder.mappingDialog.noArrayFieldsHint", "No array fields found in schema. Enter the array path manually:")
1429
+ }), /* @__PURE__ */ jsx(Input, {
1430
+ placeholder: tr("fluidgrids.builder.mappingDialog.arrayPathPlaceholder", "e.g., searchEmails.emails"),
1431
+ value: selectedSourceArray,
1432
+ onChange: (e) => handleSourceArrayChange(e.target.value),
1433
+ className: "mt-2 font-mono"
1434
+ })]
1435
+ })]
1436
+ }),
1437
+ /* @__PURE__ */ jsxs("div", {
1438
+ className: "grid gap-2",
1439
+ children: [/* @__PURE__ */ jsx(Label, { children: tr("fluidgrids.builder.mappingDialog.stepExtractProperty", "2. Extract Property from Each Item") }), arrayItemFields.length > 0 ? /* @__PURE__ */ jsxs("div", {
1440
+ className: "space-y-2",
1441
+ children: [
1442
+ /* @__PURE__ */ jsx("div", {
1443
+ className: "flex flex-wrap gap-1 max-h-[120px] overflow-y-auto p-1",
1444
+ children: arrayItemFields.map((field) => /* @__PURE__ */ jsxs(Badge, {
1445
+ variant: itemExpression === field.path ? "default" : "outline",
1446
+ className: `cursor-pointer hover:bg-primary hover:text-primary-foreground ${field.isNested ? "ml-2 border-dashed" : ""}`,
1447
+ onClick: () => handleItemExpressionChange(field.path),
1448
+ children: [field.isNested ? /* @__PURE__ */ jsx("span", {
1449
+ className: "font-mono text-xs",
1450
+ children: field.path
1451
+ }) : field.name, /* @__PURE__ */ jsxs("span", {
1452
+ className: "ml-1 opacity-60 text-[10px]",
1453
+ children: [
1454
+ "(",
1455
+ field.type,
1456
+ ")"
1457
+ ]
1458
+ })]
1459
+ }, field.path))
1460
+ }),
1461
+ /* @__PURE__ */ jsx("p", {
1462
+ className: "text-xs text-muted-foreground",
1463
+ children: tr("fluidgrids.builder.mappingDialog.clickFieldOrCustomPath", "Click a field above or enter a custom path:")
1464
+ }),
1465
+ /* @__PURE__ */ jsx(Input, {
1466
+ placeholder: tr("fluidgrids.builder.mappingDialog.itemPropertyPlaceholder", "e.g., metadata.id, user.email"),
1467
+ value: itemExpression,
1468
+ onChange: (e) => handleItemExpressionChange(e.target.value),
1469
+ className: "font-mono"
1470
+ })
1471
+ ]
1472
+ }) : /* @__PURE__ */ jsx(Input, {
1473
+ placeholder: tr("fluidgrids.builder.mappingDialog.itemPropertyPlaceholderShort", "e.g., metadata.id, user.email, id"),
1474
+ value: itemExpression,
1475
+ onChange: (e) => handleItemExpressionChange(e.target.value),
1476
+ className: "font-mono"
1477
+ })]
1478
+ }),
1479
+ /* @__PURE__ */ jsxs("div", {
1480
+ className: "grid gap-2",
1481
+ children: [/* @__PURE__ */ jsx(Label, { children: tr("fluidgrids.builder.mappingDialog.stepGeneratedExpression", "3. Generated Expression") }), /* @__PURE__ */ jsx("div", {
1482
+ className: "p-3 bg-muted rounded-md border border-default",
1483
+ children: /* @__PURE__ */ jsx("code", {
1484
+ className: "text-sm break-all block font-mono",
1485
+ children: expression || "${output.arrayField.map(item => item.property)}"
1486
+ })
1487
+ })]
1488
+ }),
1489
+ selectedSourceArray && itemExpression && /* @__PURE__ */ jsxs("div", {
1490
+ className: "p-3 bg-[var(--color-status-success-bg-subtle)] rounded-md border border-[var(--color-status-success-border)]",
1491
+ children: [/* @__PURE__ */ jsx(Label, {
1492
+ className: "text-[var(--color-status-success-text)]",
1493
+ children: tr("fluidgrids.builder.mappingDialog.resultPreview", "Result Preview:")
1494
+ }), /* @__PURE__ */ jsxs("div", {
1495
+ className: "mt-2 flex items-center gap-2 text-sm",
1496
+ children: [
1497
+ /* @__PURE__ */ jsx("code", {
1498
+ className: "bg-surface px-2 py-1 rounded",
1499
+ children: targetFieldName || "result"
1500
+ }),
1501
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 text-muted-foreground" }),
1502
+ /* @__PURE__ */ jsxs("code", {
1503
+ className: "bg-surface px-2 py-1 rounded",
1504
+ children: [
1505
+ "[",
1506
+ itemExpression,
1507
+ ", ",
1508
+ itemExpression,
1509
+ ", ...]"
1510
+ ]
1511
+ })
1512
+ ]
1513
+ })]
1514
+ })
1515
+ ] }),
1516
+ mappingType !== "array" && /* @__PURE__ */ jsx("div", {
1517
+ className: "p-4 bg-muted rounded-md",
1518
+ children: /* @__PURE__ */ jsxs("p", {
1519
+ className: "text-sm text-muted-foreground",
1520
+ children: [
1521
+ "The guided builder is optimized for ",
1522
+ /* @__PURE__ */ jsx("strong", { children: "Array" }),
1523
+ " ",
1524
+ "mappings. For ",
1525
+ mappingType,
1526
+ " mappings, use the",
1527
+ " ",
1528
+ /* @__PURE__ */ jsx("strong", { children: "Examples" }),
1529
+ " or ",
1530
+ /* @__PURE__ */ jsx("strong", { children: "Editor" }),
1531
+ " tabs."
1532
+ ]
1533
+ })
1534
+ }),
1535
+ sourceFields.length > 0 && /* @__PURE__ */ jsxs("div", {
1536
+ className: "grid gap-2",
1537
+ children: [/* @__PURE__ */ jsx(Label, { children: tr("fluidgrids.builder.mappingDialog.availableSourceFields", "Available Source Fields") }), /* @__PURE__ */ jsx("div", {
1538
+ className: "p-3 border rounded-md max-h-[150px] overflow-y-auto bg-muted/50",
1539
+ children: /* @__PURE__ */ jsxs("div", {
1540
+ className: "space-y-1",
1541
+ children: [sourceFields.slice(0, 15).map((field) => /* @__PURE__ */ jsxs("div", {
1542
+ className: "flex items-center gap-2 text-xs",
1543
+ children: [/* @__PURE__ */ jsx("code", {
1544
+ className: "font-mono",
1545
+ children: field.path
1546
+ }), /* @__PURE__ */ jsx(Badge, {
1547
+ variant: "outline",
1548
+ className: "text-[10px]",
1549
+ children: field.isList ? `[${field.type}]` : field.type
1550
+ })]
1551
+ }, field.path)), sourceFields.length > 15 && /* @__PURE__ */ jsxs("p", {
1552
+ className: "text-xs text-muted-foreground mt-2",
1553
+ children: [
1554
+ "...and ",
1555
+ sourceFields.length - 15,
1556
+ " more fields"
1557
+ ]
1558
+ })]
1559
+ })
1560
+ })]
1561
+ })
1562
+ ]
1563
+ }),
1564
+ /* @__PURE__ */ jsxs(TabsContent, {
1565
+ value: "examples",
1566
+ className: "space-y-4 mt-4",
1567
+ children: [examples.length > 0 && /* @__PURE__ */ jsxs("div", {
1568
+ className: "grid gap-2",
1569
+ children: [/* @__PURE__ */ jsx(Label, { children: tr("fluidgrids.builder.mappingDialog.selectExampleLabel", "Select an example to start with:") }), /* @__PURE__ */ jsxs(Select, {
1570
+ value: selectedExample,
1571
+ onValueChange: handleExampleChange,
1572
+ children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: tr("fluidgrids.builder.mappingDialog.chooseExamplePlaceholder", "Choose an example") }) }), /* @__PURE__ */ jsxs(SelectContent, {
1573
+ className: "z-[100003]",
1574
+ children: [/* @__PURE__ */ jsx(SelectItem, {
1575
+ value: "choose",
1576
+ children: tr("fluidgrids.builder.mappingDialog.chooseExamplePlaceholder", "Choose an example")
1577
+ }), examples.map((example) => /* @__PURE__ */ jsxs(SelectItem, {
1578
+ value: example.name,
1579
+ children: [
1580
+ example.name,
1581
+ " - ",
1582
+ example.description
1583
+ ]
1584
+ }, example.name))]
1585
+ })]
1586
+ })]
1587
+ }), /* @__PURE__ */ jsxs("div", {
1588
+ className: "grid gap-2",
1589
+ children: [/* @__PURE__ */ jsx(Label, { children: tr("fluidgrids.builder.mappingDialog.quickExamples", "Quick Examples:") }), /* @__PURE__ */ jsx("div", {
1590
+ className: "grid grid-cols-1 gap-2 max-h-[200px] overflow-y-auto",
1591
+ children: examples.slice(0, 8).map((example) => /* @__PURE__ */ jsxs("div", {
1592
+ className: "p-2 border rounded-md cursor-pointer hover:bg-muted transition-colors",
1593
+ onClick: () => {
1594
+ setExpression(example.expression);
1595
+ setActiveTab("editor");
1596
+ },
1597
+ children: [/* @__PURE__ */ jsx("div", {
1598
+ className: "font-medium text-sm",
1599
+ children: example.name
1600
+ }), /* @__PURE__ */ jsx("code", {
1601
+ className: "text-xs text-muted-foreground block mt-1 break-all",
1602
+ children: example.expression
1603
+ })]
1604
+ }, example.name))
1605
+ })]
1606
+ })]
1607
+ }),
1608
+ /* @__PURE__ */ jsxs(TabsContent, {
1609
+ value: "editor",
1610
+ className: "space-y-4 mt-4",
1611
+ children: [
1612
+ /* @__PURE__ */ jsxs("div", {
1613
+ className: "grid gap-2",
1614
+ children: [/* @__PURE__ */ jsx(Label, { children: tr("fluidgrids.builder.mappingDialog.quickInsert", "Quick Insert:") }), /* @__PURE__ */ jsx("div", {
1615
+ className: "flex flex-wrap gap-1",
1616
+ children: getQuickInserts().map((item) => /* @__PURE__ */ jsx(Badge, {
1617
+ variant: "secondary",
1618
+ className: "cursor-pointer hover:bg-primary hover:text-primary-foreground",
1619
+ onClick: () => insertSnippet(item.snippet),
1620
+ children: item.label
1621
+ }, item.label))
1622
+ })]
1623
+ }),
1624
+ /* @__PURE__ */ jsxs("div", {
1625
+ className: "grid gap-2",
1626
+ children: [
1627
+ /* @__PURE__ */ jsx(Label, {
1628
+ htmlFor: "expression-input",
1629
+ children: tr("fluidgrids.builder.mappingDialog.templateExpression", "Template Expression")
1630
+ }),
1631
+ /* @__PURE__ */ jsx(Textarea, {
1632
+ id: "expression-input",
1633
+ placeholder: getPlaceholder(),
1634
+ value: expression,
1635
+ onChange: (e) => setExpression(e.target.value),
1636
+ className: "h-32 font-mono text-sm"
1637
+ }),
1638
+ /* @__PURE__ */ jsxs("p", {
1639
+ className: "text-xs text-muted-foreground",
1640
+ children: [
1641
+ tr("fluidgrids.builder.mappingDialog.templateSyntaxHint", "Use JavaScript template literal syntax:"),
1642
+ " ",
1643
+ /* @__PURE__ */ jsxs("code", {
1644
+ className: "bg-muted px-1 rounded",
1645
+ children: [
1646
+ "$",
1647
+ "{",
1648
+ "expression",
1649
+ "}"
1650
+ ]
1651
+ })
1652
+ ]
1653
+ })
1654
+ ]
1655
+ }),
1656
+ (sourceField || targetField) && /* @__PURE__ */ jsxs("div", {
1657
+ className: "p-3 bg-muted rounded-md",
1658
+ children: [/* @__PURE__ */ jsx("h4", {
1659
+ className: "text-sm font-medium mb-2",
1660
+ children: tr("fluidgrids.builder.mappingDialog.mappingContext", "Mapping Context")
1661
+ }), /* @__PURE__ */ jsxs("div", {
1662
+ className: "text-xs space-y-1",
1663
+ children: [sourceField && /* @__PURE__ */ jsxs("div", { children: [
1664
+ /* @__PURE__ */ jsx("span", {
1665
+ className: "text-muted-foreground",
1666
+ children: tr("fluidgrids.builder.mappingDialog.sourceFieldLabel", "Source field:")
1667
+ }),
1668
+ " ",
1669
+ /* @__PURE__ */ jsx("code", {
1670
+ className: "bg-background px-1 rounded",
1671
+ children: sourceField
1672
+ })
1673
+ ] }), targetField && /* @__PURE__ */ jsxs("div", { children: [
1674
+ /* @__PURE__ */ jsx("span", {
1675
+ className: "text-muted-foreground",
1676
+ children: tr("fluidgrids.builder.mappingDialog.targetFieldLabel", "Target field:")
1677
+ }),
1678
+ " ",
1679
+ /* @__PURE__ */ jsx("code", {
1680
+ className: "bg-background px-1 rounded",
1681
+ children: targetField
1682
+ })
1683
+ ] })]
1684
+ })]
1685
+ }),
1686
+ /* @__PURE__ */ jsxs("div", {
1687
+ className: "p-3 bg-muted rounded-md",
1688
+ children: [/* @__PURE__ */ jsx("h4", {
1689
+ className: "text-sm font-medium mb-2",
1690
+ children: tr("fluidgrids.builder.mappingDialog.mappingValue", "Mapping Value")
1691
+ }), /* @__PURE__ */ jsx("code", {
1692
+ className: "text-xs break-all block",
1693
+ children: expression || tr("fluidgrids.builder.mappingDialog.emptyExpression", "(empty)")
1694
+ })]
1695
+ })
1696
+ ]
1697
+ }),
1698
+ /* @__PURE__ */ jsxs(TabsContent, {
1699
+ value: "help",
1700
+ className: "space-y-4 mt-4",
1701
+ children: [
1702
+ /* @__PURE__ */ jsxs("div", {
1703
+ className: "p-3 bg-muted rounded-md",
1704
+ children: [/* @__PURE__ */ jsx("h4", {
1705
+ className: "text-sm font-medium mb-2",
1706
+ children: tr("fluidgrids.builder.mappingDialog.availableVariables", "Available Variables")
1707
+ }), /* @__PURE__ */ jsxs("div", {
1708
+ className: "text-xs space-y-2",
1709
+ children: [
1710
+ /* @__PURE__ */ jsxs("div", { children: [
1711
+ /* @__PURE__ */ jsx("code", {
1712
+ className: "bg-background px-1 rounded",
1713
+ children: "output"
1714
+ }),
1715
+ " -",
1716
+ " ",
1717
+ tr("fluidgrids.builder.mappingDialog.varOutput", "Output from the previous node")
1718
+ ] }),
1719
+ /* @__PURE__ */ jsxs("div", { children: [
1720
+ /* @__PURE__ */ jsx("code", {
1721
+ className: "bg-background px-1 rounded",
1722
+ children: "TriggerInput"
1723
+ }),
1724
+ " ",
1725
+ "-",
1726
+ " ",
1727
+ tr("fluidgrids.builder.mappingDialog.varTriggerInput", "Original trigger payload")
1728
+ ] }),
1729
+ /* @__PURE__ */ jsxs("div", { children: [
1730
+ /* @__PURE__ */ jsx("code", {
1731
+ className: "bg-background px-1 rounded",
1732
+ children: "WorkflowState"
1733
+ }),
1734
+ " ",
1735
+ "-",
1736
+ " ",
1737
+ tr("fluidgrids.builder.mappingDialog.varWorkflowState", "Outputs from all previous nodes")
1738
+ ] }),
1739
+ /* @__PURE__ */ jsxs("div", { children: [
1740
+ /* @__PURE__ */ jsx("code", {
1741
+ className: "bg-background px-1 rounded",
1742
+ children: "RunContext"
1743
+ }),
1744
+ " ",
1745
+ "-",
1746
+ " ",
1747
+ tr("fluidgrids.builder.mappingDialog.varRunContext", "Workflow execution metadata")
1748
+ ] }),
1749
+ /* @__PURE__ */ jsxs("div", { children: [
1750
+ /* @__PURE__ */ jsx("code", {
1751
+ className: "bg-background px-1 rounded",
1752
+ children: "item"
1753
+ }),
1754
+ " -",
1755
+ " ",
1756
+ tr("fluidgrids.builder.mappingDialog.varItem", "Current item (in array operations)")
1757
+ ] }),
1758
+ /* @__PURE__ */ jsxs("div", { children: [
1759
+ /* @__PURE__ */ jsx("code", {
1760
+ className: "bg-background px-1 rounded",
1761
+ children: "index"
1762
+ }),
1763
+ " -",
1764
+ " ",
1765
+ tr("fluidgrids.builder.mappingDialog.varIndex", "Current index (in array operations)")
1766
+ ] })
1767
+ ]
1768
+ })]
1769
+ }),
1770
+ safeBuiltins.length > 0 && /* @__PURE__ */ jsxs("div", {
1771
+ className: "p-3 bg-muted rounded-md",
1772
+ children: [/* @__PURE__ */ jsx("h4", {
1773
+ className: "text-sm font-medium mb-2",
1774
+ children: tr("fluidgrids.builder.mappingDialog.availableFunctions", "Available Functions")
1775
+ }), /* @__PURE__ */ jsx("div", {
1776
+ className: "text-xs grid grid-cols-3 gap-1",
1777
+ children: safeBuiltins.map((func) => /* @__PURE__ */ jsx("code", {
1778
+ className: "bg-background px-1 rounded",
1779
+ children: func
1780
+ }, func))
1781
+ })]
1782
+ }),
1783
+ /* @__PURE__ */ jsxs("div", {
1784
+ className: "p-3 bg-muted rounded-md",
1785
+ children: [/* @__PURE__ */ jsx("h4", {
1786
+ className: "text-sm font-medium mb-2",
1787
+ children: tr("fluidgrids.builder.mappingDialog.syntaxTips", "Syntax Tips")
1788
+ }), /* @__PURE__ */ jsxs("div", {
1789
+ className: "text-xs space-y-1",
1790
+ children: [
1791
+ /* @__PURE__ */ jsxs("div", { children: [
1792
+ /* @__PURE__ */ jsx("strong", { children: tr("fluidgrids.builder.mappingDialog.tipOptionalChaining", "Optional chaining:") }),
1793
+ " ",
1794
+ /* @__PURE__ */ jsx("code", {
1795
+ className: "bg-background px-1 rounded",
1796
+ children: "output.user?.email"
1797
+ })
1798
+ ] }),
1799
+ /* @__PURE__ */ jsxs("div", { children: [
1800
+ /* @__PURE__ */ jsx("strong", { children: tr("fluidgrids.builder.mappingDialog.tipNullishCoalescing", "Nullish coalescing:") }),
1801
+ " ",
1802
+ /* @__PURE__ */ jsx("code", {
1803
+ className: "bg-background px-1 rounded",
1804
+ children: `output.value ?? 'default'`
1805
+ })
1806
+ ] }),
1807
+ /* @__PURE__ */ jsxs("div", { children: [
1808
+ /* @__PURE__ */ jsx("strong", { children: tr("fluidgrids.builder.mappingDialog.tipTernary", "Ternary:") }),
1809
+ " ",
1810
+ /* @__PURE__ */ jsx("code", {
1811
+ className: "bg-background px-1 rounded",
1812
+ children: `output.active ? 'Yes' : 'No'`
1813
+ })
1814
+ ] }),
1815
+ /* @__PURE__ */ jsxs("div", { children: [
1816
+ /* @__PURE__ */ jsx("strong", { children: tr("fluidgrids.builder.mappingDialog.tipArrayAccess", "Array access:") }),
1817
+ " ",
1818
+ /* @__PURE__ */ jsx("code", {
1819
+ className: "bg-background px-1 rounded",
1820
+ children: "output.items[0].name"
1821
+ })
1822
+ ] })
1823
+ ]
1824
+ })]
1825
+ })
1826
+ ]
1827
+ })
1828
+ ]
1829
+ })]
1830
+ }),
1831
+ /* @__PURE__ */ jsxs("div", {
1832
+ className: "p-6 border-t",
1833
+ children: [!isFormValid && /* @__PURE__ */ jsx("div", {
1834
+ className: "mb-3 p-2 bg-[var(--color-status-warning-bg-subtle)] border border-[var(--color-status-warning-border)] rounded-md",
1835
+ children: /* @__PURE__ */ jsx("p", {
1836
+ className: "text-sm text-[var(--color-status-warning-text)]",
1837
+ children: getValidationMessage()
1838
+ })
1839
+ }), /* @__PURE__ */ jsxs("div", {
1840
+ className: "flex justify-between items-center",
1841
+ children: [/* @__PURE__ */ jsx("div", {
1842
+ className: "text-xs text-muted-foreground",
1843
+ children: targetFieldName && expression && /* @__PURE__ */ jsxs("code", {
1844
+ className: "bg-muted px-2 py-1 rounded",
1845
+ children: [
1846
+ targetFieldName,
1847
+ ":",
1848
+ " ",
1849
+ expression.length > 40 ? expression.substring(0, 40) + "..." : expression
1850
+ ]
1851
+ })
1852
+ }), /* @__PURE__ */ jsxs("div", {
1853
+ className: "flex gap-2",
1854
+ children: [/* @__PURE__ */ jsx(Button, {
1855
+ variant: "outline",
1856
+ onClick: () => onOpenChange(false),
1857
+ children: tr("fluidgrids.builder.mappingDialog.cancel", "Cancel")
1858
+ }), /* @__PURE__ */ jsx(Button, {
1859
+ onClick: handleSave,
1860
+ disabled: !isFormValid,
1861
+ children: tr("fluidgrids.builder.mappingDialog.applyMapping", "Apply Mapping")
1862
+ })]
1863
+ })]
1864
+ })]
1865
+ })
1866
+ ]
1867
+ })
1868
+ }), document.body);
1869
+ }
1870
+
1871
+ // src/builder/components/lib/mapping-utils.ts
1872
+ const DEFAULT_CONFIG = {
1873
+ timeout: 5e3,
1874
+ maxTemplateLength: 1e4,
1875
+ debug: false
1876
+ };
1877
+ /**
1878
+ * Safe built-ins available in the sandbox
1879
+ */
1880
+ const SAFE_GLOBALS = {
1881
+ parseInt,
1882
+ parseFloat,
1883
+ isNaN,
1884
+ isFinite,
1885
+ Number,
1886
+ String,
1887
+ Boolean,
1888
+ JSON: {
1889
+ parse: JSON.parse,
1890
+ stringify: JSON.stringify
1891
+ },
1892
+ Date,
1893
+ Math,
1894
+ Array,
1895
+ Object,
1896
+ console: {
1897
+ log: (..._args) => {},
1898
+ error: (...args) => console.error("[Mapper]", ...args),
1899
+ warn: (...args) => console.warn("[Mapper]", ...args)
1900
+ }
1901
+ };
1902
+ /**
1903
+ * Parse a template string to extract the expression
1904
+ * Template literals must be in the format: ${expression}
1905
+ */
1906
+ function parseTemplate(template) {
1907
+ if (typeof template !== "string") return {
1908
+ isTemplate: false,
1909
+ expression: null,
1910
+ error: null
1911
+ };
1912
+ const match = template.match(/^\$\{(.+)\}$/s);
1913
+ if (!match) return {
1914
+ isTemplate: false,
1915
+ expression: null,
1916
+ error: null
1917
+ };
1918
+ const expression = match[1].trim();
1919
+ if (!expression) return {
1920
+ isTemplate: true,
1921
+ expression: null,
1922
+ error: "Empty template expression"
1923
+ };
1924
+ return {
1925
+ isTemplate: true,
1926
+ expression,
1927
+ error: null
1928
+ };
1929
+ }
1930
+ /**
1931
+ * Build the sandbox with safe globals and scope variables
1932
+ */
1933
+ function buildSandbox(scope) {
1934
+ return {
1935
+ ...SAFE_GLOBALS,
1936
+ output: scope.output,
1937
+ TriggerInput: scope.TriggerInput,
1938
+ WorkflowState: scope.WorkflowState,
1939
+ RunContext: scope.RunContext,
1940
+ item: scope.item,
1941
+ index: scope.index
1942
+ };
1943
+ }
1944
+ /**
1945
+ * Evaluate a JavaScript expression in a sandboxed environment
1946
+ */
1947
+ async function evaluateExpression(expression, scope, config = DEFAULT_CONFIG) {
1948
+ const sandbox = buildSandbox(scope);
1949
+ const paramNames = Object.keys(sandbox);
1950
+ const paramValues = Object.values(sandbox);
1951
+ try {
1952
+ const fn = new Function(...paramNames, `"use strict"; return (${expression});`);
1953
+ const timeoutPromise = new Promise((_, reject) => {
1954
+ setTimeout(() => reject(/* @__PURE__ */ new Error("Execution timeout exceeded")), config.timeout || DEFAULT_CONFIG.timeout);
1955
+ });
1956
+ const resultPromise = Promise.resolve(fn(...paramValues));
1957
+ return await Promise.race([resultPromise, timeoutPromise]);
1958
+ } catch (error) {
1959
+ if (config.debug) console.error("[Mapper] Expression evaluation error:", error);
1960
+ throw error;
1961
+ }
1962
+ }
1963
+ /**
1964
+ * Map a definition object using template literals
1965
+ * This is the main entry point for applying mappings
1966
+ */
1967
+ async function mapDefinition(definition, scope, config = DEFAULT_CONFIG) {
1968
+ if (definition === null || definition === void 0) return definition;
1969
+ if (typeof definition !== "object" && typeof definition !== "string") return definition;
1970
+ if (typeof definition === "string") {
1971
+ const parseResult = parseTemplate(definition);
1972
+ if (!parseResult.isTemplate) return definition;
1973
+ if (parseResult.error) throw new Error(parseResult.error);
1974
+ return evaluateExpression(parseResult.expression, scope, config);
1975
+ }
1976
+ if (Array.isArray(definition)) return await Promise.all(definition.map((item) => mapDefinition(item, scope, config)));
1977
+ const result = {};
1978
+ for (const key of Object.keys(definition)) result[key] = await mapDefinition(definition[key], scope, config);
1979
+ return result;
1980
+ }
1981
+ /**
1982
+ * Validate a mapping definition for syntax errors
1983
+ * Returns an array of error messages
1984
+ */
1985
+ function validateMapping(definition, path = "root") {
1986
+ const errors = [];
1987
+ if (definition === null || definition === void 0) return errors;
1988
+ if (typeof definition === "string") {
1989
+ const parseResult = parseTemplate(definition);
1990
+ if (parseResult.isTemplate && parseResult.error) errors.push(`${path}: ${parseResult.error}`);
1991
+ return errors;
1992
+ }
1993
+ if (Array.isArray(definition)) {
1994
+ definition.forEach((item, index) => {
1995
+ errors.push(...validateMapping(item, `${path}[${index}]`));
1996
+ });
1997
+ return errors;
1998
+ }
1999
+ if (typeof definition === "object") for (const key of Object.keys(definition)) errors.push(...validateMapping(definition[key], `${path}.${key}`));
2000
+ return errors;
2001
+ }
2002
+ /**
2003
+ * Generate default mapping between source and target schemas
2004
+ */
2005
+ function generateDefaultMapping(sourceSchema, sourceNode, sourceOperation, targetSchema, targetNode, targetOperation) {
2006
+ const mapping = {};
2007
+ const sourceReturnTypeName = getReturnTypeForOperation(sourceNode, sourceOperation);
2008
+ let sourceOutputType = null;
2009
+ if (sourceReturnTypeName) sourceOutputType = sourceSchema.types[sourceReturnTypeName];
2010
+ else {
2011
+ let sourceOperationField = null;
2012
+ if (sourceSchema.queryType && sourceSchema.types[sourceSchema.queryType]?.fields[sourceOperation]) sourceOperationField = sourceSchema.types[sourceSchema.queryType].fields[sourceOperation];
2013
+ else if (sourceSchema.mutationType && sourceSchema.types[sourceSchema.mutationType]?.fields[sourceOperation]) sourceOperationField = sourceSchema.types[sourceSchema.mutationType].fields[sourceOperation];
2014
+ if (sourceOperationField) {
2015
+ const sourceOutputTypeName = sourceOperationField.type;
2016
+ sourceOutputType = sourceSchema.types[sourceOutputTypeName];
2017
+ }
2018
+ }
2019
+ const targetInputTypeName = getInputTypeForOperation(targetNode, targetOperation);
2020
+ const targetInputType = targetInputTypeName ? targetSchema.types[targetInputTypeName] : null;
2021
+ if (!sourceOutputType || !targetInputType) return mapping;
2022
+ const sourceFields = sourceOutputType.fields || {};
2023
+ const targetFields = targetInputType.inputFields || targetInputType.fields || {};
2024
+ const addMapping = (path, sourcePath) => {
2025
+ const templateValue = `\${output.${sourcePath}}`;
2026
+ if (path.includes(".")) {
2027
+ const pathParts = path.split(".");
2028
+ let currentObj = mapping;
2029
+ for (let i = 0; i < pathParts.length - 1; i++) {
2030
+ const part = pathParts[i];
2031
+ if (!currentObj[part]) currentObj[part] = {};
2032
+ currentObj = currentObj[part];
2033
+ }
2034
+ currentObj[pathParts[pathParts.length - 1]] = templateValue;
2035
+ } else mapping[path] = templateValue;
2036
+ };
2037
+ const processFields = (fields, parentPath = "") => {
2038
+ for (const fieldName in fields) {
2039
+ const field = fields[fieldName];
2040
+ const fullPath = parentPath ? `${parentPath}.${fieldName}` : fieldName;
2041
+ if (field.type && targetSchema.types[field.type] && (targetSchema.types[field.type].kind === "type" || targetSchema.types[field.type].kind === "input")) {
2042
+ const nestedFields = targetSchema.types[field.type].fields || targetSchema.types[field.type].inputFields || {};
2043
+ processFields(nestedFields, fullPath);
2044
+ } else {
2045
+ if (sourceFields[fieldName]) {
2046
+ addMapping(fullPath, fieldName);
2047
+ continue;
2048
+ }
2049
+ const lowerTargetField = fieldName.toLowerCase();
2050
+ for (const sourceFieldName in sourceFields) if (sourceFieldName.toLowerCase() === lowerTargetField) {
2051
+ addMapping(fullPath, sourceFieldName);
2052
+ break;
2053
+ }
2054
+ }
2055
+ }
2056
+ };
2057
+ processFields(targetFields);
2058
+ return mapping;
2059
+ }
2060
+ /**
2061
+ * Apply a mapping to input data using the new template literal syntax
2062
+ * This is used for preview/testing in the UI
2063
+ */
2064
+ async function applyMapping(mapping, inputData, config = DEFAULT_CONFIG) {
2065
+ return await mapDefinition(mapping, {
2066
+ output: inputData,
2067
+ TriggerInput: {},
2068
+ WorkflowState: {},
2069
+ RunContext: {
2070
+ runId: "preview-run",
2071
+ workflowKey: "preview-workflow",
2072
+ version: "1.0.0",
2073
+ tenantId: "preview-tenant",
2074
+ workspaceId: "preview-workspace",
2075
+ triggeredAt: (/* @__PURE__ */ new Date()).toISOString()
2076
+ }
2077
+ }, config);
2078
+ }
2079
+
2080
+ // src/builder/components/mapper/visual-mapper.tsx
2081
+ const nodeTypes = {
2082
+ schemaNode: SchemaNode,
2083
+ nodeGroup: NodeGroup
2084
+ };
2085
+ const edgeTypes = { mappingEdge: MappingEdge };
2086
+ function isSchemaNodeData(data) {
2087
+ return data !== null && typeof data === "object" && "path" in data && "type" in data && "side" in data;
2088
+ }
2089
+ /**
2090
+ * Detect the mapping type from a template literal expression
2091
+ */
2092
+ function detectMappingType(value) {
2093
+ if (typeof value !== "string") return "direct";
2094
+ const parseResult = parseTemplate(value);
2095
+ if (!parseResult.isTemplate) return "direct";
2096
+ const expr = parseResult.expression || "";
2097
+ if (expr.includes(".map(") || expr.includes(".filter(") || expr.includes(".reduce(") || expr.includes(".find(") || expr.includes(".some(") || expr.includes(".every(") || expr.includes(".flat(") || expr.includes(".flatMap(") || expr.includes(".sort(")) return "array";
2098
+ if (expr.includes("Object.keys(") || expr.includes("Object.values(") || expr.includes("Object.entries(") || expr.includes("Object.assign(") || expr.includes("Object.fromEntries(") || expr.startsWith("({") || expr.startsWith("{ ...")) return "object";
2099
+ if (expr.startsWith("parseInt(") || expr.startsWith("parseFloat(") || expr.startsWith("String(") || expr.startsWith("Boolean(") || expr.startsWith("Number(")) return "cast";
2100
+ if (expr.includes("TriggerInput.") || expr.includes("WorkflowState.") || expr.includes("RunContext.")) return "context";
2101
+ if (expr.includes(".toUpperCase()") || expr.includes(".toLowerCase()") || expr.includes(".trim()") || expr.includes(".split(") || expr.includes(".join(") || expr.includes(".replace(") || expr.includes(".substring(") || expr.includes(".slice(")) return "transform";
2102
+ if (expr.includes(" + ") || expr.includes(" - ") || expr.includes(" * ") || expr.includes(" / ") || expr.includes(" ? ") || expr.includes(" && ") || expr.includes(" || ") || expr.includes(" ?? ") || expr.includes("Math.")) return "expression";
2103
+ return "direct";
2104
+ }
2105
+ function VisualMapperContent({ sourceSchema, targetSchema, sourceNode, sourceOperation, targetNode, targetOperation, mapping, onMappingChange }) {
2106
+ const { toast } = useToast();
2107
+ const tr = useTr();
2108
+ const reactFlowWrapper = useRef(null);
2109
+ const [selectedSourceNode, setSelectedSourceNode] = useState(null);
2110
+ const [selectedTargetNode, setSelectedTargetNode] = useState(null);
2111
+ const [mappingDialogOpen, setMappingDialogOpen] = useState(false);
2112
+ const [currentMappingType, setCurrentMappingType] = useState("expression");
2113
+ const [nodes, setNodes, onNodesChange] = useNodesState([]);
2114
+ const [edges, setEdges, onEdgesChange] = useEdgesState([]);
2115
+ useEffect(() => {
2116
+ if (sourceSchema && targetSchema && sourceNode && sourceOperation && targetNode && targetOperation) {
2117
+ const { nodes: generatedNodes } = generateSchemaNodes(sourceSchema, sourceNode, sourceOperation, targetSchema, targetNode, targetOperation);
2118
+ if (generatedNodes.length === 0) toast({
2119
+ title: tr("fluidgrids.builder.visualMapper.noFieldsFoundTitle", "No fields found"),
2120
+ description: tr("fluidgrids.builder.visualMapper.noFieldsFoundDescription", "Could not find fields to map between these nodes and operations."),
2121
+ variant: "destructive"
2122
+ });
2123
+ else {
2124
+ setNodes(generatedNodes);
2125
+ setTimeout(() => {
2126
+ document.querySelector(".react-flow__controls-fitview")?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
2127
+ }, 100);
2128
+ }
2129
+ }
2130
+ }, [
2131
+ sourceSchema,
2132
+ targetSchema,
2133
+ sourceNode,
2134
+ sourceOperation,
2135
+ targetNode,
2136
+ targetOperation,
2137
+ setNodes,
2138
+ toast,
2139
+ tr
2140
+ ]);
2141
+ useEffect(() => {
2142
+ const newEdges = [];
2143
+ const processMapping = (obj, parentPath = "") => {
2144
+ for (const key in obj) {
2145
+ const value = obj[key];
2146
+ const currentPath = parentPath ? `${parentPath}.${key}` : key;
2147
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) processMapping(value, currentPath);
2148
+ else if (typeof value === "string") {
2149
+ const parseResult = parseTemplate(value);
2150
+ const mappingType = detectMappingType(value);
2151
+ const targetNodeObj = nodes.find((n) => isSchemaNodeData(n.data) && n.data.path === currentPath && n.data.side === "target");
2152
+ if (targetNodeObj && isSchemaNodeData(targetNodeObj.data)) {
2153
+ if (parseResult.isTemplate) {
2154
+ const simpleFieldMatch = (parseResult.expression || "").match(/^output\.([a-zA-Z0-9_.]+)$/);
2155
+ if (simpleFieldMatch && mappingType === "direct") {
2156
+ const sourcePath = simpleFieldMatch[1];
2157
+ const sourceNodeObj = nodes.find((n) => isSchemaNodeData(n.data) && n.data.path === sourcePath && n.data.side === "source");
2158
+ if (sourceNodeObj && isSchemaNodeData(sourceNodeObj.data)) {
2159
+ const isCompatible = areTypesCompatible(sourceNodeObj.data.type, targetNodeObj.data.type);
2160
+ newEdges.push({
2161
+ id: `${sourceNodeObj.id}-${targetNodeObj.id}`,
2162
+ source: sourceNodeObj.id,
2163
+ target: targetNodeObj.id,
2164
+ type: "mappingEdge",
2165
+ animated: true,
2166
+ data: {
2167
+ mappingType: "direct",
2168
+ isCompatible,
2169
+ color: compatibilityColor(isCompatible)
2170
+ }
2171
+ });
2172
+ continue;
2173
+ }
2174
+ }
2175
+ newEdges.push({
2176
+ id: `mapping-${currentPath}`,
2177
+ source: "virtual-source",
2178
+ target: targetNodeObj.id,
2179
+ type: "mappingEdge",
2180
+ animated: true,
2181
+ data: {
2182
+ mappingType,
2183
+ expression: value,
2184
+ color: mappingTypeColor(mappingType)
2185
+ }
2186
+ });
2187
+ }
2188
+ }
2189
+ }
2190
+ }
2191
+ };
2192
+ processMapping(mapping);
2193
+ setEdges(newEdges);
2194
+ }, [
2195
+ mapping,
2196
+ nodes,
2197
+ setEdges
2198
+ ]);
2199
+ const onConnect = useCallback((connection) => {
2200
+ const sourceNodeObj = nodes.find((n) => n.id === connection.source);
2201
+ const targetNodeObj = nodes.find((n) => n.id === connection.target);
2202
+ if (sourceNodeObj && targetNodeObj && isSchemaNodeData(sourceNodeObj.data) && isSchemaNodeData(targetNodeObj.data) && sourceNodeObj.data.side === "source" && targetNodeObj.data.side === "target") {
2203
+ const sourceType = sourceNodeObj.data.type;
2204
+ const targetType = targetNodeObj.data.type;
2205
+ const isCompatible = areTypesCompatible(sourceType, targetType);
2206
+ const newEdge = {
2207
+ ...connection,
2208
+ type: "mappingEdge",
2209
+ animated: true,
2210
+ data: {
2211
+ mappingType: "direct",
2212
+ isCompatible,
2213
+ color: compatibilityColor(isCompatible)
2214
+ }
2215
+ };
2216
+ setEdges((eds) => addEdge(newEdge, eds));
2217
+ const updatedMapping = { ...mapping };
2218
+ const sourcePath = sourceNodeObj.data.path;
2219
+ const targetPath = targetNodeObj.data.path;
2220
+ const templateValue = `\${output.${sourcePath}}`;
2221
+ if (targetPath.includes(".")) {
2222
+ const pathParts = targetPath.split(".");
2223
+ let currentObj = updatedMapping;
2224
+ for (let i = 0; i < pathParts.length - 1; i++) {
2225
+ const part = pathParts[i];
2226
+ if (!currentObj[part]) currentObj[part] = {};
2227
+ else if (typeof currentObj[part] !== "object") currentObj[part] = {};
2228
+ currentObj = currentObj[part];
2229
+ }
2230
+ currentObj[pathParts[pathParts.length - 1]] = templateValue;
2231
+ } else updatedMapping[targetPath] = templateValue;
2232
+ onMappingChange(updatedMapping);
2233
+ if (isCompatible) toast({
2234
+ title: tr("fluidgrids.builder.visualMapper.mappingCreatedTitle", "Mapping created"),
2235
+ description: `Mapped ${sourcePath} (${sourceType}) to ${targetPath} (${targetType})`
2236
+ });
2237
+ else toast({
2238
+ title: tr("fluidgrids.builder.visualMapper.typeMismatchTitle", "Type mismatch warning"),
2239
+ description: `Mapped ${sourcePath} (${sourceType}) to ${targetPath} (${targetType}). Types may not be compatible.`,
2240
+ variant: "destructive"
2241
+ });
2242
+ } else toast({
2243
+ title: tr("fluidgrids.builder.visualMapper.invalidMappingTitle", "Invalid mapping"),
2244
+ description: tr("fluidgrids.builder.visualMapper.invalidMappingDescription", "You can only map from source to target fields"),
2245
+ variant: "destructive"
2246
+ });
2247
+ }, [
2248
+ nodes,
2249
+ mapping,
2250
+ onMappingChange,
2251
+ toast,
2252
+ tr,
2253
+ setEdges
2254
+ ]);
2255
+ const onEdgeDelete = useCallback((edge) => {
2256
+ const targetNodeObj = nodes.find((n) => n.id === edge.target);
2257
+ if (targetNodeObj && isSchemaNodeData(targetNodeObj.data)) {
2258
+ const targetPath = targetNodeObj.data.path;
2259
+ const updatedMapping = { ...mapping };
2260
+ if (targetPath.includes(".")) {
2261
+ const pathParts = targetPath.split(".");
2262
+ let currentObj = updatedMapping;
2263
+ let parentObj = null;
2264
+ let lastPart = null;
2265
+ for (let i = 0; i < pathParts.length - 1; i++) {
2266
+ const part = pathParts[i];
2267
+ if (!currentObj[part] || typeof currentObj[part] !== "object") return;
2268
+ parentObj = currentObj;
2269
+ currentObj = currentObj[part];
2270
+ lastPart = pathParts[i + 1];
2271
+ }
2272
+ if (parentObj && lastPart) {
2273
+ delete currentObj[pathParts[pathParts.length - 1]];
2274
+ if (Object.keys(currentObj).length === 0 && pathParts.length > 1) delete parentObj[pathParts[pathParts.length - 2]];
2275
+ }
2276
+ } else delete updatedMapping[targetPath];
2277
+ onMappingChange(updatedMapping);
2278
+ }
2279
+ setEdges((eds) => eds.filter((e) => e.id !== edge.id));
2280
+ }, [
2281
+ nodes,
2282
+ mapping,
2283
+ onMappingChange,
2284
+ setEdges
2285
+ ]);
2286
+ const onNodeClick = useCallback((_event, node) => {
2287
+ if (node.data && typeof node.data === "object" && isSchemaNodeData(node.data)) {
2288
+ const schemaNode = {
2289
+ id: node.id,
2290
+ data: node.data
2291
+ };
2292
+ if (schemaNode.data.side === "source") setSelectedSourceNode(schemaNode);
2293
+ else if (schemaNode.data.side === "target") setSelectedTargetNode(schemaNode);
2294
+ }
2295
+ }, []);
2296
+ const openMappingDialog = (type) => {
2297
+ setCurrentMappingType(type);
2298
+ setMappingDialogOpen(true);
2299
+ };
2300
+ const handleSaveMappingDialog = (expression, targetFieldName) => {
2301
+ const targetPath = targetFieldName || selectedTargetNode?.data?.path;
2302
+ if (!targetPath) {
2303
+ toast({
2304
+ title: tr("fluidgrids.builder.visualMapper.noTargetFieldTitle", "No target field specified"),
2305
+ description: tr("fluidgrids.builder.visualMapper.noTargetFieldDescription", "Please enter a target field name or select a target field in the visual mapper"),
2306
+ variant: "destructive"
2307
+ });
2308
+ return;
2309
+ }
2310
+ const updatedMapping = { ...mapping };
2311
+ if (targetPath.includes(".")) {
2312
+ const pathParts = targetPath.split(".");
2313
+ let currentObj = updatedMapping;
2314
+ for (let i = 0; i < pathParts.length - 1; i++) {
2315
+ const part = pathParts[i];
2316
+ if (!currentObj[part]) currentObj[part] = {};
2317
+ else if (typeof currentObj[part] !== "object") currentObj[part] = {};
2318
+ currentObj = currentObj[part];
2319
+ }
2320
+ currentObj[pathParts[pathParts.length - 1]] = expression;
2321
+ } else updatedMapping[targetPath] = expression;
2322
+ onMappingChange(updatedMapping);
2323
+ const mappingType = detectMappingType(expression);
2324
+ toast({
2325
+ title: `${mappingType.charAt(0).toUpperCase() + mappingType.slice(1)} mapping created`,
2326
+ description: `${tr("fluidgrids.builder.visualMapper.appliedMappingTo", "Applied mapping to")} ${targetPath}`
2327
+ });
2328
+ };
2329
+ const mappingTypeItems = [
2330
+ {
2331
+ type: "direct",
2332
+ label: tr("fluidgrids.builder.visualMapper.typeDirectLabel", "Direct"),
2333
+ icon: Type,
2334
+ description: tr("fluidgrids.builder.visualMapper.typeDirectDescription", "Simple field access")
2335
+ },
2336
+ {
2337
+ type: "expression",
2338
+ label: tr("fluidgrids.builder.visualMapper.typeExpressionLabel", "Expression"),
2339
+ icon: Code,
2340
+ description: tr("fluidgrids.builder.visualMapper.typeExpressionDescription", "Custom JavaScript expression")
2341
+ },
2342
+ {
2343
+ type: "transform",
2344
+ label: tr("fluidgrids.builder.visualMapper.typeTransformLabel", "Transform"),
2345
+ icon: Type,
2346
+ description: tr("fluidgrids.builder.visualMapper.typeTransformDescription", "String transformations")
2347
+ },
2348
+ {
2349
+ type: "cast",
2350
+ label: tr("fluidgrids.builder.visualMapper.typeCastLabel", "Cast"),
2351
+ icon: Hash,
2352
+ description: tr("fluidgrids.builder.visualMapper.typeCastDescription", "Type conversions")
2353
+ },
2354
+ {
2355
+ type: "array",
2356
+ label: tr("fluidgrids.builder.visualMapper.typeArrayLabel", "Array"),
2357
+ icon: List,
2358
+ description: tr("fluidgrids.builder.visualMapper.typeArrayDescription", "Array operations (map, filter, reduce)")
2359
+ },
2360
+ {
2361
+ type: "object",
2362
+ label: tr("fluidgrids.builder.visualMapper.typeObjectLabel", "Object"),
2363
+ icon: Braces,
2364
+ description: tr("fluidgrids.builder.visualMapper.typeObjectDescription", "Object manipulation")
2365
+ },
2366
+ {
2367
+ type: "context",
2368
+ label: tr("fluidgrids.builder.visualMapper.typeContextLabel", "Context"),
2369
+ icon: Workflow,
2370
+ description: tr("fluidgrids.builder.visualMapper.typeContextDescription", "Workflow state access")
2371
+ }
2372
+ ];
2373
+ return /* @__PURE__ */ jsxs("div", {
2374
+ className: "h-[550px] w-full border rounded-md",
2375
+ ref: reactFlowWrapper,
2376
+ children: [/* @__PURE__ */ jsxs(ReactFlow, {
2377
+ nodes,
2378
+ edges,
2379
+ onNodesChange,
2380
+ onEdgesChange,
2381
+ onConnect,
2382
+ onEdgeClick: (_, edge) => onEdgeDelete(edge),
2383
+ onNodeClick,
2384
+ nodeTypes,
2385
+ edgeTypes,
2386
+ fitView: true,
2387
+ fitViewOptions: { padding: .2 },
2388
+ minZoom: .4,
2389
+ maxZoom: 1.5,
2390
+ defaultViewport: {
2391
+ x: 0,
2392
+ y: 0,
2393
+ zoom: .7
2394
+ },
2395
+ attributionPosition: "bottom-right",
2396
+ children: [
2397
+ /* @__PURE__ */ jsx(Controls, {}),
2398
+ /* @__PURE__ */ jsx(MiniMap, {}),
2399
+ /* @__PURE__ */ jsx(Background, {
2400
+ gap: 12,
2401
+ size: 1
2402
+ }),
2403
+ /* @__PURE__ */ jsx(Panel, {
2404
+ position: "top-right",
2405
+ children: /* @__PURE__ */ jsxs("div", {
2406
+ className: "flex flex-col gap-2",
2407
+ children: [/* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
2408
+ asChild: true,
2409
+ children: /* @__PURE__ */ jsxs(Button, {
2410
+ variant: "outline",
2411
+ size: "sm",
2412
+ className: "flex items-center gap-1",
2413
+ children: [
2414
+ /* @__PURE__ */ jsx(PlusCircle, { className: "h-4 w-4" }),
2415
+ tr("fluidgrids.builder.visualMapper.addMapping", "Add Mapping"),
2416
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" })
2417
+ ]
2418
+ })
2419
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
2420
+ align: "end",
2421
+ className: "w-56 z-[100000]",
2422
+ children: [
2423
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: tr("fluidgrids.builder.visualMapper.mappingTypes", "Mapping Types") }),
2424
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2425
+ mappingTypeItems.map((item) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
2426
+ onClick: () => openMappingDialog(item.type),
2427
+ className: "flex items-start gap-2 cursor-pointer",
2428
+ children: [/* @__PURE__ */ jsx(item.icon, {
2429
+ className: "h-4 w-4 mt-0.5",
2430
+ style: { color: mappingTypeColor(item.type) }
2431
+ }), /* @__PURE__ */ jsxs("div", {
2432
+ className: "flex flex-col",
2433
+ children: [/* @__PURE__ */ jsx("span", {
2434
+ className: "font-medium",
2435
+ children: item.label
2436
+ }), /* @__PURE__ */ jsx("span", {
2437
+ className: "text-xs text-muted-foreground",
2438
+ children: item.description
2439
+ })]
2440
+ })]
2441
+ }, item.type))
2442
+ ]
2443
+ })] }), selectedTargetNode && /* @__PURE__ */ jsxs("div", {
2444
+ className: "p-2 bg-muted rounded-md text-xs",
2445
+ children: [/* @__PURE__ */ jsx("div", {
2446
+ className: "text-muted-foreground",
2447
+ children: tr("fluidgrids.builder.visualMapper.targetIndicator", "Target:")
2448
+ }), /* @__PURE__ */ jsx("div", {
2449
+ className: "font-mono",
2450
+ children: selectedTargetNode.data.path
2451
+ })]
2452
+ })]
2453
+ })
2454
+ })
2455
+ ]
2456
+ }), /* @__PURE__ */ jsx(MappingDialog, {
2457
+ open: mappingDialogOpen,
2458
+ onOpenChange: setMappingDialogOpen,
2459
+ onSave: handleSaveMappingDialog,
2460
+ mappingType: currentMappingType,
2461
+ sourceField: selectedSourceNode?.data?.path,
2462
+ targetField: selectedTargetNode?.data?.path,
2463
+ sourceSchema,
2464
+ sourceOperation,
2465
+ targetSchema,
2466
+ targetOperation
2467
+ })]
2468
+ });
2469
+ }
2470
+ function VisualMapper(props) {
2471
+ return /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(VisualMapperContent, { ...props }) });
2472
+ }
2473
+
2474
+ // src/builder/components/mapper/code-editor.tsx
2475
+ function CodeEditor({ value, onChange, language: _language = "json", onBlur }) {
2476
+ const editorRef = useRef(null);
2477
+ useEffect(() => {
2478
+ if (editorRef.current) editorRef.current.value = value;
2479
+ }, [value]);
2480
+ return /* @__PURE__ */ jsx(Card, {
2481
+ className: "relative ",
2482
+ children: /* @__PURE__ */ jsx("textarea", {
2483
+ ref: editorRef,
2484
+ className: "w-full h-[400px] p-4 font-mono bg-surface text-sm resize-none focus:outline-none focus:ring-2 focus:ring-primary transition-shadow duration-200",
2485
+ defaultValue: value,
2486
+ onChange,
2487
+ spellCheck: false,
2488
+ onBlur
2489
+ })
2490
+ });
2491
+ }
2492
+
2493
+ // src/builder/components/mapper/mapping-preview.tsx
2494
+ function MappingPreview({ input, mapping, output }) {
2495
+ const tr = useTr();
2496
+ const generatedOutput = useMemo(() => {
2497
+ try {
2498
+ return applyMapping(mapping, input);
2499
+ } catch (error) {
2500
+ console.error("Error applying mapping:", error);
2501
+ return {
2502
+ error: true,
2503
+ message: error instanceof Error ? error.message : tr("fluidgrids.builder.mappingPreview.unknownError", "Unknown error occurred while applying mapping"),
2504
+ input
2505
+ };
2506
+ }
2507
+ }, [
2508
+ input,
2509
+ mapping,
2510
+ tr
2511
+ ]);
2512
+ return /* @__PURE__ */ jsxs(Tabs, {
2513
+ defaultValue: "input",
2514
+ children: [
2515
+ /* @__PURE__ */ jsxs(TabsList, {
2516
+ className: "mb-4",
2517
+ children: [
2518
+ /* @__PURE__ */ jsx(TabsTrigger, {
2519
+ value: "input",
2520
+ children: tr("fluidgrids.builder.mappingPreview.tabInput", "Input")
2521
+ }),
2522
+ /* @__PURE__ */ jsx(TabsTrigger, {
2523
+ value: "mapping",
2524
+ children: tr("fluidgrids.builder.mappingPreview.tabMapping", "Mapping")
2525
+ }),
2526
+ /* @__PURE__ */ jsx(TabsTrigger, {
2527
+ value: "output",
2528
+ children: tr("fluidgrids.builder.mappingPreview.tabOutput", "Output")
2529
+ })
2530
+ ]
2531
+ }),
2532
+ /* @__PURE__ */ jsx(TabsContent, {
2533
+ value: "input",
2534
+ children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, {
2535
+ className: "p-4",
2536
+ children: /* @__PURE__ */ jsx("pre", {
2537
+ className: "text-sm overflow-auto max-h-[400px]",
2538
+ children: JSON.stringify(input, null, 2)
2539
+ })
2540
+ }) })
2541
+ }),
2542
+ /* @__PURE__ */ jsx(TabsContent, {
2543
+ value: "mapping",
2544
+ children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, {
2545
+ className: "p-4",
2546
+ children: /* @__PURE__ */ jsx("pre", {
2547
+ className: "text-sm overflow-auto max-h-[400px]",
2548
+ children: JSON.stringify(mapping, null, 2)
2549
+ })
2550
+ }) })
2551
+ }),
2552
+ /* @__PURE__ */ jsx(TabsContent, {
2553
+ value: "output",
2554
+ children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, {
2555
+ className: "p-4",
2556
+ children: /* @__PURE__ */ jsx("pre", {
2557
+ className: "text-sm overflow-auto max-h-[400px]",
2558
+ children: output ? JSON.stringify(output, null, 2) : generatedOutput ? JSON.stringify(generatedOutput, null, 2) : tr("fluidgrids.builder.mappingPreview.noOutput", "No output generated yet")
2559
+ })
2560
+ }) })
2561
+ })
2562
+ ]
2563
+ });
2564
+ }
2565
+
2566
+ // src/builder/components/mapper/mapping-editor.tsx
2567
+ function generateSampleValueForType(typeName, schema) {
2568
+ if (typeName.startsWith("[") && typeName.endsWith("]")) return [generateSampleValueForType(typeName.substring(1, typeName.length - 1).replace(/!$/, ""), schema)];
2569
+ const baseType = typeName.endsWith("!") ? typeName.slice(0, -1) : typeName;
2570
+ switch (baseType) {
2571
+ case "String": return "Sample string";
2572
+ case "Int": return 42;
2573
+ case "Float": return 3.14;
2574
+ case "Boolean": return true;
2575
+ case "ID": return "id-123456";
2576
+ default:
2577
+ if (schema.types[baseType]) {
2578
+ const type = schema.types[baseType];
2579
+ if (type.kind === "type" || type.kind === "input") {
2580
+ const obj = {};
2581
+ for (const fieldName in type.fields || {}) obj[fieldName] = generateSampleValueForType(type.fields[fieldName].type, schema);
2582
+ return obj;
2583
+ }
2584
+ if (type.kind === "enum") return `ENUM_${baseType}`;
2585
+ }
2586
+ return null;
2587
+ }
2588
+ }
2589
+ function generateSampleInput(schema, nodeType, operation) {
2590
+ const returnTypeName = getReturnTypeForOperation(nodeType, operation);
2591
+ if (!returnTypeName || !schema.types[returnTypeName]) return {};
2592
+ const returnType = schema.types[returnTypeName];
2593
+ const result = {};
2594
+ for (const fieldName in returnType.fields || {}) {
2595
+ const field = returnType.fields[fieldName];
2596
+ result[fieldName] = generateSampleValueForType(field.type, schema);
2597
+ }
2598
+ return result;
2599
+ }
2600
+ function MappingEditor({ sourceSchema, targetSchema, sourceNode, sourceOperation, targetNode, targetOperation, className, setEdges, edgeId }) {
2601
+ const { toast } = useToast();
2602
+ const tr = useTr();
2603
+ const [mappingJson, setMappingJson] = useState({});
2604
+ const [jsonDataString, setJsonDataString] = useState(JSON.stringify(mappingJson, null, 2));
2605
+ const [jsonError, setJsonError] = useState(null);
2606
+ const [validationErrors, setValidationErrors] = useState([]);
2607
+ const [sampleInput, setSampleInput] = useState({});
2608
+ const [previewOutput, setPreviewOutput] = useState(null);
2609
+ const [isTestingMapping, setIsTestingMapping] = useState(false);
2610
+ useEffect(() => {
2611
+ const defaultMapping = generateDefaultMapping(sourceSchema, sourceNode, sourceOperation, targetSchema, targetNode, targetOperation);
2612
+ setMappingJson(defaultMapping);
2613
+ setJsonDataString(JSON.stringify(defaultMapping, null, 2));
2614
+ const generatedSampleInput = generateSampleInput(sourceSchema, sourceNode, sourceOperation);
2615
+ setSampleInput(generatedSampleInput);
2616
+ const errors = validateMapping(defaultMapping);
2617
+ setValidationErrors(errors);
2618
+ }, [
2619
+ sourceSchema,
2620
+ targetSchema,
2621
+ sourceNode,
2622
+ sourceOperation,
2623
+ targetNode,
2624
+ targetOperation
2625
+ ]);
2626
+ const handleJsonStringChange = (e) => {
2627
+ setJsonDataString(e.target.value);
2628
+ setJsonError(null);
2629
+ };
2630
+ const handleJsonBlur = () => {
2631
+ try {
2632
+ const parsed = JSON.parse(jsonDataString);
2633
+ setMappingJson(parsed);
2634
+ setJsonError(null);
2635
+ const errors = validateMapping(parsed);
2636
+ setValidationErrors(errors);
2637
+ } catch (error) {
2638
+ console.error("JSON parsing error:", error);
2639
+ setJsonError(tr("fluidgrids.builder.mappingEditor.invalidJsonFormat", "Invalid JSON format. Please correct it."));
2640
+ }
2641
+ };
2642
+ const handleMappingChange = (newMapping) => {
2643
+ setMappingJson(newMapping);
2644
+ setJsonDataString(JSON.stringify(newMapping, null, 2));
2645
+ const errors = validateMapping(newMapping);
2646
+ setValidationErrors(errors);
2647
+ if (setEdges && edgeId && errors.length === 0) setEdges((edges) => {
2648
+ return edges.map((edge) => {
2649
+ if (edge.id === edgeId) return {
2650
+ ...edge,
2651
+ mapping: {
2652
+ definition: newMapping,
2653
+ comment: `Mapping from ${sourceNode}.${sourceOperation} to ${targetNode}.${targetOperation}`
2654
+ }
2655
+ };
2656
+ return edge;
2657
+ });
2658
+ });
2659
+ };
2660
+ const checkJsonValidity = () => {
2661
+ setJsonError(null);
2662
+ try {
2663
+ const parsedData = JSON.parse(jsonDataString);
2664
+ setMappingJson(parsedData);
2665
+ const errors = validateMapping(parsedData);
2666
+ if (errors.length > 0) {
2667
+ setValidationErrors(errors);
2668
+ throw new Error(`Validation errors: ${errors.join(", ")}`);
2669
+ }
2670
+ if (setEdges && edgeId) setEdges((edges) => {
2671
+ return edges.map((edge) => {
2672
+ if (edge.id === edgeId) return {
2673
+ ...edge,
2674
+ mapping: {
2675
+ definition: parsedData,
2676
+ comment: `Mapping from ${sourceNode}.${sourceOperation} to ${targetNode}.${targetOperation}`
2677
+ }
2678
+ };
2679
+ return edge;
2680
+ });
2681
+ });
2682
+ return parsedData;
2683
+ } catch (error) {
2684
+ if (error instanceof SyntaxError) setJsonError(tr("fluidgrids.builder.mappingEditor.cannotSubmitInvalidJson", "Cannot submit: Mapping data must be valid JSON."));
2685
+ console.error("Submission failed:", error);
2686
+ throw error;
2687
+ }
2688
+ };
2689
+ const handleSaveMapping = () => {
2690
+ try {
2691
+ checkJsonValidity();
2692
+ toast({
2693
+ title: tr("fluidgrids.builder.mappingEditor.mappingSavedTitle", "Mapping saved"),
2694
+ description: tr("fluidgrids.builder.mappingEditor.mappingSavedDescription", "Your mapping configuration has been saved successfully.")
2695
+ });
2696
+ } catch (error) {
2697
+ toast({
2698
+ title: tr("fluidgrids.builder.mappingEditor.errorSavingTitle", "Error saving mapping"),
2699
+ description: error instanceof Error ? error.message : tr("fluidgrids.builder.mappingEditor.errorSavingFallback", "Invalid mapping configuration"),
2700
+ variant: "destructive"
2701
+ });
2702
+ }
2703
+ };
2704
+ const handleTestMapping = async () => {
2705
+ try {
2706
+ setIsTestingMapping(true);
2707
+ const parsedData = checkJsonValidity();
2708
+ const result = await applyMapping(parsedData, sampleInput);
2709
+ setPreviewOutput(result);
2710
+ toast({
2711
+ title: tr("fluidgrids.builder.mappingEditor.mappingTestedTitle", "Mapping tested"),
2712
+ description: tr("fluidgrids.builder.mappingEditor.mappingTestedDescription", "Test completed successfully.")
2713
+ });
2714
+ } catch (error) {
2715
+ console.error("Test mapping error:", error);
2716
+ toast({
2717
+ title: tr("fluidgrids.builder.mappingEditor.mappingTestFailedTitle", "Mapping test failed"),
2718
+ description: error instanceof Error ? error.message : tr("fluidgrids.builder.mappingEditor.mappingTestFailedFallback", "Error executing mapping"),
2719
+ variant: "destructive"
2720
+ });
2721
+ } finally {
2722
+ setIsTestingMapping(false);
2723
+ }
2724
+ };
2725
+ const detectMappingTypes = (mapping) => {
2726
+ const types = /* @__PURE__ */ new Set();
2727
+ const processValue = (value) => {
2728
+ if (typeof value === "string") {
2729
+ const parseResult = parseTemplate(value);
2730
+ if (parseResult.isTemplate) {
2731
+ const expr = parseResult.expression || "";
2732
+ if (expr.includes(".map(") || expr.includes(".filter(") || expr.includes(".reduce(")) types.add("array");
2733
+ else if (expr.includes("Object.") || expr.startsWith("({")) types.add("object");
2734
+ else if (expr.startsWith("parseInt(") || expr.startsWith("parseFloat(") || expr.startsWith("String(")) types.add("cast");
2735
+ else if (expr.includes("TriggerInput.") || expr.includes("WorkflowState.") || expr.includes("RunContext.")) types.add("context");
2736
+ else if (expr.includes(".toUpperCase()") || expr.includes(".toLowerCase()") || expr.includes(".trim()")) types.add("transform");
2737
+ else if (expr.includes(" + ") || expr.includes(" ? ") || expr.includes("Math.")) types.add("expression");
2738
+ else types.add("direct");
2739
+ }
2740
+ } else if (typeof value === "object" && value !== null) Object.values(value).forEach(processValue);
2741
+ };
2742
+ Object.values(mapping).forEach(processValue);
2743
+ return types;
2744
+ };
2745
+ const usedMappingTypes = detectMappingTypes(mappingJson);
2746
+ return /* @__PURE__ */ jsx("div", {
2747
+ className,
2748
+ children: /* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsxs(CardHeader, { children: [
2749
+ /* @__PURE__ */ jsxs(CardTitle, {
2750
+ className: "flex items-center justify-between",
2751
+ children: [/* @__PURE__ */ jsx("span", { children: tr("fluidgrids.builder.mappingEditor.cardTitle", "Mapping Configuration") }), validationErrors.length === 0 ? /* @__PURE__ */ jsxs(Badge, {
2752
+ variant: "outline",
2753
+ className: "text-[var(--color-status-success-text)] border-[var(--color-status-success-border)]",
2754
+ children: [/* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3 mr-1" }), tr("fluidgrids.builder.mappingEditor.badgeValid", "Valid")]
2755
+ }) : /* @__PURE__ */ jsxs(Badge, {
2756
+ variant: "outline",
2757
+ className: "text-[var(--color-status-error-text)] border-[var(--color-status-error-border)]",
2758
+ children: [
2759
+ /* @__PURE__ */ jsx(AlertCircle, { className: "h-3 w-3 mr-1" }),
2760
+ validationErrors.length,
2761
+ " Error",
2762
+ validationErrors.length > 1 ? "s" : ""
2763
+ ]
2764
+ })]
2765
+ }),
2766
+ /* @__PURE__ */ jsxs(CardDescription, { children: [
2767
+ "Create a mapping from ",
2768
+ sourceNode,
2769
+ ".",
2770
+ sourceOperation,
2771
+ " to ",
2772
+ targetNode,
2773
+ ".",
2774
+ targetOperation
2775
+ ] }),
2776
+ usedMappingTypes.size > 0 && /* @__PURE__ */ jsx("div", {
2777
+ className: "flex flex-wrap gap-1 mt-2",
2778
+ children: Array.from(usedMappingTypes).map((type) => /* @__PURE__ */ jsx(Badge, {
2779
+ variant: "secondary",
2780
+ className: "text-xs",
2781
+ children: type
2782
+ }, type))
2783
+ })
2784
+ ] }), /* @__PURE__ */ jsxs(CardContent, { children: [/* @__PURE__ */ jsxs(Tabs, {
2785
+ defaultValue: "visual",
2786
+ className: "w-full",
2787
+ children: [
2788
+ /* @__PURE__ */ jsxs(TabsList, {
2789
+ className: "mb-4",
2790
+ children: [
2791
+ /* @__PURE__ */ jsx(TabsTrigger, {
2792
+ value: "visual",
2793
+ children: tr("fluidgrids.builder.mappingEditor.tabVisualMapper", "Visual Mapper")
2794
+ }),
2795
+ /* @__PURE__ */ jsx(TabsTrigger, {
2796
+ value: "code",
2797
+ children: tr("fluidgrids.builder.mappingEditor.tabJsonEditor", "JSON Editor")
2798
+ }),
2799
+ /* @__PURE__ */ jsx(TabsTrigger, {
2800
+ value: "preview",
2801
+ children: tr("fluidgrids.builder.mappingEditor.tabPreview", "Preview")
2802
+ })
2803
+ ]
2804
+ }),
2805
+ /* @__PURE__ */ jsx(TabsContent, {
2806
+ value: "visual",
2807
+ children: /* @__PURE__ */ jsx(VisualMapper, {
2808
+ sourceSchema,
2809
+ targetSchema,
2810
+ sourceNode,
2811
+ sourceOperation,
2812
+ targetNode,
2813
+ targetOperation,
2814
+ mapping: mappingJson,
2815
+ onMappingChange: handleMappingChange
2816
+ })
2817
+ }),
2818
+ /* @__PURE__ */ jsxs(TabsContent, {
2819
+ value: "code",
2820
+ children: [/* @__PURE__ */ jsx(CodeEditor, {
2821
+ value: jsonDataString,
2822
+ onBlur: handleJsonBlur,
2823
+ onChange: handleJsonStringChange
2824
+ }), /* @__PURE__ */ jsxs("div", {
2825
+ className: "mt-2 space-y-1",
2826
+ children: [
2827
+ /* @__PURE__ */ jsxs("p", {
2828
+ className: "text-xs text-muted-foreground",
2829
+ children: [
2830
+ tr("fluidgrids.builder.mappingEditor.templateSyntaxHint", "Use JavaScript template literal syntax:"),
2831
+ " ",
2832
+ /* @__PURE__ */ jsxs("code", {
2833
+ className: "bg-muted px-1 rounded",
2834
+ children: [
2835
+ "$",
2836
+ "{",
2837
+ "output.field",
2838
+ "}"
2839
+ ]
2840
+ })
2841
+ ]
2842
+ }),
2843
+ jsonError && /* @__PURE__ */ jsx("p", {
2844
+ className: "text-sm text-[var(--color-status-error-text)]",
2845
+ children: jsonError
2846
+ }),
2847
+ validationErrors.length > 0 && /* @__PURE__ */ jsxs("div", {
2848
+ className: "p-2 bg-[var(--color-status-error-bg-subtle)] rounded-md",
2849
+ children: [/* @__PURE__ */ jsx("p", {
2850
+ className: "text-sm font-medium text-[var(--color-status-error-text)]",
2851
+ children: tr("fluidgrids.builder.mappingEditor.validationErrors", "Validation Errors:")
2852
+ }), /* @__PURE__ */ jsx("ul", {
2853
+ className: "text-xs text-[var(--color-status-error-text)]/80 mt-1 list-disc list-inside",
2854
+ children: validationErrors.map((error, index) => /* @__PURE__ */ jsx("li", { children: error }, index))
2855
+ })]
2856
+ })
2857
+ ]
2858
+ })]
2859
+ }),
2860
+ /* @__PURE__ */ jsx(TabsContent, {
2861
+ value: "preview",
2862
+ children: /* @__PURE__ */ jsx(MappingPreview, {
2863
+ input: sampleInput,
2864
+ mapping: mappingJson,
2865
+ output: previewOutput
2866
+ })
2867
+ })
2868
+ ]
2869
+ }), /* @__PURE__ */ jsxs("div", {
2870
+ className: "mt-6 flex justify-end space-x-2",
2871
+ children: [/* @__PURE__ */ jsx(Button, {
2872
+ variant: "outline",
2873
+ onClick: handleTestMapping,
2874
+ disabled: isTestingMapping,
2875
+ children: isTestingMapping ? tr("fluidgrids.builder.mappingEditor.testing", "Testing...") : tr("fluidgrids.builder.mappingEditor.testMapping", "Test Mapping")
2876
+ }), /* @__PURE__ */ jsx(Button, {
2877
+ onClick: handleSaveMapping,
2878
+ children: tr("fluidgrids.builder.mappingEditor.saveMapping", "Save Mapping")
2879
+ })]
2880
+ })] })] })
2881
+ });
2882
+ }
2883
+
2884
+ // src/builder/components/lib/schema-parser.ts
2885
+ function parseGraphQLSchema(sdl) {
2886
+ const customSchema = {
2887
+ types: {},
2888
+ queryType: null,
2889
+ mutationType: null,
2890
+ subscriptionType: null
2891
+ };
2892
+ try {
2893
+ const schema = buildSchema(sdl);
2894
+ const queryType = schema.getQueryType();
2895
+ const mutationType = schema.getMutationType();
2896
+ const subscriptionType = schema.getSubscriptionType();
2897
+ if (queryType) customSchema.queryType = queryType.name;
2898
+ if (mutationType) customSchema.mutationType = mutationType.name;
2899
+ if (subscriptionType) customSchema.subscriptionType = subscriptionType.name;
2900
+ const typeMap = schema.getTypeMap();
2901
+ Object.values(typeMap).forEach((type) => {
2902
+ if (type.name.startsWith("__")) return;
2903
+ if (type instanceof GraphQLObjectType) processObjectType(type, customSchema);
2904
+ else if (type instanceof GraphQLInputObjectType) processInputObjectType(type, customSchema);
2905
+ else if (type instanceof GraphQLEnumType) processEnumType(type, customSchema);
2906
+ else if (type instanceof GraphQLInterfaceType) processInterfaceType(type, customSchema);
2907
+ else if (type instanceof GraphQLUnionType) processUnionType(type, customSchema);
2908
+ });
2909
+ return customSchema;
2910
+ } catch (error) {
2911
+ console.error("Error parsing GraphQL schema:", error);
2912
+ return customSchema;
2913
+ }
2914
+ }
2915
+ function processObjectType(type, customSchema) {
2916
+ const fields = type.getFields();
2917
+ const processedFields = {};
2918
+ Object.values(fields).forEach((field) => {
2919
+ processedFields[field.name] = processField(field);
2920
+ });
2921
+ customSchema.types[type.name] = {
2922
+ name: type.name,
2923
+ kind: "type",
2924
+ fields: processedFields
2925
+ };
2926
+ }
2927
+ function processInputObjectType(type, customSchema) {
2928
+ const fields = type.getFields();
2929
+ const processedFields = {};
2930
+ Object.values(fields).forEach((field) => {
2931
+ processedFields[field.name] = processInputField(field);
2932
+ });
2933
+ customSchema.types[type.name] = {
2934
+ name: type.name,
2935
+ kind: "input",
2936
+ fields: processedFields,
2937
+ inputFields: processedFields
2938
+ };
2939
+ }
2940
+ function processEnumType(type, customSchema) {
2941
+ customSchema.types[type.name] = {
2942
+ name: type.name,
2943
+ kind: "enum",
2944
+ fields: {}
2945
+ };
2946
+ }
2947
+ function processInterfaceType(type, customSchema) {
2948
+ const fields = type.getFields();
2949
+ const processedFields = {};
2950
+ Object.values(fields).forEach((field) => {
2951
+ processedFields[field.name] = processField(field);
2952
+ });
2953
+ customSchema.types[type.name] = {
2954
+ name: type.name,
2955
+ kind: "interface",
2956
+ fields: processedFields
2957
+ };
2958
+ }
2959
+ function processUnionType(type, customSchema) {
2960
+ customSchema.types[type.name] = {
2961
+ name: type.name,
2962
+ kind: "union",
2963
+ fields: {}
2964
+ };
2965
+ }
2966
+ function processField(field) {
2967
+ const fieldType = field.type;
2968
+ const typeInfo = getTypeInfo(fieldType);
2969
+ const args = field.args.map((arg) => processArgument(arg));
2970
+ return {
2971
+ name: field.name,
2972
+ type: typeInfo.typeName,
2973
+ isNonNull: typeInfo.isNonNull,
2974
+ isList: typeInfo.isList,
2975
+ args
2976
+ };
2977
+ }
2978
+ function processInputField(field) {
2979
+ const fieldType = field.type;
2980
+ const typeInfo = getTypeInfo(fieldType);
2981
+ return {
2982
+ name: field.name,
2983
+ type: typeInfo.typeName,
2984
+ isNonNull: typeInfo.isNonNull,
2985
+ isList: typeInfo.isList,
2986
+ args: []
2987
+ };
2988
+ }
2989
+ function processArgument(arg) {
2990
+ const argType = arg.type;
2991
+ const typeInfo = getTypeInfo(argType);
2992
+ return {
2993
+ name: arg.name,
2994
+ type: typeInfo.typeName,
2995
+ isNonNull: typeInfo.isNonNull,
2996
+ isList: typeInfo.isList
2997
+ };
2998
+ }
2999
+ function getTypeInfo(inputType) {
3000
+ let typeName = "";
3001
+ let isNonNull = false;
3002
+ let isList = false;
3003
+ let currentType = inputType;
3004
+ if (currentType instanceof GraphQLNonNull) {
3005
+ isNonNull = true;
3006
+ currentType = currentType.ofType;
3007
+ }
3008
+ if (currentType instanceof GraphQLList) {
3009
+ isList = true;
3010
+ currentType = currentType.ofType;
3011
+ if (currentType instanceof GraphQLNonNull) currentType = currentType.ofType;
3012
+ }
3013
+ if (currentType.name) typeName = currentType.name;
3014
+ else if (currentType.ofType?.name) typeName = currentType.ofType.name;
3015
+ return {
3016
+ typeName,
3017
+ isNonNull,
3018
+ isList
3019
+ };
3020
+ }
3021
+
3022
+ // src/builder/components/mapper/config/default-data-config.ts
3023
+ /**
3024
+ * Default data config for the mapper component.
3025
+ *
3026
+ * Note: Node configurations (with schemas) are passed dynamically via props
3027
+ * from the edge component. This default config only contains mapping type
3028
+ * examples and type compatibility rules.
3029
+ */
3030
+ const defaultDataConfig = {
3031
+ nodes: {},
3032
+ mappingTypes: {
3033
+ direct: {
3034
+ displayName: "Direct Mapping",
3035
+ description: "Map a source field directly to a target field using ${output.field} syntax",
3036
+ color: {
3037
+ compatible: MAPPING_COMPATIBILITY_COLORS.compatible,
3038
+ incompatible: MAPPING_COMPATIBILITY_COLORS.incompatible
3039
+ },
3040
+ examples: [
3041
+ {
3042
+ name: "Simple field access",
3043
+ expression: "${output.fieldName}",
3044
+ description: "Access a direct field from the output"
3045
+ },
3046
+ {
3047
+ name: "Nested field access",
3048
+ expression: "${output.user.email}",
3049
+ description: "Access nested properties"
3050
+ },
3051
+ {
3052
+ name: "Array element access",
3053
+ expression: "${output.items[0].name}",
3054
+ description: "Access specific array elements"
3055
+ },
3056
+ {
3057
+ name: "With fallback",
3058
+ expression: "${output.user?.email || 'default@example.com'}",
3059
+ description: "Safe access with default value"
3060
+ }
3061
+ ]
3062
+ },
3063
+ expression: {
3064
+ displayName: "Expression Mapping",
3065
+ description: "Create a custom JavaScript expression to transform the data",
3066
+ color: MAPPING_TYPE_COLORS.expression,
3067
+ examples: [
3068
+ {
3069
+ name: "String concatenation",
3070
+ expression: "${output.firstName + ' ' + output.lastName}",
3071
+ description: "Combine first and last name"
3072
+ },
3073
+ {
3074
+ name: "Template literal string",
3075
+ expression: "${`Hello ${output.name}!`}",
3076
+ description: "Use nested template literals for formatting"
3077
+ },
3078
+ {
3079
+ name: "Mathematical operation",
3080
+ expression: "${output.price * (1 - output.discount)}",
3081
+ description: "Calculate discounted price"
3082
+ },
3083
+ {
3084
+ name: "Conditional logic (ternary)",
3085
+ expression: "${output.age >= 18 ? 'Adult' : 'Minor'}",
3086
+ description: "Determine if adult or minor"
3087
+ },
3088
+ {
3089
+ name: "Nullish coalescing",
3090
+ expression: "${output.value ?? 'default'}",
3091
+ description: "Use default if null/undefined"
3092
+ },
3093
+ {
3094
+ name: "Logical OR fallback",
3095
+ expression: "${output.error || 'Success'}",
3096
+ description: "Fallback for falsy values"
3097
+ },
3098
+ {
3099
+ name: "Array length",
3100
+ expression: "${output.items?.length || 0}",
3101
+ description: "Get the length of an array safely"
3102
+ },
3103
+ {
3104
+ name: "Min value",
3105
+ expression: "${Math.min(...output.values)}",
3106
+ description: "Get the minimum value in an array"
3107
+ },
3108
+ {
3109
+ name: "Max value",
3110
+ expression: "${Math.max(...output.values)}",
3111
+ description: "Get the maximum value in an array"
3112
+ },
3113
+ {
3114
+ name: "Round number",
3115
+ expression: "${Math.round(output.value)}",
3116
+ description: "Round to nearest integer"
3117
+ },
3118
+ {
3119
+ name: "JSON parsing",
3120
+ expression: "${JSON.parse(output.jsonString)}",
3121
+ description: "Parse a JSON string to an object"
3122
+ },
3123
+ {
3124
+ name: "JSON stringify",
3125
+ expression: "${JSON.stringify(output.data)}",
3126
+ description: "Convert object to JSON string"
3127
+ },
3128
+ {
3129
+ name: "Current timestamp",
3130
+ expression: "${new Date().toISOString()}",
3131
+ description: "Get current date/time in ISO format"
3132
+ },
3133
+ {
3134
+ name: "Object creation",
3135
+ expression: "${({ id: output.user.id, email: output.user.email })}",
3136
+ description: "Create a new object from fields"
3137
+ }
3138
+ ],
3139
+ safeBuiltins: [
3140
+ "parseInt",
3141
+ "parseFloat",
3142
+ "isNaN",
3143
+ "isFinite",
3144
+ "Number",
3145
+ "String",
3146
+ "Boolean",
3147
+ "Math.min",
3148
+ "Math.max",
3149
+ "Math.round",
3150
+ "Math.floor",
3151
+ "Math.ceil",
3152
+ "Math.abs",
3153
+ "Array.isArray",
3154
+ "JSON.parse",
3155
+ "JSON.stringify",
3156
+ "Object.keys",
3157
+ "Object.values",
3158
+ "Object.entries",
3159
+ "Object.assign",
3160
+ "Date",
3161
+ "new Date()"
3162
+ ]
3163
+ },
3164
+ transform: {
3165
+ displayName: "Transform Mapping",
3166
+ description: "Apply string and data transformation functions",
3167
+ color: MAPPING_TYPE_COLORS.transform,
3168
+ examples: [
3169
+ {
3170
+ name: "Uppercase",
3171
+ expression: "${output.field.toUpperCase()}",
3172
+ description: "Convert text to uppercase"
3173
+ },
3174
+ {
3175
+ name: "Lowercase",
3176
+ expression: "${output.field.toLowerCase()}",
3177
+ description: "Convert text to lowercase"
3178
+ },
3179
+ {
3180
+ name: "Trim whitespace",
3181
+ expression: "${output.field.trim()}",
3182
+ description: "Remove leading/trailing whitespace"
3183
+ },
3184
+ {
3185
+ name: "Split string",
3186
+ expression: "${output.field.split(',')}",
3187
+ description: "Split string into array by delimiter"
3188
+ },
3189
+ {
3190
+ name: "Join array",
3191
+ expression: "${output.items.join(', ')}",
3192
+ description: "Join array elements with delimiter"
3193
+ },
3194
+ {
3195
+ name: "Replace text",
3196
+ expression: "${output.field.replace(/old/g, 'new')}",
3197
+ description: "Replace all occurrences of text"
3198
+ },
3199
+ {
3200
+ name: "Substring",
3201
+ expression: "${output.field.substring(0, 10)}",
3202
+ description: "Extract part of a string"
3203
+ },
3204
+ {
3205
+ name: "Slice",
3206
+ expression: "${output.field.slice(-5)}",
3207
+ description: "Get last 5 characters"
3208
+ },
3209
+ {
3210
+ name: "Includes check",
3211
+ expression: "${output.field.includes('search')}",
3212
+ description: "Check if string contains text"
3213
+ },
3214
+ {
3215
+ name: "Starts with",
3216
+ expression: "${output.field.startsWith('prefix')}",
3217
+ description: "Check if string starts with text"
3218
+ }
3219
+ ],
3220
+ functions: [
3221
+ {
3222
+ name: "toUpperCase",
3223
+ displayName: "Uppercase",
3224
+ description: "Convert text to uppercase",
3225
+ example: "${output.field.toUpperCase()}"
3226
+ },
3227
+ {
3228
+ name: "toLowerCase",
3229
+ displayName: "Lowercase",
3230
+ description: "Convert text to lowercase",
3231
+ example: "${output.field.toLowerCase()}"
3232
+ },
3233
+ {
3234
+ name: "trim",
3235
+ displayName: "Trim",
3236
+ description: "Remove whitespace from start and end",
3237
+ example: "${output.field.trim()}"
3238
+ },
3239
+ {
3240
+ name: "split",
3241
+ displayName: "Split",
3242
+ description: "Split string into array by delimiter",
3243
+ example: "${output.field.split(',')}"
3244
+ },
3245
+ {
3246
+ name: "join",
3247
+ displayName: "Join",
3248
+ description: "Join array elements with delimiter",
3249
+ example: "${output.items.join('-')}"
3250
+ },
3251
+ {
3252
+ name: "replace",
3253
+ displayName: "Replace",
3254
+ description: "Replace text in string",
3255
+ example: "${output.field.replace('old', 'new')}"
3256
+ },
3257
+ {
3258
+ name: "concat",
3259
+ displayName: "Concatenate",
3260
+ description: "Join multiple strings together",
3261
+ example: "${output.first + ' ' + output.last}"
3262
+ }
3263
+ ]
3264
+ },
3265
+ cast: {
3266
+ displayName: "Cast Mapping",
3267
+ description: "Convert data from one type to another using JavaScript functions",
3268
+ color: MAPPING_TYPE_COLORS.cast,
3269
+ examples: [
3270
+ {
3271
+ name: "String to Integer",
3272
+ expression: "${parseInt(output.numberString)}",
3273
+ description: "Convert string to integer"
3274
+ },
3275
+ {
3276
+ name: "String to Float",
3277
+ expression: "${parseFloat(output.decimalString)}",
3278
+ description: "Convert string to decimal number"
3279
+ },
3280
+ {
3281
+ name: "To String",
3282
+ expression: "${String(output.value)}",
3283
+ description: "Convert any value to string"
3284
+ },
3285
+ {
3286
+ name: "To Boolean",
3287
+ expression: "${Boolean(output.value)}",
3288
+ description: "Convert to true/false"
3289
+ },
3290
+ {
3291
+ name: "Number with default",
3292
+ expression: "${Number(output.value) || 0}",
3293
+ description: "Convert to number with fallback"
3294
+ },
3295
+ {
3296
+ name: "Parse with radix",
3297
+ expression: "${parseInt(output.hex, 16)}",
3298
+ description: "Parse hexadecimal string"
3299
+ },
3300
+ {
3301
+ name: "Fixed decimals",
3302
+ expression: "${parseFloat(output.price).toFixed(2)}",
3303
+ description: "Format number with 2 decimal places"
3304
+ }
3305
+ ],
3306
+ types: [
3307
+ {
3308
+ name: "parseInt",
3309
+ displayName: "Integer",
3310
+ description: "Convert to whole number",
3311
+ example: "${parseInt(output.field)}"
3312
+ },
3313
+ {
3314
+ name: "parseFloat",
3315
+ displayName: "Float",
3316
+ description: "Convert to decimal number",
3317
+ example: "${parseFloat(output.field)}"
3318
+ },
3319
+ {
3320
+ name: "String",
3321
+ displayName: "String",
3322
+ description: "Convert to text",
3323
+ example: "${String(output.field)}"
3324
+ },
3325
+ {
3326
+ name: "Boolean",
3327
+ displayName: "Boolean",
3328
+ description: "Convert to true/false",
3329
+ example: "${Boolean(output.field)}"
3330
+ },
3331
+ {
3332
+ name: "Number",
3333
+ displayName: "Number",
3334
+ description: "Convert to number",
3335
+ example: "${Number(output.field)}"
3336
+ }
3337
+ ]
3338
+ },
3339
+ array: {
3340
+ displayName: "Array Mapping",
3341
+ description: "Transform arrays using map, filter, reduce and other array methods",
3342
+ color: MAPPING_TYPE_COLORS.array,
3343
+ examples: [
3344
+ {
3345
+ name: "Map - Extract IDs",
3346
+ expression: "${output.users.map(u => u.id)}",
3347
+ description: "Extract a single field from each item"
3348
+ },
3349
+ {
3350
+ name: "Map - Transform objects",
3351
+ expression: "${output.items.map(item => ({ name: item.name, value: item.value }))}",
3352
+ description: "Transform each item to new shape"
3353
+ },
3354
+ {
3355
+ name: "Map - With index",
3356
+ expression: "${output.items.map((item, index) => ({ ...item, position: index + 1 }))}",
3357
+ description: "Include index in transformation"
3358
+ },
3359
+ {
3360
+ name: "Filter - Active users",
3361
+ expression: "${output.users.filter(u => u.active)}",
3362
+ description: "Keep only items matching condition"
3363
+ },
3364
+ {
3365
+ name: "Filter - By value",
3366
+ expression: "${output.items.filter(item => item.price > 100)}",
3367
+ description: "Filter by numeric comparison"
3368
+ },
3369
+ {
3370
+ name: "Filter + Map",
3371
+ expression: "${output.users.filter(u => u.active).map(u => u.id)}",
3372
+ description: "Chain filter and map operations"
3373
+ },
3374
+ {
3375
+ name: "Reduce - Sum",
3376
+ expression: "${output.items.reduce((sum, item) => sum + item.price, 0)}",
3377
+ description: "Calculate total of all prices"
3378
+ },
3379
+ {
3380
+ name: "Reduce - Average",
3381
+ expression: "${output.items.reduce((sum, item) => sum + item.value, 0) / output.items.length}",
3382
+ description: "Calculate average value"
3383
+ },
3384
+ {
3385
+ name: "Reduce - Group by",
3386
+ expression: "${output.items.reduce((acc, item) => ({ ...acc, [item.category]: [...(acc[item.category] || []), item] }), {})}",
3387
+ description: "Group items by category"
3388
+ },
3389
+ {
3390
+ name: "Find - First match",
3391
+ expression: "${output.items.find(item => item.id === TriggerInput.itemId)}",
3392
+ description: "Find first item matching condition"
3393
+ },
3394
+ {
3395
+ name: "Some - Any match",
3396
+ expression: "${output.items.some(item => item.active)}",
3397
+ description: "Check if any item matches"
3398
+ },
3399
+ {
3400
+ name: "Every - All match",
3401
+ expression: "${output.items.every(item => item.valid)}",
3402
+ description: "Check if all items match"
3403
+ },
3404
+ {
3405
+ name: "Flat - Flatten array",
3406
+ expression: "${output.nestedArrays.flat()}",
3407
+ description: "Flatten one level of nesting"
3408
+ },
3409
+ {
3410
+ name: "FlatMap - Map and flatten",
3411
+ expression: "${output.users.flatMap(u => u.permissions)}",
3412
+ description: "Map then flatten results"
3413
+ },
3414
+ {
3415
+ name: "Sort - Ascending",
3416
+ expression: "${[...output.items].sort((a, b) => a.price - b.price)}",
3417
+ description: "Sort items by price ascending"
3418
+ },
3419
+ {
3420
+ name: "Sort - Descending",
3421
+ expression: "${[...output.items].sort((a, b) => b.price - a.price)}",
3422
+ description: "Sort items by price descending"
3423
+ },
3424
+ {
3425
+ name: "Slice - First N",
3426
+ expression: "${output.items.slice(0, 5)}",
3427
+ description: "Get first 5 items"
3428
+ },
3429
+ {
3430
+ name: "Slice - Last N",
3431
+ expression: "${output.items.slice(-3)}",
3432
+ description: "Get last 3 items"
3433
+ },
3434
+ {
3435
+ name: "Unique values",
3436
+ expression: "${[...new Set(output.items.map(i => i.category))]}",
3437
+ description: "Get unique categories"
3438
+ },
3439
+ {
3440
+ name: "Concat arrays",
3441
+ expression: "${output.list1.concat(output.list2)}",
3442
+ description: "Combine two arrays"
3443
+ },
3444
+ {
3445
+ name: "Includes check",
3446
+ expression: "${output.tags.includes('important')}",
3447
+ description: "Check if array contains value"
3448
+ },
3449
+ {
3450
+ name: "Index of",
3451
+ expression: "${output.items.findIndex(i => i.id === 'target')}",
3452
+ description: "Find index of matching item"
3453
+ }
3454
+ ]
3455
+ },
3456
+ object: {
3457
+ displayName: "Object Mapping",
3458
+ description: "Transform and manipulate objects",
3459
+ color: MAPPING_TYPE_COLORS.object,
3460
+ examples: [
3461
+ {
3462
+ name: "Get keys",
3463
+ expression: "${Object.keys(output.metadata)}",
3464
+ description: "Get all property names as array"
3465
+ },
3466
+ {
3467
+ name: "Get values",
3468
+ expression: "${Object.values(output.metadata)}",
3469
+ description: "Get all property values as array"
3470
+ },
3471
+ {
3472
+ name: "Get entries",
3473
+ expression: "${Object.entries(output.metadata)}",
3474
+ description: "Get key-value pairs as array"
3475
+ },
3476
+ {
3477
+ name: "Merge objects",
3478
+ expression: "${Object.assign({}, output.user, output.preferences)}",
3479
+ description: "Combine multiple objects"
3480
+ },
3481
+ {
3482
+ name: "Spread merge",
3483
+ expression: "${{ ...output.defaults, ...output.overrides }}",
3484
+ description: "Merge with spread operator"
3485
+ },
3486
+ {
3487
+ name: "Pick fields",
3488
+ expression: "${({ id: output.user.id, email: output.user.email })}",
3489
+ description: "Select specific fields only"
3490
+ },
3491
+ {
3492
+ name: "From entries",
3493
+ expression: "${Object.fromEntries(output.pairs)}",
3494
+ description: "Create object from key-value pairs"
3495
+ },
3496
+ {
3497
+ name: "Has property",
3498
+ expression: "${'email' in output.user}",
3499
+ description: "Check if property exists"
3500
+ }
3501
+ ]
3502
+ },
3503
+ context: {
3504
+ displayName: "Workflow Context",
3505
+ description: "Access workflow execution context and state from previous nodes",
3506
+ color: MAPPING_TYPE_COLORS.context,
3507
+ examples: [
3508
+ {
3509
+ name: "Trigger input",
3510
+ expression: "${TriggerInput.userId}",
3511
+ description: "Access original trigger payload"
3512
+ },
3513
+ {
3514
+ name: "Trigger nested data",
3515
+ expression: "${TriggerInput.webhookData.eventType}",
3516
+ description: "Access nested trigger data"
3517
+ },
3518
+ {
3519
+ name: "Previous node output",
3520
+ expression: "${WorkflowState.fetch_user.output.name}",
3521
+ description: "Access output from a specific previous node"
3522
+ },
3523
+ {
3524
+ name: "Node status",
3525
+ expression: "${WorkflowState.validate_data.status}",
3526
+ description: "Check status of a previous node"
3527
+ },
3528
+ {
3529
+ name: "Combine node outputs",
3530
+ expression: "${WorkflowState.step1.output.count + WorkflowState.step2.output.count}",
3531
+ description: "Combine data from multiple nodes"
3532
+ },
3533
+ {
3534
+ name: "Run ID",
3535
+ expression: "${RunContext.runId}",
3536
+ description: "Current workflow run identifier"
3537
+ },
3538
+ {
3539
+ name: "Workflow key",
3540
+ expression: "${RunContext.workflowKey}",
3541
+ description: "Workflow definition identifier"
3542
+ },
3543
+ {
3544
+ name: "Tenant ID",
3545
+ expression: "${RunContext.tenantId}",
3546
+ description: "Current tenant identifier"
3547
+ },
3548
+ {
3549
+ name: "Workspace ID",
3550
+ expression: "${RunContext.workspaceId}",
3551
+ description: "Current workspace identifier"
3552
+ },
3553
+ {
3554
+ name: "Triggered at",
3555
+ expression: "${RunContext.triggeredAt}",
3556
+ description: "Workflow trigger timestamp"
3557
+ },
3558
+ {
3559
+ name: "Triggered by",
3560
+ expression: "${RunContext.triggeredBy}",
3561
+ description: "User who triggered the workflow"
3562
+ }
3563
+ ]
3564
+ }
3565
+ },
3566
+ typeCompatibility: {
3567
+ String: ["ID", "String"],
3568
+ ID: ["String", "ID"],
3569
+ Int: [
3570
+ "Float",
3571
+ "Int",
3572
+ "String"
3573
+ ],
3574
+ Float: ["String", "Float"],
3575
+ Boolean: ["Boolean", "String"]
3576
+ },
3577
+ sampleData: {
3578
+ search: { response: [{
3579
+ metadata: {
3580
+ title: "Introduction to Machine Learning",
3581
+ source: "https://example.com/ml-intro",
3582
+ sourceLabel: "Example ML Guide",
3583
+ sourceType: "webpage",
3584
+ sourceInfo: "Educational resource",
3585
+ partition: "default",
3586
+ score: .95,
3587
+ images: ["https://example.com/ml-image.jpg"]
3588
+ },
3589
+ content: "Machine learning is a branch of artificial intelligence..."
3590
+ }, {
3591
+ metadata: {
3592
+ title: "Deep Learning Fundamentals",
3593
+ source: "https://example.com/dl-basics",
3594
+ sourceLabel: "Deep Learning Guide",
3595
+ sourceType: "webpage",
3596
+ sourceInfo: "Technical documentation",
3597
+ partition: "default",
3598
+ score: .87,
3599
+ images: ["https://example.com/dl-image.jpg"]
3600
+ },
3601
+ content: "Deep learning is a subset of machine learning..."
3602
+ }] },
3603
+ insert: {
3604
+ success: true,
3605
+ count: 1
3606
+ }
3607
+ }
3608
+ };
3609
+
3610
+ // src/builder/components/mapper/app.tsx
3611
+ function convertInlineSchemaToGraphQL(inlineSchema, nodeType) {
3612
+ const schema = {
3613
+ types: {},
3614
+ queryType: "Query",
3615
+ mutationType: null,
3616
+ subscriptionType: null
3617
+ };
3618
+ if (inlineSchema.outputFields && inlineSchema.outputFields.length > 0) {
3619
+ const outputFields = {};
3620
+ inlineSchema.outputFields.forEach((field) => {
3621
+ outputFields[field.name] = {
3622
+ name: field.name,
3623
+ type: field.type,
3624
+ isNonNull: field.required || false,
3625
+ isList: field.type.startsWith("["),
3626
+ args: []
3627
+ };
3628
+ });
3629
+ const outputTypeName = `${nodeType}Output`;
3630
+ schema.types[outputTypeName] = {
3631
+ name: outputTypeName,
3632
+ kind: "type",
3633
+ fields: outputFields
3634
+ };
3635
+ schema.types["Query"] = {
3636
+ name: "Query",
3637
+ kind: "type",
3638
+ fields: { execute: {
3639
+ name: "execute",
3640
+ type: outputTypeName,
3641
+ isNonNull: false,
3642
+ isList: false,
3643
+ args: []
3644
+ } }
3645
+ };
3646
+ }
3647
+ if (inlineSchema.inputFields && inlineSchema.inputFields.length > 0) {
3648
+ const inputFields = {};
3649
+ inlineSchema.inputFields.forEach((field) => {
3650
+ inputFields[field.name] = {
3651
+ name: field.name,
3652
+ type: field.type,
3653
+ isNonNull: field.required || false,
3654
+ isList: field.type.startsWith("["),
3655
+ args: []
3656
+ };
3657
+ });
3658
+ const inputTypeName = `${nodeType}Input`;
3659
+ schema.types[inputTypeName] = {
3660
+ name: inputTypeName,
3661
+ kind: "input",
3662
+ fields: {},
3663
+ inputFields
3664
+ };
3665
+ }
3666
+ return schema;
3667
+ }
3668
+ function App({ dataConfig = defaultDataConfig, sourceSchema: propSourceSchema, targetSchema: propTargetSchema, sourceOperation, targetOperation, sourceNode, targetNode, setEdges, edgeId }) {
3669
+ const tr = useTr();
3670
+ const initialParsedSchemas = useMemo(() => {
3671
+ const parsed = {};
3672
+ initializeConfig(parsed, dataConfig);
3673
+ return parsed;
3674
+ }, [dataConfig]);
3675
+ const [parsedSchemas, setParsedSchemas] = useState(initialParsedSchemas);
3676
+ const configInitialized = parsedSchemas === initialParsedSchemas || Object.keys(parsedSchemas).length > 0;
3677
+ const [selectedSourceNode, _setSelectedSourceNode] = useState(sourceNode ?? null);
3678
+ const [selectedSourceOperation, _setSelectedSourceOperation] = useState(sourceOperation ?? null);
3679
+ const [selectedTargetNode, _setSelectedTargetNode] = useState(targetNode ?? null);
3680
+ const [selectedTargetOperation, _setSelectedTargetOperation] = useState(targetOperation ?? null);
3681
+ useEffect(() => {
3682
+ if (configInitialized) {
3683
+ const initializeSchemas = () => {
3684
+ const newParsedSchemas = {};
3685
+ if (propSourceSchema && selectedSourceNode) newParsedSchemas[selectedSourceNode] = propSourceSchema;
3686
+ if (propTargetSchema && selectedTargetNode) newParsedSchemas[selectedTargetNode] = propTargetSchema;
3687
+ Object.keys(dataConfig.nodes).forEach((nodeKey) => {
3688
+ if (!newParsedSchemas[nodeKey]) {
3689
+ const nodeInfo = dataConfig.nodes[nodeKey];
3690
+ if (nodeInfo?.schema && typeof nodeInfo.schema !== "string" && (nodeInfo.schema.inputFields || nodeInfo.schema.outputFields)) newParsedSchemas[nodeKey] = convertInlineSchemaToGraphQL(nodeInfo.schema, nodeKey);
3691
+ else newParsedSchemas[nodeKey] = {
3692
+ types: {},
3693
+ queryType: null,
3694
+ mutationType: null,
3695
+ subscriptionType: null
3696
+ };
3697
+ }
3698
+ });
3699
+ setParsedSchemas((prev) => {
3700
+ return {
3701
+ ...prev,
3702
+ ...newParsedSchemas
3703
+ };
3704
+ });
3705
+ initializeConfig(newParsedSchemas, dataConfig);
3706
+ };
3707
+ initializeSchemas();
3708
+ }
3709
+ }, [
3710
+ configInitialized,
3711
+ dataConfig,
3712
+ propSourceSchema,
3713
+ propTargetSchema,
3714
+ selectedSourceNode,
3715
+ selectedTargetNode
3716
+ ]);
3717
+ const getSchemaForNode = (nodeType, isSource) => {
3718
+ if (!nodeType) return null;
3719
+ if (isSource && propSourceSchema) return propSourceSchema;
3720
+ if (!isSource && propTargetSchema) return propTargetSchema;
3721
+ if (parsedSchemas[nodeType]) return parsedSchemas[nodeType];
3722
+ const nodeInfo = dataConfig.nodes[nodeType];
3723
+ if (nodeInfo) {
3724
+ if (nodeInfo.schema && typeof nodeInfo.schema !== "string" && (nodeInfo.schema.inputFields || nodeInfo.schema.outputFields)) {
3725
+ const convertedSchema = convertInlineSchemaToGraphQL(nodeInfo.schema, nodeType);
3726
+ setParsedSchemas((prev) => ({
3727
+ ...prev,
3728
+ [nodeType]: convertedSchema
3729
+ }));
3730
+ return convertedSchema;
3731
+ }
3732
+ if (typeof nodeInfo.schema === "string") {
3733
+ const parsedSchema = parseGraphQLSchema(nodeInfo.schema);
3734
+ setParsedSchemas((prev) => ({
3735
+ ...prev,
3736
+ [nodeType]: parsedSchema
3737
+ }));
3738
+ return parsedSchema;
3739
+ }
3740
+ }
3741
+ console.warn(`Could not find or parse schema for node type: ${nodeType}`);
3742
+ return null;
3743
+ };
3744
+ const currentSourceSchema = propSourceSchema || getSchemaForNode(selectedSourceNode, true);
3745
+ const currentTargetSchema = propTargetSchema || getSchemaForNode(selectedTargetNode, false);
3746
+ return /* @__PURE__ */ jsx(DataConfigProvider, {
3747
+ config: dataConfig,
3748
+ children: /* @__PURE__ */ jsxs(ThemeProvider$1, {
3749
+ defaultTheme: "light",
3750
+ storageKey: "vite-ui-theme",
3751
+ children: [/* @__PURE__ */ jsx("div", {
3752
+ className: "min-h-screen bg-background",
3753
+ children: /* @__PURE__ */ jsxs("main", {
3754
+ className: "container py-6",
3755
+ children: [currentSourceSchema && currentTargetSchema && selectedSourceNode && selectedSourceOperation && selectedTargetNode && selectedTargetOperation && /* @__PURE__ */ jsxs("div", {
3756
+ className: "mt-8 p-4 border rounded-lg",
3757
+ children: [/* @__PURE__ */ jsx("h2", {
3758
+ className: "text-lg font-medium mb-4",
3759
+ children: tr("fluidgrids.builder.mapperApp.dataMappingHeading", "Data Mapping")
3760
+ }), /* @__PURE__ */ jsx(MappingEditor, {
3761
+ sourceSchema: currentSourceSchema,
3762
+ targetSchema: currentTargetSchema,
3763
+ sourceNode: selectedSourceNode,
3764
+ sourceOperation: selectedSourceOperation,
3765
+ targetNode: selectedTargetNode,
3766
+ targetOperation: selectedTargetOperation,
3767
+ setEdges,
3768
+ edgeId
3769
+ })]
3770
+ }), process.env.NODE_ENV === "development" && /* @__PURE__ */ jsxs("div", {
3771
+ className: "mt-8 p-4 border border-default rounded-lg bg-muted",
3772
+ children: [/* @__PURE__ */ jsx("h3", {
3773
+ className: "text-md font-medium mb-2",
3774
+ children: "Debug Information"
3775
+ }), /* @__PURE__ */ jsxs("div", {
3776
+ className: "text-sm",
3777
+ children: [
3778
+ /* @__PURE__ */ jsxs("p", { children: ["Source Node: ", selectedSourceNode || "None"] }),
3779
+ /* @__PURE__ */ jsxs("p", { children: ["Source Operation: ", selectedSourceOperation || "None"] }),
3780
+ /* @__PURE__ */ jsxs("p", { children: ["Target Node: ", selectedTargetNode || "None"] }),
3781
+ /* @__PURE__ */ jsxs("p", { children: ["Target Operation: ", selectedTargetOperation || "None"] }),
3782
+ /* @__PURE__ */ jsxs("p", { children: [
3783
+ "Source Schema:",
3784
+ " ",
3785
+ currentSourceSchema ? "Available" : "Not available"
3786
+ ] }),
3787
+ /* @__PURE__ */ jsxs("p", { children: [
3788
+ "Target Schema:",
3789
+ " ",
3790
+ currentTargetSchema ? "Available" : "Not available"
3791
+ ] }),
3792
+ /* @__PURE__ */ jsxs("p", { children: [
3793
+ "Parsed Schemas:",
3794
+ " ",
3795
+ Object.keys(parsedSchemas).join(", ") || "None"
3796
+ ] }),
3797
+ /* @__PURE__ */ jsxs("details", { children: [/* @__PURE__ */ jsx("summary", { children: "Schema Details" }), /* @__PURE__ */ jsx("pre", {
3798
+ className: "text-xs mt-2 overflow-auto max-h-[200px]",
3799
+ children: JSON.stringify({
3800
+ sourceSchema: currentSourceSchema ? Object.keys(currentSourceSchema.types).length + " types" : "Not available",
3801
+ targetSchema: currentTargetSchema ? Object.keys(currentTargetSchema.types).length + " types" : "Not available"
3802
+ }, null, 2)
3803
+ })] })
3804
+ ]
3805
+ })]
3806
+ })]
3807
+ })
3808
+ }), /* @__PURE__ */ jsx(Toaster, {})]
3809
+ })
3810
+ });
3811
+ }
3812
+
3813
+ export { App as default };