@sqlrooms/data-table 0.7.0 → 0.8.0
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/DataTableModal.d.ts +4 -10
- package/dist/DataTableModal.d.ts.map +1 -1
- package/dist/DataTableModal.js +3 -7
- package/dist/DataTableModal.js.map +1 -1
- package/dist/QueryDataTable.d.ts.map +1 -1
- package/dist/QueryDataTable.js +15 -5
- package/dist/QueryDataTable.js.map +1 -1
- package/package.json +5 -5
package/dist/DataTableModal.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { UseDisclosureReturnValue } from '@sqlrooms/ui';
|
|
1
2
|
import { FC } from 'react';
|
|
2
3
|
/**
|
|
3
4
|
* A modal component for displaying a table with data from a SQL query.
|
|
@@ -14,16 +15,12 @@ import { FC } from 'react';
|
|
|
14
15
|
* import { DataTableModal } from '@sqlrooms/data-table';
|
|
15
16
|
*
|
|
16
17
|
* const MyComponent = () => {
|
|
17
|
-
* const
|
|
18
|
-
*
|
|
18
|
+
* const tableModal = useDisclosure();
|
|
19
19
|
* return (
|
|
20
20
|
* <DataTableModal
|
|
21
21
|
* title="Users"
|
|
22
22
|
* query="SELECT * FROM users LIMIT 10"
|
|
23
|
-
* tableModal={
|
|
24
|
-
* isOpen,
|
|
25
|
-
* onClose: () => setIsOpen(false)
|
|
26
|
-
* }}
|
|
23
|
+
* tableModal={tableModal}
|
|
27
24
|
* />
|
|
28
25
|
* );
|
|
29
26
|
* };
|
|
@@ -32,10 +29,7 @@ import { FC } from 'react';
|
|
|
32
29
|
declare const DataTableModal: FC<{
|
|
33
30
|
title: string | undefined;
|
|
34
31
|
query: string | undefined;
|
|
35
|
-
tableModal:
|
|
36
|
-
isOpen: boolean;
|
|
37
|
-
onClose: () => void;
|
|
38
|
-
};
|
|
32
|
+
tableModal: Pick<UseDisclosureReturnValue, 'isOpen' | 'onClose'>;
|
|
39
33
|
}>;
|
|
40
34
|
export default DataTableModal;
|
|
41
35
|
//# sourceMappingURL=DataTableModal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTableModal.d.ts","sourceRoot":"","sources":["../src/DataTableModal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DataTableModal.d.ts","sourceRoot":"","sources":["../src/DataTableModal.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,wBAAwB,EACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAGzB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,cAAc,EAAE,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,UAAU,EAAE,IAAI,CAAC,wBAAwB,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;CAClE,CAyBA,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
package/dist/DataTableModal.js
CHANGED
|
@@ -16,23 +16,19 @@ import QueryDataTable from './QueryDataTable';
|
|
|
16
16
|
* import { DataTableModal } from '@sqlrooms/data-table';
|
|
17
17
|
*
|
|
18
18
|
* const MyComponent = () => {
|
|
19
|
-
* const
|
|
20
|
-
*
|
|
19
|
+
* const tableModal = useDisclosure();
|
|
21
20
|
* return (
|
|
22
21
|
* <DataTableModal
|
|
23
22
|
* title="Users"
|
|
24
23
|
* query="SELECT * FROM users LIMIT 10"
|
|
25
|
-
* tableModal={
|
|
26
|
-
* isOpen,
|
|
27
|
-
* onClose: () => setIsOpen(false)
|
|
28
|
-
* }}
|
|
24
|
+
* tableModal={tableModal}
|
|
29
25
|
* />
|
|
30
26
|
* );
|
|
31
27
|
* };
|
|
32
28
|
* ```
|
|
33
29
|
*/
|
|
34
30
|
const DataTableModal = ({ title, query, tableModal }) => {
|
|
35
|
-
return (_jsx(Dialog, { open: tableModal.isOpen, onOpenChange: (isOpen) => !isOpen && tableModal.onClose(), children: _jsxs(DialogContent, { className: "h-[80vh] max-w-[75vw]", "aria-describedby": "data-table-modal", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title ? `Table "${title}"` : '' }), _jsx(DialogDescription, { className: "hidden", children: title })] }), _jsx("div", { className: "flex-1
|
|
31
|
+
return (_jsx(Dialog, { open: tableModal.isOpen, onOpenChange: (isOpen) => !isOpen && tableModal.onClose(), children: _jsxs(DialogContent, { className: "h-[80vh] max-w-[75vw]", "aria-describedby": "data-table-modal", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title ? `Table "${title}"` : '' }), _jsx(DialogDescription, { className: "hidden", children: title })] }), _jsx("div", { className: "bg-muted flex-1 overflow-hidden", children: tableModal.isOpen && query ? _jsx(QueryDataTable, { query: query }) : null }), _jsx(DialogFooter, { children: _jsx(Button, { variant: "outline", onClick: tableModal.onClose, children: "Close" }) })] }) }));
|
|
36
32
|
};
|
|
37
33
|
export default DataTableModal;
|
|
38
34
|
//# sourceMappingURL=DataTableModal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTableModal.js","sourceRoot":"","sources":["../src/DataTableModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,
|
|
1
|
+
{"version":3,"file":"DataTableModal.js","sourceRoot":"","sources":["../src/DataTableModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,GAEZ,MAAM,cAAc,CAAC;AAEtB,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,cAAc,GAIf,CAAC,EAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAC,EAAE,EAAE;IAClC,OAAO,CACL,KAAC,MAAM,IACL,IAAI,EAAE,UAAU,CAAC,MAAM,EACvB,YAAY,EAAE,CAAC,MAAe,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,UAAU,CAAC,OAAO,EAAE,YAElE,MAAC,aAAa,IACZ,SAAS,EAAC,uBAAuB,sBAChB,kBAAkB,aAEnC,MAAC,YAAY,eACX,KAAC,WAAW,cAAE,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,GAAe,EAC5D,KAAC,iBAAiB,IAAC,SAAS,EAAC,QAAQ,YAAE,KAAK,GAAqB,IACpD,EACf,cAAK,SAAS,EAAC,iCAAiC,YAC7C,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAC,cAAc,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAC,CAAC,IAAI,GACjE,EACN,KAAC,YAAY,cACX,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,UAAU,CAAC,OAAO,sBAE5C,GACI,IACD,GACT,CACV,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["import {\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n UseDisclosureReturnValue,\n} from '@sqlrooms/ui';\nimport {FC} from 'react';\nimport QueryDataTable from './QueryDataTable';\n\n/**\n * A modal component for displaying a table with data from a SQL query.\n *\n * @component\n * @param props - Component props\n * @param props.title - The title of the table\n * @param props.query - The SQL query to execute and display in the table\n * @param props.tableModal - An object containing the modal's open state and close function\n *\n * @example\n * ```tsx\n * import { useState } from 'react';\n * import { DataTableModal } from '@sqlrooms/data-table';\n *\n * const MyComponent = () => {\n * const tableModal = useDisclosure();\n * return (\n * <DataTableModal\n * title=\"Users\"\n * query=\"SELECT * FROM users LIMIT 10\"\n * tableModal={tableModal}\n * />\n * );\n * };\n * ```\n */\nconst DataTableModal: FC<{\n title: string | undefined;\n query: string | undefined;\n tableModal: Pick<UseDisclosureReturnValue, 'isOpen' | 'onClose'>;\n}> = ({title, query, tableModal}) => {\n return (\n <Dialog\n open={tableModal.isOpen}\n onOpenChange={(isOpen: boolean) => !isOpen && tableModal.onClose()}\n >\n <DialogContent\n className=\"h-[80vh] max-w-[75vw]\"\n aria-describedby=\"data-table-modal\"\n >\n <DialogHeader>\n <DialogTitle>{title ? `Table \"${title}\"` : ''}</DialogTitle>\n <DialogDescription className=\"hidden\">{title}</DialogDescription>\n </DialogHeader>\n <div className=\"bg-muted flex-1 overflow-hidden\">\n {tableModal.isOpen && query ? <QueryDataTable query={query} /> : null}\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={tableModal.onClose}>\n Close\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n};\n\nexport default DataTableModal;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryDataTable.d.ts","sourceRoot":"","sources":["../src/QueryDataTable.tsx"],"names":[],"mappings":"AASA,OAAO,EAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"QueryDataTable.d.ts","sourceRoot":"","sources":["../src/QueryDataTable.tsx"],"names":[],"mappings":"AASA,OAAO,EAAC,EAAE,EAAyC,MAAM,OAAO,CAAC;AAIjE,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC;CAChC,CAAC;AAoGF,QAAA,MAAM,0BAA0B,EAAE,EAAE,CAAC,mBAAmB,CASvD,CAAC;AAEF,eAAe,0BAA0B,CAAC"}
|
package/dist/QueryDataTable.js
CHANGED
|
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { SpinnerPane } from '@sqlrooms/ui';
|
|
4
4
|
import { escapeId, exportToCsv, getColValAsNumber, useDuckDb, } from '@sqlrooms/duckdb';
|
|
5
5
|
import { genRandomStr } from '@sqlrooms/utils';
|
|
6
|
-
import { Suspense, useEffect, useState } from 'react';
|
|
6
|
+
import { Suspense, useEffect, useMemo, useState } from 'react';
|
|
7
7
|
import DataTablePaginated from './DataTablePaginated';
|
|
8
8
|
import useArrowDataTable from './useArrowDataTable';
|
|
9
9
|
const QueryDataTable = ({ query }) => {
|
|
@@ -17,12 +17,22 @@ const QueryDataTable = ({ query }) => {
|
|
|
17
17
|
const [data, setData] = useState(null);
|
|
18
18
|
const [isFetching, setIsFetching] = useState(false);
|
|
19
19
|
const [isExporting, setIsExporting] = useState(false);
|
|
20
|
+
// Sanitize the query generated by LLM to remove trailing semicolons, comments, and extra spaces
|
|
21
|
+
const sanitizedQuery = useMemo(() => {
|
|
22
|
+
return query
|
|
23
|
+
.trim() // Remove leading/trailing whitespace
|
|
24
|
+
.replace(/;+$/, '') // Remove all trailing semicolons
|
|
25
|
+
.replace(/--.*$/gm, '') // Remove single-line comments
|
|
26
|
+
.replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
|
|
27
|
+
.replace(/\s+/g, ' '); // Normalize whitespace to single spaces
|
|
28
|
+
}, [query]);
|
|
20
29
|
// Fetch row count
|
|
21
30
|
useEffect(() => {
|
|
22
31
|
const fetchCount = async () => {
|
|
23
32
|
try {
|
|
24
33
|
setIsFetching(true);
|
|
25
|
-
const
|
|
34
|
+
const countQuery = `SELECT COUNT(*)::int FROM (${sanitizedQuery})`;
|
|
35
|
+
const result = await conn.query(countQuery);
|
|
26
36
|
setCount(getColValAsNumber(result));
|
|
27
37
|
}
|
|
28
38
|
catch (error) {
|
|
@@ -33,14 +43,14 @@ const QueryDataTable = ({ query }) => {
|
|
|
33
43
|
}
|
|
34
44
|
};
|
|
35
45
|
fetchCount();
|
|
36
|
-
}, [
|
|
46
|
+
}, [conn, sanitizedQuery]);
|
|
37
47
|
// Fetch data
|
|
38
48
|
useEffect(() => {
|
|
39
49
|
const fetchData = async () => {
|
|
40
50
|
try {
|
|
41
51
|
setIsFetching(true);
|
|
42
52
|
const result = await conn.query(`SELECT * FROM (
|
|
43
|
-
${
|
|
53
|
+
${sanitizedQuery}
|
|
44
54
|
) ${sorting.length > 0
|
|
45
55
|
? `ORDER BY ${sorting
|
|
46
56
|
.map((d) => `${escapeId(d.id)}${d.desc ? ' DESC' : ''}`)
|
|
@@ -58,7 +68,7 @@ const QueryDataTable = ({ query }) => {
|
|
|
58
68
|
}
|
|
59
69
|
};
|
|
60
70
|
fetchData();
|
|
61
|
-
}, [
|
|
71
|
+
}, [pagination, sorting, conn, sanitizedQuery]);
|
|
62
72
|
const arrowTableData = useArrowDataTable(data);
|
|
63
73
|
const handleExport = async () => {
|
|
64
74
|
if (!query)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryDataTable.js","sourceRoot":"","sources":["../src/QueryDataTable.tsx"],"names":[],"mappings":";;AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AACzC,OAAO,EACL,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAK,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"QueryDataTable.js","sourceRoot":"","sources":["../src/QueryDataTable.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SpinnerPane} from '@sqlrooms/ui';\nimport {\n escapeId,\n exportToCsv,\n getColValAsNumber,\n useDuckDb,\n} from '@sqlrooms/duckdb';\nimport {genRandomStr} from '@sqlrooms/utils';\nimport {PaginationState, SortingState} from '@tanstack/table-core';\nimport {FC, Suspense, useEffect, useMemo, useState} from 'react';\nimport DataTablePaginated from './DataTablePaginated';\nimport useArrowDataTable from './useArrowDataTable';\n\nexport type QueryDataTableProps = {\n query: string;\n queryKeyComponents?: unknown[];\n};\n\nconst QueryDataTable: FC<QueryDataTableProps> = ({query}) => {\n const {conn} = useDuckDb();\n const [sorting, setSorting] = useState<SortingState>([]);\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 100,\n });\n\n const [count, setCount] = useState<number | undefined>(undefined);\n const [data, setData] = useState<any>(null);\n const [isFetching, setIsFetching] = useState(false);\n const [isExporting, setIsExporting] = useState(false);\n\n // Sanitize the query generated by LLM to remove trailing semicolons, comments, and extra spaces\n const sanitizedQuery = useMemo(() => {\n return query\n .trim() // Remove leading/trailing whitespace\n .replace(/;+$/, '') // Remove all trailing semicolons\n .replace(/--.*$/gm, '') // Remove single-line comments\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Remove multi-line comments\n .replace(/\\s+/g, ' '); // Normalize whitespace to single spaces\n }, [query]);\n\n // Fetch row count\n useEffect(() => {\n const fetchCount = async () => {\n try {\n setIsFetching(true);\n const countQuery = `SELECT COUNT(*)::int FROM (${sanitizedQuery})`;\n const result = await conn.query(countQuery);\n setCount(getColValAsNumber(result));\n } catch (error) {\n console.error('Error fetching count:', error);\n } finally {\n setIsFetching(false);\n }\n };\n\n fetchCount();\n }, [conn, sanitizedQuery]);\n\n // Fetch data\n useEffect(() => {\n const fetchData = async () => {\n try {\n setIsFetching(true);\n const result = await conn.query(\n `SELECT * FROM (\n ${sanitizedQuery}\n ) ${\n sorting.length > 0\n ? `ORDER BY ${sorting\n .map((d) => `${escapeId(d.id)}${d.desc ? ' DESC' : ''}`)\n .join(', ')}`\n : ''\n }\n OFFSET ${pagination.pageIndex * pagination.pageSize}\n LIMIT ${pagination.pageSize}`,\n );\n setData(result);\n } catch (error) {\n console.error('Error fetching data:', error);\n } finally {\n setIsFetching(false);\n }\n };\n\n fetchData();\n }, [pagination, sorting, conn, sanitizedQuery]);\n\n const arrowTableData = useArrowDataTable(data);\n\n const handleExport = async () => {\n if (!query) return;\n try {\n setIsExporting(true);\n await exportToCsv(query, `export-${genRandomStr(5)}.csv`);\n } finally {\n setIsExporting(false);\n }\n };\n\n return (\n <DataTablePaginated\n {...arrowTableData}\n pageCount={Math.ceil((count ?? 0) / pagination.pageSize)}\n numRows={count}\n isFetching={isFetching}\n pagination={pagination}\n onPaginationChange={setPagination}\n sorting={sorting}\n onSortingChange={setSorting}\n onExport={handleExport}\n isExporting={isExporting}\n />\n );\n};\n\nconst QueryDataTableWithSuspense: FC<QueryDataTableProps> = (props) => {\n return (\n <Suspense fallback={<SpinnerPane className=\"w-full h-full\" />}>\n <QueryDataTable\n {...props}\n key={props.query} // reset state when query changes\n />\n </Suspense>\n );\n};\n\nexport default QueryDataTableWithSuspense;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sqlrooms/data-table",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@heroicons/react": "*",
|
|
23
|
-
"@sqlrooms/duckdb": "0.
|
|
24
|
-
"@sqlrooms/ui": "0.
|
|
25
|
-
"@sqlrooms/utils": "0.
|
|
23
|
+
"@sqlrooms/duckdb": "0.8.0",
|
|
24
|
+
"@sqlrooms/ui": "0.8.0",
|
|
25
|
+
"@sqlrooms/utils": "0.8.0",
|
|
26
26
|
"@tanstack/react-table": "^8.10.7",
|
|
27
27
|
"@tanstack/table-core": "^8.10.7",
|
|
28
28
|
"react-virtual": "2.10.4"
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"lint": "eslint .",
|
|
39
39
|
"typedoc": "typedoc"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "99b46a96ab900e6b005bcd30cfbfe7b3c9d51f8d"
|
|
42
42
|
}
|