@burdenoff/fluidgrids-fe-sdk 2026.923.4 → 2026.923.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,28 +31,28 @@ export { useActivateWorkflow, useCreateWorkflow, useCreateWorkflowVersion, useDa
31
31
  export { config, getFluidGridsConfig, getGraphQLEndpoint, resetFluidGridsConfig, setFluidGridsConfig } from './chunk-WWU2O2SR.js';
32
32
  export { useFlowStore } from './chunk-YMD3T6J2.js';
33
33
  export { ActivateWorkflowDefinitionDocument, ActiveExecutionsDocument, AvailableFluidgridsTagsDocument, CancelExecutionDocument, CreateFluidgridsTagDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, DashboardSummaryDocument, DeactivateWorkflowDefinitionDocument, DeleteWorkflowDefinitionDocument, DuplicateWorkflowDocument, EventRegistrationsDocument, ExecutionDetailDocument, ExecutionLogsDocument, ExecutionStatsDocument, ExecutionsListDocument, FluidgridsAvailableTagFieldsFragmentDoc, FluidgridsEntityTagsDocument, FluidgridsTagAssignmentFieldsFragmentDoc, ImportWorkflowDocument, ImportWorkflowTemplateDocument, NodeEndpointConfigDocument, NodeEndpointConfigsDocument, NodeManifestDocument, NodeSchemaIntrospectionDocument, NodeStatesDocument, NodeUsageStatusDocument, PauseExecutionDocument, PinNodeDataDocument, RegisterNodeDocument, RemoveNodeFromWorkflowsDocument, ReplaceFluidgridsEntityTagsDocument, RestoreWorkflowVersionDocument, ResumeExecutionDocument, RetryNodeDocument, RunFromNodeDocument, RunLogAppendedDocument, RunLogLineFieldsFragmentDoc, RunLogsDocument, SearchFluidgridsTagsDocument, TagFluidgridsEntityDocument, TerminateExecutionDocument, TriggerWorkflowDocument, UnpinNodeDataDocument, UntagFluidgridsEntityDocument, UpdateWorkflowDefinitionDocument, UsageTimeSeriesDocument, WorkflowDefinitionDocument, WorkflowDefinitionsDocument, WorkflowDefinitionsTagsDocument, WorkflowPinnedDataDocument, WorkflowRunDocument, WorkflowRunsDocument, WorkflowVersionsDocument, useActivateWorkflowDefinitionMutation, useActiveExecutionsLazyQuery, useActiveExecutionsQuery, useActiveExecutionsSuspenseQuery, useAvailableFluidgridsTagsLazyQuery, useAvailableFluidgridsTagsQuery, useAvailableFluidgridsTagsSuspenseQuery, useCancelExecutionMutation, useCreateFluidgridsTagMutation, useCreateWorkflowDefinitionMutation, useCreateWorkflowVersionMutation, useDashboardSummaryLazyQuery, useDashboardSummaryQuery, useDashboardSummarySuspenseQuery, useDeactivateWorkflowDefinitionMutation, useDeleteWorkflowDefinitionMutation, useDuplicateWorkflowMutation, useEventRegistrationsLazyQuery, useEventRegistrationsQuery, useEventRegistrationsSuspenseQuery, useExecutionDetailLazyQuery, useExecutionDetailQuery, useExecutionDetailSuspenseQuery, useExecutionLogsLazyQuery, useExecutionLogsQuery, useExecutionLogsSuspenseQuery, useExecutionStatsLazyQuery, useExecutionStatsQuery, useExecutionStatsSuspenseQuery, useExecutionsListLazyQuery, useExecutionsListQuery, useExecutionsListSuspenseQuery, useFluidgridsEntityTagsLazyQuery, useFluidgridsEntityTagsQuery, useFluidgridsEntityTagsSuspenseQuery, useImportWorkflowMutation, useImportWorkflowTemplateMutation, useNodeEndpointConfigLazyQuery, useNodeEndpointConfigQuery, useNodeEndpointConfigSuspenseQuery, useNodeEndpointConfigsLazyQuery, useNodeEndpointConfigsQuery, useNodeEndpointConfigsSuspenseQuery, useNodeManifestLazyQuery, useNodeManifestQuery, useNodeManifestSuspenseQuery, useNodeSchemaIntrospectionLazyQuery, useNodeSchemaIntrospectionQuery, useNodeSchemaIntrospectionSuspenseQuery, useNodeStatesLazyQuery, useNodeStatesQuery, useNodeStatesSuspenseQuery, useNodeUsageStatusLazyQuery, useNodeUsageStatusQuery, useNodeUsageStatusSuspenseQuery, usePauseExecutionMutation, usePinNodeDataMutation, useRegisterNodeMutation, useRemoveNodeFromWorkflowsMutation, useReplaceFluidgridsEntityTagsMutation, useRestoreWorkflowVersionMutation, useResumeExecutionMutation, useRetryNodeMutation, useRunFromNodeMutation, useRunLogAppendedSubscription, useRunLogsLazyQuery, useRunLogsQuery, useRunLogsSuspenseQuery, useSearchFluidgridsTagsLazyQuery, useSearchFluidgridsTagsQuery, useSearchFluidgridsTagsSuspenseQuery, useTagFluidgridsEntityMutation, useTerminateExecutionMutation, useTriggerWorkflowMutation, useUnpinNodeDataMutation, useUntagFluidgridsEntityMutation, useUpdateWorkflowDefinitionMutation, useUsageTimeSeriesLazyQuery, useUsageTimeSeriesQuery, useUsageTimeSeriesSuspenseQuery, useWorkflowDefinitionLazyQuery, useWorkflowDefinitionQuery, useWorkflowDefinitionSuspenseQuery, useWorkflowDefinitionsLazyQuery, useWorkflowDefinitionsQuery, useWorkflowDefinitionsSuspenseQuery, useWorkflowDefinitionsTagsLazyQuery, useWorkflowDefinitionsTagsQuery, useWorkflowDefinitionsTagsSuspenseQuery, useWorkflowPinnedDataLazyQuery, useWorkflowPinnedDataQuery, useWorkflowPinnedDataSuspenseQuery, useWorkflowRunLazyQuery, useWorkflowRunQuery, useWorkflowRunSuspenseQuery, useWorkflowRunsLazyQuery, useWorkflowRunsQuery, useWorkflowRunsSuspenseQuery, useWorkflowVersionsLazyQuery, useWorkflowVersionsQuery, useWorkflowVersionsSuspenseQuery } from './chunk-UBKJDGYS.js';
34
- import { throwIfResultError } from './chunk-LMO5ASOE.js';
34
+ import { throwIfResultError, describeOperationError } from './chunk-LMO5ASOE.js';
35
35
  export { describeOperationError, throwIfResultError } from './chunk-LMO5ASOE.js';
36
36
  import { useTr } from './chunk-7YWBH2A5.js';
37
37
  export { ENGLISH_FALLBACK_TRANSLATOR, FluidGridsTranslationProvider, useTr } from './chunk-7YWBH2A5.js';
38
38
  import { getFluidGridsClient, createFluidGridsClient } from './chunk-5BDQNSP3.js';
39
39
  export { createFluidGridsClient, getFluidGridsClient, getFluidGridsClientSafe, isFluidGridsClientReady, resetFluidGridsClient, setFluidGridsClient, waitForFluidGridsClient } from './chunk-5BDQNSP3.js';
40
40
  import * as React4 from 'react';
41
- import { lazy, Suspense, useMemo, useState, useEffect, useCallback } from 'react';
41
+ import { lazy, Suspense, useMemo, useState, useEffect, useCallback, useRef } from 'react';
42
42
  import { Routes, Route, Navigate, useNavigate } from 'react-router';
43
43
  import { jsx, jsxs } from 'react/jsx-runtime';
44
44
  import { Icon } from '@iconify/react';
45
45
  import { ErrorBoundary } from '@burdenoff/fe-libs/shared/components';
46
46
  import '@xyflow/react/dist/style.css';
47
47
  import { Button } from '@burdenoff/fe-libs/button';
48
- import { Tabs, TabsList, TabsTrigger, TabsContent, Card, CardContent, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Badge, CardHeader, Label, Input, Switch, Dialog, DialogContent, DialogHeader, DialogTitle, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DialogFooter, Textarea } from '@burdenoff/fe-libs/ui';
48
+ import { Tabs, TabsList, TabsTrigger, TabsContent, Card, CardContent, CardHeader, CardTitle, Badge, Input, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Label, Switch, CardDescription, Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Textarea } from '@burdenoff/fe-libs/ui';
49
49
  import { toast } from 'sonner';
50
50
  import { gql } from '@apollo/client';
51
+ import { ChevronDown, ChevronUp, Check, ChevronRight, Circle, Database, ArrowLeft, Plus, Search, Table2, RefreshCw, Pencil, Trash2, ArrowUpFromLine, ArrowDownToLine } from 'lucide-react';
51
52
  import * as TabsPrimitive from '@radix-ui/react-tabs';
52
53
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
53
54
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
54
55
  import * as SelectPrimitive from '@radix-ui/react-select';
55
- import { ChevronDown, ChevronUp, Check, ChevronRight, Circle } from 'lucide-react';
56
56
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
57
57
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
58
58
  import * as SwitchPrimitives from '@radix-ui/react-switch';
@@ -1581,6 +1581,1413 @@ function ApprovalInboxPage() {
1581
1581
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-2", children: items.map((request) => /* @__PURE__ */ jsx(RequestCard, { request, onDecided: refetch }, request.id)) })
1582
1582
  ] });
1583
1583
  }
1584
+ var DATA_TABLE_FIELDS = gql`
1585
+ fragment DataTableFields on DataTable {
1586
+ id
1587
+ workspaceId
1588
+ name
1589
+ description
1590
+ columns {
1591
+ key
1592
+ label
1593
+ type
1594
+ required
1595
+ defaultValue
1596
+ }
1597
+ rowCount
1598
+ sizeBytes
1599
+ createdAt
1600
+ updatedAt
1601
+ createdBy
1602
+ updatedBy
1603
+ }
1604
+ `;
1605
+ var DATA_TABLE_ROW_FIELDS = gql`
1606
+ fragment DataTableRowFields on DataTableRow {
1607
+ id
1608
+ tableId
1609
+ data
1610
+ createdAt
1611
+ updatedAt
1612
+ }
1613
+ `;
1614
+ var GET_DATA_TABLES = gql`
1615
+ ${DATA_TABLE_FIELDS}
1616
+ query GetDataTables($search: String, $limit: Int, $offset: Int) {
1617
+ dataTables(search: $search, limit: $limit, offset: $offset) {
1618
+ tables {
1619
+ ...DataTableFields
1620
+ }
1621
+ total
1622
+ }
1623
+ }
1624
+ `;
1625
+ var GET_DATA_TABLE_ROWS = gql`
1626
+ ${DATA_TABLE_ROW_FIELDS}
1627
+ query GetDataTableRows($input: DataTableRowsQueryInput!) {
1628
+ dataTableRows(input: $input) {
1629
+ rows {
1630
+ ...DataTableRowFields
1631
+ }
1632
+ total
1633
+ }
1634
+ }
1635
+ `;
1636
+ var CREATE_DATA_TABLE = gql`
1637
+ ${DATA_TABLE_FIELDS}
1638
+ mutation CreateDataTable($input: CreateDataTableInput!) {
1639
+ createDataTable(input: $input) {
1640
+ success
1641
+ message
1642
+ table {
1643
+ ...DataTableFields
1644
+ }
1645
+ }
1646
+ }
1647
+ `;
1648
+ var UPDATE_DATA_TABLE = gql`
1649
+ ${DATA_TABLE_FIELDS}
1650
+ mutation UpdateDataTable($id: ID!, $input: UpdateDataTableInput!) {
1651
+ updateDataTable(id: $id, input: $input) {
1652
+ success
1653
+ message
1654
+ table {
1655
+ ...DataTableFields
1656
+ }
1657
+ }
1658
+ }
1659
+ `;
1660
+ var DELETE_DATA_TABLE = gql`
1661
+ mutation DeleteDataTable($id: ID!) {
1662
+ deleteDataTable(id: $id) {
1663
+ success
1664
+ message
1665
+ }
1666
+ }
1667
+ `;
1668
+ var INSERT_DATA_TABLE_ROW = gql`
1669
+ ${DATA_TABLE_ROW_FIELDS}
1670
+ mutation InsertDataTableRow($tableId: ID!, $data: JSON!) {
1671
+ insertDataTableRow(tableId: $tableId, data: $data) {
1672
+ success
1673
+ message
1674
+ row {
1675
+ ...DataTableRowFields
1676
+ }
1677
+ }
1678
+ }
1679
+ `;
1680
+ var UPDATE_DATA_TABLE_ROW = gql`
1681
+ ${DATA_TABLE_ROW_FIELDS}
1682
+ mutation UpdateDataTableRow($id: ID!, $data: JSON!) {
1683
+ updateDataTableRow(id: $id, data: $data) {
1684
+ success
1685
+ message
1686
+ row {
1687
+ ...DataTableRowFields
1688
+ }
1689
+ }
1690
+ }
1691
+ `;
1692
+ var DELETE_DATA_TABLE_ROWS = gql`
1693
+ mutation DeleteDataTableRows($tableId: ID!, $ids: [ID!]!) {
1694
+ deleteDataTableRows(tableId: $tableId, ids: $ids) {
1695
+ success
1696
+ message
1697
+ affected
1698
+ }
1699
+ }
1700
+ `;
1701
+ function toRow(row) {
1702
+ return {
1703
+ id: row.id,
1704
+ tableId: row.tableId,
1705
+ data: toRecord(row.data),
1706
+ createdAt: row.createdAt,
1707
+ updatedAt: row.updatedAt
1708
+ };
1709
+ }
1710
+ function toRecord(value) {
1711
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
1712
+ }
1713
+ function operationError(error, fallback) {
1714
+ return new Error(describeOperationError(error, fallback));
1715
+ }
1716
+ function useDataTables(search) {
1717
+ const [tables, setTables] = useState([]);
1718
+ const [total, setTotal] = useState(0);
1719
+ const [loading, setLoading] = useState(true);
1720
+ const [error, setError] = useState(null);
1721
+ const fetchTables = useCallback(async () => {
1722
+ setLoading(true);
1723
+ setError(null);
1724
+ try {
1725
+ const result = throwIfResultError(
1726
+ await getFluidGridsClient().query({
1727
+ query: GET_DATA_TABLES,
1728
+ variables: {
1729
+ search: search?.trim() || void 0,
1730
+ limit: 200,
1731
+ offset: 0
1732
+ },
1733
+ fetchPolicy: "network-only"
1734
+ })
1735
+ );
1736
+ setTables(result.data?.dataTables.tables ?? []);
1737
+ setTotal(result.data?.dataTables.total ?? 0);
1738
+ } catch (err) {
1739
+ setError(operationError(err, "Failed to load data tables"));
1740
+ } finally {
1741
+ setLoading(false);
1742
+ }
1743
+ }, [search]);
1744
+ useEffect(() => {
1745
+ void fetchTables();
1746
+ }, [fetchTables]);
1747
+ return { tables, total, loading, error, refetch: fetchTables };
1748
+ }
1749
+ function useDataTableRows(tableId) {
1750
+ const [rows, setRows] = useState([]);
1751
+ const [total, setTotal] = useState(0);
1752
+ const [loading, setLoading] = useState(false);
1753
+ const [error, setError] = useState(null);
1754
+ const fetchRows = useCallback(async () => {
1755
+ if (!tableId) {
1756
+ setRows([]);
1757
+ setTotal(0);
1758
+ setLoading(false);
1759
+ setError(null);
1760
+ return;
1761
+ }
1762
+ setLoading(true);
1763
+ setError(null);
1764
+ try {
1765
+ const result = throwIfResultError(
1766
+ await getFluidGridsClient().query({
1767
+ query: GET_DATA_TABLE_ROWS,
1768
+ variables: { input: { tableId, limit: 5e3, offset: 0 } },
1769
+ fetchPolicy: "network-only"
1770
+ })
1771
+ );
1772
+ const response = result.data?.dataTableRows;
1773
+ setRows(response?.rows.map(toRow) ?? []);
1774
+ setTotal(response?.total ?? 0);
1775
+ } catch (err) {
1776
+ setError(operationError(err, "Failed to load data table rows"));
1777
+ } finally {
1778
+ setLoading(false);
1779
+ }
1780
+ }, [tableId]);
1781
+ useEffect(() => {
1782
+ void fetchRows();
1783
+ }, [fetchRows]);
1784
+ return { rows, total, loading, error, refetch: fetchRows };
1785
+ }
1786
+ function useCreateDataTable() {
1787
+ const [loading, setLoading] = useState(false);
1788
+ const createDataTable = useCallback(async (input) => {
1789
+ setLoading(true);
1790
+ try {
1791
+ const result = throwIfResultError(
1792
+ await getFluidGridsClient().mutate({ mutation: CREATE_DATA_TABLE, variables: { input } })
1793
+ );
1794
+ const response = result.data?.createDataTable;
1795
+ if (!response?.success) {
1796
+ throw new Error(response?.message || "Failed to create data table");
1797
+ }
1798
+ return response.table ?? null;
1799
+ } finally {
1800
+ setLoading(false);
1801
+ }
1802
+ }, []);
1803
+ return { createDataTable, loading };
1804
+ }
1805
+ function useUpdateDataTable() {
1806
+ const [loading, setLoading] = useState(false);
1807
+ const updateDataTable = useCallback(
1808
+ async (id, input) => {
1809
+ setLoading(true);
1810
+ try {
1811
+ const result = throwIfResultError(
1812
+ await getFluidGridsClient().mutate({ mutation: UPDATE_DATA_TABLE, variables: { id, input } })
1813
+ );
1814
+ const response = result.data?.updateDataTable;
1815
+ if (!response?.success) {
1816
+ throw new Error(response?.message || "Failed to update data table");
1817
+ }
1818
+ return response.table ?? null;
1819
+ } finally {
1820
+ setLoading(false);
1821
+ }
1822
+ },
1823
+ []
1824
+ );
1825
+ return { updateDataTable, loading };
1826
+ }
1827
+ function useDeleteDataTable() {
1828
+ const [loading, setLoading] = useState(false);
1829
+ const deleteDataTable = useCallback(async (id) => {
1830
+ setLoading(true);
1831
+ try {
1832
+ const result = throwIfResultError(
1833
+ await getFluidGridsClient().mutate({ mutation: DELETE_DATA_TABLE, variables: { id } })
1834
+ );
1835
+ const response = result.data?.deleteDataTable;
1836
+ if (!response?.success) {
1837
+ throw new Error(response?.message || "Failed to delete data table");
1838
+ }
1839
+ return true;
1840
+ } finally {
1841
+ setLoading(false);
1842
+ }
1843
+ }, []);
1844
+ return { deleteDataTable, loading };
1845
+ }
1846
+ function useInsertDataTableRow() {
1847
+ const [loading, setLoading] = useState(false);
1848
+ const insertDataTableRow = useCallback(
1849
+ async (tableId, data) => {
1850
+ setLoading(true);
1851
+ try {
1852
+ const result = throwIfResultError(
1853
+ await getFluidGridsClient().mutate({
1854
+ mutation: INSERT_DATA_TABLE_ROW,
1855
+ variables: { tableId, data }
1856
+ })
1857
+ );
1858
+ const response = result.data?.insertDataTableRow;
1859
+ if (!response?.success) {
1860
+ throw new Error(response?.message || "Failed to insert row");
1861
+ }
1862
+ return response.row ? toRow(response.row) : null;
1863
+ } finally {
1864
+ setLoading(false);
1865
+ }
1866
+ },
1867
+ []
1868
+ );
1869
+ return { insertDataTableRow, loading };
1870
+ }
1871
+ function useUpdateDataTableRow() {
1872
+ const [loading, setLoading] = useState(false);
1873
+ const updateDataTableRow = useCallback(
1874
+ async (id, data) => {
1875
+ setLoading(true);
1876
+ try {
1877
+ const result = throwIfResultError(
1878
+ await getFluidGridsClient().mutate({ mutation: UPDATE_DATA_TABLE_ROW, variables: { id, data } })
1879
+ );
1880
+ const response = result.data?.updateDataTableRow;
1881
+ if (!response?.success) {
1882
+ throw new Error(response?.message || "Failed to update row");
1883
+ }
1884
+ return response.row ? toRow(response.row) : null;
1885
+ } finally {
1886
+ setLoading(false);
1887
+ }
1888
+ },
1889
+ []
1890
+ );
1891
+ return { updateDataTableRow, loading };
1892
+ }
1893
+ function useDeleteDataTableRows() {
1894
+ const [loading, setLoading] = useState(false);
1895
+ const deleteDataTableRows = useCallback(
1896
+ async (tableId, ids) => {
1897
+ setLoading(true);
1898
+ try {
1899
+ const result = throwIfResultError(
1900
+ await getFluidGridsClient().mutate({
1901
+ mutation: DELETE_DATA_TABLE_ROWS,
1902
+ variables: { tableId, ids }
1903
+ })
1904
+ );
1905
+ const response = result.data?.deleteDataTableRows;
1906
+ if (!response?.success) {
1907
+ throw new Error(response?.message || "Failed to delete rows");
1908
+ }
1909
+ return response.affected;
1910
+ } finally {
1911
+ setLoading(false);
1912
+ }
1913
+ },
1914
+ []
1915
+ );
1916
+ return { deleteDataTableRows, loading };
1917
+ }
1918
+
1919
+ // src/modules/data-tables/utils/csv.ts
1920
+ function parseCsv(text) {
1921
+ const rows = [];
1922
+ let row = [];
1923
+ let cell = "";
1924
+ let quoted = false;
1925
+ for (let index = 0; index < text.length; index += 1) {
1926
+ const character = text[index];
1927
+ const next = text[index + 1];
1928
+ if (quoted) {
1929
+ if (character === '"' && next === '"') {
1930
+ cell += '"';
1931
+ index += 1;
1932
+ } else if (character === '"') {
1933
+ quoted = false;
1934
+ } else {
1935
+ cell += character;
1936
+ }
1937
+ continue;
1938
+ }
1939
+ if (character === '"' && cell.length === 0) {
1940
+ quoted = true;
1941
+ } else if (character === ",") {
1942
+ row.push(cell);
1943
+ cell = "";
1944
+ } else if (character === "\n" || character === "\r") {
1945
+ if (character === "\r" && next === "\n") index += 1;
1946
+ row.push(cell);
1947
+ cell = "";
1948
+ if (row.some((value) => value.length > 0)) rows.push(row);
1949
+ row = [];
1950
+ } else {
1951
+ cell += character;
1952
+ }
1953
+ }
1954
+ if (quoted) {
1955
+ throw new Error("CSV contains an unterminated quoted value");
1956
+ }
1957
+ if (cell.length > 0 || row.length > 0) {
1958
+ row.push(cell);
1959
+ if (row.some((value) => value.length > 0)) rows.push(row);
1960
+ }
1961
+ return rows;
1962
+ }
1963
+ function parseValue(value, type) {
1964
+ if (value === "") {
1965
+ return type === "STRING" ? "" : null;
1966
+ }
1967
+ switch (type) {
1968
+ case "NUMBER": {
1969
+ const parsed = Number(value);
1970
+ if (!Number.isFinite(parsed))
1971
+ throw new Error(`Expected a number, got "${value}"`);
1972
+ return parsed;
1973
+ }
1974
+ case "BOOLEAN": {
1975
+ const normalized = value.trim().toLowerCase();
1976
+ if (normalized === "true") return true;
1977
+ if (normalized === "false") return false;
1978
+ throw new Error(`Expected true or false, got "${value}"`);
1979
+ }
1980
+ case "JSON":
1981
+ try {
1982
+ return JSON.parse(value);
1983
+ } catch {
1984
+ throw new Error(`Expected valid JSON, got "${value}"`);
1985
+ }
1986
+ case "DATE":
1987
+ case "STRING":
1988
+ return value;
1989
+ }
1990
+ }
1991
+ function csvToRows(text, columns) {
1992
+ const parsed = parseCsv(text);
1993
+ if (parsed.length < 2) return [];
1994
+ const headers = parsed[0].map((header) => header.trim());
1995
+ const columnByKey = new Map(columns.map((column) => [column.key, column]));
1996
+ const seen = /* @__PURE__ */ new Set();
1997
+ for (const header of headers) {
1998
+ if (!header || seen.has(header)) {
1999
+ throw new Error("CSV must have unique, non-empty column headers");
2000
+ }
2001
+ if (!columnByKey.has(header)) {
2002
+ throw new Error(`CSV contains an unknown column "${header}"`);
2003
+ }
2004
+ seen.add(header);
2005
+ }
2006
+ return parsed.slice(1).map((values, rowIndex) => {
2007
+ const row = {};
2008
+ headers.forEach((header, columnIndex) => {
2009
+ const column = columnByKey.get(header);
2010
+ if (!column) return;
2011
+ const rawValue = values[columnIndex] ?? "";
2012
+ try {
2013
+ row[header] = parseValue(rawValue, column.type);
2014
+ } catch (error) {
2015
+ const message = error instanceof Error ? error.message : "Invalid value";
2016
+ throw new Error(`Row ${rowIndex + 2}, ${column.label}: ${message}`);
2017
+ }
2018
+ });
2019
+ return row;
2020
+ });
2021
+ }
2022
+ function csvCell(value) {
2023
+ if (value === null || value === void 0) return "";
2024
+ const text = typeof value === "object" ? JSON.stringify(value) : String(value);
2025
+ return /[",\r\n]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
2026
+ }
2027
+ function rowsToCsv(columns, rows) {
2028
+ const header = columns.map((column) => csvCell(column.key)).join(",");
2029
+ const values = rows.map(
2030
+ (row) => columns.map((column) => csvCell(row.data[column.key])).join(",")
2031
+ );
2032
+ return [header, ...values].join("\r\n");
2033
+ }
2034
+ var COLUMN_TYPES = [
2035
+ "STRING",
2036
+ "NUMBER",
2037
+ "BOOLEAN",
2038
+ "DATE",
2039
+ "JSON"
2040
+ ];
2041
+ function emptyColumn(index) {
2042
+ return {
2043
+ key: `column_${index}`,
2044
+ label: `Column ${index}`,
2045
+ type: "STRING",
2046
+ required: false
2047
+ };
2048
+ }
2049
+ function formatBytes(bytes) {
2050
+ if (bytes < 1024) return `${bytes} B`;
2051
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
2052
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2053
+ }
2054
+ function formatValue(value) {
2055
+ if (value === null || value === void 0) return "\u2014";
2056
+ if (typeof value === "object") return JSON.stringify(value);
2057
+ return String(value);
2058
+ }
2059
+ function columnTypeLabel(type) {
2060
+ return type === "JSON" ? "JSON" : type[0] + type.slice(1).toLowerCase();
2061
+ }
2062
+ function asFormValue(value, type) {
2063
+ if (value === null || value === void 0) return "";
2064
+ if (type === "JSON") return JSON.stringify(value, null, 2);
2065
+ return String(value);
2066
+ }
2067
+ function parseFormValue(value, type) {
2068
+ if (type === "STRING" || type === "DATE") return value;
2069
+ if (value.trim() === "") return null;
2070
+ if (type === "NUMBER") {
2071
+ const number = Number(value);
2072
+ if (!Number.isFinite(number)) throw new Error(`"${value}" is not a number`);
2073
+ return number;
2074
+ }
2075
+ if (type === "BOOLEAN") {
2076
+ if (value === "true") return true;
2077
+ if (value === "false") return false;
2078
+ throw new Error("Boolean values must be true or false");
2079
+ }
2080
+ try {
2081
+ return JSON.parse(value);
2082
+ } catch {
2083
+ throw new Error("JSON values must contain valid JSON");
2084
+ }
2085
+ }
2086
+ function TableFormDialog({
2087
+ open,
2088
+ table,
2089
+ onOpenChange,
2090
+ onSaved
2091
+ }) {
2092
+ const tr = useTr();
2093
+ const { createDataTable, loading: creating } = useCreateDataTable();
2094
+ const { updateDataTable, loading: updating } = useUpdateDataTable();
2095
+ const [name, setName] = useState("");
2096
+ const [description, setDescription] = useState("");
2097
+ const [columns, setColumns] = useState([]);
2098
+ const editing = table !== null;
2099
+ const saving = creating || updating;
2100
+ useEffect(() => {
2101
+ if (!open) return;
2102
+ setName(table?.name ?? "");
2103
+ setDescription(table?.description ?? "");
2104
+ setColumns(
2105
+ table?.columns.map((column) => ({
2106
+ key: column.key,
2107
+ label: column.label,
2108
+ type: column.type,
2109
+ required: column.required,
2110
+ ...column.defaultValue !== void 0 ? { defaultValue: column.defaultValue } : {}
2111
+ })) ?? [emptyColumn(1)]
2112
+ );
2113
+ }, [open, table]);
2114
+ const updateColumn = useCallback(
2115
+ (index, patch) => {
2116
+ setColumns(
2117
+ (current) => current.map(
2118
+ (column, columnIndex) => columnIndex === index ? { ...column, ...patch } : column
2119
+ )
2120
+ );
2121
+ },
2122
+ []
2123
+ );
2124
+ const handleSubmit = useCallback(async () => {
2125
+ const trimmedName = name.trim();
2126
+ if (!trimmedName) {
2127
+ toast.error(
2128
+ tr("fluidgrids.dataTables.nameRequired", "Table name is required")
2129
+ );
2130
+ return;
2131
+ }
2132
+ if (columns.length === 0 || columns.some((column) => !column.key.trim() || !column.label.trim())) {
2133
+ toast.error(
2134
+ tr(
2135
+ "fluidgrids.dataTables.columnsRequired",
2136
+ "Add at least one column with a key and label"
2137
+ )
2138
+ );
2139
+ return;
2140
+ }
2141
+ const normalizedColumns = columns.map((column) => ({
2142
+ ...column,
2143
+ key: column.key.trim(),
2144
+ label: column.label.trim()
2145
+ }));
2146
+ const keys = new Set(normalizedColumns.map((column) => column.key));
2147
+ if (keys.size !== normalizedColumns.length) {
2148
+ toast.error(
2149
+ tr("fluidgrids.dataTables.uniqueKeys", "Column keys must be unique")
2150
+ );
2151
+ return;
2152
+ }
2153
+ try {
2154
+ const saved = editing ? await updateDataTable(table.id, {
2155
+ name: trimmedName,
2156
+ description: description.trim() || void 0,
2157
+ columns: normalizedColumns
2158
+ }) : await createDataTable({
2159
+ name: trimmedName,
2160
+ description: description.trim() || void 0,
2161
+ columns: normalizedColumns
2162
+ });
2163
+ toast.success(
2164
+ editing ? tr("fluidgrids.dataTables.updated", "Data table updated") : tr("fluidgrids.dataTables.created", "Data table created")
2165
+ );
2166
+ onSaved(saved);
2167
+ onOpenChange(false);
2168
+ } catch (error) {
2169
+ toast.error(
2170
+ describeOperationError(
2171
+ error,
2172
+ tr("fluidgrids.dataTables.saveFailed", "Failed to save data table")
2173
+ )
2174
+ );
2175
+ }
2176
+ }, [
2177
+ columns,
2178
+ createDataTable,
2179
+ description,
2180
+ editing,
2181
+ name,
2182
+ onOpenChange,
2183
+ onSaved,
2184
+ table,
2185
+ tr,
2186
+ updateDataTable
2187
+ ]);
2188
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[90vh] max-w-3xl overflow-y-auto", children: [
2189
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: editing ? tr("fluidgrids.dataTables.editTable", "Edit data table") : tr("fluidgrids.dataTables.newTable", "New data table") }) }),
2190
+ /* @__PURE__ */ jsxs("div", { className: "space-y-5 py-2", children: [
2191
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
2192
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2193
+ /* @__PURE__ */ jsx(Label, { htmlFor: "data-table-name", children: tr("fluidgrids.dataTables.name", "Name") }),
2194
+ /* @__PURE__ */ jsx(
2195
+ Input,
2196
+ {
2197
+ id: "data-table-name",
2198
+ value: name,
2199
+ onChange: (event) => setName(event.target.value),
2200
+ placeholder: "contacts",
2201
+ autoFocus: true
2202
+ }
2203
+ )
2204
+ ] }),
2205
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2206
+ /* @__PURE__ */ jsx(Label, { htmlFor: "data-table-description", children: tr("fluidgrids.dataTables.description", "Description") }),
2207
+ /* @__PURE__ */ jsx(
2208
+ Input,
2209
+ {
2210
+ id: "data-table-description",
2211
+ value: description,
2212
+ onChange: (event) => setDescription(event.target.value),
2213
+ placeholder: tr(
2214
+ "fluidgrids.dataTables.descriptionPlaceholder",
2215
+ "Optional"
2216
+ )
2217
+ }
2218
+ )
2219
+ ] })
2220
+ ] }),
2221
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
2222
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
2223
+ /* @__PURE__ */ jsxs("div", { children: [
2224
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-text-primary", children: tr("fluidgrids.dataTables.columns", "Columns") }),
2225
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: tr(
2226
+ "fluidgrids.dataTables.columnsHint",
2227
+ "Column keys are used by workflow nodes and must be unique."
2228
+ ) })
2229
+ ] }),
2230
+ /* @__PURE__ */ jsxs(
2231
+ Button,
2232
+ {
2233
+ type: "button",
2234
+ variant: "outline",
2235
+ size: "sm",
2236
+ onClick: () => setColumns((current) => [
2237
+ ...current,
2238
+ emptyColumn(current.length + 1)
2239
+ ]),
2240
+ children: [
2241
+ /* @__PURE__ */ jsx(Plus, { className: "mr-1.5 size-4", "aria-hidden": "true" }),
2242
+ tr("fluidgrids.dataTables.addColumn", "Add column")
2243
+ ]
2244
+ }
2245
+ )
2246
+ ] }),
2247
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: columns.map((column, index) => /* @__PURE__ */ jsxs(
2248
+ "div",
2249
+ {
2250
+ className: "grid gap-2 rounded-md border border-border-secondary p-3 sm:grid-cols-[1fr_1fr_8rem_auto] sm:items-end",
2251
+ children: [
2252
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2253
+ /* @__PURE__ */ jsx(Label, { htmlFor: `data-table-column-key-${index}`, children: tr("fluidgrids.dataTables.key", "Key") }),
2254
+ /* @__PURE__ */ jsx(
2255
+ Input,
2256
+ {
2257
+ id: `data-table-column-key-${index}`,
2258
+ value: column.key,
2259
+ onChange: (event) => updateColumn(index, { key: event.target.value })
2260
+ }
2261
+ )
2262
+ ] }),
2263
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2264
+ /* @__PURE__ */ jsx(Label, { htmlFor: `data-table-column-label-${index}`, children: tr("fluidgrids.dataTables.label", "Label") }),
2265
+ /* @__PURE__ */ jsx(
2266
+ Input,
2267
+ {
2268
+ id: `data-table-column-label-${index}`,
2269
+ value: column.label,
2270
+ onChange: (event) => updateColumn(index, { label: event.target.value })
2271
+ }
2272
+ )
2273
+ ] }),
2274
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2275
+ /* @__PURE__ */ jsx(Label, { htmlFor: `data-table-column-type-${index}`, children: tr("fluidgrids.dataTables.type", "Type") }),
2276
+ /* @__PURE__ */ jsx(
2277
+ "select",
2278
+ {
2279
+ id: `data-table-column-type-${index}`,
2280
+ className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-text-primary",
2281
+ value: column.type,
2282
+ onChange: (event) => updateColumn(index, {
2283
+ type: event.target.value
2284
+ }),
2285
+ children: COLUMN_TYPES.map((type) => /* @__PURE__ */ jsx("option", { value: type, children: columnTypeLabel(type) }, type))
2286
+ }
2287
+ )
2288
+ ] }),
2289
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 pb-2 sm:flex-col sm:items-center sm:gap-1", children: [
2290
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs text-text-secondary", children: [
2291
+ /* @__PURE__ */ jsx(
2292
+ "input",
2293
+ {
2294
+ type: "checkbox",
2295
+ checked: column.required ?? false,
2296
+ onChange: (event) => updateColumn(index, {
2297
+ required: event.target.checked
2298
+ })
2299
+ }
2300
+ ),
2301
+ tr("fluidgrids.dataTables.required", "Required")
2302
+ ] }),
2303
+ /* @__PURE__ */ jsx(
2304
+ "button",
2305
+ {
2306
+ type: "button",
2307
+ className: "rounded p-1 text-text-secondary hover:bg-background-tertiary hover:text-text-primary disabled:opacity-40",
2308
+ onClick: () => setColumns(
2309
+ (current) => current.filter(
2310
+ (_, columnIndex) => columnIndex !== index
2311
+ )
2312
+ ),
2313
+ disabled: columns.length === 1,
2314
+ title: tr(
2315
+ "fluidgrids.dataTables.removeColumn",
2316
+ "Remove column"
2317
+ ),
2318
+ "aria-label": tr(
2319
+ "fluidgrids.dataTables.removeColumn",
2320
+ "Remove column"
2321
+ ),
2322
+ children: /* @__PURE__ */ jsx(Trash2, { className: "size-4", "aria-hidden": "true" })
2323
+ }
2324
+ )
2325
+ ] })
2326
+ ]
2327
+ },
2328
+ `${column.key}-${index}`
2329
+ )) })
2330
+ ] })
2331
+ ] }),
2332
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
2333
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: tr("fluidgrids.dataTables.cancel", "Cancel") }),
2334
+ /* @__PURE__ */ jsx(Button, { onClick: handleSubmit, disabled: saving, children: saving ? tr("fluidgrids.dataTables.saving", "Saving\u2026") : tr("fluidgrids.dataTables.save", "Save table") })
2335
+ ] })
2336
+ ] }) });
2337
+ }
2338
+ function RowFormDialog({
2339
+ open,
2340
+ table,
2341
+ row,
2342
+ onOpenChange,
2343
+ onSaved
2344
+ }) {
2345
+ const tr = useTr();
2346
+ const { insertDataTableRow, loading: inserting } = useInsertDataTableRow();
2347
+ const { updateDataTableRow, loading: updating } = useUpdateDataTableRow();
2348
+ const [values, setValues] = useState({});
2349
+ const editing = row !== null;
2350
+ const saving = inserting || updating;
2351
+ useEffect(() => {
2352
+ if (!open || !table) return;
2353
+ const next = {};
2354
+ for (const column of table.columns) {
2355
+ next[column.key] = asFormValue(row?.data[column.key], column.type);
2356
+ }
2357
+ setValues(next);
2358
+ }, [open, row, table]);
2359
+ const handleSubmit = useCallback(async () => {
2360
+ if (!table) return;
2361
+ try {
2362
+ const data = {};
2363
+ for (const column of table.columns) {
2364
+ const value = values[column.key] ?? "";
2365
+ if (column.required && value.trim() === "") {
2366
+ throw new Error(`${column.label} is required`);
2367
+ }
2368
+ data[column.key] = parseFormValue(value, column.type);
2369
+ }
2370
+ if (editing && row) {
2371
+ await updateDataTableRow(row.id, data);
2372
+ } else {
2373
+ await insertDataTableRow(table.id, data);
2374
+ }
2375
+ toast.success(
2376
+ editing ? tr("fluidgrids.dataTables.rowUpdated", "Row updated") : tr("fluidgrids.dataTables.rowCreated", "Row added")
2377
+ );
2378
+ onSaved();
2379
+ onOpenChange(false);
2380
+ } catch (error) {
2381
+ toast.error(
2382
+ describeOperationError(
2383
+ error,
2384
+ tr("fluidgrids.dataTables.rowSaveFailed", "Failed to save row")
2385
+ )
2386
+ );
2387
+ }
2388
+ }, [
2389
+ editing,
2390
+ insertDataTableRow,
2391
+ onOpenChange,
2392
+ onSaved,
2393
+ row,
2394
+ table,
2395
+ tr,
2396
+ updateDataTableRow,
2397
+ values
2398
+ ]);
2399
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[90vh] max-w-2xl overflow-y-auto", children: [
2400
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: editing ? tr("fluidgrids.dataTables.editRow", "Edit row") : tr("fluidgrids.dataTables.addRow", "Add row") }) }),
2401
+ table && /* @__PURE__ */ jsx("div", { className: "space-y-4 py-2", children: table.columns.map((column) => /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2402
+ /* @__PURE__ */ jsxs(Label, { htmlFor: `data-table-row-${column.key}`, children: [
2403
+ column.label,
2404
+ /* @__PURE__ */ jsxs("span", { className: "ml-1 text-xs text-text-secondary", children: [
2405
+ "(",
2406
+ column.key,
2407
+ " \xB7 ",
2408
+ columnTypeLabel(column.type),
2409
+ ")"
2410
+ ] }),
2411
+ column.required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-text-secondary", children: "*" })
2412
+ ] }),
2413
+ column.type === "JSON" ? /* @__PURE__ */ jsx(
2414
+ Textarea,
2415
+ {
2416
+ id: `data-table-row-${column.key}`,
2417
+ value: values[column.key] ?? "",
2418
+ onChange: (event) => setValues((current) => ({
2419
+ ...current,
2420
+ [column.key]: event.target.value
2421
+ })),
2422
+ rows: 4,
2423
+ placeholder: "{ }"
2424
+ }
2425
+ ) : /* @__PURE__ */ jsx(
2426
+ Input,
2427
+ {
2428
+ id: `data-table-row-${column.key}`,
2429
+ type: column.type === "NUMBER" ? "number" : column.type === "DATE" ? "datetime-local" : "text",
2430
+ value: values[column.key] ?? "",
2431
+ onChange: (event) => setValues((current) => ({
2432
+ ...current,
2433
+ [column.key]: event.target.value
2434
+ }))
2435
+ }
2436
+ )
2437
+ ] }, column.key)) }),
2438
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
2439
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: tr("fluidgrids.dataTables.cancel", "Cancel") }),
2440
+ /* @__PURE__ */ jsx(Button, { onClick: handleSubmit, disabled: saving || !table, children: saving ? tr("fluidgrids.dataTables.saving", "Saving\u2026") : tr("fluidgrids.dataTables.saveRow", "Save row") })
2441
+ ] })
2442
+ ] }) });
2443
+ }
2444
+ function TableRowsPanel({ table, onTableChanged }) {
2445
+ const tr = useTr();
2446
+ const { rows, total, loading, error, refetch } = useDataTableRows(table.id);
2447
+ const { deleteDataTableRows, loading: deleting } = useDeleteDataTableRows();
2448
+ const { insertDataTableRow } = useInsertDataTableRow();
2449
+ const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
2450
+ const [rowDialogOpen, setRowDialogOpen] = useState(false);
2451
+ const [editingRow, setEditingRow] = useState(null);
2452
+ const fileInputRef = useRef(null);
2453
+ useEffect(() => {
2454
+ setSelectedIds((current) => {
2455
+ const visible = new Set(rows.map((row) => row.id));
2456
+ return new Set([...current].filter((id) => visible.has(id)));
2457
+ });
2458
+ }, [rows]);
2459
+ const allVisibleSelected = rows.length > 0 && selectedIds.size === rows.length;
2460
+ const toggleAll = useCallback(() => {
2461
+ setSelectedIds(
2462
+ allVisibleSelected ? /* @__PURE__ */ new Set() : new Set(rows.map((row) => row.id))
2463
+ );
2464
+ }, [allVisibleSelected, rows]);
2465
+ const handleDeleteRows = useCallback(async () => {
2466
+ if (selectedIds.size === 0) return;
2467
+ if (!window.confirm(
2468
+ tr(
2469
+ "fluidgrids.dataTables.confirmDeleteRows",
2470
+ `Delete ${selectedIds.size} selected row(s)?`
2471
+ )
2472
+ )) {
2473
+ return;
2474
+ }
2475
+ try {
2476
+ const affected = await deleteDataTableRows(table.id, [...selectedIds]);
2477
+ toast.success(
2478
+ tr("fluidgrids.dataTables.rowsDeleted", `${affected} row(s) deleted`)
2479
+ );
2480
+ setSelectedIds(/* @__PURE__ */ new Set());
2481
+ await refetch();
2482
+ onTableChanged();
2483
+ } catch (error2) {
2484
+ toast.error(
2485
+ describeOperationError(
2486
+ error2,
2487
+ tr("fluidgrids.dataTables.deleteRowsFailed", "Failed to delete rows")
2488
+ )
2489
+ );
2490
+ }
2491
+ }, [deleteDataTableRows, onTableChanged, refetch, selectedIds, table.id, tr]);
2492
+ const handleExport = useCallback(() => {
2493
+ const csv = rowsToCsv(table.columns, rows);
2494
+ const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
2495
+ const url = URL.createObjectURL(blob);
2496
+ const anchor = document.createElement("a");
2497
+ anchor.href = url;
2498
+ anchor.download = `${table.name}.csv`;
2499
+ anchor.click();
2500
+ URL.revokeObjectURL(url);
2501
+ toast.success(
2502
+ tr("fluidgrids.dataTables.exported", "Visible rows exported to CSV")
2503
+ );
2504
+ }, [rows, table.columns, table.name, tr]);
2505
+ const handleImport = useCallback(
2506
+ async (event) => {
2507
+ const file = event.target.files?.[0];
2508
+ event.target.value = "";
2509
+ if (!file) return;
2510
+ try {
2511
+ const importedRows = csvToRows(await file.text(), table.columns);
2512
+ let inserted = 0;
2513
+ for (const data of importedRows) {
2514
+ await insertDataTableRow(table.id, data);
2515
+ inserted += 1;
2516
+ }
2517
+ toast.success(
2518
+ tr("fluidgrids.dataTables.imported", `${inserted} row(s) imported`)
2519
+ );
2520
+ await refetch();
2521
+ onTableChanged();
2522
+ } catch (error2) {
2523
+ toast.error(
2524
+ describeOperationError(
2525
+ error2,
2526
+ tr("fluidgrids.dataTables.importFailed", "Failed to import CSV")
2527
+ )
2528
+ );
2529
+ }
2530
+ },
2531
+ [insertDataTableRow, onTableChanged, refetch, table.columns, table.id, tr]
2532
+ );
2533
+ const openNewRow = useCallback(() => {
2534
+ setEditingRow(null);
2535
+ setRowDialogOpen(true);
2536
+ }, []);
2537
+ const openEditRow = useCallback((row) => {
2538
+ setEditingRow(row);
2539
+ setRowDialogOpen(true);
2540
+ }, []);
2541
+ return /* @__PURE__ */ jsxs(Card, { className: "min-w-0 border-border-secondary", children: [
2542
+ /* @__PURE__ */ jsxs(CardHeader, { className: "gap-3 border-b border-border-secondary p-4 sm:p-5", children: [
2543
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between", children: [
2544
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2545
+ /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2 text-lg", children: [
2546
+ /* @__PURE__ */ jsx(
2547
+ Table2,
2548
+ {
2549
+ className: "size-5 text-text-secondary",
2550
+ "aria-hidden": "true"
2551
+ }
2552
+ ),
2553
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: table.name })
2554
+ ] }),
2555
+ /* @__PURE__ */ jsx(CardDescription, { className: "mt-1", children: table.description || tr("fluidgrids.dataTables.noDescription", "No description") })
2556
+ ] }),
2557
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
2558
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: openNewRow, children: [
2559
+ /* @__PURE__ */ jsx(Plus, { className: "mr-1.5 size-4", "aria-hidden": "true" }),
2560
+ tr("fluidgrids.dataTables.addRow", "Add row")
2561
+ ] }),
2562
+ /* @__PURE__ */ jsxs(
2563
+ Button,
2564
+ {
2565
+ variant: "outline",
2566
+ size: "sm",
2567
+ onClick: () => fileInputRef.current?.click(),
2568
+ children: [
2569
+ /* @__PURE__ */ jsx(ArrowUpFromLine, { className: "mr-1.5 size-4", "aria-hidden": "true" }),
2570
+ tr("fluidgrids.dataTables.import", "Import CSV")
2571
+ ]
2572
+ }
2573
+ ),
2574
+ /* @__PURE__ */ jsx(
2575
+ "input",
2576
+ {
2577
+ ref: fileInputRef,
2578
+ type: "file",
2579
+ accept: ".csv,text/csv",
2580
+ className: "hidden",
2581
+ onChange: handleImport
2582
+ }
2583
+ ),
2584
+ /* @__PURE__ */ jsxs(
2585
+ Button,
2586
+ {
2587
+ variant: "outline",
2588
+ size: "sm",
2589
+ onClick: handleExport,
2590
+ disabled: rows.length === 0,
2591
+ children: [
2592
+ /* @__PURE__ */ jsx(ArrowDownToLine, { className: "mr-1.5 size-4", "aria-hidden": "true" }),
2593
+ tr("fluidgrids.dataTables.export", "Export CSV")
2594
+ ]
2595
+ }
2596
+ )
2597
+ ] })
2598
+ ] }),
2599
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-text-secondary", children: [
2600
+ /* @__PURE__ */ jsxs(Badge, { variant: "outline", children: [
2601
+ total,
2602
+ " ",
2603
+ tr("fluidgrids.dataTables.rows", "rows")
2604
+ ] }),
2605
+ /* @__PURE__ */ jsxs(Badge, { variant: "outline", children: [
2606
+ table.columns.length,
2607
+ " ",
2608
+ tr("fluidgrids.dataTables.columns", "columns")
2609
+ ] }),
2610
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", children: formatBytes(table.sizeBytes) }),
2611
+ selectedIds.size > 0 && /* @__PURE__ */ jsxs(
2612
+ Button,
2613
+ {
2614
+ variant: "outline",
2615
+ size: "sm",
2616
+ onClick: handleDeleteRows,
2617
+ disabled: deleting,
2618
+ children: [
2619
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-1.5 size-4", "aria-hidden": "true" }),
2620
+ deleting ? tr("fluidgrids.dataTables.deleting", "Deleting\u2026") : tr(
2621
+ "fluidgrids.dataTables.deleteSelected",
2622
+ `Delete ${selectedIds.size} selected`
2623
+ )
2624
+ ]
2625
+ }
2626
+ )
2627
+ ] })
2628
+ ] }),
2629
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
2630
+ error && /* @__PURE__ */ jsx("div", { className: "m-4 rounded-md border border-border-secondary bg-background-secondary p-3 text-sm text-text-secondary", children: error.message }),
2631
+ /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs(Table, { children: [
2632
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
2633
+ /* @__PURE__ */ jsx(TableHead, { className: "w-10", children: /* @__PURE__ */ jsx(
2634
+ "input",
2635
+ {
2636
+ type: "checkbox",
2637
+ checked: allVisibleSelected,
2638
+ onChange: toggleAll,
2639
+ "aria-label": tr(
2640
+ "fluidgrids.dataTables.selectAll",
2641
+ "Select all rows"
2642
+ )
2643
+ }
2644
+ ) }),
2645
+ /* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.dataTables.rowId", "Row") }),
2646
+ table.columns.map((column) => /* @__PURE__ */ jsx(TableHead, { children: column.label }, column.key)),
2647
+ /* @__PURE__ */ jsx(TableHead, { className: "text-right", children: tr("fluidgrids.dataTables.actions", "Actions") })
2648
+ ] }) }),
2649
+ /* @__PURE__ */ jsxs(TableBody, { children: [
2650
+ loading && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
2651
+ TableCell,
2652
+ {
2653
+ colSpan: table.columns.length + 3,
2654
+ className: "py-10 text-center text-text-secondary",
2655
+ children: tr("fluidgrids.dataTables.loadingRows", "Loading rows\u2026")
2656
+ }
2657
+ ) }),
2658
+ !loading && rows.length === 0 && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
2659
+ TableCell,
2660
+ {
2661
+ colSpan: table.columns.length + 3,
2662
+ className: "py-10 text-center text-text-secondary",
2663
+ children: tr(
2664
+ "fluidgrids.dataTables.emptyRows",
2665
+ "No rows yet. Add a row or import a CSV to get started."
2666
+ )
2667
+ }
2668
+ ) }),
2669
+ !loading && rows.map((row) => /* @__PURE__ */ jsxs(TableRow, { children: [
2670
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(
2671
+ "input",
2672
+ {
2673
+ type: "checkbox",
2674
+ checked: selectedIds.has(row.id),
2675
+ onChange: () => setSelectedIds((current) => {
2676
+ const next = new Set(current);
2677
+ if (next.has(row.id)) next.delete(row.id);
2678
+ else next.add(row.id);
2679
+ return next;
2680
+ }),
2681
+ "aria-label": tr(
2682
+ "fluidgrids.dataTables.selectRow",
2683
+ "Select row"
2684
+ )
2685
+ }
2686
+ ) }),
2687
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("code", { className: "text-xs text-text-secondary", children: row.id.slice(0, 8) }) }),
2688
+ table.columns.map((column) => /* @__PURE__ */ jsx(
2689
+ TableCell,
2690
+ {
2691
+ className: "max-w-[16rem] truncate text-sm",
2692
+ title: formatValue(row.data[column.key]),
2693
+ children: formatValue(row.data[column.key])
2694
+ },
2695
+ column.key
2696
+ )),
2697
+ /* @__PURE__ */ jsx(TableCell, { className: "text-right", children: /* @__PURE__ */ jsx(
2698
+ Button,
2699
+ {
2700
+ variant: "ghost",
2701
+ size: "icon",
2702
+ onClick: () => openEditRow(row),
2703
+ title: tr("fluidgrids.dataTables.editRow", "Edit row"),
2704
+ "aria-label": tr(
2705
+ "fluidgrids.dataTables.editRow",
2706
+ "Edit row"
2707
+ ),
2708
+ children: /* @__PURE__ */ jsx(Pencil, { className: "size-4", "aria-hidden": "true" })
2709
+ }
2710
+ ) })
2711
+ ] }, row.id))
2712
+ ] })
2713
+ ] }) }),
2714
+ total > rows.length && !loading && /* @__PURE__ */ jsx("p", { className: "border-t border-border-secondary px-4 py-3 text-xs text-text-secondary", children: tr(
2715
+ "fluidgrids.dataTables.rowLimitNote",
2716
+ "Showing the first 5,000 rows. Use workflow filters for larger tables."
2717
+ ) })
2718
+ ] }),
2719
+ /* @__PURE__ */ jsx(
2720
+ RowFormDialog,
2721
+ {
2722
+ open: rowDialogOpen,
2723
+ table,
2724
+ row: editingRow,
2725
+ onOpenChange: setRowDialogOpen,
2726
+ onSaved: async () => {
2727
+ await refetch();
2728
+ onTableChanged();
2729
+ }
2730
+ }
2731
+ )
2732
+ ] });
2733
+ }
2734
+ function DataTablesPage() {
2735
+ const tr = useTr();
2736
+ const navigate = useNavigate();
2737
+ const [searchInput, setSearchInput] = useState("");
2738
+ const [search, setSearch] = useState("");
2739
+ const { tables, total, loading, error, refetch } = useDataTables(search);
2740
+ const { deleteDataTable, loading: deleting } = useDeleteDataTable();
2741
+ const [selectedId, setSelectedId] = useState(null);
2742
+ const [tableDialogOpen, setTableDialogOpen] = useState(false);
2743
+ const [editingTable, setEditingTable] = useState(null);
2744
+ const selectedTable = useMemo(
2745
+ () => tables.find((table) => table.id === selectedId) ?? null,
2746
+ [selectedId, tables]
2747
+ );
2748
+ useEffect(() => {
2749
+ if (tables.length === 0) {
2750
+ setSelectedId(null);
2751
+ return;
2752
+ }
2753
+ if (!selectedId || !tables.some((table) => table.id === selectedId)) {
2754
+ setSelectedId(tables[0].id);
2755
+ }
2756
+ }, [selectedId, tables]);
2757
+ const refresh = useCallback(async () => {
2758
+ await refetch();
2759
+ }, [refetch]);
2760
+ const handleDeleteTable = useCallback(async () => {
2761
+ if (!selectedTable) return;
2762
+ if (!window.confirm(
2763
+ tr(
2764
+ "fluidgrids.dataTables.confirmDeleteTable",
2765
+ `Delete table "${selectedTable.name}" and all of its rows?`
2766
+ )
2767
+ )) {
2768
+ return;
2769
+ }
2770
+ try {
2771
+ await deleteDataTable(selectedTable.id);
2772
+ toast.success(tr("fluidgrids.dataTables.deleted", "Data table deleted"));
2773
+ setSelectedId(null);
2774
+ await refetch();
2775
+ } catch (error2) {
2776
+ toast.error(
2777
+ describeOperationError(
2778
+ error2,
2779
+ tr(
2780
+ "fluidgrids.dataTables.deleteFailed",
2781
+ "Failed to delete data table"
2782
+ )
2783
+ )
2784
+ );
2785
+ }
2786
+ }, [deleteDataTable, refetch, selectedTable, tr]);
2787
+ const handleTableSaved = useCallback(
2788
+ (table) => {
2789
+ if (table) setSelectedId(table.id);
2790
+ void refetch();
2791
+ },
2792
+ [refetch]
2793
+ );
2794
+ const submitSearch = useCallback(
2795
+ (event) => {
2796
+ event.preventDefault();
2797
+ setSearch(searchInput);
2798
+ },
2799
+ [searchInput]
2800
+ );
2801
+ return /* @__PURE__ */ jsxs("div", { className: "min-h-screen bg-background-primary p-4 sm:p-6", children: [
2802
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-[1500px] flex-col gap-5", children: [
2803
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between", children: [
2804
+ /* @__PURE__ */ jsxs("div", { children: [
2805
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2 text-sm text-text-secondary", children: [
2806
+ /* @__PURE__ */ jsx(Database, { className: "size-4", "aria-hidden": "true" }),
2807
+ tr("fluidgrids.dataTables.workflowData", "Workflow data")
2808
+ ] }),
2809
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-text-primary sm:text-3xl", children: tr("fluidgrids.dataTables.pageTitle", "Data Tables") }),
2810
+ /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-2xl text-text-secondary", children: tr(
2811
+ "fluidgrids.dataTables.pageSubtitle",
2812
+ "Store structured workspace data that your workflows can read and write across runs."
2813
+ ) })
2814
+ ] }),
2815
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
2816
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: () => navigate("../list"), children: [
2817
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2 size-4", "aria-hidden": "true" }),
2818
+ tr("fluidgrids.dataTables.backToWorkflows", "Back to Workflows")
2819
+ ] }),
2820
+ /* @__PURE__ */ jsxs(
2821
+ Button,
2822
+ {
2823
+ onClick: () => {
2824
+ setEditingTable(null);
2825
+ setTableDialogOpen(true);
2826
+ },
2827
+ children: [
2828
+ /* @__PURE__ */ jsx(Plus, { className: "mr-2 size-4", "aria-hidden": "true" }),
2829
+ tr("fluidgrids.dataTables.newTable", "New data table")
2830
+ ]
2831
+ }
2832
+ )
2833
+ ] })
2834
+ ] }),
2835
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-5 lg:grid-cols-[minmax(16rem,22rem)_minmax(0,1fr)]", children: [
2836
+ /* @__PURE__ */ jsxs(Card, { className: "h-fit border-border-secondary", children: [
2837
+ /* @__PURE__ */ jsxs(CardHeader, { className: "gap-3 border-b border-border-secondary p-4", children: [
2838
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
2839
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: tr("fluidgrids.dataTables.tables", "Tables") }),
2840
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", children: total })
2841
+ ] }),
2842
+ /* @__PURE__ */ jsxs("form", { className: "flex gap-2", onSubmit: submitSearch, children: [
2843
+ /* @__PURE__ */ jsxs("div", { className: "relative min-w-0 flex-1", children: [
2844
+ /* @__PURE__ */ jsx(
2845
+ Search,
2846
+ {
2847
+ className: "pointer-events-none absolute left-2.5 top-2.5 size-4 text-text-secondary",
2848
+ "aria-hidden": "true"
2849
+ }
2850
+ ),
2851
+ /* @__PURE__ */ jsx(
2852
+ Input,
2853
+ {
2854
+ className: "pl-8",
2855
+ value: searchInput,
2856
+ onChange: (event) => setSearchInput(event.target.value),
2857
+ placeholder: tr(
2858
+ "fluidgrids.dataTables.search",
2859
+ "Search tables"
2860
+ ),
2861
+ "aria-label": tr(
2862
+ "fluidgrids.dataTables.search",
2863
+ "Search tables"
2864
+ )
2865
+ }
2866
+ )
2867
+ ] }),
2868
+ /* @__PURE__ */ jsx(Button, { type: "submit", variant: "outline", size: "sm", children: tr("fluidgrids.dataTables.searchAction", "Search") })
2869
+ ] })
2870
+ ] }),
2871
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-2", children: [
2872
+ loading && /* @__PURE__ */ jsx("p", { className: "p-4 text-sm text-text-secondary", children: tr("fluidgrids.dataTables.loading", "Loading tables\u2026") }),
2873
+ !loading && tables.length === 0 && /* @__PURE__ */ jsxs("div", { className: "p-4 text-sm text-text-secondary", children: [
2874
+ /* @__PURE__ */ jsx("p", { children: tr("fluidgrids.dataTables.empty", "No data tables yet") }),
2875
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs", children: tr(
2876
+ "fluidgrids.dataTables.emptyHint",
2877
+ "Create a table to give your workflows a shared data store."
2878
+ ) })
2879
+ ] }),
2880
+ !loading && tables.map((table) => /* @__PURE__ */ jsxs(
2881
+ "button",
2882
+ {
2883
+ type: "button",
2884
+ onClick: () => setSelectedId(table.id),
2885
+ className: `mb-1 flex w-full items-start justify-between gap-3 rounded-md px-3 py-3 text-left transition-colors ${selectedId === table.id ? "bg-background-tertiary text-text-primary" : "text-text-secondary hover:bg-background-secondary hover:text-text-primary"}`,
2886
+ children: [
2887
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
2888
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-medium", children: table.name }),
2889
+ /* @__PURE__ */ jsxs("span", { className: "mt-1 block text-xs text-text-secondary", children: [
2890
+ table.rowCount,
2891
+ " ",
2892
+ tr("fluidgrids.dataTables.rows", "rows"),
2893
+ " \xB7",
2894
+ " ",
2895
+ table.columns.length,
2896
+ " ",
2897
+ tr("fluidgrids.dataTables.columns", "columns")
2898
+ ] })
2899
+ ] }),
2900
+ /* @__PURE__ */ jsx(
2901
+ Table2,
2902
+ {
2903
+ className: "mt-0.5 size-4 shrink-0",
2904
+ "aria-hidden": "true"
2905
+ }
2906
+ )
2907
+ ]
2908
+ },
2909
+ table.id
2910
+ ))
2911
+ ] })
2912
+ ] }),
2913
+ error && !selectedTable && /* @__PURE__ */ jsx(Card, { className: "border-border-secondary", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-6 text-sm text-text-secondary", children: [
2914
+ /* @__PURE__ */ jsx("p", { children: error.message }),
2915
+ /* @__PURE__ */ jsxs(
2916
+ Button,
2917
+ {
2918
+ className: "mt-4",
2919
+ variant: "outline",
2920
+ onClick: () => void refresh(),
2921
+ children: [
2922
+ /* @__PURE__ */ jsx(RefreshCw, { className: "mr-2 size-4", "aria-hidden": "true" }),
2923
+ tr("fluidgrids.dataTables.retry", "Try again")
2924
+ ]
2925
+ }
2926
+ )
2927
+ ] }) }),
2928
+ !error && !selectedTable && !loading && /* @__PURE__ */ jsx(Card, { className: "border-border-secondary", children: /* @__PURE__ */ jsxs(CardContent, { className: "flex min-h-[22rem] flex-col items-center justify-center p-6 text-center", children: [
2929
+ /* @__PURE__ */ jsx(
2930
+ Database,
2931
+ {
2932
+ className: "mb-3 size-10 text-text-secondary",
2933
+ "aria-hidden": "true"
2934
+ }
2935
+ ),
2936
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-text-primary", children: tr(
2937
+ "fluidgrids.dataTables.selectTitle",
2938
+ "Select a data table"
2939
+ ) }),
2940
+ /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-sm text-sm text-text-secondary", children: tr(
2941
+ "fluidgrids.dataTables.selectDescription",
2942
+ "Choose a table to view and edit its rows, or create your first table."
2943
+ ) })
2944
+ ] }) }),
2945
+ selectedTable && /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-3", children: [
2946
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap justify-end gap-2", children: [
2947
+ /* @__PURE__ */ jsxs(
2948
+ Button,
2949
+ {
2950
+ variant: "outline",
2951
+ size: "sm",
2952
+ onClick: () => {
2953
+ setEditingTable(selectedTable);
2954
+ setTableDialogOpen(true);
2955
+ },
2956
+ children: [
2957
+ /* @__PURE__ */ jsx(Pencil, { className: "mr-1.5 size-4", "aria-hidden": "true" }),
2958
+ tr("fluidgrids.dataTables.editTable", "Edit table")
2959
+ ]
2960
+ }
2961
+ ),
2962
+ /* @__PURE__ */ jsxs(
2963
+ Button,
2964
+ {
2965
+ variant: "outline",
2966
+ size: "sm",
2967
+ onClick: handleDeleteTable,
2968
+ disabled: deleting,
2969
+ children: [
2970
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-1.5 size-4", "aria-hidden": "true" }),
2971
+ deleting ? tr("fluidgrids.dataTables.deleting", "Deleting\u2026") : tr("fluidgrids.dataTables.deleteTable", "Delete table")
2972
+ ]
2973
+ }
2974
+ )
2975
+ ] }),
2976
+ /* @__PURE__ */ jsx(TableRowsPanel, { table: selectedTable, onTableChanged: refresh })
2977
+ ] })
2978
+ ] })
2979
+ ] }),
2980
+ /* @__PURE__ */ jsx(
2981
+ TableFormDialog,
2982
+ {
2983
+ open: tableDialogOpen,
2984
+ table: editingTable,
2985
+ onOpenChange: setTableDialogOpen,
2986
+ onSaved: handleTableSaved
2987
+ }
2988
+ )
2989
+ ] });
2990
+ }
1584
2991
 
1585
2992
  // src/graphql/client-helpers.ts
1586
2993
  function createFluidGridsClients(config2) {
@@ -1644,7 +3051,7 @@ var NODE_STATUS_CONFIG = {
1644
3051
  error: { label: "Error", color: "text-red-600", bgColor: "bg-red-100" },
1645
3052
  skipped: { label: "Skipped", color: "text-gray-400", bgColor: "bg-gray-50" }
1646
3053
  };
1647
- var Textarea2 = React4.forwardRef(
3054
+ var Textarea3 = React4.forwardRef(
1648
3055
  ({ className, ...props }, ref) => {
1649
3056
  return /* @__PURE__ */ jsx(
1650
3057
  "textarea",
@@ -1659,7 +3066,7 @@ var Textarea2 = React4.forwardRef(
1659
3066
  );
1660
3067
  }
1661
3068
  );
1662
- Textarea2.displayName = "Textarea";
3069
+ Textarea3.displayName = "Textarea";
1663
3070
  function Tabs2({
1664
3071
  className,
1665
3072
  ...props
@@ -2080,6 +3487,6 @@ var PopoverContent = React4.forwardRef(({ className, align = "center", sideOffse
2080
3487
  ) }));
2081
3488
  PopoverContent.displayName = PopoverPrimitive.Content.displayName;
2082
3489
 
2083
- export { ApprovalInboxPage, Checkbox, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FluidGridsRoot, NODE_STATUS_CONFIG, Popover, PopoverContent, PopoverTrigger, RUN_STATUS_CONFIG, ScrollArea, ScrollBar, Select2 as Select, SelectContent2 as SelectContent, SelectGroup, SelectItem2 as SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger2 as SelectTrigger, SelectValue2 as SelectValue, Separator, Switch2 as Switch, Tabs2 as Tabs, TabsContent2 as TabsContent, TabsList2 as TabsList, TabsTrigger2 as TabsTrigger, Textarea2 as Textarea, VariablesPage, WorkflowEmbedPage, createFluidGridsClients, useCreateVariable, useDecideToolApproval, useDeleteVariable, usePendingToolApprovals, useRevealVariableValue, useSaveSecretsProviderConfig, useSecretsProviderConfigs, useTestSecretsProviderConnection, useUpdateVariable, useVariables };
3490
+ export { ApprovalInboxPage, Checkbox, DataTablesPage, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FluidGridsRoot, NODE_STATUS_CONFIG, Popover, PopoverContent, PopoverTrigger, RUN_STATUS_CONFIG, ScrollArea, ScrollBar, Select2 as Select, SelectContent2 as SelectContent, SelectGroup, SelectItem2 as SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger2 as SelectTrigger, SelectValue2 as SelectValue, Separator, Switch2 as Switch, Tabs2 as Tabs, TabsContent2 as TabsContent, TabsList2 as TabsList, TabsTrigger2 as TabsTrigger, Textarea3 as Textarea, VariablesPage, WorkflowEmbedPage, createFluidGridsClients, csvToRows, parseCsv, rowsToCsv, useCreateDataTable, useCreateVariable, useDataTableRows, useDataTables, useDecideToolApproval, useDeleteDataTable, useDeleteDataTableRows, useDeleteVariable, useInsertDataTableRow, usePendingToolApprovals, useRevealVariableValue, useSaveSecretsProviderConfig, useSecretsProviderConfigs, useTestSecretsProviderConnection, useUpdateDataTable, useUpdateDataTableRow, useUpdateVariable, useVariables };
2084
3491
  //# sourceMappingURL=index.js.map
2085
3492
  //# sourceMappingURL=index.js.map