@datatechsolutions/ui 2.11.43 → 2.11.44

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.
@@ -8,7 +8,7 @@ import { Position, NodeResizer, MarkerType, useReactFlow, getBezierPath, BaseEdg
8
8
  import '@xyflow/react/dist/style.css';
9
9
  import { create } from 'zustand';
10
10
  import { PlusIcon, XMarkIcon } from '@heroicons/react/24/solid';
11
- import { Bars2Icon, CursorArrowRaysIcon, HandRaisedIcon, MagnifyingGlassPlusIcon, MagnifyingGlassMinusIcon, ArrowsPointingInIcon, ArrowUturnLeftIcon, ArrowUturnRightIcon, MapIcon, EllipsisHorizontalIcon, Squares2X2Icon, ArrowsRightLeftIcon, CommandLineIcon, ExclamationTriangleIcon, CpuChipIcon, TrashIcon, WrenchScrewdriverIcon, NewspaperIcon, ChartBarIcon, CloudIcon, ScaleIcon, AdjustmentsHorizontalIcon, CircleStackIcon, PlayIcon, StopIcon, ArrowsPointingOutIcon, CodeBracketIcon, GlobeAltIcon, DocumentTextIcon, ArrowPathIcon, BookOpenIcon, ChatBubbleLeftRightIcon, QuestionMarkCircleIcon, AdjustmentsVerticalIcon, Square3Stack3DIcon, DocumentMagnifyingGlassIcon, ListBulletIcon, PlayCircleIcon, PencilSquareIcon, ServerStackIcon, KeyIcon, RectangleGroupIcon, ChevronDownIcon, ChevronUpIcon, PresentationChartBarIcon, ChartPieIcon, ChartBarSquareIcon, CurrencyDollarIcon, ShieldCheckIcon, ClipboardDocumentCheckIcon, FireIcon, ShoppingBagIcon, UsersIcon, BuildingStorefrontIcon, PencilIcon, DocumentDuplicateIcon, ClipboardDocumentIcon, ClipboardIcon, PlusIcon as PlusIcon$1, XMarkIcon as XMarkIcon$1, CheckIcon, TableCellsIcon, MagnifyingGlassIcon, VariableIcon, FunnelIcon } from '@heroicons/react/24/outline';
11
+ import { Bars2Icon, CursorArrowRaysIcon, HandRaisedIcon, MagnifyingGlassPlusIcon, MagnifyingGlassMinusIcon, ArrowsPointingInIcon, ArrowUturnLeftIcon, ArrowUturnRightIcon, MapIcon, EllipsisHorizontalIcon, Squares2X2Icon, ArrowsRightLeftIcon, CommandLineIcon, ExclamationTriangleIcon, CpuChipIcon, TrashIcon, WrenchScrewdriverIcon, NewspaperIcon, ChartBarIcon, CloudIcon, ScaleIcon, AdjustmentsHorizontalIcon, CircleStackIcon, PlayIcon, StopIcon, ArrowsPointingOutIcon, CodeBracketIcon, GlobeAltIcon, DocumentTextIcon, ArrowPathIcon, BookOpenIcon, ChatBubbleLeftRightIcon, QuestionMarkCircleIcon, AdjustmentsVerticalIcon, Square3Stack3DIcon, DocumentMagnifyingGlassIcon, ListBulletIcon, PlayCircleIcon, PencilSquareIcon, ServerStackIcon, KeyIcon, RectangleGroupIcon, ChevronDownIcon, ChevronUpIcon, PresentationChartBarIcon, ChartPieIcon, ChartBarSquareIcon, CurrencyDollarIcon, ShieldCheckIcon, ClipboardDocumentCheckIcon, FireIcon, ShoppingBagIcon, UsersIcon, BuildingStorefrontIcon, PencilIcon, DocumentDuplicateIcon, ClipboardDocumentIcon, ClipboardIcon, PlusIcon as PlusIcon$1, XMarkIcon as XMarkIcon$1, TableCellsIcon, FunnelIcon, Cog6ToothIcon, VariableIcon, MagnifyingGlassIcon, CheckIcon } from '@heroicons/react/24/outline';
12
12
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
13
13
 
14
14
  var DEFAULT_PASTE_OFFSET = 40;
@@ -1153,6 +1153,481 @@ function getEntityHandleColor(entityKey) {
1153
1153
  function getEntityMinimapColor(entityKey) {
1154
1154
  return presetFromKey(entityKey).minimapColor;
1155
1155
  }
1156
+ var DATASOURCE_LOGOS = {
1157
+ bigquery: "/logos/datasources/bigquery.svg",
1158
+ postgres: "/logos/datasources/postgres.svg",
1159
+ snowflake: "/logos/datasources/snowflake.svg",
1160
+ mongodb: "/logos/datasources/mongodb.svg",
1161
+ redis: "/logos/datasources/redis.svg",
1162
+ mysql: "/logos/datasources/mysql.svg",
1163
+ clickhouse: "/logos/datasources/clickhouse.svg",
1164
+ elasticsearch: "/logos/datasources/elasticsearch.svg",
1165
+ duckdb: "/logos/datasources/duckdb.svg",
1166
+ sqlite: "/logos/datasources/sqlite.svg",
1167
+ mariadb: "/logos/datasources/mariadb.svg",
1168
+ oracle: "/logos/datasources/oracle.svg",
1169
+ mssql: "/logos/datasources/mssql.svg",
1170
+ sqlserver: "/logos/datasources/mssql.svg",
1171
+ cassandra: "/logos/datasources/cassandra.svg",
1172
+ dynamodb: "/logos/datasources/dynamodb.svg",
1173
+ cockroach: "/logos/datasources/cockroachdb.svg",
1174
+ supabase: "/logos/datasources/supabase.svg",
1175
+ firebase: "/logos/datasources/firebase.svg",
1176
+ neo4j: "/logos/datasources/neo4j.svg"
1177
+ };
1178
+ function getDatasourceLogo(datasourceId, dialect) {
1179
+ const search = (dialect ?? datasourceId).toLowerCase();
1180
+ for (const [key, url] of Object.entries(DATASOURCE_LOGOS)) {
1181
+ if (search.includes(key)) return url;
1182
+ }
1183
+ return null;
1184
+ }
1185
+ var TYPE_COLORS = {
1186
+ string: "bg-gray-500/10 text-gray-500 dark:text-gray-400",
1187
+ varchar: "bg-gray-500/10 text-gray-500 dark:text-gray-400",
1188
+ text: "bg-gray-500/10 text-gray-500 dark:text-gray-400",
1189
+ integer: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
1190
+ int: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
1191
+ bigint: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
1192
+ number: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
1193
+ decimal: "bg-indigo-500/10 text-indigo-600 dark:text-indigo-400",
1194
+ float: "bg-indigo-500/10 text-indigo-600 dark:text-indigo-400",
1195
+ boolean: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
1196
+ date: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
1197
+ timestamp: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
1198
+ datetime: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
1199
+ json: "bg-violet-500/10 text-violet-600 dark:text-violet-400",
1200
+ jsonb: "bg-violet-500/10 text-violet-600 dark:text-violet-400",
1201
+ uuid: "bg-teal-500/10 text-teal-600 dark:text-teal-400",
1202
+ array: "bg-pink-500/10 text-pink-600 dark:text-pink-400"
1203
+ };
1204
+ var SIDEBAR_SECTIONS = [
1205
+ { id: "connection", label: "Connection", icon: CircleStackIcon },
1206
+ { id: "table", label: "Table", icon: TableCellsIcon },
1207
+ { id: "columns", label: "Columns", icon: TableCellsIcon },
1208
+ { id: "filters", label: "Filters", icon: FunnelIcon },
1209
+ { id: "output", label: "Output", icon: Cog6ToothIcon }
1210
+ ];
1211
+ function DatasourceNodeConfigForm({
1212
+ open,
1213
+ nodeId,
1214
+ config,
1215
+ onSave,
1216
+ onCancel,
1217
+ datasources,
1218
+ onLoadTables,
1219
+ onLoadSchema
1220
+ }) {
1221
+ const t = useTranslations("agents.workflow.datasourceNodeConfig");
1222
+ const [activeSectionId, setActiveSectionId] = useState("connection");
1223
+ const [selectedDatasourceId, setSelectedDatasourceId] = useState(config.datasourceId ?? "");
1224
+ const [selectedTable, setSelectedTable] = useState(config.table ?? "");
1225
+ const [availableTables, setAvailableTables] = useState([]);
1226
+ const [availableColumns, setAvailableColumns] = useState([]);
1227
+ const [selectedColumns, setSelectedColumns] = useState([...config.selectedColumns ?? []]);
1228
+ const [outputVariable, setOutputVariable] = useState(config.outputVariable);
1229
+ const [limit, setLimit] = useState(config.limit);
1230
+ const [filterVariables, setFilterVariables] = useState({ ...config.filterVariables });
1231
+ const [tableSearch, setTableSearch] = useState("");
1232
+ const [columnSearch, setColumnSearch] = useState("");
1233
+ const allColumnNames = availableColumns.map((column) => column.name);
1234
+ const allSelected = selectedColumns.length > 0 && selectedColumns.length === allColumnNames.length;
1235
+ const selectedDatasource = datasources.find((datasource) => datasource.id === selectedDatasourceId);
1236
+ const filteredTables = useMemo(
1237
+ () => tableSearch ? availableTables.filter((table) => table.toLowerCase().includes(tableSearch.toLowerCase())) : availableTables,
1238
+ [availableTables, tableSearch]
1239
+ );
1240
+ const filteredColumns = useMemo(
1241
+ () => columnSearch ? availableColumns.filter((column) => column.name.toLowerCase().includes(columnSearch.toLowerCase())) : availableColumns,
1242
+ [availableColumns, columnSearch]
1243
+ );
1244
+ const loadTables = useCallback(async (datasourceId) => {
1245
+ if (!datasourceId) {
1246
+ setAvailableTables([]);
1247
+ return;
1248
+ }
1249
+ const tables = await onLoadTables(datasourceId);
1250
+ setAvailableTables(tables);
1251
+ }, [onLoadTables]);
1252
+ const loadSchema = useCallback(async (datasourceId, table) => {
1253
+ if (!datasourceId || !table) {
1254
+ setAvailableColumns([]);
1255
+ return;
1256
+ }
1257
+ const columns = await onLoadSchema(datasourceId, table);
1258
+ setAvailableColumns(columns);
1259
+ }, [onLoadSchema]);
1260
+ useEffect(() => {
1261
+ if (selectedDatasourceId) loadTables(selectedDatasourceId);
1262
+ }, [selectedDatasourceId, loadTables]);
1263
+ useEffect(() => {
1264
+ if (selectedDatasourceId && selectedTable) loadSchema(selectedDatasourceId, selectedTable);
1265
+ }, [selectedDatasourceId, selectedTable, loadSchema]);
1266
+ const handleDatasourceChange = (datasourceId) => {
1267
+ setSelectedDatasourceId(datasourceId);
1268
+ setSelectedTable("");
1269
+ setAvailableTables([]);
1270
+ setAvailableColumns([]);
1271
+ setSelectedColumns([]);
1272
+ setFilterVariables({});
1273
+ setTableSearch("");
1274
+ setColumnSearch("");
1275
+ };
1276
+ const handleTableChange = (table) => {
1277
+ setSelectedTable(table);
1278
+ setAvailableColumns([]);
1279
+ setSelectedColumns([]);
1280
+ setFilterVariables({});
1281
+ setColumnSearch("");
1282
+ };
1283
+ const handleToggleColumn = (columnName) => {
1284
+ setSelectedColumns(
1285
+ (previous) => previous.includes(columnName) ? previous.filter((name) => name !== columnName) : [...previous, columnName]
1286
+ );
1287
+ };
1288
+ const handleAddFilter = () => {
1289
+ setFilterVariables((previous) => ({ ...previous, [`field_${Object.keys(previous).length}`]: "" }));
1290
+ };
1291
+ const handleUpdateFilterVariable = (oldKey, newKey) => {
1292
+ setFilterVariables((previous) => {
1293
+ const updated = { ...previous };
1294
+ const value = updated[oldKey] ?? "";
1295
+ delete updated[oldKey];
1296
+ updated[newKey] = value;
1297
+ return updated;
1298
+ });
1299
+ };
1300
+ const handleUpdateFilterField = (key, newValue) => {
1301
+ setFilterVariables((previous) => ({ ...previous, [key]: newValue }));
1302
+ };
1303
+ const handleRemoveFilter = (key) => {
1304
+ setFilterVariables((previous) => {
1305
+ const updated = { ...previous };
1306
+ delete updated[key];
1307
+ return updated;
1308
+ });
1309
+ };
1310
+ const handleSave = () => {
1311
+ const cleanedFilters = {};
1312
+ for (const [key, value] of Object.entries(filterVariables)) {
1313
+ if (key.trim() && value.trim()) cleanedFilters[key.trim()] = value.trim();
1314
+ }
1315
+ onSave({
1316
+ ...config,
1317
+ datasourceId: selectedDatasourceId,
1318
+ dialect: selectedDatasource?.dialect ?? "",
1319
+ table: selectedTable,
1320
+ selectedColumns,
1321
+ outputVariable: outputVariable.trim(),
1322
+ limit,
1323
+ filterVariables: cleanedFilters
1324
+ });
1325
+ };
1326
+ const filterEntries = Object.entries(filterVariables);
1327
+ const canSave = selectedDatasourceId && selectedTable && selectedColumns.length > 0;
1328
+ function renderSection() {
1329
+ switch (activeSectionId) {
1330
+ case "connection":
1331
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1332
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("datasourceHelp") }),
1333
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: datasources.map((datasource) => {
1334
+ const isSelected = datasource.id === selectedDatasourceId;
1335
+ const logo2 = getDatasourceLogo(datasource.id, datasource.dialect);
1336
+ return /* @__PURE__ */ jsxs(
1337
+ "button",
1338
+ {
1339
+ type: "button",
1340
+ onClick: () => {
1341
+ handleDatasourceChange(datasource.id);
1342
+ setActiveSectionId("table");
1343
+ },
1344
+ className: `flex items-center gap-3 rounded-xl border px-3 py-2.5 text-left transition-all ${isSelected ? "border-cyan-500/50 bg-cyan-500/5 ring-1 ring-cyan-500/20 dark:border-cyan-400/40 dark:bg-cyan-400/5" : "border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm dark:border-white/10 dark:bg-white/[0.03] dark:hover:border-white/20"}`,
1345
+ children: [
1346
+ /* @__PURE__ */ jsx("div", { className: "flex h-9 w-9 shrink-0 items-center justify-center", children: logo2 ? /* @__PURE__ */ jsx("img", { src: logo2, alt: datasource.dialect, className: "h-7 w-7" }) : /* @__PURE__ */ jsx(ServerStackIcon, { className: "h-6 w-6 text-gray-400" }) }),
1347
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1348
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs font-semibold text-gray-900 dark:text-white", children: datasource.name }),
1349
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: datasource.dialect })
1350
+ ] }),
1351
+ isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4 shrink-0 text-cyan-500 dark:text-cyan-400" })
1352
+ ]
1353
+ },
1354
+ datasource.id
1355
+ );
1356
+ }) })
1357
+ ] });
1358
+ case "table":
1359
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1360
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("tableHelp") }),
1361
+ !selectedDatasourceId ? /* @__PURE__ */ jsx("p", { className: "py-8 text-center text-xs text-gray-400", children: t("selectDatasource") }) : /* @__PURE__ */ jsxs("div", { className: "liquid-surface rounded-xl border border-white/30 dark:border-white/10", children: [
1362
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-gray-200/50 px-3 py-2 dark:border-white/5", children: [
1363
+ /* @__PURE__ */ jsx(MagnifyingGlassIcon, { className: "h-3.5 w-3.5 text-gray-400" }),
1364
+ /* @__PURE__ */ jsx(
1365
+ "input",
1366
+ {
1367
+ type: "text",
1368
+ value: tableSearch,
1369
+ onChange: (event) => setTableSearch(event.target.value),
1370
+ placeholder: t("selectTable"),
1371
+ className: "flex-1 bg-transparent text-xs text-gray-900 outline-none placeholder:text-gray-400 dark:text-white dark:placeholder:text-gray-500"
1372
+ }
1373
+ ),
1374
+ availableTables.length > 0 && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400", children: availableTables.length })
1375
+ ] }),
1376
+ /* @__PURE__ */ jsxs("div", { className: "max-h-64 overflow-y-auto p-1", children: [
1377
+ filteredTables.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-[10px] text-gray-400", children: t("noColumnsAvailable") }),
1378
+ filteredTables.map((table) => {
1379
+ const isSelected = table === selectedTable;
1380
+ return /* @__PURE__ */ jsxs(
1381
+ "button",
1382
+ {
1383
+ type: "button",
1384
+ onClick: () => {
1385
+ handleTableChange(table);
1386
+ setActiveSectionId("columns");
1387
+ },
1388
+ className: `flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-xs transition-colors ${isSelected ? "bg-cyan-500/10 font-semibold text-cyan-700 dark:text-cyan-300" : "text-gray-700 hover:bg-gray-100/60 dark:text-gray-300 dark:hover:bg-white/5"}`,
1389
+ children: [
1390
+ /* @__PURE__ */ jsx(TableCellsIcon, { className: "h-3.5 w-3.5 shrink-0 text-gray-400" }),
1391
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: table }),
1392
+ isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-cyan-500" })
1393
+ ]
1394
+ },
1395
+ table
1396
+ );
1397
+ })
1398
+ ] })
1399
+ ] })
1400
+ ] });
1401
+ case "columns":
1402
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1403
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1404
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
1405
+ selectedColumns.length,
1406
+ "/",
1407
+ availableColumns.length,
1408
+ " selected"
1409
+ ] }),
1410
+ /* @__PURE__ */ jsx(
1411
+ "button",
1412
+ {
1413
+ type: "button",
1414
+ onClick: () => setSelectedColumns(allSelected ? [] : [...allColumnNames]),
1415
+ disabled: availableColumns.length === 0,
1416
+ className: "text-[10px] font-semibold text-cyan-600 hover:text-cyan-700 disabled:opacity-40 dark:text-cyan-400",
1417
+ children: allSelected ? t("deselectAll") : t("selectAll")
1418
+ }
1419
+ )
1420
+ ] }),
1421
+ !selectedTable ? /* @__PURE__ */ jsx("p", { className: "py-8 text-center text-xs text-gray-400", children: t("selectTable") }) : /* @__PURE__ */ jsxs("div", { className: "liquid-surface rounded-xl border border-white/30 dark:border-white/10", children: [
1422
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-gray-200/50 px-3 py-2 dark:border-white/5", children: [
1423
+ /* @__PURE__ */ jsx(MagnifyingGlassIcon, { className: "h-3.5 w-3.5 text-gray-400" }),
1424
+ /* @__PURE__ */ jsx(
1425
+ "input",
1426
+ {
1427
+ type: "text",
1428
+ value: columnSearch,
1429
+ onChange: (event) => setColumnSearch(event.target.value),
1430
+ placeholder: "Search columns...",
1431
+ className: "flex-1 bg-transparent text-xs text-gray-900 outline-none placeholder:text-gray-400 dark:text-white dark:placeholder:text-gray-500"
1432
+ }
1433
+ )
1434
+ ] }),
1435
+ /* @__PURE__ */ jsxs("div", { className: "max-h-64 overflow-y-auto p-1", children: [
1436
+ filteredColumns.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-[10px] text-gray-400", children: t("noColumnsAvailable") }),
1437
+ filteredColumns.map((column) => {
1438
+ const isSelected = selectedColumns.includes(column.name);
1439
+ const typeColor = TYPE_COLORS[column.type.toLowerCase()] ?? TYPE_COLORS.string;
1440
+ return /* @__PURE__ */ jsxs(
1441
+ "button",
1442
+ {
1443
+ type: "button",
1444
+ onClick: () => handleToggleColumn(column.name),
1445
+ className: `flex w-full items-center gap-2 rounded-lg px-3 py-1.5 text-left transition-colors ${isSelected ? "bg-cyan-500/8 dark:bg-cyan-400/5" : "hover:bg-gray-100/60 dark:hover:bg-white/5"}`,
1446
+ children: [
1447
+ /* @__PURE__ */ jsx("div", { className: `flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors ${isSelected ? "border-cyan-500 bg-cyan-500 dark:border-cyan-400 dark:bg-cyan-400" : "border-gray-300 dark:border-gray-600"}`, children: isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "h-2.5 w-2.5 text-white" }) }),
1448
+ /* @__PURE__ */ jsxs("span", { className: "flex-1 truncate text-xs text-gray-900 dark:text-white", children: [
1449
+ column.name,
1450
+ column.nullable && /* @__PURE__ */ jsx("span", { className: "ml-1 text-[9px] text-gray-400", children: "?" })
1451
+ ] }),
1452
+ /* @__PURE__ */ jsx("span", { className: `shrink-0 rounded-full px-1.5 py-0.5 text-[9px] font-medium ${typeColor}`, children: column.type })
1453
+ ]
1454
+ },
1455
+ column.name
1456
+ );
1457
+ })
1458
+ ] })
1459
+ ] })
1460
+ ] });
1461
+ case "filters":
1462
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1463
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1464
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("filtersHelp") }),
1465
+ /* @__PURE__ */ jsxs(
1466
+ "button",
1467
+ {
1468
+ type: "button",
1469
+ onClick: handleAddFilter,
1470
+ className: "flex items-center gap-1 text-[10px] font-semibold text-cyan-600 hover:text-cyan-700 dark:text-cyan-400",
1471
+ children: [
1472
+ /* @__PURE__ */ jsx(PlusIcon$1, { className: "h-3 w-3" }),
1473
+ t("addFilter")
1474
+ ]
1475
+ }
1476
+ )
1477
+ ] }),
1478
+ filterEntries.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-8", children: [
1479
+ /* @__PURE__ */ jsx(FunnelIcon, { className: "h-8 w-8 text-gray-300 dark:text-gray-600" }),
1480
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400", children: "No filters configured" }),
1481
+ /* @__PURE__ */ jsxs(
1482
+ "button",
1483
+ {
1484
+ type: "button",
1485
+ onClick: handleAddFilter,
1486
+ className: "flex items-center gap-1 rounded-lg bg-cyan-500/10 px-3 py-1.5 text-[10px] font-semibold text-cyan-600 hover:bg-cyan-500/15 dark:text-cyan-400",
1487
+ children: [
1488
+ /* @__PURE__ */ jsx(PlusIcon$1, { className: "h-3 w-3" }),
1489
+ t("addFilter")
1490
+ ]
1491
+ }
1492
+ )
1493
+ ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-2", children: filterEntries.map(([variableName, columnName], index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-xl border border-gray-200 bg-white px-3 py-2 dark:border-white/10 dark:bg-white/[0.03]", children: [
1494
+ /* @__PURE__ */ jsxs(
1495
+ "select",
1496
+ {
1497
+ value: columnName,
1498
+ onChange: (event) => handleUpdateFilterField(variableName, event.target.value),
1499
+ className: "flex-1 rounded bg-transparent text-xs text-gray-900 outline-none dark:text-white",
1500
+ children: [
1501
+ /* @__PURE__ */ jsx("option", { value: "", children: t("columnName") }),
1502
+ availableColumns.map((column) => /* @__PURE__ */ jsx("option", { value: column.name, children: column.name }, column.name))
1503
+ ]
1504
+ }
1505
+ ),
1506
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold text-gray-400", children: "=" }),
1507
+ /* @__PURE__ */ jsx(
1508
+ "input",
1509
+ {
1510
+ type: "text",
1511
+ value: variableName,
1512
+ onChange: (event) => handleUpdateFilterVariable(variableName, event.target.value),
1513
+ placeholder: t("variableReference"),
1514
+ className: "flex-1 bg-transparent text-xs text-gray-900 outline-none placeholder:text-gray-400 dark:text-white dark:placeholder:text-gray-500"
1515
+ }
1516
+ ),
1517
+ /* @__PURE__ */ jsx(
1518
+ "button",
1519
+ {
1520
+ type: "button",
1521
+ onClick: () => handleRemoveFilter(variableName),
1522
+ className: "shrink-0 rounded-md p-1 text-gray-400 transition-colors hover:bg-red-50 hover:text-red-500 dark:hover:bg-red-900/20",
1523
+ children: /* @__PURE__ */ jsx(XMarkIcon$1, { className: "h-3 w-3" })
1524
+ }
1525
+ )
1526
+ ] }, index)) })
1527
+ ] });
1528
+ case "output":
1529
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
1530
+ /* @__PURE__ */ jsxs("div", { children: [
1531
+ /* @__PURE__ */ jsx("label", { className: "mb-1.5 block text-xs font-medium text-gray-700 dark:text-gray-300", children: t("outputVariableLabel") }),
1532
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-[10px] text-gray-500 dark:text-gray-400", children: t("outputVariableHelp") }),
1533
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-xl border border-gray-200 bg-white px-3 py-2.5 dark:border-white/10 dark:bg-white/[0.03]", children: [
1534
+ /* @__PURE__ */ jsx(VariableIcon, { className: "h-4 w-4 text-gray-400" }),
1535
+ /* @__PURE__ */ jsx(
1536
+ "input",
1537
+ {
1538
+ type: "text",
1539
+ value: outputVariable,
1540
+ onChange: (event) => setOutputVariable(event.target.value),
1541
+ placeholder: "datasourceResult",
1542
+ className: "flex-1 bg-transparent text-sm text-gray-900 outline-none placeholder:text-gray-400 dark:text-white dark:placeholder:text-gray-500"
1543
+ }
1544
+ )
1545
+ ] })
1546
+ ] }),
1547
+ /* @__PURE__ */ jsxs("div", { children: [
1548
+ /* @__PURE__ */ jsx("label", { className: "mb-1.5 block text-xs font-medium text-gray-700 dark:text-gray-300", children: t("limitLabel") }),
1549
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-[10px] text-gray-500 dark:text-gray-400", children: t("limitHelp") }),
1550
+ /* @__PURE__ */ jsx(
1551
+ "input",
1552
+ {
1553
+ type: "number",
1554
+ value: limit,
1555
+ onChange: (event) => setLimit(Math.max(1, Number.parseInt(event.target.value, 10) || 1)),
1556
+ min: 1,
1557
+ max: 1e4,
1558
+ className: "w-32 rounded-xl border border-gray-200 bg-white px-3 py-2.5 text-sm text-gray-900 outline-none focus:border-cyan-400 dark:border-white/10 dark:bg-white/[0.03] dark:text-white"
1559
+ }
1560
+ )
1561
+ ] }),
1562
+ selectedDatasource && selectedTable && /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-cyan-500/20 bg-cyan-500/5 p-3 dark:border-cyan-400/15 dark:bg-cyan-400/5", children: [
1563
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2", children: "Summary" }),
1564
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1 text-xs text-gray-600 dark:text-gray-300", children: [
1565
+ /* @__PURE__ */ jsxs("p", { children: [
1566
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "Source:" }),
1567
+ " ",
1568
+ selectedDatasource.name,
1569
+ " (",
1570
+ selectedDatasource.dialect,
1571
+ ")"
1572
+ ] }),
1573
+ /* @__PURE__ */ jsxs("p", { children: [
1574
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "Table:" }),
1575
+ " ",
1576
+ selectedTable
1577
+ ] }),
1578
+ /* @__PURE__ */ jsxs("p", { children: [
1579
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "Columns:" }),
1580
+ " ",
1581
+ selectedColumns.length,
1582
+ " of ",
1583
+ availableColumns.length
1584
+ ] }),
1585
+ /* @__PURE__ */ jsxs("p", { children: [
1586
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "Filters:" }),
1587
+ " ",
1588
+ filterEntries.length
1589
+ ] }),
1590
+ /* @__PURE__ */ jsxs("p", { children: [
1591
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "Limit:" }),
1592
+ " ",
1593
+ limit
1594
+ ] }),
1595
+ /* @__PURE__ */ jsxs("p", { children: [
1596
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "Output:" }),
1597
+ " ",
1598
+ outputVariable || "\u2014"
1599
+ ] })
1600
+ ] })
1601
+ ] })
1602
+ ] });
1603
+ default:
1604
+ return null;
1605
+ }
1606
+ }
1607
+ const logo = getDatasourceLogo(selectedDatasourceId, selectedDatasource?.dialect);
1608
+ return /* @__PURE__ */ jsx(
1609
+ GlassModal,
1610
+ {
1611
+ open,
1612
+ onClose: onCancel,
1613
+ title: selectedDatasource?.name ?? t("datasourceLabel"),
1614
+ subtitle: selectedTable ? `${selectedDatasource?.dialect} \xB7 ${selectedTable}` : void 0,
1615
+ icon: logo ? /* @__PURE__ */ jsx("img", { src: logo, alt: "", className: "h-5 w-5" }) : /* @__PURE__ */ jsx(ServerStackIcon, { className: "h-5 w-5 text-white" }),
1616
+ gradient: "from-cyan-500 to-blue-600",
1617
+ maxWidth: "3xl",
1618
+ sidebar: {
1619
+ sections: SIDEBAR_SECTIONS,
1620
+ activeSectionId,
1621
+ onSectionChange: setActiveSectionId
1622
+ },
1623
+ footer: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 px-6 py-3", children: [
1624
+ /* @__PURE__ */ jsx(Button, { outline: true, onClick: onCancel, children: t("cancel") }),
1625
+ /* @__PURE__ */ jsx(Button, { color: "cyan", onClick: handleSave, disabled: !canSave, children: t("save") })
1626
+ ] }),
1627
+ children: renderSection()
1628
+ }
1629
+ );
1630
+ }
1156
1631
  function LangChainIcon({ className }) {
1157
1632
  return /* @__PURE__ */ jsx("svg", { role: "img", viewBox: "0 0 24 24", fill: "currentColor", className, "aria-label": "LangChain", children: /* @__PURE__ */ jsx("path", { d: "M6.0988 5.9175C2.7359 5.9175 0 8.6462 0 12s2.736 6.0825 6.0988 6.0825h11.8024C21.2641 18.0825 24 15.3538 24 12s-2.736-6.0825-6.0988-6.0825ZM5.9774 7.851c.493.0124 1.02.2496 1.273.6228.3673.4592.4778 1.0668.8944 1.4932.5604.6118 1.199 1.1505 1.7161 1.802.4892.5954.8386 1.2937 1.1436 1.9975.1244.2335.1257.5202.31.7197.0908.1204.5346.4483.4383.5645.0555.1204.4702.286.3263.4027-.1944.04-.4129.0476-.5616-.1074-.0549.126-.183.0596-.2819.0432a4 4 0 0 0-.025.0736c-.3288.0219-.5754-.3126-.732-.565-.3111-.168-.6642-.2702-.982-.446-.0182.2895.0452.6485-.231.8353-.014.5565.8436.0656.9222.4804-.061.0067-.1286-.0095-.1774.0373-.2239.2172-.4805-.1645-.7385-.007-.3464.174-.3808.3161-.8096.352-.0237-.0359-.0143-.0592.0059-.0811.1207-.1399.1295-.3046.3356-.3643-.2122-.0334-.3899.0833-.5686.1757-.2323.095-.2304-.2141-.5878.0164-.0396-.0322-.0208-.0615.0018-.0864.0908-.1107.2102-.127.345-.1208-.663-.3686-.9751.4507-1.2813.0432-.092.0243-.1265.1068-.1845.1652-.05-.0548-.0123-.1212-.0099-.1857-.0598-.028-.1356-.041-.1179-.1366-.1171-.0395-.1988.0295-.286.0952-.0787-.0608.0532-.1492.0776-.2125.0702-.1216.23-.025.3111-.1126.2306-.1308.552.0814.8155.0455.203.0255.4544-.1825.3526-.39-.2171-.2767-.179-.6386-.1839-.9695-.0268-.1929-.491-.4382-.6252-.6462-.1659-.1873-.295-.4047-.4243-.6182-.4666-.9008-.3198-2.0584-.9077-2.8947-.266.1466-.6125.0774-.8418-.119-.1238.1125-.1292.2598-.139.4161-.297-.2962-.2593-.8559-.022-1.1855.0969-.1302.2127-.2373.342-.3316.0292-.0213.0391-.0419.0385-.0747.1174-.5267.5764-.7391 1.0694-.7267m12.4071.46c.5575 0 1.0806.2159 1.474.6082s.61.9145.61 1.4704c0 .556-.2167 1.078-.61 1.4698v.0006l-.902.8995a2.08 2.08 0 0 1-.8597.5166l-.0164.0047-.0058.0164a2.05 2.05 0 0 1-.474.7308l-.9018.8995c-.3934.3924-.917.6083-1.4745.6083s-1.0806-.216-1.474-.6083c-.813-.8107-.813-2.1294 0-2.9402l.9019-.8995a2.056 2.056 0 0 1 .858-.5143l.017-.0053.0058-.0158a2.07 2.07 0 0 1 .4752-.7337l.9018-.8995c.3934-.3924.9171-.6083 1.4745-.6083zm0 .8965a1.18 1.18 0 0 0-.8388.3462l-.9018.8995a1.181 1.181 0 0 0-.3427.9252l.0053.0572c.0323.2652.149.5044.3374.6917.13.1296.2733.2114.4471.2686a.9.9 0 0 1 .014.1582.884.884 0 0 1-.2609.6304l-.0554.0554c-.3013-.1028-.5525-.253-.7794-.4792a2.06 2.06 0 0 1-.5761-1.0968l-.0099-.0578-.0461.0368a1.1 1.1 0 0 0-.0876.0794l-.9024.8995c-.4623.461-.4623 1.212 0 1.673.2311.2305.535.346.8394.3461.3043 0 .6077-.1156.8388-.3462l.9019-.8995c.4623-.461.4623-1.2113 0-1.673a1.17 1.17 0 0 0-.4367-.2749 1 1 0 0 1-.014-.1611c0-.2591.1023-.505.2901-.6923.3019.1028.57.2694.7962.495.3007.2999.4994.679.5756 1.0968l.0105.0578.0455-.0373a1.1 1.1 0 0 0 .0887-.0794l.902-.8996c.4622-.461.4628-1.2124 0-1.6735a1.18 1.18 0 0 0-.8395-.3462Zm-9.973 5.1567-.0006.0006c-.0793.3078-.1048.8318-.506.847-.033.1776.1228.2445.2655.1874.141-.0645.2081.0508.2557.1657.2177.0317.5394-.0725.5516-.3298-.325-.1867-.4253-.5418-.5662-.8709" }) });
1158
1633
  }
@@ -2838,7 +3313,7 @@ var NoteFlowNode = memo(function NoteFlowNode2({ data, selected }) {
2838
3313
  }
2839
3314
  );
2840
3315
  });
2841
- var DATASOURCE_LOGOS = {
3316
+ var DATASOURCE_LOGOS2 = {
2842
3317
  bigquery: "/logos/datasources/bigquery.svg",
2843
3318
  postgres: "/logos/datasources/postgres.svg",
2844
3319
  snowflake: "/logos/datasources/snowflake.svg",
@@ -2860,9 +3335,9 @@ var DATASOURCE_LOGOS = {
2860
3335
  firebase: "/logos/datasources/firebase.svg",
2861
3336
  neo4j: "/logos/datasources/neo4j.svg"
2862
3337
  };
2863
- function getDatasourceLogo(datasourceId, dialect) {
3338
+ function getDatasourceLogo2(datasourceId, dialect) {
2864
3339
  const search = (dialect ?? datasourceId).toLowerCase();
2865
- for (const [key, url] of Object.entries(DATASOURCE_LOGOS)) {
3340
+ for (const [key, url] of Object.entries(DATASOURCE_LOGOS2)) {
2866
3341
  if (search.includes(key)) return url;
2867
3342
  }
2868
3343
  return null;
@@ -2889,7 +3364,7 @@ var DatasourceFlowNode = memo(function DatasourceFlowNode2({ id, data, selected
2889
3364
  }
2890
3365
  const columnCount = config.selectedColumns?.length ?? 0;
2891
3366
  const filterCount = config.filterVariables ? Object.keys(config.filterVariables).length : 0;
2892
- const logo = getDatasourceLogo(config.datasourceId, config.dialect);
3367
+ const logo = getDatasourceLogo2(config.datasourceId, config.dialect);
2893
3368
  const content = /* @__PURE__ */ jsxs(NodeCard, { compact: isCompact, selected, nodeType: "datasource", children: [
2894
3369
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
2895
3370
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
@@ -4510,331 +4985,54 @@ function ListOperatorNodeConfigForm({ config, onSave, onCancel }) {
4510
4985
  "input",
4511
4986
  {
4512
4987
  type: "text",
4513
- value: condition,
4514
- onChange: (event) => setCondition(event.target.value),
4515
- placeholder: t("conditionPlaceholder"),
4516
- className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
4517
- }
4518
- )
4519
- ] }),
4520
- showSortFields && /* @__PURE__ */ jsxs(Fragment, { children: [
4521
- /* @__PURE__ */ jsxs("div", { children: [
4522
- /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("sortKeyLabel") }),
4523
- /* @__PURE__ */ jsx(
4524
- "input",
4525
- {
4526
- type: "text",
4527
- value: sortKey,
4528
- onChange: (event) => setSortKey(event.target.value),
4529
- placeholder: t("sortKeyPlaceholder"),
4530
- className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
4531
- }
4532
- )
4533
- ] }),
4534
- /* @__PURE__ */ jsxs("div", { children: [
4535
- /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("sortOrderLabel") }),
4536
- /* @__PURE__ */ jsx(
4537
- "select",
4538
- {
4539
- value: sortOrder,
4540
- onChange: (event) => setSortOrder(event.target.value),
4541
- className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500",
4542
- children: SORT_ORDER_OPTIONS.map((order) => /* @__PURE__ */ jsx("option", { value: order, children: t(`sortOrder_${order}`) }, order))
4543
- }
4544
- )
4545
- ] })
4546
- ] }),
4547
- showLimitField && /* @__PURE__ */ jsxs("div", { children: [
4548
- /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("limitCountLabel") }),
4549
- /* @__PURE__ */ jsx(
4550
- "input",
4551
- {
4552
- type: "number",
4553
- value: limitCount,
4554
- onChange: (event) => setLimitCount(Number(event.target.value)),
4555
- min: 1,
4556
- className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
4557
- }
4558
- )
4559
- ] }),
4560
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
4561
- /* @__PURE__ */ jsx(
4562
- "button",
4563
- {
4564
- type: "button",
4565
- onClick: onCancel,
4566
- className: "rounded-lg border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800",
4567
- children: t("cancel")
4568
- }
4569
- ),
4570
- /* @__PURE__ */ jsx(
4571
- "button",
4572
- {
4573
- type: "button",
4574
- onClick: handleSave,
4575
- className: "rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600",
4576
- children: t("save")
4577
- }
4578
- )
4579
- ] })
4580
- ] });
4581
- }
4582
- function IterationStartNodeConfigForm({ config, onSave, onCancel }) {
4583
- const t = useTranslations("agents.workflow.iterationStartNodeConfig");
4584
- const [iteratorVariable, setIteratorVariable] = useState(config.iteratorVariable);
4585
- const [itemVariable, setItemVariable] = useState(config.itemVariable);
4586
- const [indexVariable, setIndexVariable] = useState(config.indexVariable);
4587
- const handleSave = () => {
4588
- onSave({ ...config, iteratorVariable, itemVariable, indexVariable });
4589
- };
4590
- return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
4591
- /* @__PURE__ */ jsx(
4592
- FormInput,
4593
- {
4594
- type: "text",
4595
- label: t("iteratorVariableLabel"),
4596
- value: iteratorVariable,
4597
- onValueChange: setIteratorVariable,
4598
- placeholder: t("iteratorVariablePlaceholder")
4599
- }
4600
- ),
4601
- /* @__PURE__ */ jsx(
4602
- FormInput,
4603
- {
4604
- type: "text",
4605
- label: t("itemVariableLabel"),
4606
- value: itemVariable,
4607
- onValueChange: setItemVariable,
4608
- placeholder: t("itemVariablePlaceholder")
4609
- }
4610
- ),
4611
- /* @__PURE__ */ jsx(
4612
- FormInput,
4613
- {
4614
- type: "text",
4615
- label: t("indexVariableLabel"),
4616
- value: indexVariable,
4617
- onValueChange: setIndexVariable,
4618
- placeholder: t("indexVariablePlaceholder")
4619
- }
4620
- ),
4621
- /* @__PURE__ */ jsx(
4622
- ConfigFormActions,
4623
- {
4624
- cancelLabel: t("cancel"),
4625
- saveLabel: t("save"),
4626
- onCancel,
4627
- onSave: handleSave
4628
- }
4629
- )
4630
- ] });
4631
- }
4632
- var FIELD_TYPE_BADGE_COLORS = {
4633
- string: "bg-gray-100 text-gray-600 dark:bg-gray-500/20 dark:text-gray-300",
4634
- number: "bg-blue-100 text-blue-600 dark:bg-blue-500/20 dark:text-blue-300",
4635
- boolean: "bg-green-100 text-green-600 dark:bg-green-500/20 dark:text-green-300",
4636
- date: "bg-amber-100 text-amber-600 dark:bg-amber-500/20 dark:text-amber-300",
4637
- object: "bg-purple-100 text-purple-600 dark:bg-purple-500/20 dark:text-purple-300",
4638
- array: "bg-teal-100 text-teal-600 dark:bg-teal-500/20 dark:text-teal-300"
4639
- };
4640
- function EntityNodeConfigForm({ config, entities = [], onSave, onCancel }) {
4641
- const t = useTranslations("agents.workflow.entityNodeConfig");
4642
- const [selectedFields, setSelectedFields] = useState([...config.selectedFields]);
4643
- const [outputVariable, setOutputVariable] = useState(config.outputVariable);
4644
- const [limit, setLimit] = useState(config.limit);
4645
- const [filterVariables, setFilterVariables] = useState({ ...config.filterVariables });
4646
- const entityDefinition = useMemo(
4647
- () => entities.find((entity) => entity.id === config.entityMasterId),
4648
- [entities, config.entityMasterId]
4649
- );
4650
- const availableFields = useMemo(() => entityDefinition?.fields ?? [], [entityDefinition]);
4651
- const allFieldNames = useMemo(() => availableFields.map((field) => field.name), [availableFields]);
4652
- const allSelected = selectedFields.length === allFieldNames.length;
4653
- const gradient = getEntityGradient(config.entityMasterId);
4654
- const badgeColor = getEntityBadgeColor(config.entityMasterId);
4655
- const handleToggleSelectAll = () => {
4656
- if (allSelected) {
4657
- setSelectedFields([]);
4658
- } else {
4659
- setSelectedFields([...allFieldNames]);
4660
- }
4661
- };
4662
- const handleToggleField = (fieldName) => {
4663
- setSelectedFields(
4664
- (previous) => previous.includes(fieldName) ? previous.filter((name) => name !== fieldName) : [...previous, fieldName]
4665
- );
4666
- };
4667
- const handleAddFilter = () => {
4668
- setFilterVariables((previous) => ({ ...previous, "": "" }));
4669
- };
4670
- const handleUpdateFilterVariable = (oldKey, newKey) => {
4671
- setFilterVariables((previous) => {
4672
- const updated = { ...previous };
4673
- const value = updated[oldKey] ?? "";
4674
- delete updated[oldKey];
4675
- updated[newKey] = value;
4676
- return updated;
4677
- });
4678
- };
4679
- const handleUpdateFilterField = (key, newValue) => {
4680
- setFilterVariables((previous) => ({ ...previous, [key]: newValue }));
4681
- };
4682
- const handleRemoveFilter = (key) => {
4683
- setFilterVariables((previous) => {
4684
- const updated = { ...previous };
4685
- delete updated[key];
4686
- return updated;
4687
- });
4688
- };
4689
- const handleSave = () => {
4690
- const cleanedFilters = {};
4691
- for (const [key, value] of Object.entries(filterVariables)) {
4692
- if (key.trim() && value.trim()) {
4693
- cleanedFilters[key.trim()] = value.trim();
4694
- }
4695
- }
4696
- onSave({
4697
- ...config,
4698
- selectedFields,
4699
- outputVariable: outputVariable.trim(),
4700
- limit,
4701
- filterVariables: cleanedFilters
4702
- });
4703
- };
4704
- const filterEntries = Object.entries(filterVariables);
4705
- return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
4706
- /* @__PURE__ */ jsxs("div", { children: [
4707
- /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("entityTypeLabel") }),
4708
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4709
- /* @__PURE__ */ jsx("div", { className: `flex h-6 w-6 items-center justify-center rounded-md bg-gradient-to-br ${gradient}`, children: /* @__PURE__ */ jsx("span", { className: "text-[10px] text-white font-bold", children: (entityDefinition?.label ?? config.entityMasterId ?? "?").charAt(0).toUpperCase() }) }),
4710
- /* @__PURE__ */ jsx("span", { className: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${badgeColor}`, children: entityDefinition?.label ?? config.entityMasterId ?? t("entityTypeLabel") })
4711
- ] }),
4712
- !entityDefinition && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-amber-600 dark:text-amber-400", children: t("entityNotConfigured") })
4713
- ] }),
4714
- /* @__PURE__ */ jsxs("div", { children: [
4715
- /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("outputVariableLabel") }),
4716
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-gray-500 dark:text-gray-400", children: t("outputVariableHelp") }),
4717
- /* @__PURE__ */ jsx(
4718
- "input",
4719
- {
4720
- type: "text",
4721
- value: outputVariable,
4722
- onChange: (event) => setOutputVariable(event.target.value),
4723
- placeholder: `${(entityDefinition?.label ?? "entity").replace(/\s+/g, "")}Data`,
4724
- className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
4725
- }
4726
- )
4727
- ] }),
4728
- /* @__PURE__ */ jsxs("div", { children: [
4729
- /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("limitLabel") }),
4730
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-gray-500 dark:text-gray-400", children: t("limitHelp") }),
4731
- /* @__PURE__ */ jsx(
4732
- "input",
4733
- {
4734
- type: "number",
4735
- value: limit,
4736
- onChange: (event) => setLimit(Math.max(1, Number.parseInt(event.target.value, 10) || 1)),
4737
- min: 1,
4738
- max: 1e3,
4739
- className: "w-32 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white"
4988
+ value: condition,
4989
+ onChange: (event) => setCondition(event.target.value),
4990
+ placeholder: t("conditionPlaceholder"),
4991
+ className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
4740
4992
  }
4741
4993
  )
4742
4994
  ] }),
4743
- /* @__PURE__ */ jsxs("div", { children: [
4744
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
4745
- /* @__PURE__ */ jsx("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t("fieldsLabel") }),
4995
+ showSortFields && /* @__PURE__ */ jsxs(Fragment, { children: [
4996
+ /* @__PURE__ */ jsxs("div", { children: [
4997
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("sortKeyLabel") }),
4746
4998
  /* @__PURE__ */ jsx(
4747
- "button",
4748
- {
4749
- type: "button",
4750
- onClick: handleToggleSelectAll,
4751
- className: "text-xs font-medium text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300",
4752
- children: allSelected ? t("deselectAll") : t("selectAll")
4753
- }
4754
- )
4755
- ] }),
4756
- selectedFields.length === 0 && /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-amber-600 dark:text-amber-400", children: t("noFieldsSelected") }),
4757
- /* @__PURE__ */ jsxs("div", { className: "max-h-48 space-y-1 overflow-y-auto rounded-lg border border-gray-200 p-2 dark:border-gray-700", children: [
4758
- availableFields.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-2 py-2 text-xs text-gray-500 dark:text-gray-400", children: t("noFieldsSelected") }),
4759
- availableFields.map((field) => {
4760
- const isSelected = selectedFields.includes(field.name);
4761
- const typeBadgeColor = FIELD_TYPE_BADGE_COLORS[field.type] ?? FIELD_TYPE_BADGE_COLORS.string;
4762
- return /* @__PURE__ */ jsxs(
4763
- "label",
4764
- {
4765
- className: `flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 transition-colors ${isSelected ? "bg-indigo-50 dark:bg-indigo-500/10" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
4766
- children: [
4767
- /* @__PURE__ */ jsx(
4768
- "input",
4769
- {
4770
- type: "checkbox",
4771
- checked: isSelected,
4772
- onChange: () => handleToggleField(field.name),
4773
- className: "h-3.5 w-3.5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 dark:border-gray-600"
4774
- }
4775
- ),
4776
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-xs font-medium text-gray-900 dark:text-white", children: field.name }),
4777
- /* @__PURE__ */ jsx("span", { className: `rounded-full px-1.5 py-0.5 text-[9px] font-medium ${typeBadgeColor}`, children: field.type })
4778
- ]
4779
- },
4780
- field.name
4781
- );
4782
- })
4783
- ] })
4784
- ] }),
4785
- /* @__PURE__ */ jsxs("div", { children: [
4786
- /* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center justify-between", children: [
4787
- /* @__PURE__ */ jsx("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t("filtersLabel") }),
4788
- /* @__PURE__ */ jsxs(
4789
- "button",
4999
+ "input",
4790
5000
  {
4791
- type: "button",
4792
- onClick: handleAddFilter,
4793
- className: "flex items-center gap-1 text-xs font-medium text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300",
4794
- children: [
4795
- /* @__PURE__ */ jsx(PlusIcon$1, { className: "h-3 w-3" }),
4796
- t("addFilter")
4797
- ]
5001
+ type: "text",
5002
+ value: sortKey,
5003
+ onChange: (event) => setSortKey(event.target.value),
5004
+ placeholder: t("sortKeyPlaceholder"),
5005
+ className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
4798
5006
  }
4799
5007
  )
4800
5008
  ] }),
4801
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-gray-500 dark:text-gray-400", children: t("filtersHelp") }),
4802
- filterEntries.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: filterEntries.map(([variableName, fieldName], index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5009
+ /* @__PURE__ */ jsxs("div", { children: [
5010
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("sortOrderLabel") }),
4803
5011
  /* @__PURE__ */ jsx(
4804
- "input",
4805
- {
4806
- type: "text",
4807
- value: variableName,
4808
- onChange: (event) => handleUpdateFilterVariable(variableName, event.target.value),
4809
- placeholder: t("variableName"),
4810
- className: "flex-1 rounded-lg border border-gray-300 bg-white px-2 py-1.5 text-xs text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-1 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
4811
- }
4812
- ),
4813
- /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: "\u2192" }),
4814
- /* @__PURE__ */ jsxs(
4815
5012
  "select",
4816
5013
  {
4817
- value: fieldName,
4818
- onChange: (event) => handleUpdateFilterField(variableName, event.target.value),
4819
- className: "flex-1 rounded-lg border border-gray-300 bg-white px-2 py-1.5 text-xs text-gray-900 outline-none focus:border-indigo-400 focus:ring-1 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white",
4820
- children: [
4821
- /* @__PURE__ */ jsx("option", { value: "", children: t("fieldName") }),
4822
- availableFields.map((field) => /* @__PURE__ */ jsx("option", { value: field.name, children: field.name }, field.name))
4823
- ]
4824
- }
4825
- ),
4826
- /* @__PURE__ */ jsx(
4827
- "button",
4828
- {
4829
- type: "button",
4830
- onClick: () => handleRemoveFilter(variableName),
4831
- className: "rounded-md p-1 text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20",
4832
- children: /* @__PURE__ */ jsx(XMarkIcon$1, { className: "h-3.5 w-3.5" })
5014
+ value: sortOrder,
5015
+ onChange: (event) => setSortOrder(event.target.value),
5016
+ className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500",
5017
+ children: SORT_ORDER_OPTIONS.map((order) => /* @__PURE__ */ jsx("option", { value: order, children: t(`sortOrder_${order}`) }, order))
4833
5018
  }
4834
5019
  )
4835
- ] }, index)) })
5020
+ ] })
4836
5021
  ] }),
4837
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 border-t border-gray-200 pt-4 dark:border-gray-700", children: [
5022
+ showLimitField && /* @__PURE__ */ jsxs("div", { children: [
5023
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("limitCountLabel") }),
5024
+ /* @__PURE__ */ jsx(
5025
+ "input",
5026
+ {
5027
+ type: "number",
5028
+ value: limitCount,
5029
+ onChange: (event) => setLimitCount(Number(event.target.value)),
5030
+ min: 1,
5031
+ className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
5032
+ }
5033
+ )
5034
+ ] }),
5035
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
4838
5036
  /* @__PURE__ */ jsx(
4839
5037
  "button",
4840
5038
  {
@@ -4849,149 +5047,100 @@ function EntityNodeConfigForm({ config, entities = [], onSave, onCancel }) {
4849
5047
  {
4850
5048
  type: "button",
4851
5049
  onClick: handleSave,
4852
- disabled: selectedFields.length === 0,
4853
- className: "rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-indigo-500 dark:hover:bg-indigo-600",
5050
+ className: "rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600",
4854
5051
  children: t("save")
4855
5052
  }
4856
5053
  )
4857
5054
  ] })
4858
5055
  ] });
4859
5056
  }
4860
- var DATASOURCE_LOGOS2 = {
4861
- bigquery: "/logos/datasources/bigquery.svg",
4862
- postgres: "/logos/datasources/postgres.svg",
4863
- snowflake: "/logos/datasources/snowflake.svg",
4864
- mongodb: "/logos/datasources/mongodb.svg",
4865
- redis: "/logos/datasources/redis.svg",
4866
- mysql: "/logos/datasources/mysql.svg",
4867
- clickhouse: "/logos/datasources/clickhouse.svg",
4868
- elasticsearch: "/logos/datasources/elasticsearch.svg",
4869
- duckdb: "/logos/datasources/duckdb.svg",
4870
- sqlite: "/logos/datasources/sqlite.svg",
4871
- mariadb: "/logos/datasources/mariadb.svg",
4872
- oracle: "/logos/datasources/oracle.svg",
4873
- mssql: "/logos/datasources/mssql.svg",
4874
- sqlserver: "/logos/datasources/mssql.svg",
4875
- cassandra: "/logos/datasources/cassandra.svg",
4876
- dynamodb: "/logos/datasources/dynamodb.svg",
4877
- cockroach: "/logos/datasources/cockroachdb.svg",
4878
- supabase: "/logos/datasources/supabase.svg",
4879
- firebase: "/logos/datasources/firebase.svg",
4880
- neo4j: "/logos/datasources/neo4j.svg"
4881
- };
4882
- function getDatasourceLogo2(datasourceId, dialect) {
4883
- const search = (dialect ?? datasourceId).toLowerCase();
4884
- for (const [key, url] of Object.entries(DATASOURCE_LOGOS2)) {
4885
- if (search.includes(key)) return url;
4886
- }
4887
- return null;
4888
- }
4889
- var TYPE_COLORS = {
4890
- string: "bg-gray-500/10 text-gray-500 dark:text-gray-400",
4891
- varchar: "bg-gray-500/10 text-gray-500 dark:text-gray-400",
4892
- text: "bg-gray-500/10 text-gray-500 dark:text-gray-400",
4893
- integer: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
4894
- int: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
4895
- bigint: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
4896
- number: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
4897
- decimal: "bg-indigo-500/10 text-indigo-600 dark:text-indigo-400",
4898
- float: "bg-indigo-500/10 text-indigo-600 dark:text-indigo-400",
4899
- boolean: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
4900
- date: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
4901
- timestamp: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
4902
- datetime: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
4903
- json: "bg-violet-500/10 text-violet-600 dark:text-violet-400",
4904
- jsonb: "bg-violet-500/10 text-violet-600 dark:text-violet-400",
4905
- uuid: "bg-teal-500/10 text-teal-600 dark:text-teal-400",
4906
- array: "bg-pink-500/10 text-pink-600 dark:text-pink-400"
4907
- };
4908
- function SectionHeader({ icon: Icon, title, badge }) {
4909
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
4910
- /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-gray-400 dark:text-gray-500" }),
4911
- /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400", children: title }),
4912
- badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-auto rounded-full bg-indigo-500/10 px-2 py-0.5 text-[10px] font-semibold text-indigo-600 dark:text-indigo-400", children: badge })
5057
+ function IterationStartNodeConfigForm({ config, onSave, onCancel }) {
5058
+ const t = useTranslations("agents.workflow.iterationStartNodeConfig");
5059
+ const [iteratorVariable, setIteratorVariable] = useState(config.iteratorVariable);
5060
+ const [itemVariable, setItemVariable] = useState(config.itemVariable);
5061
+ const [indexVariable, setIndexVariable] = useState(config.indexVariable);
5062
+ const handleSave = () => {
5063
+ onSave({ ...config, iteratorVariable, itemVariable, indexVariable });
5064
+ };
5065
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
5066
+ /* @__PURE__ */ jsx(
5067
+ FormInput,
5068
+ {
5069
+ type: "text",
5070
+ label: t("iteratorVariableLabel"),
5071
+ value: iteratorVariable,
5072
+ onValueChange: setIteratorVariable,
5073
+ placeholder: t("iteratorVariablePlaceholder")
5074
+ }
5075
+ ),
5076
+ /* @__PURE__ */ jsx(
5077
+ FormInput,
5078
+ {
5079
+ type: "text",
5080
+ label: t("itemVariableLabel"),
5081
+ value: itemVariable,
5082
+ onValueChange: setItemVariable,
5083
+ placeholder: t("itemVariablePlaceholder")
5084
+ }
5085
+ ),
5086
+ /* @__PURE__ */ jsx(
5087
+ FormInput,
5088
+ {
5089
+ type: "text",
5090
+ label: t("indexVariableLabel"),
5091
+ value: indexVariable,
5092
+ onValueChange: setIndexVariable,
5093
+ placeholder: t("indexVariablePlaceholder")
5094
+ }
5095
+ ),
5096
+ /* @__PURE__ */ jsx(
5097
+ ConfigFormActions,
5098
+ {
5099
+ cancelLabel: t("cancel"),
5100
+ saveLabel: t("save"),
5101
+ onCancel,
5102
+ onSave: handleSave
5103
+ }
5104
+ )
4913
5105
  ] });
4914
5106
  }
4915
- function DatasourceNodeConfigForm({
4916
- nodeId,
4917
- config,
4918
- onSave,
4919
- onCancel,
4920
- datasources,
4921
- onLoadTables,
4922
- onLoadSchema
4923
- }) {
4924
- const t = useTranslations("agents.workflow.datasourceNodeConfig");
4925
- const [selectedDatasourceId, setSelectedDatasourceId] = useState(config.datasourceId ?? "");
4926
- const [selectedTable, setSelectedTable] = useState(config.table ?? "");
4927
- const [availableTables, setAvailableTables] = useState([]);
4928
- const [availableColumns, setAvailableColumns] = useState([]);
4929
- const [selectedColumns, setSelectedColumns] = useState([...config.selectedColumns ?? []]);
4930
- const [outputVariable, setOutputVariable] = useState(config.outputVariable);
4931
- const [limit, setLimit] = useState(config.limit);
4932
- const [filterVariables, setFilterVariables] = useState({ ...config.filterVariables });
4933
- const [tableSearch, setTableSearch] = useState("");
4934
- const [columnSearch, setColumnSearch] = useState("");
4935
- const allColumnNames = availableColumns.map((column) => column.name);
4936
- const allSelected = selectedColumns.length > 0 && selectedColumns.length === allColumnNames.length;
4937
- const selectedDatasource = datasources.find((datasource) => datasource.id === selectedDatasourceId);
4938
- const filteredTables = useMemo(
4939
- () => tableSearch ? availableTables.filter((table) => table.toLowerCase().includes(tableSearch.toLowerCase())) : availableTables,
4940
- [availableTables, tableSearch]
4941
- );
4942
- const filteredColumns = useMemo(
4943
- () => columnSearch ? availableColumns.filter((column) => column.name.toLowerCase().includes(columnSearch.toLowerCase())) : availableColumns,
4944
- [availableColumns, columnSearch]
5107
+ var FIELD_TYPE_BADGE_COLORS = {
5108
+ string: "bg-gray-100 text-gray-600 dark:bg-gray-500/20 dark:text-gray-300",
5109
+ number: "bg-blue-100 text-blue-600 dark:bg-blue-500/20 dark:text-blue-300",
5110
+ boolean: "bg-green-100 text-green-600 dark:bg-green-500/20 dark:text-green-300",
5111
+ date: "bg-amber-100 text-amber-600 dark:bg-amber-500/20 dark:text-amber-300",
5112
+ object: "bg-purple-100 text-purple-600 dark:bg-purple-500/20 dark:text-purple-300",
5113
+ array: "bg-teal-100 text-teal-600 dark:bg-teal-500/20 dark:text-teal-300"
5114
+ };
5115
+ function EntityNodeConfigForm({ config, entities = [], onSave, onCancel }) {
5116
+ const t = useTranslations("agents.workflow.entityNodeConfig");
5117
+ const [selectedFields, setSelectedFields] = useState([...config.selectedFields]);
5118
+ const [outputVariable, setOutputVariable] = useState(config.outputVariable);
5119
+ const [limit, setLimit] = useState(config.limit);
5120
+ const [filterVariables, setFilterVariables] = useState({ ...config.filterVariables });
5121
+ const entityDefinition = useMemo(
5122
+ () => entities.find((entity) => entity.id === config.entityMasterId),
5123
+ [entities, config.entityMasterId]
4945
5124
  );
4946
- const loadTables = useCallback(async (datasourceId) => {
4947
- if (!datasourceId) {
4948
- setAvailableTables([]);
4949
- return;
4950
- }
4951
- const tables = await onLoadTables(datasourceId);
4952
- setAvailableTables(tables);
4953
- }, [onLoadTables]);
4954
- const loadSchema = useCallback(async (datasourceId, table) => {
4955
- if (!datasourceId || !table) {
4956
- setAvailableColumns([]);
4957
- return;
4958
- }
4959
- const columns = await onLoadSchema(datasourceId, table);
4960
- setAvailableColumns(columns);
4961
- }, [onLoadSchema]);
4962
- useEffect(() => {
4963
- if (selectedDatasourceId) loadTables(selectedDatasourceId);
4964
- }, [selectedDatasourceId, loadTables]);
4965
- useEffect(() => {
4966
- if (selectedDatasourceId && selectedTable) loadSchema(selectedDatasourceId, selectedTable);
4967
- }, [selectedDatasourceId, selectedTable, loadSchema]);
4968
- const handleDatasourceChange = (datasourceId) => {
4969
- setSelectedDatasourceId(datasourceId);
4970
- setSelectedTable("");
4971
- setAvailableTables([]);
4972
- setAvailableColumns([]);
4973
- setSelectedColumns([]);
4974
- setFilterVariables({});
4975
- setTableSearch("");
4976
- setColumnSearch("");
4977
- };
4978
- const handleTableChange = (table) => {
4979
- setSelectedTable(table);
4980
- setAvailableColumns([]);
4981
- setSelectedColumns([]);
4982
- setFilterVariables({});
4983
- setColumnSearch("");
4984
- };
5125
+ const availableFields = useMemo(() => entityDefinition?.fields ?? [], [entityDefinition]);
5126
+ const allFieldNames = useMemo(() => availableFields.map((field) => field.name), [availableFields]);
5127
+ const allSelected = selectedFields.length === allFieldNames.length;
5128
+ const gradient = getEntityGradient(config.entityMasterId);
5129
+ const badgeColor = getEntityBadgeColor(config.entityMasterId);
4985
5130
  const handleToggleSelectAll = () => {
4986
- setSelectedColumns(allSelected ? [] : [...allColumnNames]);
5131
+ if (allSelected) {
5132
+ setSelectedFields([]);
5133
+ } else {
5134
+ setSelectedFields([...allFieldNames]);
5135
+ }
4987
5136
  };
4988
- const handleToggleColumn = (columnName) => {
4989
- setSelectedColumns(
4990
- (previous) => previous.includes(columnName) ? previous.filter((name) => name !== columnName) : [...previous, columnName]
5137
+ const handleToggleField = (fieldName) => {
5138
+ setSelectedFields(
5139
+ (previous) => previous.includes(fieldName) ? previous.filter((name) => name !== fieldName) : [...previous, fieldName]
4991
5140
  );
4992
5141
  };
4993
5142
  const handleAddFilter = () => {
4994
- setFilterVariables((previous) => ({ ...previous, [`field_${Object.keys(previous).length}`]: "" }));
5143
+ setFilterVariables((previous) => ({ ...previous, "": "" }));
4995
5144
  };
4996
5145
  const handleUpdateFilterVariable = (oldKey, newKey) => {
4997
5146
  setFilterVariables((previous) => {
@@ -5015,185 +5164,108 @@ function DatasourceNodeConfigForm({
5015
5164
  const handleSave = () => {
5016
5165
  const cleanedFilters = {};
5017
5166
  for (const [key, value] of Object.entries(filterVariables)) {
5018
- if (key.trim() && value.trim()) cleanedFilters[key.trim()] = value.trim();
5167
+ if (key.trim() && value.trim()) {
5168
+ cleanedFilters[key.trim()] = value.trim();
5169
+ }
5019
5170
  }
5020
5171
  onSave({
5021
5172
  ...config,
5022
- datasourceId: selectedDatasourceId,
5023
- dialect: selectedDatasource?.dialect ?? "",
5024
- table: selectedTable,
5025
- selectedColumns,
5173
+ selectedFields,
5026
5174
  outputVariable: outputVariable.trim(),
5027
5175
  limit,
5028
5176
  filterVariables: cleanedFilters
5029
5177
  });
5030
5178
  };
5031
5179
  const filterEntries = Object.entries(filterVariables);
5032
- return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
5180
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
5033
5181
  /* @__PURE__ */ jsxs("div", { children: [
5034
- /* @__PURE__ */ jsx(SectionHeader, { icon: CircleStackIcon, title: t("datasourceLabel"), badge: datasources.length }),
5035
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: datasources.map((datasource) => {
5036
- const isSelected = datasource.id === selectedDatasourceId;
5037
- const logo = getDatasourceLogo2(datasource.id, datasource.dialect);
5038
- return /* @__PURE__ */ jsxs(
5039
- "button",
5040
- {
5041
- type: "button",
5042
- onClick: () => handleDatasourceChange(datasource.id),
5043
- className: `flex items-center gap-3 rounded-xl border px-3 py-2.5 text-left transition-all ${isSelected ? "border-cyan-500/50 bg-cyan-500/5 ring-1 ring-cyan-500/20 dark:border-cyan-400/40 dark:bg-cyan-400/5" : "border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm dark:border-white/10 dark:bg-white/[0.03] dark:hover:border-white/20"}`,
5044
- children: [
5045
- /* @__PURE__ */ jsx("div", { className: "flex h-9 w-9 shrink-0 items-center justify-center", children: logo ? /* @__PURE__ */ jsx("img", { src: logo, alt: datasource.dialect, className: "h-7 w-7" }) : /* @__PURE__ */ jsx(ServerStackIcon, { className: "h-6 w-6 text-gray-400" }) }),
5046
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
5047
- /* @__PURE__ */ jsx("p", { className: "truncate text-xs font-semibold text-gray-900 dark:text-white", children: datasource.name }),
5048
- /* @__PURE__ */ jsx("p", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: datasource.dialect })
5049
- ] }),
5050
- isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4 shrink-0 text-cyan-500 dark:text-cyan-400" })
5051
- ]
5052
- },
5053
- datasource.id
5054
- );
5055
- }) })
5182
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("entityTypeLabel") }),
5183
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5184
+ /* @__PURE__ */ jsx("div", { className: `flex h-6 w-6 items-center justify-center rounded-md bg-gradient-to-br ${gradient}`, children: /* @__PURE__ */ jsx("span", { className: "text-[10px] text-white font-bold", children: (entityDefinition?.label ?? config.entityMasterId ?? "?").charAt(0).toUpperCase() }) }),
5185
+ /* @__PURE__ */ jsx("span", { className: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${badgeColor}`, children: entityDefinition?.label ?? config.entityMasterId ?? t("entityTypeLabel") })
5186
+ ] }),
5187
+ !entityDefinition && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-amber-600 dark:text-amber-400", children: t("entityNotConfigured") })
5056
5188
  ] }),
5057
- selectedDatasourceId && /* @__PURE__ */ jsxs("div", { children: [
5058
- /* @__PURE__ */ jsx(SectionHeader, { icon: TableCellsIcon, title: t("tableLabel"), badge: availableTables.length || void 0 }),
5059
- /* @__PURE__ */ jsxs("div", { className: "liquid-surface rounded-xl border border-white/30 dark:border-white/10", children: [
5060
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-gray-200/50 px-3 py-2 dark:border-white/5", children: [
5061
- /* @__PURE__ */ jsx(MagnifyingGlassIcon, { className: "h-3.5 w-3.5 text-gray-400" }),
5062
- /* @__PURE__ */ jsx(
5063
- "input",
5064
- {
5065
- type: "text",
5066
- value: tableSearch,
5067
- onChange: (event) => setTableSearch(event.target.value),
5068
- placeholder: t("selectTable"),
5069
- className: "flex-1 bg-transparent text-xs text-gray-900 outline-none placeholder:text-gray-400 dark:text-white dark:placeholder:text-gray-500"
5070
- }
5071
- )
5072
- ] }),
5073
- /* @__PURE__ */ jsxs("div", { className: "max-h-36 overflow-y-auto p-1", children: [
5074
- filteredTables.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-center text-[10px] text-gray-400", children: availableTables.length === 0 ? t("noColumnsAvailable") : "No matches" }),
5075
- filteredTables.map((table) => {
5076
- const isSelected = table === selectedTable;
5077
- return /* @__PURE__ */ jsxs(
5078
- "button",
5079
- {
5080
- type: "button",
5081
- onClick: () => handleTableChange(table),
5082
- className: `flex w-full items-center gap-2 rounded-lg px-3 py-1.5 text-left text-xs transition-colors ${isSelected ? "bg-cyan-500/10 font-semibold text-cyan-700 dark:text-cyan-300" : "text-gray-700 hover:bg-gray-100/60 dark:text-gray-300 dark:hover:bg-white/5"}`,
5083
- children: [
5084
- /* @__PURE__ */ jsx(TableCellsIcon, { className: "h-3 w-3 shrink-0 text-gray-400" }),
5085
- /* @__PURE__ */ jsx("span", { className: "truncate", children: table }),
5086
- isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "ml-auto h-3 w-3 shrink-0 text-cyan-500" })
5087
- ]
5088
- },
5089
- table
5090
- );
5091
- })
5092
- ] })
5093
- ] })
5189
+ /* @__PURE__ */ jsxs("div", { children: [
5190
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("outputVariableLabel") }),
5191
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-gray-500 dark:text-gray-400", children: t("outputVariableHelp") }),
5192
+ /* @__PURE__ */ jsx(
5193
+ "input",
5194
+ {
5195
+ type: "text",
5196
+ value: outputVariable,
5197
+ onChange: (event) => setOutputVariable(event.target.value),
5198
+ placeholder: `${(entityDefinition?.label ?? "entity").replace(/\s+/g, "")}Data`,
5199
+ className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
5200
+ }
5201
+ )
5094
5202
  ] }),
5095
- selectedTable && /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-3", children: [
5096
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
5097
- /* @__PURE__ */ jsx("label", { className: "mb-1 block text-[10px] font-medium text-gray-500 dark:text-gray-400", children: t("outputVariableLabel") }),
5098
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2 dark:border-white/10 dark:bg-white/[0.03]", children: [
5099
- /* @__PURE__ */ jsx(VariableIcon, { className: "h-3.5 w-3.5 text-gray-400" }),
5100
- /* @__PURE__ */ jsx(
5101
- "input",
5102
- {
5103
- type: "text",
5104
- value: outputVariable,
5105
- onChange: (event) => setOutputVariable(event.target.value),
5106
- placeholder: "datasourceResult",
5107
- className: "flex-1 bg-transparent text-xs text-gray-900 outline-none placeholder:text-gray-400 dark:text-white dark:placeholder:text-gray-500"
5108
- }
5109
- )
5110
- ] })
5111
- ] }),
5112
- /* @__PURE__ */ jsxs("div", { className: "w-24", children: [
5113
- /* @__PURE__ */ jsx("label", { className: "mb-1 block text-[10px] font-medium text-gray-500 dark:text-gray-400", children: t("limitLabel") }),
5114
- /* @__PURE__ */ jsx(
5115
- "input",
5116
- {
5117
- type: "number",
5118
- value: limit,
5119
- onChange: (event) => setLimit(Math.max(1, Number.parseInt(event.target.value, 10) || 1)),
5120
- min: 1,
5121
- max: 1e4,
5122
- className: "w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-xs text-gray-900 outline-none focus:border-cyan-400 dark:border-white/10 dark:bg-white/[0.03] dark:text-white"
5123
- }
5124
- )
5125
- ] })
5203
+ /* @__PURE__ */ jsxs("div", { children: [
5204
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300", children: t("limitLabel") }),
5205
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-gray-500 dark:text-gray-400", children: t("limitHelp") }),
5206
+ /* @__PURE__ */ jsx(
5207
+ "input",
5208
+ {
5209
+ type: "number",
5210
+ value: limit,
5211
+ onChange: (event) => setLimit(Math.max(1, Number.parseInt(event.target.value, 10) || 1)),
5212
+ min: 1,
5213
+ max: 1e3,
5214
+ className: "w-32 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 outline-none focus:border-indigo-400 focus:ring-2 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white"
5215
+ }
5216
+ )
5126
5217
  ] }),
5127
- selectedTable && /* @__PURE__ */ jsxs("div", { children: [
5128
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
5129
- /* @__PURE__ */ jsx(
5130
- SectionHeader,
5131
- {
5132
- icon: TableCellsIcon,
5133
- title: t("columnsLabel"),
5134
- badge: `${selectedColumns.length}/${availableColumns.length}`
5135
- }
5136
- ),
5218
+ /* @__PURE__ */ jsxs("div", { children: [
5219
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
5220
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t("fieldsLabel") }),
5137
5221
  /* @__PURE__ */ jsx(
5138
5222
  "button",
5139
5223
  {
5140
5224
  type: "button",
5141
5225
  onClick: handleToggleSelectAll,
5142
- disabled: availableColumns.length === 0,
5143
- className: "text-[10px] font-semibold text-cyan-600 hover:text-cyan-700 disabled:opacity-40 dark:text-cyan-400 dark:hover:text-cyan-300",
5226
+ className: "text-xs font-medium text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300",
5144
5227
  children: allSelected ? t("deselectAll") : t("selectAll")
5145
5228
  }
5146
5229
  )
5147
5230
  ] }),
5148
- /* @__PURE__ */ jsxs("div", { className: "liquid-surface rounded-xl border border-white/30 dark:border-white/10", children: [
5149
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-gray-200/50 px-3 py-2 dark:border-white/5", children: [
5150
- /* @__PURE__ */ jsx(MagnifyingGlassIcon, { className: "h-3.5 w-3.5 text-gray-400" }),
5151
- /* @__PURE__ */ jsx(
5152
- "input",
5231
+ selectedFields.length === 0 && /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-amber-600 dark:text-amber-400", children: t("noFieldsSelected") }),
5232
+ /* @__PURE__ */ jsxs("div", { className: "max-h-48 space-y-1 overflow-y-auto rounded-lg border border-gray-200 p-2 dark:border-gray-700", children: [
5233
+ availableFields.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-2 py-2 text-xs text-gray-500 dark:text-gray-400", children: t("noFieldsSelected") }),
5234
+ availableFields.map((field) => {
5235
+ const isSelected = selectedFields.includes(field.name);
5236
+ const typeBadgeColor = FIELD_TYPE_BADGE_COLORS[field.type] ?? FIELD_TYPE_BADGE_COLORS.string;
5237
+ return /* @__PURE__ */ jsxs(
5238
+ "label",
5153
5239
  {
5154
- type: "text",
5155
- value: columnSearch,
5156
- onChange: (event) => setColumnSearch(event.target.value),
5157
- placeholder: "Search columns...",
5158
- className: "flex-1 bg-transparent text-xs text-gray-900 outline-none placeholder:text-gray-400 dark:text-white dark:placeholder:text-gray-500"
5159
- }
5160
- )
5161
- ] }),
5162
- /* @__PURE__ */ jsxs("div", { className: "max-h-52 overflow-y-auto p-1", children: [
5163
- filteredColumns.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-center text-[10px] text-gray-400", children: t("noColumnsAvailable") }),
5164
- filteredColumns.map((column) => {
5165
- const isSelected = selectedColumns.includes(column.name);
5166
- const typeColor = TYPE_COLORS[column.type.toLowerCase()] ?? TYPE_COLORS.string;
5167
- return /* @__PURE__ */ jsxs(
5168
- "button",
5169
- {
5170
- type: "button",
5171
- onClick: () => handleToggleColumn(column.name),
5172
- className: `flex w-full items-center gap-2 rounded-lg px-3 py-1.5 text-left transition-colors ${isSelected ? "bg-cyan-500/8 dark:bg-cyan-400/5" : "hover:bg-gray-100/60 dark:hover:bg-white/5"}`,
5173
- children: [
5174
- /* @__PURE__ */ jsx("div", { className: `flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors ${isSelected ? "border-cyan-500 bg-cyan-500 dark:border-cyan-400 dark:bg-cyan-400" : "border-gray-300 dark:border-gray-600"}`, children: isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "h-2.5 w-2.5 text-white" }) }),
5175
- /* @__PURE__ */ jsxs("span", { className: "flex-1 truncate text-xs text-gray-900 dark:text-white", children: [
5176
- column.name,
5177
- column.nullable && /* @__PURE__ */ jsx("span", { className: "ml-1 text-[9px] text-gray-400", children: "?" })
5178
- ] }),
5179
- /* @__PURE__ */ jsx("span", { className: `shrink-0 rounded-full px-1.5 py-0.5 text-[9px] font-medium ${typeColor}`, children: column.type })
5180
- ]
5181
- },
5182
- column.name
5183
- );
5184
- })
5185
- ] })
5240
+ className: `flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 transition-colors ${isSelected ? "bg-indigo-50 dark:bg-indigo-500/10" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
5241
+ children: [
5242
+ /* @__PURE__ */ jsx(
5243
+ "input",
5244
+ {
5245
+ type: "checkbox",
5246
+ checked: isSelected,
5247
+ onChange: () => handleToggleField(field.name),
5248
+ className: "h-3.5 w-3.5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 dark:border-gray-600"
5249
+ }
5250
+ ),
5251
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-xs font-medium text-gray-900 dark:text-white", children: field.name }),
5252
+ /* @__PURE__ */ jsx("span", { className: `rounded-full px-1.5 py-0.5 text-[9px] font-medium ${typeBadgeColor}`, children: field.type })
5253
+ ]
5254
+ },
5255
+ field.name
5256
+ );
5257
+ })
5186
5258
  ] })
5187
5259
  ] }),
5188
- selectedTable && /* @__PURE__ */ jsxs("div", { children: [
5189
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
5190
- /* @__PURE__ */ jsx(SectionHeader, { icon: FunnelIcon, title: t("filtersLabel"), badge: filterEntries.length || void 0 }),
5260
+ /* @__PURE__ */ jsxs("div", { children: [
5261
+ /* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center justify-between", children: [
5262
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t("filtersLabel") }),
5191
5263
  /* @__PURE__ */ jsxs(
5192
5264
  "button",
5193
5265
  {
5194
5266
  type: "button",
5195
5267
  onClick: handleAddFilter,
5196
- className: "flex items-center gap-1 text-[10px] font-semibold text-cyan-600 hover:text-cyan-700 dark:text-cyan-400 dark:hover:text-cyan-300",
5268
+ className: "flex items-center gap-1 text-xs font-medium text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300",
5197
5269
  children: [
5198
5270
  /* @__PURE__ */ jsx(PlusIcon$1, { className: "h-3 w-3" }),
5199
5271
  t("addFilter")
@@ -5201,28 +5273,29 @@ function DatasourceNodeConfigForm({
5201
5273
  }
5202
5274
  )
5203
5275
  ] }),
5204
- filterEntries.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: filterEntries.map(([variableName, columnName], index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-2 py-1.5 dark:border-white/10 dark:bg-white/[0.03]", children: [
5205
- /* @__PURE__ */ jsxs(
5206
- "select",
5207
- {
5208
- value: columnName,
5209
- onChange: (event) => handleUpdateFilterField(variableName, event.target.value),
5210
- className: "flex-1 rounded bg-transparent text-xs text-gray-900 outline-none dark:text-white",
5211
- children: [
5212
- /* @__PURE__ */ jsx("option", { value: "", children: t("columnName") }),
5213
- availableColumns.map((column) => /* @__PURE__ */ jsx("option", { value: column.name, children: column.name }, column.name))
5214
- ]
5215
- }
5216
- ),
5217
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-gray-400", children: "=" }),
5276
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-gray-500 dark:text-gray-400", children: t("filtersHelp") }),
5277
+ filterEntries.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: filterEntries.map(([variableName, fieldName], index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5218
5278
  /* @__PURE__ */ jsx(
5219
5279
  "input",
5220
5280
  {
5221
5281
  type: "text",
5222
5282
  value: variableName,
5223
5283
  onChange: (event) => handleUpdateFilterVariable(variableName, event.target.value),
5224
- placeholder: t("variableReference"),
5225
- className: "flex-1 bg-transparent text-xs text-gray-900 outline-none placeholder:text-gray-400 dark:text-white dark:placeholder:text-gray-500"
5284
+ placeholder: t("variableName"),
5285
+ className: "flex-1 rounded-lg border border-gray-300 bg-white px-2 py-1.5 text-xs text-gray-900 placeholder-gray-400 outline-none focus:border-indigo-400 focus:ring-1 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
5286
+ }
5287
+ ),
5288
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: "\u2192" }),
5289
+ /* @__PURE__ */ jsxs(
5290
+ "select",
5291
+ {
5292
+ value: fieldName,
5293
+ onChange: (event) => handleUpdateFilterField(variableName, event.target.value),
5294
+ className: "flex-1 rounded-lg border border-gray-300 bg-white px-2 py-1.5 text-xs text-gray-900 outline-none focus:border-indigo-400 focus:ring-1 focus:ring-indigo-400/20 dark:border-gray-600 dark:bg-gray-800 dark:text-white",
5295
+ children: [
5296
+ /* @__PURE__ */ jsx("option", { value: "", children: t("fieldName") }),
5297
+ availableFields.map((field) => /* @__PURE__ */ jsx("option", { value: field.name, children: field.name }, field.name))
5298
+ ]
5226
5299
  }
5227
5300
  ),
5228
5301
  /* @__PURE__ */ jsx(
@@ -5230,20 +5303,29 @@ function DatasourceNodeConfigForm({
5230
5303
  {
5231
5304
  type: "button",
5232
5305
  onClick: () => handleRemoveFilter(variableName),
5233
- className: "shrink-0 rounded-md p-1 text-gray-400 transition-colors hover:bg-red-50 hover:text-red-500 dark:hover:bg-red-900/20",
5234
- children: /* @__PURE__ */ jsx(XMarkIcon$1, { className: "h-3 w-3" })
5306
+ className: "rounded-md p-1 text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20",
5307
+ children: /* @__PURE__ */ jsx(XMarkIcon$1, { className: "h-3.5 w-3.5" })
5235
5308
  }
5236
5309
  )
5237
5310
  ] }, index)) })
5238
5311
  ] }),
5239
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 border-t border-gray-200/50 pt-4 dark:border-white/5", children: [
5240
- /* @__PURE__ */ jsx(Button, { outline: true, onClick: onCancel, children: t("cancel") }),
5312
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 border-t border-gray-200 pt-4 dark:border-gray-700", children: [
5313
+ /* @__PURE__ */ jsx(
5314
+ "button",
5315
+ {
5316
+ type: "button",
5317
+ onClick: onCancel,
5318
+ className: "rounded-lg border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800",
5319
+ children: t("cancel")
5320
+ }
5321
+ ),
5241
5322
  /* @__PURE__ */ jsx(
5242
- Button,
5323
+ "button",
5243
5324
  {
5244
- color: "cyan",
5325
+ type: "button",
5245
5326
  onClick: handleSave,
5246
- disabled: !selectedDatasourceId || !selectedTable || selectedColumns.length === 0,
5327
+ disabled: selectedFields.length === 0,
5328
+ className: "rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-indigo-500 dark:hover:bg-indigo-600",
5247
5329
  children: t("save")
5248
5330
  }
5249
5331
  )
@@ -5611,18 +5693,8 @@ function LogicNodeModal({ onSave, entities = [], datasources = [], onLoadTables,
5611
5693
  case "iteration_start":
5612
5694
  return /* @__PURE__ */ jsx(IterationStartNodeConfigForm, { config, onSave: handleSave, onCancel: closeModal });
5613
5695
  case "datasource":
5614
- return /* @__PURE__ */ jsx(
5615
- DatasourceNodeConfigForm,
5616
- {
5617
- nodeId,
5618
- config,
5619
- onSave: handleSave,
5620
- onCancel: closeModal,
5621
- datasources,
5622
- onLoadTables: onLoadTables ?? (async () => []),
5623
- onLoadSchema: onLoadSchema ?? (async () => [])
5624
- }
5625
- );
5696
+ return null;
5697
+ // Datasource uses its own GlassModal with sidebar — rendered separately
5626
5698
  case "entity":
5627
5699
  return /* @__PURE__ */ jsx(EntityNodeConfigForm, { config, entities, onSave: handleSave, onCancel: closeModal });
5628
5700
  case "group":
@@ -6054,6 +6126,9 @@ function WorkflowCanvasInner({
6054
6126
  agentTools = [],
6055
6127
  rules,
6056
6128
  entities = [],
6129
+ datasources = [],
6130
+ onLoadTables,
6131
+ onLoadSchema,
6057
6132
  initialGraph,
6058
6133
  onGraphChange,
6059
6134
  onEditTool,
@@ -7410,7 +7485,7 @@ function WorkflowCanvasInner({
7410
7485
  const handleEdgeClick = useCallback(() => {
7411
7486
  closeContextMenu();
7412
7487
  }, [closeContextMenu]);
7413
- useMemo(() => {
7488
+ const editingLogicNode = useMemo(() => {
7414
7489
  if (!editingLogicNodeId) return null;
7415
7490
  const node = nodes.find((matchingNode) => matchingNode.id === editingLogicNodeId);
7416
7491
  if (!node) return null;
@@ -7586,6 +7661,22 @@ function WorkflowCanvasInner({
7586
7661
  },
7587
7662
  entities: allEntities
7588
7663
  }
7664
+ ),
7665
+ editingLogicNode?.config?.type === "datasource" && /* @__PURE__ */ jsx(
7666
+ DatasourceNodeConfigForm,
7667
+ {
7668
+ open: true,
7669
+ nodeId: editingLogicNode.nodeId,
7670
+ config: editingLogicNode.config,
7671
+ onSave: (updatedConfig) => {
7672
+ handleSaveLogicNodeConfig(editingLogicNode.nodeId, updatedConfig);
7673
+ setEditingLogicNodeId(null);
7674
+ },
7675
+ onCancel: () => setEditingLogicNodeId(null),
7676
+ datasources,
7677
+ onLoadTables: onLoadTables ?? (async () => []),
7678
+ onLoadSchema: onLoadSchema ?? (async () => [])
7679
+ }
7589
7680
  )
7590
7681
  ] });
7591
7682
  }
@@ -7724,5 +7815,5 @@ function Workspace({
7724
7815
  }
7725
7816
 
7726
7817
  export { AgentFlowNode, AgentToolFlowNode, AnswerFlowNode, AnthropicIcon, CATEGORY_COLORS, CATEGORY_PILL_COLORS, CodeFlowNode, CrewAIIcon, DocumentExtractorFlowNode, EndFlowNode, EntityFlowNode, FRAMEWORK_META, GoogleADKIcon, GroupFlowNode, HttpRequestFlowNode, ICON_MAP, IfElseFlowNode, IterationFlowNode, IterationStartFlowNode, KnowledgeBaseFlowNode, LOGIC_ICON_MAP, LOGIC_NODE_BADGE_COLORS, LOGIC_NODE_GRADIENTS, LOGIC_NODE_HANDLE_COLORS, LangChainIcon, ListOperatorFlowNode, LogicNodeModal, MINIMAP_NODE_COLORS, ModelProviderFlowNode, NODE_EXECUTION_ACCENT_COLORS, NodeCard, NodeContextMenu, NoteFlowNode, OpenAIIcon, PanelContextMenu, ParameterExtractorFlowNode, QuestionClassifierFlowNode, RuleFlowNode, SelectionContextMenu, StartFlowNode, StrandsIcon, TemplateTransformFlowNode, ToolFlowNode, VariableAggregatorFlowNode, VariableAssignerFlowNode, WorkflowBuilderProvider, WorkflowCanvas, Workspace, getCompatibleModels, getDefaultFrameworkForModel, getEntityBadgeColor, getEntityGradient, getEntityHandleColor, getEntityIcon, getEntityMinimapColor, getFrameworkMeta, getNodeExecutionAccent, getNodeExecutionAccentRgb, isFrameworkCompatibleWithProviders, isModelCompatibleWithFramework, useModalStore, useWorkflowBuilderClient, useWorkflowBuilderClientOptional, useWorkflowStore };
7727
- //# sourceMappingURL=chunk-RCOGWCF2.mjs.map
7728
- //# sourceMappingURL=chunk-RCOGWCF2.mjs.map
7818
+ //# sourceMappingURL=chunk-IWATRHQP.mjs.map
7819
+ //# sourceMappingURL=chunk-IWATRHQP.mjs.map