mirror of
https://github.com/sqlchat/sqlchat.git
synced 2025-07-29 18:23:25 +08:00
feat: implement delete connection/chat
This commit is contained in:
@ -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 (
|
||||||
|
@ -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
|
||||||
|
@ -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)}>
|
</button>
|
||||||
Clear data
|
</h4>
|
||||||
</button>
|
<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>
|
||||||
|
@ -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
14
pnpm-lock.yaml
generated
@ -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'}
|
||||||
|
@ -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",
|
||||||
|
@ -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",
|
||||||
|
Reference in New Issue
Block a user