feat: use drawer instead of modal for sql query

This commit is contained in:
steven
2023-03-28 16:43:15 +08:00
parent 2fb70e11ff
commit 65f2100f50
8 changed files with 503 additions and 88 deletions

View File

@ -1,11 +1,8 @@
import { useState } from "react";
import { createPortal } from "react-dom";
import { toast } from "react-hot-toast";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { useConnectionStore } from "@/store";
import { useConnectionStore, useQueryStore } from "@/store";
import Icon from "./Icon";
import ExecuteStatementModal from "./ExecuteStatementModal";
interface Props {
language: string;
@ -19,7 +16,7 @@ const checkStatementIsSelect = (statement: string) => {
export const CodeBlock = (props: Props) => {
const { language, value } = props;
const connectionStore = useConnectionStore();
const [showExecuteQueryModal, setShowExecuteQueryModal] = useState(false);
const queryStore = useQueryStore();
const currentConnectionCtx = connectionStore.currentConnectionCtx;
// Only show execute button in the following situations:
// * SQL code, and it is a SELECT statement;
@ -37,44 +34,44 @@ export const CodeBlock = (props: Props) => {
});
};
const handleExecuteQuery = () => {
if (!currentConnectionCtx) {
toast.error("Please select a connection first");
return;
}
queryStore.setContext({
connection: currentConnectionCtx.connection,
database: currentConnectionCtx.database,
statement: value,
});
queryStore.toggleDrawer(true);
};
return (
<>
<div className="w-full max-w-full relative font-sans text-[16px]">
<div className="flex items-center justify-between py-2 px-4">
<span className="text-xs text-white font-mono">{language}</span>
<div className="flex items-center space-x-2">
<div className="w-full max-w-full relative font-sans text-[16px]">
<div className="flex items-center justify-between py-2 px-4">
<span className="text-xs text-white font-mono">{language}</span>
<div className="flex items-center space-x-2">
<button
className="flex justify-center items-center rounded bg-none w-6 h-6 p-1 text-xs text-white bg-gray-500 opacity-70 hover:opacity-100"
onClick={copyToClipboard}
>
<Icon.BiClipboard className="w-full h-auto" />
</button>
{showExecuteButton && (
<button
className="flex justify-center items-center rounded bg-none w-6 h-6 p-1 text-xs text-white bg-gray-500 opacity-70 hover:opacity-100"
onClick={copyToClipboard}
onClick={handleExecuteQuery}
>
<Icon.BiClipboard className="w-full h-auto" />
<Icon.IoPlay className="w-full h-auto" />
</button>
{showExecuteButton && (
<button
className="flex justify-center items-center rounded bg-none w-6 h-6 p-1 text-xs text-white bg-gray-500 opacity-70 hover:opacity-100"
onClick={() => setShowExecuteQueryModal(true)}
>
<Icon.IoPlay className="w-full h-auto" />
</button>
)}
</div>
)}
</div>
<SyntaxHighlighter language={language.toLowerCase()} style={oneDark} customStyle={{ margin: 0 }}>
{value}
</SyntaxHighlighter>
</div>
{showExecuteQueryModal &&
showExecuteButton &&
createPortal(
<ExecuteStatementModal
connection={currentConnectionCtx.connection}
databaseName={currentConnectionCtx.database?.name || ""}
statement={value}
close={() => setShowExecuteQueryModal(false)}
/>,
document.body
)}
</>
<SyntaxHighlighter language={language.toLowerCase()} style={oneDark} customStyle={{ margin: 0 }}>
{value}
</SyntaxHighlighter>
</div>
);
};

View File

@ -1,23 +1,18 @@
import { Drawer } from "@mui/material";
import { head } from "lodash-es";
import { useEffect, useState } from "react";
import DataTable from "react-data-table-component";
import { toast } from "react-hot-toast";
import { Connection } from "@/types";
import { useQueryStore } from "@/store";
import Icon from "./Icon";
interface Props {
connection: Connection;
databaseName: string;
statement: string;
close: () => void;
}
type RawQueryResult = {
[key: string]: any;
};
const ExecuteStatementModal = (props: Props) => {
const { close, connection, databaseName, statement } = props;
const QueryDrawer = () => {
const queryStore = useQueryStore();
const context = queryStore.context;
const [rawResults, setRawResults] = useState<RawQueryResult[]>([]);
const [isLoading, setIsLoading] = useState(true);
const columns = Object.keys(head(rawResults) || {}).map((key) => {
@ -28,6 +23,16 @@ const ExecuteStatementModal = (props: Props) => {
});
useEffect(() => {
if (!context) {
toast.error("No execution context found.");
setIsLoading(false);
setRawResults([]);
return;
}
setIsLoading(true);
setRawResults([]);
const { connection, database, statement } = context;
const executeStatement = async () => {
try {
const response = await fetch("/api/connection/execute", {
@ -37,7 +42,7 @@ const ExecuteStatementModal = (props: Props) => {
},
body: JSON.stringify({
connection,
db: databaseName,
db: database?.name,
statement,
}),
});
@ -51,15 +56,17 @@ const ExecuteStatementModal = (props: Props) => {
};
executeStatement();
}, []);
}, [context]);
const close = () => queryStore.toggleDrawer(false);
return (
<div className="modal modal-middle modal-open">
<div className="modal-box w-full">
<h3 className="font-bold text-lg">Execute query</h3>
<button className="btn btn-sm btn-circle absolute right-4 top-4" onClick={close}>
<Drawer open={queryStore.showDrawer} anchor="right" className="w-full" onClose={close}>
<div className="w-screen sm:w-[640px] max-w-full flex flex-col justify-start items-start p-4">
<button className="btn btn-sm btn-circle" onClick={close}>
<Icon.IoMdClose className="w-5 h-auto" />
</button>
<h3 className="font-bold text-lg mt-4">Execute query</h3>
<div className="w-full flex flex-col justify-start items-start space-y-3 pt-4">
{isLoading ? (
<div className="w-full flex justify-center py-6 pt-8">
@ -69,13 +76,13 @@ const ExecuteStatementModal = (props: Props) => {
<div className="w-full flex justify-center py-6 pt-8">No data return.</div>
) : (
<div className="w-full">
<DataTable className="w-full" columns={columns} data={rawResults} pagination responsive />
<DataTable className="w-full border" columns={columns} data={rawResults} pagination responsive />
</div>
)}
</div>
</div>
</div>
</Drawer>
);
};
export default ExecuteStatementModal;
export default QueryDrawer;

View File

@ -7,6 +7,10 @@
"start": "next start"
},
"dependencies": {
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@mui/material": "^5.11.14",
"@mui/styled-engine-sc": "^5.11.11",
"@vercel/analytics": "^0.1.11",
"axios": "^1.3.4",
"csstype": "^3.1.1",
@ -21,6 +25,7 @@
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.0",
"react-icons": "^4.8.0",
"react-is": "^18.2.0",
"react-loader-spinner": "^5.3.4",
"react-markdown": "^8.0.6",
"react-textarea-autosize": "^8.4.0",

View File

@ -3,6 +3,7 @@ import Head from "next/head";
import dynamic from "next/dynamic";
import React, { useEffect } from "react";
import { ResponsiveWidth, useLayoutStore } from "@/store";
import QueryDrawer from "@/components/QueryDrawer";
// Use dynamic import to avoid page hydrated.
// reference: https://github.com/pmndrs/zustand/issues/1145#issuecomment-1316431268
@ -51,6 +52,7 @@ const ChatPage: NextPage = () => {
/>
<ChatView />
<ConnectionSidebar />
<QueryDrawer />
</main>
</div>
);

434
pnpm-lock.yaml generated
View File

@ -1,6 +1,10 @@
lockfileVersion: 5.4
specifiers:
'@emotion/react': ^11.10.6
'@emotion/styled': ^11.10.6
'@mui/material': ^5.11.14
'@mui/styled-engine-sc': ^5.11.11
'@tailwindcss/typography': ^0.5.9
'@types/lodash-es': ^4.17.7
'@types/node': ^18.11.18
@ -29,6 +33,7 @@ specifiers:
react-dom: ^18.2.0
react-hot-toast: ^2.4.0
react-icons: ^4.8.0
react-is: ^18.2.0
react-loader-spinner: ^5.3.4
react-markdown: ^8.0.6
react-syntax-highlighter: ^15.5.0
@ -41,6 +46,10 @@ specifiers:
zustand: ^4.3.6
dependencies:
'@emotion/react': 11.10.6_pmekkgnqduwlme35zpnqhenc34
'@emotion/styled': 11.10.6_oouaibmszuch5k64ms7uxp2aia
'@mui/material': 5.11.14_xqeqsl5kvjjtyxwyi3jhw3yuli
'@mui/styled-engine-sc': 5.11.11_styled-components@5.3.9
'@vercel/analytics': 0.1.11_react@18.2.0
axios: 1.3.4
csstype: 3.1.1
@ -55,11 +64,12 @@ dependencies:
react-dom: 18.2.0_react@18.2.0
react-hot-toast: 2.4.0_owo25xnefcwdq3zjgtohz6dbju
react-icons: 4.8.0_react@18.2.0
react-is: 18.2.0
react-loader-spinner: 5.3.4_biqbaboplfbrettd7655fr4n2y
react-markdown: 8.0.6_pmekkgnqduwlme35zpnqhenc34
react-textarea-autosize: 8.4.0_pmekkgnqduwlme35zpnqhenc34
remark-gfm: 3.0.1
styled-components: 5.3.9_biqbaboplfbrettd7655fr4n2y
styled-components: 5.3.9_7i5myeigehqah43i5u7wbekgba
uuid: 9.0.0
zustand: 4.3.6_react@18.2.0
@ -211,6 +221,36 @@ packages:
to-fast-properties: 2.0.0
dev: false
/@emotion/babel-plugin/11.10.6:
resolution: {integrity: sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==}
dependencies:
'@babel/helper-module-imports': 7.18.6
'@babel/runtime': 7.21.0
'@emotion/hash': 0.9.0
'@emotion/memoize': 0.8.0
'@emotion/serialize': 1.1.1
babel-plugin-macros: 3.1.0
convert-source-map: 1.9.0
escape-string-regexp: 4.0.0
find-root: 1.1.0
source-map: 0.5.7
stylis: 4.1.3
dev: false
/@emotion/cache/11.10.5:
resolution: {integrity: sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==}
dependencies:
'@emotion/memoize': 0.8.0
'@emotion/sheet': 1.2.1
'@emotion/utils': 1.2.0
'@emotion/weak-memoize': 0.3.0
stylis: 4.1.3
dev: false
/@emotion/hash/0.9.0:
resolution: {integrity: sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==}
dev: false
/@emotion/is-prop-valid/1.2.0:
resolution: {integrity: sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==}
dependencies:
@ -221,6 +261,62 @@ packages:
resolution: {integrity: sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==}
dev: false
/@emotion/react/11.10.6_pmekkgnqduwlme35zpnqhenc34:
resolution: {integrity: sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==}
peerDependencies:
'@types/react': '*'
react: '>=16.8.0'
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.21.0
'@emotion/babel-plugin': 11.10.6
'@emotion/cache': 11.10.5
'@emotion/serialize': 1.1.1
'@emotion/use-insertion-effect-with-fallbacks': 1.0.0_react@18.2.0
'@emotion/utils': 1.2.0
'@emotion/weak-memoize': 0.3.0
'@types/react': 18.0.28
hoist-non-react-statics: 3.3.2
react: 18.2.0
dev: false
/@emotion/serialize/1.1.1:
resolution: {integrity: sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==}
dependencies:
'@emotion/hash': 0.9.0
'@emotion/memoize': 0.8.0
'@emotion/unitless': 0.8.0
'@emotion/utils': 1.2.0
csstype: 3.1.1
dev: false
/@emotion/sheet/1.2.1:
resolution: {integrity: sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==}
dev: false
/@emotion/styled/11.10.6_oouaibmszuch5k64ms7uxp2aia:
resolution: {integrity: sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==}
peerDependencies:
'@emotion/react': ^11.0.0-rc.0
'@types/react': '*'
react: '>=16.8.0'
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.21.0
'@emotion/babel-plugin': 11.10.6
'@emotion/is-prop-valid': 1.2.0
'@emotion/react': 11.10.6_pmekkgnqduwlme35zpnqhenc34
'@emotion/serialize': 1.1.1
'@emotion/use-insertion-effect-with-fallbacks': 1.0.0_react@18.2.0
'@emotion/utils': 1.2.0
'@types/react': 18.0.28
react: 18.2.0
dev: false
/@emotion/stylis/0.8.5:
resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==}
dev: false
@ -229,6 +325,26 @@ packages:
resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==}
dev: false
/@emotion/unitless/0.8.0:
resolution: {integrity: sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==}
dev: false
/@emotion/use-insertion-effect-with-fallbacks/1.0.0_react@18.2.0:
resolution: {integrity: sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==}
peerDependencies:
react: '>=16.8.0'
dependencies:
react: 18.2.0
dev: false
/@emotion/utils/1.2.0:
resolution: {integrity: sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==}
dev: false
/@emotion/weak-memoize/0.3.0:
resolution: {integrity: sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==}
dev: false
/@eslint/eslintrc/1.4.1:
resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -291,6 +407,179 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.14
dev: false
/@mui/base/5.0.0-alpha.122_zula6vjvt3wdocc4mwcxqa6nzi:
resolution: {integrity: sha512-IgZEFQyHa39J1+Q3tekVdhPuUm1fr3icddaNLmiAIeYTVXmR7KR5FhBAIL0P+4shlPq0liUPGlXryoTm0iCeFg==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/react': ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.21.0
'@emotion/is-prop-valid': 1.2.0
'@mui/types': 7.2.3_@types+react@18.0.28
'@mui/utils': 5.11.13_react@18.2.0
'@popperjs/core': 2.11.7
'@types/react': 18.0.28
clsx: 1.2.1
prop-types: 15.8.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-is: 18.2.0
dev: false
/@mui/core-downloads-tracker/5.11.14:
resolution: {integrity: sha512-rfc08z6+3Fif+Gopx2/qmk+MEQlwYeA+gOcSK048BHkTty/ol/boHuVeL2BNC/cf9OVRjJLYHtVb/DeW791LSQ==}
dev: false
/@mui/material/5.11.14_xqeqsl5kvjjtyxwyi3jhw3yuli:
resolution: {integrity: sha512-uoiUyybmo+M+nYARBygmbXgX6s/hH0NKD56LCAv9XvmdGVoXhEGjOvxI5/Bng6FS3NNybnA8V+rgZW1Z/9OJtA==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@emotion/react': ^11.5.0
'@emotion/styled': ^11.3.0
'@types/react': ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@emotion/react':
optional: true
'@emotion/styled':
optional: true
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.21.0
'@emotion/react': 11.10.6_pmekkgnqduwlme35zpnqhenc34
'@emotion/styled': 11.10.6_oouaibmszuch5k64ms7uxp2aia
'@mui/base': 5.0.0-alpha.122_zula6vjvt3wdocc4mwcxqa6nzi
'@mui/core-downloads-tracker': 5.11.14
'@mui/system': 5.11.14_d2lgyfpecxdc2bsiwyag5wf7ti
'@mui/types': 7.2.3_@types+react@18.0.28
'@mui/utils': 5.11.13_react@18.2.0
'@types/react': 18.0.28
'@types/react-transition-group': 4.4.5
clsx: 1.2.1
csstype: 3.1.1
prop-types: 15.8.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-is: 18.2.0
react-transition-group: 4.4.5_biqbaboplfbrettd7655fr4n2y
dev: false
/@mui/private-theming/5.11.13_pmekkgnqduwlme35zpnqhenc34:
resolution: {integrity: sha512-PJnYNKzW5LIx3R+Zsp6WZVPs6w5sEKJ7mgLNnUXuYB1zo5aX71FVLtV7geyPXRcaN2tsoRNK7h444ED0t7cIjA==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/react': ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.21.0
'@mui/utils': 5.11.13_react@18.2.0
'@types/react': 18.0.28
prop-types: 15.8.1
react: 18.2.0
dev: false
/@mui/styled-engine-sc/5.11.11_styled-components@5.3.9:
resolution: {integrity: sha512-6+HsfcKHlhjQklDoEup7Itl+Xgn+BCsqEpIdIIhlxED4YlOZ38xghxIKrx78XFZznTorbhAspUgDDKIaB5vDMg==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/styled-components': ^5.1.14
styled-components: ^5.3.1
peerDependenciesMeta:
'@types/styled-components':
optional: true
dependencies:
'@babel/runtime': 7.21.0
prop-types: 15.8.1
styled-components: 5.3.9_7i5myeigehqah43i5u7wbekgba
dev: false
/@mui/styled-engine/5.11.11_xqp3pgpqjlfxxa3zxu4zoc4fba:
resolution: {integrity: sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@emotion/react': ^11.4.1
'@emotion/styled': ^11.3.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@emotion/react':
optional: true
'@emotion/styled':
optional: true
dependencies:
'@babel/runtime': 7.21.0
'@emotion/cache': 11.10.5
'@emotion/react': 11.10.6_pmekkgnqduwlme35zpnqhenc34
'@emotion/styled': 11.10.6_oouaibmszuch5k64ms7uxp2aia
csstype: 3.1.1
prop-types: 15.8.1
react: 18.2.0
dev: false
/@mui/system/5.11.14_d2lgyfpecxdc2bsiwyag5wf7ti:
resolution: {integrity: sha512-/MBv5dUoijJNEKEGi5tppIszGN0o2uejmeISi5vl0CLcaQsI1cd+uBgK+JYUP1VWvI/MtkWRLVSWtF2FWhu5Nw==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@emotion/react': ^11.5.0
'@emotion/styled': ^11.3.0
'@types/react': ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@emotion/react':
optional: true
'@emotion/styled':
optional: true
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.21.0
'@emotion/react': 11.10.6_pmekkgnqduwlme35zpnqhenc34
'@emotion/styled': 11.10.6_oouaibmszuch5k64ms7uxp2aia
'@mui/private-theming': 5.11.13_pmekkgnqduwlme35zpnqhenc34
'@mui/styled-engine': 5.11.11_xqp3pgpqjlfxxa3zxu4zoc4fba
'@mui/types': 7.2.3_@types+react@18.0.28
'@mui/utils': 5.11.13_react@18.2.0
'@types/react': 18.0.28
clsx: 1.2.1
csstype: 3.1.1
prop-types: 15.8.1
react: 18.2.0
dev: false
/@mui/types/7.2.3_@types+react@18.0.28:
resolution: {integrity: sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==}
peerDependencies:
'@types/react': '*'
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.0.28
dev: false
/@mui/utils/5.11.13_react@18.2.0:
resolution: {integrity: sha512-5ltA58MM9euOuUcnvwFJqpLdEugc9XFsRR8Gt4zZNb31XzMfSKJPR4eumulyhsOTK1rWf7K4D63NKFPfX0AxqA==}
engines: {node: '>=12.0.0'}
peerDependencies:
react: ^17.0.0 || ^18.0.0
dependencies:
'@babel/runtime': 7.21.0
'@types/prop-types': 15.7.5
'@types/react-is': 17.0.3
prop-types: 15.8.1
react: 18.2.0
react-is: 18.2.0
dev: false
/@next/env/13.2.4:
resolution: {integrity: sha512-+Mq3TtpkeeKFZanPturjcXt+KHfKYnLlX6jMLyCrmpq6OOs4i1GqBOAauSkii9QeKCMTYzGppar21JU57b/GEA==}
dev: false
@ -436,6 +725,10 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
/@popperjs/core/2.11.7:
resolution: {integrity: sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==}
dev: false
/@rushstack/eslint-patch/1.2.0:
resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==}
dev: true
@ -497,6 +790,10 @@ packages:
resolution: {integrity: sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==}
dev: true
/@types/parse-json/4.0.0:
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
dev: false
/@types/pg/8.6.6:
resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==}
dependencies:
@ -514,12 +811,24 @@ packages:
'@types/react': 18.0.28
dev: true
/@types/react-is/17.0.3:
resolution: {integrity: sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==}
dependencies:
'@types/react': 18.0.28
dev: false
/@types/react-syntax-highlighter/15.5.6:
resolution: {integrity: sha512-i7wFuLbIAFlabTeD2I1cLjEOrG/xdMa/rpx2zwzAoGHuXJDhSqp9BSfDlMHSh9JSuNfxHk9eEmMX6D55GiyjGg==}
dependencies:
'@types/react': 18.0.28
dev: true
/@types/react-transition-group/4.4.5:
resolution: {integrity: sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==}
dependencies:
'@types/react': 18.0.28
dev: false
/@types/react/18.0.28:
resolution: {integrity: sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==}
dependencies:
@ -787,6 +1096,15 @@ packages:
deep-equal: 2.2.0
dev: true
/babel-plugin-macros/3.1.0:
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
engines: {node: '>=10', npm: '>=6'}
dependencies:
'@babel/runtime': 7.21.0
cosmiconfig: 7.1.0
resolve: 1.22.1
dev: false
/babel-plugin-styled-components/2.0.7_styled-components@5.3.9:
resolution: {integrity: sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==}
peerDependencies:
@ -797,7 +1115,7 @@ packages:
babel-plugin-syntax-jsx: 6.18.0
lodash: 4.17.21
picomatch: 2.3.1
styled-components: 5.3.9_biqbaboplfbrettd7655fr4n2y
styled-components: 5.3.9_7i5myeigehqah43i5u7wbekgba
dev: false
/babel-plugin-syntax-jsx/6.18.0:
@ -854,7 +1172,6 @@ packages:
/callsites/3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
dev: true
/camelcase-css/2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
@ -922,6 +1239,11 @@ packages:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
dev: false
/clsx/1.2.1:
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
engines: {node: '>=6'}
dev: false
/color-convert/1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
@ -975,6 +1297,21 @@ packages:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/convert-source-map/1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
dev: false
/cosmiconfig/7.1.0:
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
engines: {node: '>=10'}
dependencies:
'@types/parse-json': 4.0.0
import-fresh: 3.3.0
parse-json: 5.2.0
path-type: 4.0.0
yaml: 1.10.2
dev: false
/cross-spawn/7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@ -1175,6 +1512,13 @@ packages:
esutils: 2.0.3
dev: true
/dom-helpers/5.2.1:
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
dependencies:
'@babel/runtime': 7.21.0
csstype: 3.1.1
dev: false
/electron-to-chromium/1.4.330:
resolution: {integrity: sha512-PqyefhybrVdjAJ45HaPLtuVaehiSw7C3ya0aad+rvmV53IVyXmYRk3pwIOb2TxTDTnmgQdn46NjMMaysx79/6Q==}
@ -1182,6 +1526,12 @@ packages:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
dev: true
/error-ex/1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
dependencies:
is-arrayish: 0.2.1
dev: false
/es-abstract/1.21.2:
resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==}
engines: {node: '>= 0.4'}
@ -1272,7 +1622,6 @@ packages:
/escape-string-regexp/4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
dev: true
/escape-string-regexp/5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
@ -1617,6 +1966,10 @@ packages:
dependencies:
to-regex-range: 5.0.1
/find-root/1.1.0:
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
dev: false
/flat-cache/3.0.4:
resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -1889,7 +2242,6 @@ packages:
dependencies:
parent-module: 1.0.1
resolve-from: 4.0.0
dev: true
/imurmurhash/0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
@ -1947,6 +2299,10 @@ packages:
is-typed-array: 1.1.10
dev: true
/is-arrayish/0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
dev: false
/is-arrayish/0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: false
@ -2124,6 +2480,10 @@ packages:
hasBin: true
dev: false
/json-parse-even-better-errors/2.3.1:
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
dev: false
/json-schema-traverse/0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: true
@ -2174,6 +2534,10 @@ packages:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
/lines-and-columns/1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: false
/lodash-es/4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: false
@ -2839,7 +3203,6 @@ packages:
engines: {node: '>=6'}
dependencies:
callsites: 3.1.0
dev: true
/parse-entities/2.0.0:
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
@ -2852,6 +3215,16 @@ packages:
is-hexadecimal: 1.0.4
dev: true
/parse-json/5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
dependencies:
'@babel/code-frame': 7.18.6
error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
dev: false
/path-is-absolute/1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
@ -2868,7 +3241,6 @@ packages:
/path-type/4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
dev: true
/pg-connection-string/2.5.0:
resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==}
@ -3095,7 +3467,7 @@ packages:
dependencies:
deepmerge: 4.3.1
react: 18.2.0
styled-components: 5.3.9_biqbaboplfbrettd7655fr4n2y
styled-components: 5.3.9_7i5myeigehqah43i5u7wbekgba
dev: false
/react-dom/18.2.0_react@18.2.0:
@ -3204,6 +3576,20 @@ packages:
- '@types/react'
dev: false
/react-transition-group/4.4.5_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
peerDependencies:
react: '>=16.6.0'
react-dom: '>=16.6.0'
dependencies:
'@babel/runtime': 7.21.0
dom-helpers: 5.2.1
loose-envify: 1.4.0
prop-types: 15.8.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/react/18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@ -3279,7 +3665,6 @@ packages:
/resolve-from/4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
dev: true
/resolve/1.22.1:
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
@ -3395,6 +3780,11 @@ packages:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
/source-map/0.5.7:
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
engines: {node: '>=0.10.0'}
dev: false
/space-separated-tokens/1.1.5:
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
dev: true
@ -3504,28 +3894,6 @@ packages:
supports-color: 5.5.0
dev: false
/styled-components/5.3.9_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-Aj3kb13B75DQBo2oRwRa/APdB5rSmwUfN5exyarpX+x/tlM/rwZA2vVk2vQgVSP6WKaZJHWwiFrzgHt+CLtB4A==}
engines: {node: '>=10'}
peerDependencies:
react: '>= 16.8.0'
react-dom: '>= 16.8.0'
react-is: '>= 16.8.0'
dependencies:
'@babel/helper-module-imports': 7.18.6
'@babel/traverse': 7.21.3_supports-color@5.5.0
'@emotion/is-prop-valid': 1.2.0
'@emotion/stylis': 0.8.5
'@emotion/unitless': 0.7.5
babel-plugin-styled-components: 2.0.7_styled-components@5.3.9
css-to-react-native: 3.2.0
hoist-non-react-statics: 3.3.2
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
shallowequal: 1.1.0
supports-color: 5.5.0
dev: false
/styled-jsx/5.1.1_react@18.2.0:
resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==}
engines: {node: '>= 12.0.0'}
@ -3547,6 +3915,10 @@ packages:
resolution: {integrity: sha512-IjLxzM20RMwAsx8M1QoRlCG/Kmq8lKzCGyospjtSXt/BTIIcvgTonaxQAsKnBrsZNwhpHzO9ADx5te0h76ILVg==}
dev: false
/stylis/4.1.3:
resolution: {integrity: sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==}
dev: false
/supports-color/5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}

View File

@ -4,3 +4,4 @@ export * from "./connection";
export * from "./chat";
export * from "./message";
export * from "./layout";
export * from "./query";

View File

@ -12,7 +12,7 @@ interface LayoutState {
toggleSidebar: (show?: boolean) => void;
}
export const useLayoutStore = create<LayoutState>()((set, get) => ({
export const useLayoutStore = create<LayoutState>()((set) => ({
showSidebar: true,
toggleSidebar: (show) => {
if (isUndefined(show)) {

31
store/query.ts Normal file
View File

@ -0,0 +1,31 @@
import { create } from "zustand";
import { Connection, Database } from "@/types";
interface ExecuteQueryContext {
connection: Connection;
database?: Database;
statement: string;
}
interface QueryState {
context?: ExecuteQueryContext;
showDrawer: boolean;
toggleDrawer: (show?: boolean) => void;
setContext: (context: ExecuteQueryContext | undefined) => void;
}
export const useQueryStore = create<QueryState>()((set) => ({
showDrawer: false,
toggleDrawer: (show) => {
set((state) => ({
...state,
showDrawer: show ?? !state.showDrawer,
}));
},
setContext: (context) => {
set((state) => ({
...state,
context,
}));
},
}));