feat: implement delete connection/chat

This commit is contained in:
Steven
2023-03-27 01:06:28 +08:00
parent cad70c919a
commit ca73de6c8b
7 changed files with 67 additions and 53 deletions

View File

@ -13,7 +13,7 @@ const ClearDataConfirmModal = (props: Props) => {
toast.success("Message cleared. The page will be reloaded."); toast.success("Message cleared. The page will be reloaded.");
setTimeout(() => { setTimeout(() => {
window.location.reload(); window.location.reload();
}, 1500); }, 300);
}; };
return ( return (

View File

@ -50,10 +50,21 @@ const ConnectionSidebar = () => {
}); });
}; };
const handleDeleteConnection = (connection: Connection) => {
connectionStore.clearConnection((item) => item.id !== connection.id);
if (currentConnectionCtx?.connection.id === connection.id) {
connectionStore.setCurrentConnectionCtx(undefined);
}
};
const handleDatabaseNameSelect = async (databaseName: string) => { const handleDatabaseNameSelect = async (databaseName: string) => {
if (!currentConnectionCtx?.connection) {
return;
}
const database = databaseList.find((database) => database.name === databaseName); const database = databaseList.find((database) => database.name === databaseName);
connectionStore.setCurrentConnectionCtx({ connectionStore.setCurrentConnectionCtx({
connection: currentConnectionCtx!.connection, connection: currentConnectionCtx.connection,
database: database, database: database,
}); });
}; };
@ -71,6 +82,13 @@ const ConnectionSidebar = () => {
layoutStore.toggleSidebar(false); layoutStore.toggleSidebar(false);
}; };
const handleDeleteChat = (chat: Chat) => {
chatStore.clearChat((item) => item.id !== chat.id);
if (chatStore.currentChat?.id === chat.id) {
chatStore.setCurrentChat(undefined);
}
};
return ( return (
<> <>
<aside className="drawer-side"> <aside className="drawer-side">
@ -81,11 +99,20 @@ const ConnectionSidebar = () => {
{connectionList.map((connection) => ( {connectionList.map((connection) => (
<button <button
key={connection.id} key={connection.id}
className={`w-full h-14 rounded-l-lg p-2 mt-2 ${ className={`w-full h-14 rounded-l-lg p-2 mt-2 group ${
currentConnectionCtx?.connection.id === connection.id && "bg-gray-100 shadow" currentConnectionCtx?.connection.id === connection.id && "bg-gray-100 shadow"
}`} }`}
onClick={() => handleConnectionSelect(connection)} onClick={() => handleConnectionSelect(connection)}
> >
<span
className="absolute -ml-1.5 -mt-1.5 hidden opacity-60 group-hover:block hover:opacity-80"
onClick={(e) => {
e.stopPropagation();
handleDeleteConnection(connection);
}}
>
<Icon.IoClose className="w-4 h-auto" />
</span>
<EngineIcon engine={connection.engineType} className="w-auto h-full mx-auto" /> <EngineIcon engine={connection.engineType} className="w-auto h-full mx-auto" />
</button> </button>
))} ))}
@ -135,17 +162,26 @@ const ConnectionSidebar = () => {
{chatList.map((chat) => ( {chatList.map((chat) => (
<div <div
key={chat.id} key={chat.id}
className={`w-full max-w-full mt-2 first:mt-4 py-3 px-4 rounded-lg flex flex-row justify-start items-center cursor-pointer border border-transparent hover:bg-gray-50 ${ className={`w-full mt-2 first:mt-4 py-3 px-4 pr-3 rounded-lg flex flex-row justify-start items-center cursor-pointer border border-transparent group hover:bg-gray-50 ${
chat.id === chatStore.currentChat?.id && "!bg-white border-gray-200 font-medium" chat.id === chatStore.currentChat?.id && "!bg-white border-gray-200 font-medium"
}`} }`}
onClick={() => handleChatSelect(chat)} onClick={() => handleChatSelect(chat)}
> >
{chat.id === chatStore.currentChat?.id ? ( {chat.id === chatStore.currentChat?.id ? (
<Icon.IoChatbubble className="w-5 h-auto mr-2 shrink-0" /> <Icon.IoChatbubble className="w-5 h-auto mr-1.5 shrink-0" />
) : ( ) : (
<Icon.IoChatbubbleOutline className="w-5 h-auto mr-2 opacity-80 shrink-0" /> <Icon.IoChatbubbleOutline className="w-5 h-auto mr-1.5 opacity-80 shrink-0" />
)} )}
<span className="truncate">{chat.title || "SQL Chat"}</span> <span className="truncate">{chat.title || "SQL Chat"}</span>
<span
className="ml-0.5 shrink-0 opacity-60 hidden group-hover:block hover:opacity-80"
onClick={(e) => {
e.stopPropagation();
handleDeleteChat(chat);
}}
>
<Icon.IoClose className="w-5 h-auto" />
</span>
</div> </div>
))} ))}
<button <button

View File

@ -36,14 +36,14 @@ const SettingModal = (props: Props) => {
<div className="w-full flex flex-col justify-start items-start space-y-3 pt-4"> <div className="w-full flex flex-col justify-start items-start space-y-3 pt-4">
<h3>Danger Zone</h3> <h3>Danger Zone</h3>
<div className="w-full border border-red-200 p-4 rounded-lg"> <div className="w-full border border-red-200 p-4 rounded-lg">
<div className="w-full flex flex-row justify-between items-center gap-2"> <div className="w-full flex flex-col justify-start items-start gap-2">
<div> <h4 className="w-full flex flex-row justify-between items-center leading-8">
<h4 className="leading-8">Clear all data</h4> <span>Clear all data</span>
<p className="text-gray-500 text-sm">SQLChat saves all of your data in localstorage. Please be sure to clear data.</p> <button className="btn btn-sm btn-error" onClick={() => toggleClearDataConfirmModal(true)}>
</div> Clear
<button className="btn btn-error btn-sm" onClick={() => toggleClearDataConfirmModal(true)}>
Clear data
</button> </button>
</h4>
<p className="text-gray-500 text-sm">SQLChat saves all of your data in localstorage. Please be sure to clear data.</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -7,7 +7,6 @@
"start": "next start" "start": "next start"
}, },
"dependencies": { "dependencies": {
"@headlessui/react": "^1.7.13",
"@vercel/analytics": "^0.1.11", "@vercel/analytics": "^0.1.11",
"axios": "^1.3.4", "axios": "^1.3.4",
"csstype": "^3.1.1", "csstype": "^3.1.1",

14
pnpm-lock.yaml generated
View File

@ -1,7 +1,6 @@
lockfileVersion: 5.4 lockfileVersion: 5.4
specifiers: specifiers:
'@headlessui/react': ^1.7.13
'@tailwindcss/typography': ^0.5.9 '@tailwindcss/typography': ^0.5.9
'@types/lodash-es': ^4.17.7 '@types/lodash-es': ^4.17.7
'@types/marked': ^4.0.8 '@types/marked': ^4.0.8
@ -37,7 +36,6 @@ specifiers:
zustand: ^4.3.6 zustand: ^4.3.6
dependencies: dependencies:
'@headlessui/react': 1.7.13_biqbaboplfbrettd7655fr4n2y
'@vercel/analytics': 0.1.11_react@18.2.0 '@vercel/analytics': 0.1.11_react@18.2.0
axios: 1.3.4 axios: 1.3.4
csstype: 3.1.1 csstype: 3.1.1
@ -99,18 +97,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@headlessui/react/1.7.13_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg==}
engines: {node: '>=10'}
peerDependencies:
react: ^16 || ^17 || ^18
react-dom: ^16 || ^17 || ^18
dependencies:
client-only: 0.0.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/@humanwhocodes/config-array/0.9.5: /@humanwhocodes/config-array/0.9.5:
resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==}
engines: {node: '>=10.10.0'} engines: {node: '>=10.10.0'}

View File

@ -19,6 +19,7 @@ interface ChatState {
getState: () => ChatState; getState: () => ChatState;
createChat: (connectionId?: Id, databaseName?: string) => Chat; createChat: (connectionId?: Id, databaseName?: string) => Chat;
setCurrentChat: (chat: Chat | undefined) => void; setCurrentChat: (chat: Chat | undefined) => void;
clearChat: (filter: (chat: Chat) => boolean) => void;
} }
export const useChatStore = create<ChatState>()( export const useChatStore = create<ChatState>()(
@ -39,6 +40,12 @@ export const useChatStore = create<ChatState>()(
return chat; return chat;
}, },
setCurrentChat: (chat: Chat | undefined) => set(() => ({ currentChat: chat })), setCurrentChat: (chat: Chat | undefined) => set(() => ({ currentChat: chat })),
clearChat: (filter: (chat: Chat) => boolean) => {
set((state) => ({
...state,
chatList: state.chatList.filter(filter),
}));
},
}), }),
{ {
name: "chat-storage", name: "chat-storage",

View File

@ -2,30 +2,9 @@ import axios from "axios";
import { uniqBy } from "lodash-es"; import { uniqBy } from "lodash-es";
import { create } from "zustand"; import { create } from "zustand";
import { persist } from "zustand/middleware"; import { persist } from "zustand/middleware";
import { Connection, Database, Engine, Table, UNKNOWN_ID } from "@/types"; import { Connection, Database, Table } from "@/types";
import { generateUUID } from "@/utils"; import { generateUUID } from "@/utils";
export const connectionMySQLSampleData: Connection = {
id: UNKNOWN_ID,
title: "",
engineType: Engine.MySQL,
host: "127.0.0.1",
port: "3306",
username: "root",
password: "",
};
export const connectionPostgreSQLSampleData: Connection = {
id: UNKNOWN_ID,
title: "",
engineType: Engine.PostgreSQL,
host: "127.0.0.1",
port: "5432",
username: "postgres",
password: "",
database: "test",
};
interface ConnectionContext { interface ConnectionContext {
connection: Connection; connection: Connection;
database?: Database; database?: Database;
@ -36,9 +15,10 @@ interface ConnectionState {
databaseList: Database[]; databaseList: Database[];
currentConnectionCtx?: ConnectionContext; currentConnectionCtx?: ConnectionContext;
createConnection: (connection: Connection) => Connection; createConnection: (connection: Connection) => Connection;
setCurrentConnectionCtx: (connectionCtx: ConnectionContext) => void; setCurrentConnectionCtx: (connectionCtx: ConnectionContext | undefined) => void;
getOrFetchDatabaseList: (connection: Connection) => Promise<Database[]>; getOrFetchDatabaseList: (connection: Connection) => Promise<Database[]>;
getOrFetchDatabaseSchema: (database: Database) => Promise<Table[]>; getOrFetchDatabaseSchema: (database: Database) => Promise<Table[]>;
clearConnection: (filter: (connection: Connection) => boolean) => void;
} }
export const useConnectionStore = create<ConnectionState>()( export const useConnectionStore = create<ConnectionState>()(
@ -57,7 +37,7 @@ export const useConnectionStore = create<ConnectionState>()(
})); }));
return createdConnection; return createdConnection;
}, },
setCurrentConnectionCtx: (connectionCtx: ConnectionContext) => setCurrentConnectionCtx: (connectionCtx: ConnectionContext | undefined) =>
set((state) => ({ set((state) => ({
...state, ...state,
currentConnectionCtx: connectionCtx, currentConnectionCtx: connectionCtx,
@ -98,6 +78,12 @@ export const useConnectionStore = create<ConnectionState>()(
}); });
return data; return data;
}, },
clearConnection: (filter: (connection: Connection) => boolean) => {
set((state) => ({
...state,
connectionList: state.connectionList.filter(filter),
}));
},
}), }),
{ {
name: "connection-storage", name: "connection-storage",