diff --git a/package.json b/package.json
index b0ca147..927ff42 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"@reduxjs/toolkit": "^1.7.1",
"@rematch/core": "^2.2.0",
"@rematch/immer": "^2.1.3",
+ "@types/react-virtualized": "^9.21.16",
"apache-arrow": "^6.0.1",
"chakra-react-select": "^1.3.2",
"compassql": "^0.21.2",
@@ -37,6 +38,7 @@
"react-instantsearch-dom": "^6.15.0",
"react-redux": "^7.2.6",
"react-vega": "^7.4.4",
+ "react-virtualized": "^9.22.3",
"redux": "^4.1.2",
"reselect": "^4.1.4",
"sqlstring": "^2.3.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e8b8fbc..fb42aae 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,6 +17,7 @@ specifiers:
'@types/react': ^17.0.35
'@types/react-dom': ^17.0.11
'@types/react-instantsearch-core': ^6.10.5
+ '@types/react-virtualized': ^9.21.16
apache-arrow: ^6.0.1
chakra-react-select: ^1.3.2
compassql: ^0.21.2
@@ -35,6 +36,7 @@ specifiers:
react-instantsearch-dom: ^6.15.0
react-redux: ^7.2.6
react-vega: ^7.4.4
+ react-virtualized: ^9.22.3
redux: ^4.1.2
reselect: ^4.1.4
sqlstring: ^2.3.2
@@ -57,6 +59,7 @@ dependencies:
'@reduxjs/toolkit': 1.7.1_react-redux@7.2.6+react@17.0.2
'@rematch/core': 2.2.0_redux@4.1.2
'@rematch/immer': 2.1.3_ed1556fc8f632794cbf1d2aaf9845db1
+ '@types/react-virtualized': 9.21.16
apache-arrow: 6.0.1
chakra-react-select: 1.3.2_e7d2d323dd6853664c50a66f3b0bb50f
compassql: 0.21.2_vega@5.21.0
@@ -75,6 +78,7 @@ dependencies:
react-instantsearch-dom: 6.15.0_react-dom@17.0.2+react@17.0.2
react-redux: 7.2.6_react-dom@17.0.2+react@17.0.2
react-vega: 7.4.4_4073cc14f0b3a4b719b0071b64030d94
+ react-virtualized: 9.22.3_react-dom@17.0.2+react@17.0.2
redux: 4.1.2
reselect: 4.1.4
sqlstring: 2.3.2
@@ -449,7 +453,7 @@ packages:
resolution: {integrity: sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==}
engines: {node: '>=6.9.0'}
dependencies:
- regenerator-runtime: 0.13.4
+ regenerator-runtime: 0.13.9
dev: false
/@babel/runtime/7.16.3:
@@ -2055,6 +2059,13 @@ packages:
'@types/react': 17.0.35
dev: false
+ /@types/react-virtualized/9.21.16:
+ resolution: {integrity: sha512-25QMrouz1VKq5T68+9JfRq3GP4JmN20ARi+hl5z7NMmriy07XmGd1Yh3I4EIZjmifpXhHZoQS/ny2fzZRyiAiw==}
+ dependencies:
+ '@types/prop-types': 15.7.4
+ '@types/react': 17.0.35
+ dev: false
+
/@types/react/16.14.21:
resolution: {integrity: sha512-rY4DzPKK/4aohyWiDRHS2fotN5rhBSK6/rz1X37KzNna9HJyqtaGAbq9fVttrEPWF5ywpfIP1ITL8Xi2QZn6Eg==}
dependencies:
@@ -2656,6 +2667,11 @@ packages:
engines: {node: '>=0.8'}
dev: false
+ /clsx/1.1.1:
+ resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==}
+ engines: {node: '>=6'}
+ dev: false
+
/code-point-at/1.1.0:
resolution: {integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=}
engines: {node: '>=0.10.0'}
@@ -5274,6 +5290,10 @@ packages:
/react-is/17.0.2:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+ /react-lifecycles-compat/3.0.4:
+ resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
+ dev: false
+
/react-redux/7.2.6_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==}
peerDependencies:
@@ -5402,6 +5422,22 @@ packages:
vega-lite: 5.0.0_vega@5.21.0
dev: false
+ /react-virtualized/9.22.3_react-dom@17.0.2+react@17.0.2:
+ resolution: {integrity: sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==}
+ peerDependencies:
+ react: ^15.3.0 || ^16.0.0-alpha
+ react-dom: ^15.3.0 || ^16.0.0-alpha
+ dependencies:
+ '@babel/runtime': 7.16.3
+ clsx: 1.1.1
+ dom-helpers: 5.2.1
+ loose-envify: 1.4.0
+ prop-types: 15.7.2
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-lifecycles-compat: 3.0.4
+ dev: false
+
/react/17.0.2:
resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
engines: {node: '>=0.10.0'}
diff --git a/src/features/sqlEditor/components/TableGrid.tsx b/src/features/sqlEditor/components/TableGrid.tsx
new file mode 100644
index 0000000..90bb08b
--- /dev/null
+++ b/src/features/sqlEditor/components/TableGrid.tsx
@@ -0,0 +1,11 @@
+import React from "react";
+import { useAppSelector } from "hooks";
+import { ArrowTableGrid } from "./arrow-viewer/ArrowTableGrid";
+
+export const TableGrid = () => {
+ const data = useAppSelector((s) => s.sqlQuery.data);
+ const status = useAppSelector((s) => s.sqlQuery.status);
+ return status == "completed" ? (
+
+ ) : null;
+};
diff --git a/src/features/sqlEditor/components/arrow-viewer/ArrowTableGrid.tsx b/src/features/sqlEditor/components/arrow-viewer/ArrowTableGrid.tsx
new file mode 100644
index 0000000..df5b033
--- /dev/null
+++ b/src/features/sqlEditor/components/arrow-viewer/ArrowTableGrid.tsx
@@ -0,0 +1,101 @@
+// From github.com/cwharris/arrow-viewer
+import {Table as ArrowTable} from "apache-arrow";
+
+import { valueToString } from "utils/arrow-utils"
+
+import { Table, Column, AutoSizer, Index } from "react-virtualized";
+
+import "react-virtualized/styles.css";
+import { defaultRowRenderer, TableCellProps, TableHeaderProps, TableHeaderRowProps, TableRowProps } from "react-virtualized/dist/es/Table";
+
+export function ArrowTableGrid({
+ table,
+ width,
+ height,
+}: {
+ table: ArrowTable;
+ width: number;
+ height: number;
+}): JSX.Element {
+ return (
+
+ {(size) => (
+ table.get(index)}
+ rowRenderer={(props: TableRowProps) => {
+ // console.log(props);
+
+ return defaultRowRenderer({
+ ...props,
+ style: { ...props.style, width: props.style.width - 15 },
+ });
+ }}
+ headerStyle={headerStyle()}
+ headerRowRenderer={({
+ className,
+ columns,
+ style,
+ }: TableHeaderRowProps) => (
+
+ {columns}
+
+ )}
+ >
+ {table.schema.fields.map((field, idx) => {
+ // console.log(field, idx);
+
+ return (
+ {
+ // console.log(props);
+ const d = props.rowData[idx];
+ // console.log(d);
+ return d;
+ }}
+ cellRenderer={({ cellData }: TableCellProps) =>
+ valueToString(cellData)
+ }
+ headerRenderer={({
+ label,
+ }: TableHeaderProps) => label}
+ />
+ );
+ })}
+
+ )}
+
+ );
+}
+
+const headerStyle = () =>
+ ({ textAlign: "right", textTransform: "none" } as React.CSSProperties);
+
+const rowStyle = ({ index }: Index) =>
+ index % 2 === 0
+ ? {
+ ...headerStyle(),
+ borderBottom: "1px solid #e0e0e0",
+ backgroundColor: "#fff",
+ }
+ : {
+ ...headerStyle(),
+ borderBottom: "1px solid #e0e0e0",
+ backgroundColor: "#fafafa",
+ };
diff --git a/src/features/workspace/components/Workspace.tsx b/src/features/workspace/components/Workspace.tsx
index 3377fc9..dbe17b6 100644
--- a/src/features/workspace/components/Workspace.tsx
+++ b/src/features/workspace/components/Workspace.tsx
@@ -1,6 +1,7 @@
import { Box, Text } from "@chakra-ui/react";
import { DataSelector } from "features/selectData/components/DataSelector";
import { SQLEditor } from "features/sqlEditor/components/SQLEditor";
+import { TableGrid } from "features/sqlEditor/components/TableGrid";
import {
IJsonModel,
Layout,
@@ -22,6 +23,7 @@ const ComponentsMap: Record> = {
fields: Fields,
sqlEditor: SQLEditor,
selectData: DataSelector,
+ tableGrid: TableGrid
};
export const Workspace = () => {
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
new file mode 100644
index 0000000..4a355ad
--- /dev/null
+++ b/src/hooks/index.ts
@@ -0,0 +1,6 @@
+import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
+import type { RootState, Dispatch } from 'store/store'
+
+// Use throughout your app instead of plain `useDispatch` and `useSelector`
+export const useAppDispatch = () => useDispatch()
+export const useAppSelector: TypedUseSelectorHook = useSelector
\ No newline at end of file
diff --git a/src/models/workspace.ts b/src/models/workspace.ts
index 9342af8..378e588 100644
--- a/src/models/workspace.ts
+++ b/src/models/workspace.ts
@@ -42,7 +42,7 @@ const initialModel = {
type: "tab",
enableClose: false,
name: "Table View",
- component: "button",
+ component: "tableGrid",
},
],
},
diff --git a/src/utils/arrow-utils.ts b/src/utils/arrow-utils.ts
new file mode 100644
index 0000000..0db3fc6
--- /dev/null
+++ b/src/utils/arrow-utils.ts
@@ -0,0 +1,22 @@
+// from import { valueToString } from "apache-arrow/util/pretty";
+export function valueToString(x) {
+ if (x === null) {
+ return 'null';
+ }
+ if (x === undefined) {
+ return 'undefined';
+ }
+ switch (typeof x) {
+ case 'number': return `${x}`;
+ case 'bigint': return `${x}`;
+ case 'string': return `"${x}"`;
+ }
+ // If [Symbol.toPrimitive] is implemented (like in BN)
+ // use it instead of JSON.stringify(). This ensures we
+ // print BigInts, Decimals, and Binary in their native
+ // representation
+ if (typeof x[Symbol.toPrimitive] === 'function') {
+ return x[Symbol.toPrimitive]('string');
+ }
+ return ArrayBuffer.isView(x) ? `[${x}]` : JSON.stringify(x);
+}
\ No newline at end of file