mirror of
https://github.com/sqlchat/sqlchat.git
synced 2025-09-26 09:34:13 +08:00
refactor: move conversation list into component
This commit is contained in:
@ -2,17 +2,16 @@ import { Drawer } from "@mui/material";
|
||||
import { head } from "lodash-es";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useConversationStore, useConnectionStore, useLayoutStore, ResponsiveWidth } from "@/store";
|
||||
import { Conversation, Connection } from "@/types";
|
||||
import { useConnectionStore, useLayoutStore, ResponsiveWidth } from "@/store";
|
||||
import { Connection } from "@/types";
|
||||
import Select from "./kit/Select";
|
||||
import Tooltip from "./kit/Tooltip";
|
||||
import Dropdown, { DropdownItem } from "./kit/Dropdown";
|
||||
import Icon from "./Icon";
|
||||
import EngineIcon from "./EngineIcon";
|
||||
import DarkModeSwitch from "./DarkModeSwitch";
|
||||
import CreateConnectionModal from "./CreateConnectionModal";
|
||||
import SettingModal from "./SettingModal";
|
||||
import UpdateConversationModal from "./UpdateConversationModal";
|
||||
import ConversationList from "./Sidebar/ConversationList";
|
||||
|
||||
interface State {
|
||||
showCreateConnectionModal: boolean;
|
||||
@ -24,23 +23,16 @@ const ConnectionSidebar = () => {
|
||||
const { t } = useTranslation();
|
||||
const layoutStore = useLayoutStore();
|
||||
const connectionStore = useConnectionStore();
|
||||
const conversationStore = useConversationStore();
|
||||
const [state, setState] = useState<State>({
|
||||
showCreateConnectionModal: false,
|
||||
showSettingModal: false,
|
||||
showUpdateConversationModal: false,
|
||||
});
|
||||
const [editConnectionModalContext, setEditConnectionModalContext] = useState<Connection>();
|
||||
const [updateConversationModalContext, setUpdateConversationModalContext] = useState<Conversation>();
|
||||
const [isRequestingDatabase, setIsRequestingDatabase] = useState<boolean>(false);
|
||||
const connectionList = connectionStore.connectionList;
|
||||
const currentConnectionCtx = connectionStore.currentConnectionCtx;
|
||||
const databaseList = connectionStore.databaseList.filter((database) => database.connectionId === currentConnectionCtx?.connection.id);
|
||||
const conversationList = conversationStore.conversationList.filter(
|
||||
(conversation) =>
|
||||
conversation.connectionId === currentConnectionCtx?.connection.id &&
|
||||
conversation.databaseName === currentConnectionCtx?.database?.name
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleWindowResize = () => {
|
||||
@ -87,13 +79,6 @@ const ConnectionSidebar = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const toggleUpdateConversationModal = (show = true) => {
|
||||
setState({
|
||||
...state,
|
||||
showUpdateConversationModal: show,
|
||||
});
|
||||
};
|
||||
|
||||
const handleConnectionSelect = async (connection: Connection) => {
|
||||
const databaseList = await connectionStore.getOrFetchDatabaseList(connection);
|
||||
connectionStore.setCurrentConnectionCtx({
|
||||
@ -123,36 +108,6 @@ const ConnectionSidebar = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleCreateConversation = () => {
|
||||
if (!currentConnectionCtx) {
|
||||
conversationStore.createConversation();
|
||||
} else {
|
||||
conversationStore.createConversation(currentConnectionCtx.connection.id, currentConnectionCtx.database?.name);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConversationSelect = (conversation: Conversation) => {
|
||||
conversationStore.setCurrentConversationId(conversation.id);
|
||||
if (layoutStore.isMobileView) {
|
||||
layoutStore.toggleSidebar(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditConversation = (conversation: Conversation) => {
|
||||
setUpdateConversationModalContext(conversation);
|
||||
setState({
|
||||
...state,
|
||||
showUpdateConversationModal: true,
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteConversation = (conversation: Conversation) => {
|
||||
conversationStore.clearConversation((item) => item.id !== conversation.id);
|
||||
if (conversationStore.currentConversationId === conversation.id) {
|
||||
conversationStore.setCurrentConversationId(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Drawer
|
||||
@ -240,53 +195,7 @@ const ConnectionSidebar = () => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{conversationList.map((conversation) => (
|
||||
<div
|
||||
key={conversation.id}
|
||||
className={`w-full mt-2 first:mt-4 py-3 pl-4 pr-2 rounded-lg flex flex-row justify-start items-center cursor-pointer dark:text-gray-300 border border-transparent group hover:bg-white dark:hover:bg-zinc-800 ${
|
||||
conversation.id === conversationStore.currentConversationId && "bg-white dark:bg-zinc-800 border-gray-200 font-medium"
|
||||
}`}
|
||||
onClick={() => handleConversationSelect(conversation)}
|
||||
>
|
||||
{conversation.id === conversationStore.currentConversationId ? (
|
||||
<Icon.IoChatbubble className="w-5 h-auto mr-1.5 shrink-0" />
|
||||
) : (
|
||||
<Icon.IoChatbubbleOutline className="w-5 h-auto mr-1.5 opacity-80 shrink-0" />
|
||||
)}
|
||||
<span className="truncate grow">{conversation.title || "SQL Chat"}</span>
|
||||
<Dropdown
|
||||
tigger={
|
||||
<button className="w-4 h-4 shrink-0 group-hover:visible invisible flex justify-center items-center text-gray-400 hover:text-gray-500">
|
||||
<Icon.FiMoreHorizontal className="w-full h-auto" />
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<div className="p-1 flex flex-col justify-start items-start bg-white dark:bg-zinc-900 shadow-lg rounded-lg">
|
||||
<DropdownItem
|
||||
className="w-full p-1 px-2 flex flex-row justify-start items-center rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800"
|
||||
onClick={() => handleEditConversation(conversation)}
|
||||
>
|
||||
<Icon.FiEdit3 className="w-4 h-auto mr-2 opacity-70" />
|
||||
{t("common.edit")}
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
className="w-full p-1 px-2 flex flex-row justify-start items-center rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800"
|
||||
onClick={() => handleDeleteConversation(conversation)}
|
||||
>
|
||||
<Icon.IoTrash className="w-4 h-auto mr-2 opacity-70" />
|
||||
{t("common.delete")}
|
||||
</DropdownItem>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
))}
|
||||
<button
|
||||
className="w-full my-4 py-3 px-4 border dark:border-zinc-800 rounded-lg flex flex-row justify-center items-center text-gray-500 dark:text-gray-400 hover:text-gray-700 hover:bg-gray-50 dark:hover:bg-zinc-800"
|
||||
onClick={handleCreateConversation}
|
||||
>
|
||||
<Icon.AiOutlinePlus className="w-5 h-auto mr-1" />
|
||||
{t("conversation.new-chat")}
|
||||
</button>
|
||||
<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
|
||||
@ -333,10 +242,6 @@ const ConnectionSidebar = () => {
|
||||
)}
|
||||
|
||||
{state.showSettingModal && <SettingModal close={() => toggleSettingModal(false)} />}
|
||||
|
||||
{updateConversationModalContext && state.showUpdateConversationModal && (
|
||||
<UpdateConversationModal close={() => toggleUpdateConversationModal(false)} conversation={updateConversationModalContext} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
123
src/components/Sidebar/ConversationList.tsx
Normal file
123
src/components/Sidebar/ConversationList.tsx
Normal file
@ -0,0 +1,123 @@
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useConversationStore, useConnectionStore, useLayoutStore } from "@/store";
|
||||
import { Conversation } from "@/types";
|
||||
import Dropdown, { DropdownItem } from "../kit/Dropdown";
|
||||
import Icon from "../Icon";
|
||||
import UpdateConversationModal from "../UpdateConversationModal";
|
||||
|
||||
interface State {
|
||||
showUpdateConversationModal: boolean;
|
||||
}
|
||||
|
||||
const ConversationList = () => {
|
||||
const { t } = useTranslation();
|
||||
const layoutStore = useLayoutStore();
|
||||
const connectionStore = useConnectionStore();
|
||||
const conversationStore = useConversationStore();
|
||||
const [state, setState] = useState<State>({
|
||||
showUpdateConversationModal: false,
|
||||
});
|
||||
const [updateConversationModalContext, setUpdateConversationModalContext] = useState<Conversation>();
|
||||
const currentConnectionCtx = connectionStore.currentConnectionCtx;
|
||||
const conversationList = conversationStore.conversationList.filter(
|
||||
(conversation) =>
|
||||
conversation.connectionId === currentConnectionCtx?.connection.id &&
|
||||
conversation.databaseName === currentConnectionCtx?.database?.name
|
||||
);
|
||||
|
||||
const toggleUpdateConversationModal = (show = true) => {
|
||||
setState({
|
||||
...state,
|
||||
showUpdateConversationModal: show,
|
||||
});
|
||||
};
|
||||
|
||||
const handleCreateConversation = () => {
|
||||
if (!currentConnectionCtx) {
|
||||
conversationStore.createConversation();
|
||||
} else {
|
||||
conversationStore.createConversation(currentConnectionCtx.connection.id, currentConnectionCtx.database?.name);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConversationSelect = (conversation: Conversation) => {
|
||||
conversationStore.setCurrentConversationId(conversation.id);
|
||||
if (layoutStore.isMobileView) {
|
||||
layoutStore.toggleSidebar(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditConversation = (conversation: Conversation) => {
|
||||
setUpdateConversationModalContext(conversation);
|
||||
setState({
|
||||
...state,
|
||||
showUpdateConversationModal: true,
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteConversation = (conversation: Conversation) => {
|
||||
conversationStore.clearConversation((item) => item.id !== conversation.id);
|
||||
if (conversationStore.currentConversationId === conversation.id) {
|
||||
conversationStore.setCurrentConversationId(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{conversationList.map((conversation) => (
|
||||
<div
|
||||
key={conversation.id}
|
||||
className={`w-full mt-2 first:mt-4 py-3 pl-4 pr-2 rounded-lg flex flex-row justify-start items-center cursor-pointer dark:text-gray-300 border border-transparent group hover:bg-white dark:hover:bg-zinc-800 ${
|
||||
conversation.id === conversationStore.currentConversationId && "bg-white dark:bg-zinc-800 border-gray-200 font-medium"
|
||||
}`}
|
||||
onClick={() => handleConversationSelect(conversation)}
|
||||
>
|
||||
{conversation.id === conversationStore.currentConversationId ? (
|
||||
<Icon.IoChatbubble className="w-5 h-auto mr-1.5 shrink-0" />
|
||||
) : (
|
||||
<Icon.IoChatbubbleOutline className="w-5 h-auto mr-1.5 opacity-80 shrink-0" />
|
||||
)}
|
||||
<span className="truncate grow">{conversation.title || "SQL Chat"}</span>
|
||||
<Dropdown
|
||||
tigger={
|
||||
<button className="w-4 h-4 shrink-0 group-hover:visible invisible flex justify-center items-center text-gray-400 hover:text-gray-500">
|
||||
<Icon.FiMoreHorizontal className="w-full h-auto" />
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<div className="p-1 flex flex-col justify-start items-start bg-white dark:bg-zinc-900 shadow-lg rounded-lg">
|
||||
<DropdownItem
|
||||
className="w-full p-1 px-2 flex flex-row justify-start items-center rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800"
|
||||
onClick={() => handleEditConversation(conversation)}
|
||||
>
|
||||
<Icon.FiEdit3 className="w-4 h-auto mr-2 opacity-70" />
|
||||
{t("common.edit")}
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
className="w-full p-1 px-2 flex flex-row justify-start items-center rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800"
|
||||
onClick={() => handleDeleteConversation(conversation)}
|
||||
>
|
||||
<Icon.IoTrash className="w-4 h-auto mr-2 opacity-70" />
|
||||
{t("common.delete")}
|
||||
</DropdownItem>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
))}
|
||||
<button
|
||||
className="w-full my-4 py-3 px-4 border dark:border-zinc-800 rounded-lg flex flex-row justify-center items-center text-gray-500 dark:text-gray-400 hover:text-gray-700 hover:bg-gray-50 dark:hover:bg-zinc-800"
|
||||
onClick={handleCreateConversation}
|
||||
>
|
||||
<Icon.AiOutlinePlus className="w-5 h-auto mr-1" />
|
||||
{t("conversation.new-chat")}
|
||||
</button>
|
||||
|
||||
{updateConversationModalContext && state.showUpdateConversationModal && (
|
||||
<UpdateConversationModal close={() => toggleUpdateConversationModal(false)} conversation={updateConversationModalContext} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConversationList;
|
Reference in New Issue
Block a user