mirror of
https://github.com/sqlchat/sqlchat.git
synced 2025-09-26 17:45:14 +08:00
254 lines
9.9 KiB
TypeScript
254 lines
9.9 KiB
TypeScript
import { Drawer } from "@mui/material";
|
|
import { useEffect, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import {
|
|
useConnectionStore,
|
|
useConversationStore,
|
|
useLayoutStore,
|
|
ResponsiveWidth,
|
|
} from "@/store";
|
|
import { Table } from "@/types";
|
|
import useLoading from "@/hooks/useLoading";
|
|
import Link from "next/link";
|
|
import Select from "./kit/Select";
|
|
import Tooltip from "./kit/Tooltip";
|
|
import Icon from "./Icon";
|
|
import DarkModeSwitch from "./DarkModeSwitch";
|
|
import ConversationList from "./Sidebar/ConversationList";
|
|
import ConnectionList from "./Sidebar/ConnectionList";
|
|
|
|
interface State {}
|
|
|
|
const ConnectionSidebar = () => {
|
|
const { t } = useTranslation();
|
|
const layoutStore = useLayoutStore();
|
|
const connectionStore = useConnectionStore();
|
|
const conversationStore = useConversationStore();
|
|
const [isRequestingDatabase, setIsRequestingDatabase] =
|
|
useState<boolean>(false);
|
|
const currentConnectionCtx = connectionStore.currentConnectionCtx;
|
|
const databaseList = connectionStore.databaseList.filter(
|
|
(database) => database.connectionId === currentConnectionCtx?.connection.id
|
|
);
|
|
const [tableList, updateTableList] = useState<Table[]>([]);
|
|
const tableSchemaLoadingState = useLoading();
|
|
|
|
useEffect(() => {
|
|
const handleWindowResize = () => {
|
|
if (window.innerWidth < ResponsiveWidth.sm) {
|
|
layoutStore.toggleSidebar(false);
|
|
layoutStore.setIsMobileView(true);
|
|
} else {
|
|
layoutStore.toggleSidebar(true);
|
|
layoutStore.setIsMobileView(false);
|
|
}
|
|
};
|
|
|
|
handleWindowResize();
|
|
window.addEventListener("resize", handleWindowResize);
|
|
|
|
return () => {
|
|
window.removeEventListener("resize", handleWindowResize);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (currentConnectionCtx?.connection) {
|
|
setIsRequestingDatabase(true);
|
|
connectionStore
|
|
.getOrFetchDatabaseList(currentConnectionCtx.connection)
|
|
.finally(() => {
|
|
setIsRequestingDatabase(false);
|
|
const database = databaseList.find(
|
|
(database) =>
|
|
database.name ===
|
|
useConnectionStore.getState().currentConnectionCtx?.database?.name
|
|
);
|
|
if (database) {
|
|
tableSchemaLoadingState.setLoading();
|
|
connectionStore.getOrFetchDatabaseSchema(database).then(() => {
|
|
tableSchemaLoadingState.setFinish();
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
setIsRequestingDatabase(false);
|
|
}
|
|
}, [currentConnectionCtx?.connection]);
|
|
|
|
useEffect(() => {
|
|
const tableList =
|
|
connectionStore.databaseList.find(
|
|
(database) =>
|
|
database.connectionId === currentConnectionCtx?.connection.id &&
|
|
database.name === currentConnectionCtx?.database?.name
|
|
)?.tableList || [];
|
|
|
|
updateTableList([
|
|
{
|
|
name: "",
|
|
structure: "",
|
|
} as Table,
|
|
...tableList,
|
|
]);
|
|
}, [connectionStore, currentConnectionCtx]);
|
|
|
|
const handleDatabaseNameSelect = async (databaseName: string) => {
|
|
if (!currentConnectionCtx?.connection) {
|
|
return;
|
|
}
|
|
|
|
const databaseList = await connectionStore.getOrFetchDatabaseList(
|
|
currentConnectionCtx.connection
|
|
);
|
|
const database = databaseList.find(
|
|
(database) => database.name === databaseName
|
|
);
|
|
connectionStore.setCurrentConnectionCtx({
|
|
connection: currentConnectionCtx.connection,
|
|
database: database,
|
|
});
|
|
if (database) {
|
|
tableSchemaLoadingState.setLoading();
|
|
connectionStore.getOrFetchDatabaseSchema(database).then(() => {
|
|
tableSchemaLoadingState.setFinish();
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleTableNameSelect = async (tableName: string) => {
|
|
conversationStore.updateTableName(tableName);
|
|
};
|
|
return (
|
|
<>
|
|
<Drawer
|
|
className="!z-10"
|
|
variant={layoutStore.isMobileView ? "temporary" : "persistent"}
|
|
open={layoutStore.showSidebar}
|
|
onClose={() => layoutStore.toggleSidebar(false)}
|
|
ModalProps={{ disablePortal: true }}
|
|
>
|
|
<div className="w-80 h-full overflow-y-hidden flex flex-row justify-start items-start">
|
|
<div className="w-16 h-full bg-gray-200 dark:bg-zinc-600 pl-2 py-4 pt-6 flex flex-col justify-between items-center">
|
|
<div className="w-full flex flex-col justify-start items-start">
|
|
<ConnectionList />
|
|
</div>
|
|
<div className="w-full flex flex-col justify-end items-center">
|
|
<DarkModeSwitch />
|
|
<Tooltip title={t("common.setting")} side="right">
|
|
<Link
|
|
className=" w-10 h-10 p-1 rounded-full flex flex-row justify-center items-center hover:bg-gray-100 dark:hover:bg-zinc-700"
|
|
data-tip={t("common.setting")}
|
|
href="/setting"
|
|
>
|
|
<Icon.IoMdSettings className="text-gray-600 dark:text-gray-300 w-6 h-auto" />
|
|
</Link>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
<div className="relative p-4 pb-0 w-64 h-full overflow-y-auto flex flex-col justify-start items-start bg-gray-100 dark:bg-zinc-700">
|
|
<img className="px-4 shrink-0" src="/chat-logo.webp" alt="" />
|
|
<div className="w-full grow">
|
|
{isRequestingDatabase && (
|
|
<div className="w-full h-12 flex flex-row justify-start items-center px-4 sticky top-0 border z-1 mb-4 mt-2 rounded-lg text-sm text-gray-600 dark:text-gray-400">
|
|
<Icon.BiLoaderAlt className="w-4 h-auto animate-spin mr-1" />{" "}
|
|
{t("common.loading")}
|
|
</div>
|
|
)}
|
|
{databaseList.length > 0 && (
|
|
<div className="w-full sticky top-0 z-1 my-4">
|
|
<Select
|
|
className="w-full px-4 py-3 !text-base"
|
|
value={currentConnectionCtx?.database?.name}
|
|
itemList={databaseList.map((database) => {
|
|
return {
|
|
label: database.name,
|
|
value: database.name,
|
|
};
|
|
})}
|
|
onValueChange={(databaseName) =>
|
|
handleDatabaseNameSelect(databaseName)
|
|
}
|
|
placeholder={t("connection.select-database") || ""}
|
|
/>
|
|
</div>
|
|
)}
|
|
{tableSchemaLoadingState.isLoading ? (
|
|
<div className="w-full h-12 flex flex-row justify-start items-center px-4 sticky top-0 border z-1 mb-4 mt-2 rounded-lg text-sm text-gray-600 dark:text-gray-400">
|
|
<Icon.BiLoaderAlt className="w-4 h-auto animate-spin mr-1" />{" "}
|
|
{t("common.loading")}
|
|
</div>
|
|
) : (
|
|
tableList.length > 0 && (
|
|
<div className="w-full sticky top-0 z-1 my-4">
|
|
<Select
|
|
className="w-full px-4 py-3 !text-base"
|
|
value={
|
|
conversationStore.getConversationById(
|
|
conversationStore.currentConversationId
|
|
)?.tableName || ""
|
|
}
|
|
itemList={tableList.map((table) => {
|
|
return {
|
|
label:
|
|
table.name === ""
|
|
? t("connection.all-tables")
|
|
: table.name,
|
|
value: table.name,
|
|
};
|
|
})}
|
|
onValueChange={(tableName) =>
|
|
handleTableNameSelect(tableName)
|
|
}
|
|
placeholder={t("connection.select-table") || ""}
|
|
/>
|
|
</div>
|
|
)
|
|
)}
|
|
<ConversationList />
|
|
</div>
|
|
<div className="sticky bottom-0 w-full flex flex-col justify-center bg-gray-100 dark:bg-zinc-700 backdrop-blur bg-opacity-60 pb-4 py-2">
|
|
<a
|
|
href="https://discord.gg/z6kakemDjm"
|
|
className="text-indigo-600 dark:text-indigo-400 text-sm font-medium flex flex-row justify-center items-center mb-2 hover:underline"
|
|
target="_blank"
|
|
>
|
|
<Icon.BsDiscord className="w-4 h-auto mr-1" />
|
|
{t("social.join-discord-channel")}
|
|
</a>
|
|
<a
|
|
className="dark:hidden"
|
|
href="https://www.producthunt.com/posts/sql-chat-2?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-sql-chat-2"
|
|
target="_blank"
|
|
>
|
|
<img
|
|
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=390216&theme=light"
|
|
alt="SQL Chat - ChatGPT powered SQL client for Postgres, MySQL & SQL Server | Product Hunt"
|
|
style={{ width: "250px", height: "54px" }}
|
|
width="250"
|
|
height="54"
|
|
/>
|
|
</a>
|
|
<a
|
|
className="hidden dark:block"
|
|
href="https://www.producthunt.com/posts/sql-chat-2?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-sql-chat-2"
|
|
target="_blank"
|
|
>
|
|
<img
|
|
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=390216&theme=dark"
|
|
alt="SQL Chat - ChatGPT powered SQL client for Postgres, MySQL & SQL Server | Product Hunt"
|
|
style={{ width: "250px", height: "54px" }}
|
|
width="250"
|
|
height="54"
|
|
/>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Drawer>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default ConnectionSidebar;
|