From c6c7ed06c9fb5fe051d28163f4eaff66d345857e Mon Sep 17 00:00:00 2001 From: esxr Date: Wed, 24 Apr 2024 12:31:37 +1000 Subject: [PATCH 1/6] storage: delete assistant --- backend/app/storage.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/backend/app/storage.py b/backend/app/storage.py index fdbc356a..028536ad 100644 --- a/backend/app/storage.py +++ b/backend/app/storage.py @@ -206,3 +206,19 @@ async def delete_thread(user_id: str, thread_id: str): thread_id, user_id, ) + + +async def delete_assistant(user_id: str, assistant_id: str): + """Delete an assistant by ID. + + Args: + user_id: The user's ID. + assistant_id: The assistant's ID. + + """ + async with get_pg_pool().acquire() as conn: + await conn.execute( + "DELETE FROM assistant WHERE assistant_id = $1 AND user_id = $2", + assistant_id, + user_id, + ) \ No newline at end of file From 812baa3b70864eaffcfa7d3f62dbacf7c5638cf5 Mon Sep 17 00:00:00 2001 From: esxr Date: Wed, 24 Apr 2024 12:31:54 +1000 Subject: [PATCH 2/6] api: delete assistant --- backend/app/api/assistants.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/backend/app/api/assistants.py b/backend/app/api/assistants.py index dda15581..98c2ddda 100644 --- a/backend/app/api/assistants.py +++ b/backend/app/api/assistants.py @@ -83,3 +83,18 @@ async def upsert_assistant( config=payload.config, public=payload.public, ) + + +@router.delete("/{aid}") +async def delete_assistant( + user: AuthedUser, + aid: AssistantID, +) -> dict: + """Delete an assistant by ID.""" + assistant = await storage.get_assistant(user["user_id"], aid) + if not assistant: + raise HTTPException(status_code=404, detail="Assistant not found") + if not assistant.get('public') and assistant.get('user_id') != user["user_id"]: + raise HTTPException(status_code=403, detail="Unauthorized to delete this assistant") + await storage.delete_assistant(user["user_id"], aid) + return {"message": "Assistant deleted successfully"} From 9f630f97ca10e7d3fed5ef9c8177c4a31b7e48df Mon Sep 17 00:00:00 2001 From: esxr Date: Thu, 25 Apr 2024 17:10:30 +1000 Subject: [PATCH 3/6] api: refactor --- backend/app/api/assistants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/api/assistants.py b/backend/app/api/assistants.py index 98c2ddda..4453502c 100644 --- a/backend/app/api/assistants.py +++ b/backend/app/api/assistants.py @@ -97,4 +97,4 @@ async def delete_assistant( if not assistant.get('public') and assistant.get('user_id') != user["user_id"]: raise HTTPException(status_code=403, detail="Unauthorized to delete this assistant") await storage.delete_assistant(user["user_id"], aid) - return {"message": "Assistant deleted successfully"} + return {"status": "ok"} From 912368a2659bc7e35b95597734e5b334b563ac30 Mon Sep 17 00:00:00 2001 From: esxr Date: Thu, 25 Apr 2024 17:10:45 +1000 Subject: [PATCH 4/6] ui: delete assistant --- frontend/src/App.tsx | 3 +- frontend/src/components/ConfigList.tsx | 94 +++++++++++++++----------- frontend/src/components/NewChat.tsx | 2 + frontend/src/hooks/useConfigList.ts | 12 ++++ 4 files changed, 72 insertions(+), 39 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 13949af8..4b74dabc 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -21,7 +21,7 @@ function App(props: { edit?: boolean }) { const navigate = useNavigate(); const [sidebarOpen, setSidebarOpen] = useState(false); const { chats, createChat, deleteChat } = useChatList(); - const { configs, saveConfig } = useConfigList(); + const { configs, saveConfig, deleteConfig } = useConfigList(); const { startStream, stopStream, stream } = useStreamState(); const { configSchema, configDefaults } = useSchemas(); @@ -153,6 +153,7 @@ function App(props: { edit?: boolean }) { configs={configs} saveConfig={saveConfig} enterConfig={selectConfig} + deleteConfig={deleteConfig} /> )} {!currentChat && assistantConfig && props.edit && ( diff --git a/frontend/src/components/ConfigList.tsx b/frontend/src/components/ConfigList.tsx index f93eeb7c..a65e8daf 100644 --- a/frontend/src/components/ConfigList.tsx +++ b/frontend/src/components/ConfigList.tsx @@ -1,13 +1,14 @@ import { TYPES } from "../constants"; import { Config, ConfigListProps } from "../hooks/useConfigList"; import { cn } from "../utils/cn"; -import { PencilSquareIcon } from "@heroicons/react/24/outline"; +import { PencilSquareIcon, TrashIcon } from "@heroicons/react/24/outline"; import { Link } from "react-router-dom"; function ConfigItem(props: { config: Config; currentConfig: Config | null; enterConfig: (id: string | null) => void; + deleteConfig: (id: string) => void; }) { return (
  • @@ -17,48 +18,63 @@ function ConfigItem(props: { props.config.assistant_id === props.currentConfig?.assistant_id ? "bg-gray-50 text-indigo-600" : "text-gray-700 hover:text-indigo-600 hover:bg-gray-50", - "group flex gap-x-3 rounded-md p-2 leading-6 cursor-pointer", + "group flex justify-between gap-x-3 rounded-md p-2 leading-6 cursor-pointer", )} > - - {props.config.name?.[0] ?? " "} - -
    - - {props.config.name} - - - { - TYPES[ - (props.config.config.configurable?.type ?? - "agent") as keyof typeof TYPES - ]?.title - } +
    + + {props.config.name?.[0] ?? " "} +
    + + {props.config.name} + + + { + TYPES[ + (props.config.config.configurable?.type ?? + "agent") as keyof typeof TYPES + ]?.title + } + +
    +
    +
    + event.stopPropagation()} + > + + + { + event.stopPropagation(); + props.deleteConfig(props.config.assistant_id); + }} + > + +
    - event.stopPropagation()} - > - -
  • ); } + export function ConfigList(props: { configs: ConfigListProps["configs"]; currentConfig: Config | null; enterConfig: (id: string | null) => void; + deleteConfig: (id: string) => void; }) { return ( <> @@ -74,12 +90,13 @@ export function ConfigList(props: { config={assistant} currentConfig={props.currentConfig} enterConfig={props.enterConfig} + deleteConfig={props.deleteConfig} /> )) ?? ( -
  • - ... -
  • - )} +
  • + ... +
  • + )}
    @@ -94,12 +111,13 @@ export function ConfigList(props: { config={assistant} currentConfig={props.currentConfig} enterConfig={props.enterConfig} + deleteConfig={props.deleteConfig} /> )) ?? ( -
  • - ... -
  • - )} +
  • + ... +
  • + )} ); diff --git a/frontend/src/components/NewChat.tsx b/frontend/src/components/NewChat.tsx index 4d22e19a..df01a070 100644 --- a/frontend/src/components/NewChat.tsx +++ b/frontend/src/components/NewChat.tsx @@ -15,6 +15,7 @@ interface NewChatProps extends ConfigListProps { configSchema: Schemas["configSchema"]; configDefaults: Schemas["configDefaults"]; enterConfig: (id: string | null) => void; + deleteConfig: (id: string) => Promise; startChat: ( config: ConfigInterface, message: MessageWithFiles, @@ -44,6 +45,7 @@ export function NewChat(props: NewChatProps) { configs={props.configs} currentConfig={assistantConfig} enterConfig={(id) => navigator(`/assistant/${id}`)} + deleteConfig={props.deleteConfig} />
    diff --git a/frontend/src/hooks/useConfigList.ts b/frontend/src/hooks/useConfigList.ts index bd50ddf9..675b82da 100644 --- a/frontend/src/hooks/useConfigList.ts +++ b/frontend/src/hooks/useConfigList.ts @@ -29,6 +29,7 @@ export interface ConfigListProps { isPublic: boolean, assistantId?: string, ) => Promise; + deleteConfig: (assistantId: string) => Promise; } function configsReducer( @@ -105,8 +106,19 @@ export function useConfigList(): ConfigListProps { [], ); + const deleteConfig = useCallback( + async (assistantId: string): Promise => { + await fetch(`/assistants/${assistantId}`, { + method: "DELETE", + }); + setConfigs(configs?.filter(config => config.assistant_id !== assistantId)); + }, + [configs], + ); + return { configs, saveConfig, + deleteConfig, }; } From 6953d09f8b091844f71d26e04dc30168f0ff0fec Mon Sep 17 00:00:00 2001 From: esxr Date: Fri, 26 Apr 2024 14:31:12 +1000 Subject: [PATCH 5/6] fix linter failures --- backend/app/api/assistants.py | 6 ++++-- backend/app/storage.py | 10 ++-------- frontend/src/components/ConfigList.tsx | 21 ++++++++++----------- frontend/src/hooks/useConfigList.ts | 4 +++- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/backend/app/api/assistants.py b/backend/app/api/assistants.py index 4453502c..ba0eb175 100644 --- a/backend/app/api/assistants.py +++ b/backend/app/api/assistants.py @@ -94,7 +94,9 @@ async def delete_assistant( assistant = await storage.get_assistant(user["user_id"], aid) if not assistant: raise HTTPException(status_code=404, detail="Assistant not found") - if not assistant.get('public') and assistant.get('user_id') != user["user_id"]: - raise HTTPException(status_code=403, detail="Unauthorized to delete this assistant") + if not assistant.get("public") and assistant.get("user_id") != user["user_id"]: + raise HTTPException( + status_code=403, detail="Unauthorized to delete this assistant" + ) await storage.delete_assistant(user["user_id"], aid) return {"status": "ok"} diff --git a/backend/app/storage.py b/backend/app/storage.py index 5ee9333c..0ee3ad48 100644 --- a/backend/app/storage.py +++ b/backend/app/storage.py @@ -212,16 +212,10 @@ async def delete_thread(user_id: str, thread_id: str): async def delete_assistant(user_id: str, assistant_id: str): - """Delete an assistant by ID. - - Args: - user_id: The user's ID. - assistant_id: The assistant's ID. - - """ + """Delete an assistant by ID.""" async with get_pg_pool().acquire() as conn: await conn.execute( "DELETE FROM assistant WHERE assistant_id = $1 AND user_id = $2", assistant_id, user_id, - ) \ No newline at end of file + ) diff --git a/frontend/src/components/ConfigList.tsx b/frontend/src/components/ConfigList.tsx index a65e8daf..fa587778 100644 --- a/frontend/src/components/ConfigList.tsx +++ b/frontend/src/components/ConfigList.tsx @@ -54,7 +54,7 @@ function ConfigItem(props: { > - { event.stopPropagation(); @@ -62,14 +62,13 @@ function ConfigItem(props: { }} > - + ); } - export function ConfigList(props: { configs: ConfigListProps["configs"]; currentConfig: Config | null; @@ -93,10 +92,10 @@ export function ConfigList(props: { deleteConfig={props.deleteConfig} /> )) ?? ( -
  • - ... -
  • - )} +
  • + ... +
  • + )}
    @@ -114,10 +113,10 @@ export function ConfigList(props: { deleteConfig={props.deleteConfig} /> )) ?? ( -
  • - ... -
  • - )} +
  • + ... +
  • + )} ); diff --git a/frontend/src/hooks/useConfigList.ts b/frontend/src/hooks/useConfigList.ts index 675b82da..0be896f2 100644 --- a/frontend/src/hooks/useConfigList.ts +++ b/frontend/src/hooks/useConfigList.ts @@ -111,7 +111,9 @@ export function useConfigList(): ConfigListProps { await fetch(`/assistants/${assistantId}`, { method: "DELETE", }); - setConfigs(configs?.filter(config => config.assistant_id !== assistantId)); + setConfigs( + (configs?.filter((config) => config.assistant_id !== assistantId)) || [] + ); }, [configs], ); From 2b7a203bce73f0256bfda53b76daabf3b3aa9938 Mon Sep 17 00:00:00 2001 From: esxr Date: Fri, 26 Apr 2024 15:34:10 +1000 Subject: [PATCH 6/6] frontend formatting --- frontend/src/hooks/useConfigList.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/hooks/useConfigList.ts b/frontend/src/hooks/useConfigList.ts index 0be896f2..3714e0ca 100644 --- a/frontend/src/hooks/useConfigList.ts +++ b/frontend/src/hooks/useConfigList.ts @@ -112,7 +112,7 @@ export function useConfigList(): ConfigListProps { method: "DELETE", }); setConfigs( - (configs?.filter((config) => config.assistant_id !== assistantId)) || [] + configs?.filter((config) => config.assistant_id !== assistantId) || [], ); }, [configs],