From 2b6ada03052b8811a995e9208fb82e0e94c119ae Mon Sep 17 00:00:00 2001 From: Dominic Leung Date: Sun, 13 Apr 2025 18:39:26 +0800 Subject: [PATCH 1/3] add pnpm dependencies --- .gitignore | 7 ++++++- README.md | 27 ++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index ff9d174..716b402 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,9 @@ app/src/components/.DS_Store # Workspace specific files /.vs /.idea -*.code-workspace \ No newline at end of file +*.code-workspace + +# pnlm files +pnpm-lock.yaml +node_modules/ +.pnpm-store/ diff --git a/README.md b/README.md index 517b48a..aa4f9de 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,26 @@ Inspired by the capabilities of [duckdb-wasm](https://github.com/duckdb/duckdb-w - Type your own WHERE clause. Screenshot 2024-10-06 at 9 43 27 PM -# Build and Usage Instructions +# Node.js Environment Setup -- Clone [https://github.com/yeri918/duckdb-grid](https://github.com/yeri918/duckdb-grid). -- Run `cd app` to enter the app directory. -- Run `npm i` to install dependencies. -- Run `npm start` to try it out. +Dependencies are managed by `pnpm` and dev/build processes by [Vite](https://vite.dev/). + +Follow the [pnpm docs](https://pnpm.io/installation) to install pnpm locally. For Mac, +```bash +curl -fsSL https://get.pnpm.io/install.sh | sh - +``` + +Change the `/app` directory. +```bash +# Trying to use the UI from the Vite port (5173) will lead to auth errors. +pnpm dev + +# Generate production build files will be at airflow/ui/dist +pnpm build + +# Format code in .ts, .tsx, .json, .css, .html files +pnpm format + +# Check JS/TS code in .ts, .tsx, .html files and report any errors/warnings +pnpm lint +``` From 26b925f4d134e54f481d0d0bfc4a4f38fc55012e Mon Sep 17 00:00:00 2001 From: Dominic Leung Date: Sun, 13 Apr 2025 18:51:01 +0800 Subject: [PATCH 2/3] update prettier --- app/package.json | 67 ++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/app/package.json b/app/package.json index 8dd938d..f7ea0ee 100644 --- a/app/package.json +++ b/app/package.json @@ -15,44 +15,43 @@ "deploy": "gh-pages -d dist" }, "dependencies": { - "@ag-grid-community/core": "^32.1.0", - "@ag-grid-community/react": "^32.1.0", - "@duckdb/duckdb-wasm": "^1.29.0", - "@duckdb/duckdb-wasm-shell": "^1.28.1-dev106.0", - "@emotion/react": "^11.13.3", - "@emotion/styled": "^11.13.0", - "@mui/icons-material": "^6.1.0", - "@mui/material": "^6.1.0", - "ag-grid-community": "^32.0.2", - "ag-grid-enterprise": "^32.0.2", - "ag-grid-react": "^32.0.2", + "@ag-grid-community/core": "^32.3.5", + "@ag-grid-community/react": "^32.3.5", + "@duckdb/duckdb-wasm": "1.29.1-dev132.0", + "@duckdb/duckdb-wasm-shell": "1.29.1-dev132.0", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@mui/icons-material": "^7.0.2", + "@mui/material": "^7.0.2", + "ag-grid-community": "^33.2.3", + "ag-grid-enterprise": "^33.2.3", + "ag-grid-react": "^33.2.3", "file-saver": "^2.0.5", - "papaparse": "^5.4.1", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-icons": "^5.3.0", + "papaparse": "^5.5.2", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-icons": "^5.5.0", "react-tabs": "^6.1.0", - "typescript": "5.5", + "typescript": "~5.8.3", "xlsx": "^0.18.5" }, "devDependencies": { - "@eslint/js": "^9.13.0", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^8.11.0", - "@typescript-eslint/parser": "^8.11.0", - "@vitejs/plugin-react": "^4.3.1", - "eslint": "^8.57.1", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-airbnb": "^0.0.1-security", - "eslint-plugin-react": "^7.37.2", - "eslint-plugin-react-hooks": "^4.6.2", - "eslint-plugin-react-refresh": "^0.4.7", - "gh-pages": "^6.1.1", - "globals": "^15.11.0", - "prettier": "^3.3.3", - "typescript-eslint": "^8.11.0", - "vite": "^5.3.4", - "vite-plugin-wasm": "^3.3.0" + "@eslint/js": "^9.24.0", + "@types/react": "^19.1.1", + "@types/react-dom": "^19.1.2", + "@typescript-eslint/eslint-plugin": "^8.29.1", + "@typescript-eslint/parser": "^8.29.1", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.24.0", + "eslint-config-prettier": "^10.1.2", + "eslint-plugin-airbnb": "0.0.1-security", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-refresh": "^0.4.19", + "gh-pages": "^6.3.0", + "globals": "^16.0.0", + "prettier": "^3.5.3", + "typescript-eslint": "^8.29.1", + "vite": "^6.2.6", + "vite-plugin-wasm": "^3.4.1" } } From 090a2e9e3eda3da75b9a098c5d3cfff2e9942d4d Mon Sep 17 00:00:00 2001 From: Dominic Leung Date: Sun, 13 Apr 2025 18:55:42 +0800 Subject: [PATCH 3/3] added trivago/prettier-plugin --- README.md | 9 +- app/.prettierrc.json | 13 +- app/package.json | 68 +++++---- app/src/components/grid/StdGrid.tsx | 229 +++++++++------------------- 4 files changed, 120 insertions(+), 199 deletions(-) diff --git a/README.md b/README.md index aa4f9de..36f53f5 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Inspired by the capabilities of [duckdb-wasm](https://github.com/duckdb/duckdb-w # Node.js Environment Setup -Dependencies are managed by `pnpm` and dev/build processes by [Vite](https://vite.dev/). +Dependencies are managed by `pnpm` and dev/build processes are managed by [Vite](https://vite.dev/). Follow the [pnpm docs](https://pnpm.io/installation) to install pnpm locally. For Mac, ```bash @@ -50,15 +50,8 @@ curl -fsSL https://get.pnpm.io/install.sh | sh - Change the `/app` directory. ```bash -# Trying to use the UI from the Vite port (5173) will lead to auth errors. pnpm dev - -# Generate production build files will be at airflow/ui/dist pnpm build - -# Format code in .ts, .tsx, .json, .css, .html files pnpm format - -# Check JS/TS code in .ts, .tsx, .html files and report any errors/warnings pnpm lint ``` diff --git a/app/.prettierrc.json b/app/.prettierrc.json index 358eea1..2810f90 100644 --- a/app/.prettierrc.json +++ b/app/.prettierrc.json @@ -1,5 +1,12 @@ { - "tabWidth": 2, + "$schema": "http://json.schemastore.org/prettierrc", + "endOfLine": "lf", + "importOrderSeparation": true, + "jsxSingleQuote": false, + "plugins": ["@trivago/prettier-plugin-sort-imports"], + "printWidth": 110, "singleQuote": false, - "trailingComma": "all" -} \ No newline at end of file + "tabWidth": 2, + "trailingComma": "all", + "useTabs": false +} diff --git a/app/package.json b/app/package.json index f7ea0ee..eb525ea 100644 --- a/app/package.json +++ b/app/package.json @@ -15,43 +15,45 @@ "deploy": "gh-pages -d dist" }, "dependencies": { - "@ag-grid-community/core": "^32.3.5", - "@ag-grid-community/react": "^32.3.5", - "@duckdb/duckdb-wasm": "1.29.1-dev132.0", - "@duckdb/duckdb-wasm-shell": "1.29.1-dev132.0", - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.0", - "@mui/icons-material": "^7.0.2", - "@mui/material": "^7.0.2", - "ag-grid-community": "^33.2.3", - "ag-grid-enterprise": "^33.2.3", - "ag-grid-react": "^33.2.3", + "@ag-grid-community/core": "^32.1.0", + "@ag-grid-community/react": "^32.1.0", + "@duckdb/duckdb-wasm": "^1.29.0", + "@duckdb/duckdb-wasm-shell": "^1.28.1-dev106.0", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^6.1.0", + "@mui/material": "^6.1.0", + "@trivago/prettier-plugin-sort-imports": "^5.2.2", + "ag-grid-community": "^32.0.2", + "ag-grid-enterprise": "^32.0.2", + "ag-grid-react": "^32.0.2", "file-saver": "^2.0.5", - "papaparse": "^5.5.2", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-icons": "^5.5.0", + "papaparse": "^5.4.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-icons": "^5.3.0", "react-tabs": "^6.1.0", - "typescript": "~5.8.3", + "typescript": "5.5", "xlsx": "^0.18.5" }, "devDependencies": { - "@eslint/js": "^9.24.0", - "@types/react": "^19.1.1", - "@types/react-dom": "^19.1.2", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "@vitejs/plugin-react": "^4.3.4", - "eslint": "^9.24.0", - "eslint-config-prettier": "^10.1.2", - "eslint-plugin-airbnb": "0.0.1-security", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-refresh": "^0.4.19", - "gh-pages": "^6.3.0", - "globals": "^16.0.0", - "prettier": "^3.5.3", - "typescript-eslint": "^8.29.1", - "vite": "^6.2.6", - "vite-plugin-wasm": "^3.4.1" + "@eslint/js": "^9.13.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^8.11.0", + "@typescript-eslint/parser": "^8.11.0", + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^8.57.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-airbnb": "^0.0.1-security", + "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.7", + "gh-pages": "^6.1.1", + "globals": "^15.11.0", + "prettier": "^3.3.3", + "typescript-eslint": "^8.11.0", + "vite": "^5.3.4", + "vite-plugin-wasm": "^3.3.0" } } diff --git a/app/src/components/grid/StdGrid.tsx b/app/src/components/grid/StdGrid.tsx index e13f393..2cad3f1 100644 --- a/app/src/components/grid/StdGrid.tsx +++ b/app/src/components/grid/StdGrid.tsx @@ -1,17 +1,16 @@ -import React, { - useEffect, - useState, - useMemo, - useRef, - useCallback, -} from "react"; -import { AgGridReact } from "ag-grid-react"; -import Box from "@mui/material/Box"; -import { Button, Tooltip } from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import ExpandLessIcon from "@mui/icons-material/ExpandLess"; -import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; - +// table Folder +import db from "../../duckDB"; +import AdvancedFilterBar from "./AdvancedFilterBar"; +import CustomCountBar, { + CustomFilterModelBar, + CustomRowGroupLevelBar, + CustomWaterMarkBar, +} from "./CustomStatusBar"; +import GridLoadingOverlay from "./LoadingOverlay"; +import "./StdGrid.css"; +import CustomSideBarPanel from "./customSideBarPanel"; +// duckGrid Folder +import duckGridDataSource from "./datasource/duckGridDataSource"; // grid Folder import { ColumnDataType, @@ -21,7 +20,7 @@ import { PrefetchedColumnValues, Context, } from "./interface/GridInterface"; -import handleKeyDown from "./lib/keyShortcuts"; +import { getColumnSetValues, getGroupedColumnDefs } from "./lib/columnHelper"; import { onFilterEqual, onFilterReset, @@ -29,43 +28,23 @@ import { onRowGroupExpandOneLevel, onChartSelectedCells, } from "./lib/contextMenu"; -import { getColumnSetValues, getGroupedColumnDefs } from "./lib/columnHelper"; -import initStateTable, { - fetchPreviousState, - saveState, - applySavedState, -} from "./lib/gridStates"; -import AdvancedFilterBar from "./AdvancedFilterBar"; -import CustomSideBarPanel from "./customSideBarPanel"; -import GridLoadingOverlay from "./LoadingOverlay"; -import "./StdGrid.css"; - -// duckGrid Folder -import duckGridDataSource from "./datasource/duckGridDataSource"; -import CustomCountBar, { - CustomFilterModelBar, - CustomRowGroupLevelBar, - CustomWaterMarkBar, -} from "./CustomStatusBar"; - -// table Folder -import db from "../../duckDB"; - +import initStateTable, { fetchPreviousState, saveState, applySavedState } from "./lib/gridStates"; +import handleKeyDown from "./lib/keyShortcuts"; // AgGrid imports import { StatusPanelDef } from "@ag-grid-community/core"; -import { - GridApi, - GridPreDestroyedEvent, - IsServerSideGroupOpenByDefaultParams, -} from "ag-grid-community"; -import "ag-grid-enterprise"; +import ExpandLessIcon from "@mui/icons-material/ExpandLess"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; +import { Button, Tooltip } from "@mui/material"; +import Box from "@mui/material/Box"; +import Grid from "@mui/material/Grid"; +import { GridApi, GridPreDestroyedEvent, IsServerSideGroupOpenByDefaultParams } from "ag-grid-community"; import "ag-grid-community/styles/ag-grid.css"; import "ag-grid-community/styles/ag-theme-alpine.css"; +import "ag-grid-enterprise"; +import { AgGridReact } from "ag-grid-react"; +import React, { useEffect, useState, useMemo, useRef, useCallback } from "react"; -function arePropsEqual( - prevProps: StdAgGridProps, - nextProps: StdAgGridProps, -): boolean { +function arePropsEqual(prevProps: StdAgGridProps, nextProps: StdAgGridProps): boolean { return ( prevProps.darkMode === nextProps.darkMode && prevProps.tabName === nextProps.tabName && @@ -88,9 +67,7 @@ const StdAgGrid: React.FC = (props) => { }, []); // Detect if the user prefers dark mode - const prefersDarkMode = - window.matchMedia && - window.matchMedia("(prefers-color-scheme: dark)").matches; + const prefersDarkMode = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches; const [darkMode, setDarkMode] = useState(props.darkMode || prefersDarkMode); const [fitGrid, setFitGrid] = useState(false); const [execTime, setExecTime] = useState(0); @@ -142,10 +119,7 @@ const StdAgGrid: React.FC = (props) => { const fetchColumnSetValues = async (columnDataTypes: ColumnDataType) => { const values: PrefetchedColumnValues = {}; for (const key in columnDataTypes) { - if ( - columnDataTypes[key] === "VARCHAR" || - columnDataTypes[key] === "DATE" - ) { + if (columnDataTypes[key] === "VARCHAR" || columnDataTypes[key] === "DATE") { values[key] = await getColumnSetValues(key, props.tableName); } } @@ -154,11 +128,7 @@ const StdAgGrid: React.FC = (props) => { const fetchColumnDefs = async () => { const columnDataTypes = await fetchColumnDataTypes(); const columnSetValues = await fetchColumnSetValues(columnDataTypes); - const groupedColumnDefs = getGroupedColumnDefs( - columnDataTypes, - columnSetValues, - gridApi, - ); + const groupedColumnDefs = getGroupedColumnDefs(columnDataTypes, columnSetValues, gridApi); setColumnDefs(groupedColumnDefs); }; @@ -171,9 +141,7 @@ const StdAgGrid: React.FC = (props) => { // dl: useState will trigger a rerender of the grid. The useStates will be invalid. const ctrlFDown = useRef(false); useEffect(() => { - document.addEventListener("keydown", (event: KeyboardEvent) => - handleKeyDown(event, gridApi, ctrlFDown), - ); + document.addEventListener("keydown", (event: KeyboardEvent) => handleKeyDown(event, gridApi, ctrlFDown)); return () => { // This will remove the componet when the component is unmounted. // dl: not sur eif we can remove it @@ -187,12 +155,7 @@ const StdAgGrid: React.FC = (props) => { // region: DataSource const source = `FROM ${props.tableName} SELECT *`; - const datasource = duckGridDataSource( - db!, - source, - props.tableName, - setAdvancedFilterFlag, - ); + const datasource = duckGridDataSource(db!, source, props.tableName, setAdvancedFilterFlag); // endregion // region: Context Menu @@ -200,20 +163,14 @@ const StdAgGrid: React.FC = (props) => { return [ { name: "Filters", - subMenu: [ - onFilterEqual(gridApi, params), - onFilterReset(gridApi, params), - ], + subMenu: [onFilterEqual(gridApi, params), onFilterReset(gridApi, params)], }, onFilterEqual(gridApi, params), // This is so commonly used, so we get itout. onFilterReset(gridApi, params), "separator", { name: "Groups", - subMenu: [ - onRowGroupCollapseAll(gridApi, params), - onRowGroupExpandOneLevel(gridApi, params), - ], + subMenu: [onRowGroupCollapseAll(gridApi, params), onRowGroupExpandOneLevel(gridApi, params)], }, onRowGroupCollapseAll(gridApi, params), onRowGroupExpandOneLevel(gridApi, params), @@ -235,15 +192,8 @@ const StdAgGrid: React.FC = (props) => { return { statusPanels: [ { - statusPanel: ( - customProps: CountStatusBarComponentType, - tableName: string, - ) => ( - + statusPanel: (customProps: CountStatusBarComponentType, tableName: string) => ( + ), }, { @@ -356,9 +306,7 @@ const StdAgGrid: React.FC = (props) => { gridApi.sizeColumnsToFit(); } } else { - const allColumnIds = gridApi - .getColumnDefs() - .map((column: { colId: any }) => column.colId); + const allColumnIds = gridApi.getColumnDefs().map((column: { colId: any }) => column.colId); gridApi.autoSizeColumns(allColumnIds, { autoSizeMode: "fitCellContents", }); @@ -440,42 +388,37 @@ const StdAgGrid: React.FC = (props) => { const controller = useMemo( () => ( - + - - + + - - + - - + - + - + - - - {isExpanded && ( - - - - )} - - -
{renderExecutionTime()}
-
-
+ +
+ )}
), [loading, isExpanded], @@ -562,9 +482,8 @@ const StdAgGrid: React.FC = (props) => { return ( {controller}