From 56ebc32d9351fb17e4e1e740272b6482bf02a8b3 Mon Sep 17 00:00:00 2001 From: frectonz Date: Tue, 25 Jun 2024 15:13:03 +0300 Subject: [PATCH] feat: allow users to disable auto execute --- ui/package-lock.json | 127 ++++++++++++++++++++++++++++++++ ui/package.json | 2 + ui/src/components/editor.tsx | 1 - ui/src/components/ui/toggle.tsx | 43 +++++++++++ ui/src/routes/query.lazy.tsx | 48 +++++++++--- 5 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 ui/src/components/ui/toggle.tsx diff --git a/ui/package-lock.json b/ui/package-lock.json index 3adb883..d85b1d0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -13,10 +13,12 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toggle": "^1.1.0", "@tanstack/react-query": "^5.44.0", "@tanstack/react-query-devtools": "^5.44.0", "@tanstack/react-router": "^1.35.3", "@tanstack/react-table": "^8.17.3", + "@uidotdev/usehooks": "^2.4.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.394.0", @@ -2380,6 +2382,119 @@ } } }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.0.tgz", + "integrity": "sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", @@ -3303,6 +3418,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uidotdev/usehooks": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.4.1.tgz", + "integrity": "sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg==", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", diff --git a/ui/package.json b/ui/package.json index fd70d16..d69ce08 100644 --- a/ui/package.json +++ b/ui/package.json @@ -16,10 +16,12 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toggle": "^1.1.0", "@tanstack/react-query": "^5.44.0", "@tanstack/react-query-devtools": "^5.44.0", "@tanstack/react-router": "^1.35.3", "@tanstack/react-table": "^8.17.3", + "@uidotdev/usehooks": "^2.4.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.394.0", diff --git a/ui/src/components/editor.tsx b/ui/src/components/editor.tsx index 842a724..28a1226 100644 --- a/ui/src/components/editor.tsx +++ b/ui/src/components/editor.tsx @@ -33,7 +33,6 @@ export const Editor: FunctionComponent = ({ value, onChange }) => { bottom: 20, }, fontFamily: "JetBrains Mono", - cursorStyle: "block", automaticLayout: true, readOnly: onChange === undefined, }); diff --git a/ui/src/components/ui/toggle.tsx b/ui/src/components/ui/toggle.tsx new file mode 100644 index 0000000..b20d575 --- /dev/null +++ b/ui/src/components/ui/toggle.tsx @@ -0,0 +1,43 @@ +import * as React from "react"; +import * as TogglePrimitive from "@radix-ui/react-toggle"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const toggleVariants = cva( + "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground", + { + variants: { + variant: { + default: "bg-transparent", + outline: + "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground", + }, + size: { + default: "h-10 px-3", + sm: "h-9 px-2.5", + lg: "h-11 px-5", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +const Toggle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, size, ...props }, ref) => ( + +)); + +Toggle.displayName = TogglePrimitive.Root.displayName; + +export { Toggle, toggleVariants }; diff --git a/ui/src/routes/query.lazy.tsx b/ui/src/routes/query.lazy.tsx index 97468cb..7059cb7 100644 --- a/ui/src/routes/query.lazy.tsx +++ b/ui/src/routes/query.lazy.tsx @@ -1,14 +1,18 @@ import "react-data-grid/lib/styles.css"; +import { useEffect, useState } from "react"; import { z } from "zod"; -import { useState } from "react"; import DataGrid from "react-data-grid"; +import { Play, Terminal } from "lucide-react"; import { useQuery } from "@tanstack/react-query"; +import { useDebounce } from "@uidotdev/usehooks"; import { createFileRoute } from "@tanstack/react-router"; import { cn } from "@/lib/utils"; import { fetchQuery } from "@/api"; import { Editor } from "@/components/editor"; +import { Toggle } from "@/components/ui/toggle"; +import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; import { useTheme } from "@/provider/theme.provider"; @@ -22,14 +26,19 @@ function Query() { const navigate = Route.useNavigate(); const currentTheme = useTheme(); - const [code, setCode] = useState(sql ?? "select 1 + 1"); + const [codeState, setCode] = useState(sql ?? "select 1 + 1"); + const code = useDebounce(codeState, 100); - const { data, error } = useQuery({ + const [autoExecute, setAutoExecute] = useState(true); + + const { data, refetch, isLoading } = useQuery({ queryKey: ["query", code], queryFn: () => fetchQuery(code), + enabled: autoExecute, }); + const grid = !data ? ( - !error && + isLoading && ) : ( ({ key: col, name: col }))} @@ -43,15 +52,36 @@ function Query() { /> ); - const handleChange = (sql: string) => { - setCode(sql); - navigate({ search: { sql } }); - }; + useEffect(() => { + navigate({ + search: { + sql: code, + }, + }); + }, [code]); return ( <>
- + setCode(val)} /> +
+ setAutoExecute(val)} + title={autoExecute ? "Disable Auto Execute" : "Enable Auto Execute"} + > + + + + {!autoExecute && ( + + )} +
{grid}