From c483bfa24f1259ce5dd85081c89a75426fc99b0f Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Tue, 3 Mar 2026 11:03:59 +0000 Subject: [PATCH] refactor(site): convert archive agent callbacks to React Query mutations (#22542) --- site/src/pages/AgentsPage/AgentDetail.tsx | 4 +- site/src/pages/AgentsPage/AgentsPage.tsx | 112 ++++++++++---------- site/src/pages/AgentsPage/AgentsSidebar.tsx | 15 ++- 3 files changed, 68 insertions(+), 63 deletions(-) diff --git a/site/src/pages/AgentsPage/AgentDetail.tsx b/site/src/pages/AgentsPage/AgentDetail.tsx index 63b271c479..bcfd992a7b 100644 --- a/site/src/pages/AgentsPage/AgentDetail.tsx +++ b/site/src/pages/AgentsPage/AgentDetail.tsx @@ -876,10 +876,10 @@ const AgentDetail: FC = () => { }; const handleArchiveAndDeleteWorkspaceAction = () => { - if (!agentId || isArchived) { + if (!agentId || isArchived || !workspaceId) { return; } - requestArchiveAndDeleteWorkspace(agentId); + requestArchiveAndDeleteWorkspace(agentId, workspaceId); }; if (chatQuery.isLoading) { diff --git a/site/src/pages/AgentsPage/AgentsPage.tsx b/site/src/pages/AgentsPage/AgentsPage.tsx index 0d426eb9f2..fe0c832138 100644 --- a/site/src/pages/AgentsPage/AgentsPage.tsx +++ b/site/src/pages/AgentsPage/AgentsPage.tsx @@ -88,7 +88,10 @@ export interface AgentsOutletContext { setChatErrorReason: (chatId: string, reason: string) => void; clearChatErrorReason: (chatId: string) => void; requestArchiveAgent: (chatId: string) => void; - requestArchiveAndDeleteWorkspace: (chatId: string) => void; + requestArchiveAndDeleteWorkspace: ( + chatId: string, + workspaceId: string, + ) => void; isSidebarCollapsed: boolean; onToggleSidebarCollapsed: () => void; } @@ -151,11 +154,40 @@ const AgentsPage: FC = () => { const chatModelsQuery = useQuery(chatModels()); const chatModelConfigsQuery = useQuery(chatModelConfigs()); const createMutation = useMutation(createChat(queryClient)); - const archiveMutation = useMutation(archiveChat(queryClient)); - const deleteWorkspaceMutation = useMutation({ - mutationFn: (workspaceId: string) => API.deleteWorkspace(workspaceId), + const archiveAgentMutation = useMutation({ + ...archiveChat(queryClient), + onSuccess: async (_data, chatId) => { + clearChatErrorReason(chatId); + await queryClient.invalidateQueries({ queryKey: chatKey(chatId) }); + toast.success("Agent archived."); + }, + onError: (error) => { + toast.error(getErrorMessage(error, "Failed to archive agent.")); + }, + }); + const archiveAndDeleteMutation = useMutation({ + mutationFn: async ({ + chatId, + workspaceId, + }: { + chatId: string; + workspaceId: string; + }) => { + await API.archiveChat(chatId); + await API.deleteWorkspace(workspaceId); + return { chatId, workspaceId }; + }, + onSuccess: async ({ chatId }) => { + clearChatErrorReason(chatId); + await queryClient.invalidateQueries({ queryKey: chatsKey }); + await queryClient.invalidateQueries({ queryKey: chatKey(chatId) }); + toast.success("Agent archived."); + toast.success("Workspace deletion initiated."); + }, + onError: (error) => { + toast.error(getErrorMessage(error, "Failed to archive agent.")); + }, }); - const [archivingChatId, setArchivingChatId] = useState(null); const [isConfigureAgentsDialogOpen, setConfigureAgentsDialogOpen] = useState(false); @@ -219,64 +251,30 @@ const AgentsPage: FC = () => { }); }, []); const chatList = chatsQuery.data ?? []; + const isArchiving = + archiveAgentMutation.isPending || archiveAndDeleteMutation.isPending; + const archivingChatId = + (archiveAgentMutation.isPending + ? archiveAgentMutation.variables + : undefined) ?? + (archiveAndDeleteMutation.isPending + ? archiveAndDeleteMutation.variables?.chatId + : undefined); const requestArchiveAgent = useCallback( - async (chatId: string) => { - if (archiveMutation.isPending) { - return; - } - - setArchivingChatId(chatId); - - try { - await archiveMutation.mutateAsync(chatId); - clearChatErrorReason(chatId); - await queryClient.invalidateQueries({ queryKey: chatKey(chatId) }); - toast.success("Agent archived."); - } catch (error) { - toast.error(getErrorMessage(error, "Failed to archive agent.")); - } finally { - setArchivingChatId(null); + (chatId: string) => { + if (!isArchiving) { + archiveAgentMutation.mutate(chatId); } }, - [archiveMutation, queryClient, clearChatErrorReason], + [isArchiving, archiveAgentMutation], ); const requestArchiveAndDeleteWorkspace = useCallback( - async (chatId: string) => { - if (archiveMutation.isPending || deleteWorkspaceMutation.isPending) { - return; - } - - setArchivingChatId(chatId); - - try { - await archiveMutation.mutateAsync(chatId); - clearChatErrorReason(chatId); - await queryClient.invalidateQueries({ queryKey: chatKey(chatId) }); - toast.success("Agent archived."); - } catch (error) { - toast.error(getErrorMessage(error, "Failed to archive agent.")); - return; - } finally { - setArchivingChatId(null); - } - - const chat = chatList.find((c) => c.id === chatId); - if (chat?.workspace_id) { - try { - await deleteWorkspaceMutation.mutateAsync(chat.workspace_id); - toast.success("Workspace deletion initiated."); - } catch (error) { - toast.error(getErrorMessage(error, "Failed to delete workspace.")); - } + (chatId: string, workspaceId: string) => { + if (!isArchiving) { + archiveAndDeleteMutation.mutate({ chatId, workspaceId }); } }, - [ - archiveMutation, - deleteWorkspaceMutation, - queryClient, - clearChatErrorReason, - chatList, - ], + [isArchiving, archiveAndDeleteMutation], ); const handleToggleSidebarCollapsed = useCallback( () => setIsSidebarCollapsed((prev) => !prev), @@ -457,7 +455,7 @@ const AgentsPage: FC = () => { onArchiveAndDeleteWorkspace={requestArchiveAndDeleteWorkspace} onNewAgent={handleNewAgent} isCreating={createMutation.isPending} - isArchiving={archiveMutation.isPending} + isArchiving={isArchiving} archivingChatId={archivingChatId} isLoading={chatsQuery.isLoading} loadError={chatsQuery.isError ? chatsQuery.error : undefined} diff --git a/site/src/pages/AgentsPage/AgentsSidebar.tsx b/site/src/pages/AgentsPage/AgentsSidebar.tsx index 0651428b59..3e6d4a50f6 100644 --- a/site/src/pages/AgentsPage/AgentsSidebar.tsx +++ b/site/src/pages/AgentsPage/AgentsSidebar.tsx @@ -52,7 +52,7 @@ interface AgentsSidebarProps { modelConfigs: readonly ChatModelConfig[]; logoUrl?: string; onArchiveAgent: (chatId: string) => void; - onArchiveAndDeleteWorkspace: (chatId: string) => void; + onArchiveAndDeleteWorkspace: (chatId: string, workspaceId: string) => void; onNewAgent: () => void; isCreating: boolean; isArchiving?: boolean; @@ -266,7 +266,10 @@ interface ChatTreeContextValue { readonly archivingChatId: string | null; readonly toggleExpanded: (chatID: string) => void; readonly onArchiveAgent: (chatId: string) => void; - readonly onArchiveAndDeleteWorkspace: (chatId: string) => void; + readonly onArchiveAndDeleteWorkspace: ( + chatId: string, + workspaceId: string, + ) => void; } const ChatTreeContext = createContext(null); @@ -329,6 +332,7 @@ const ChatTreeNode = memo(({ chat, isChildNode }) => { const filesChangedLabel = `${changedFiles} ${ changedFiles === 1 ? "file" : "files" }`; + const workspaceId = chat.workspace_id; const isArchivingThisChat = isArchiving && archivingChatId === chat.id; const isExpanded = normalizedSearch ? true : (expandedById[chatID] ?? false); const isExecuting = @@ -473,12 +477,15 @@ const ChatTreeNode = memo(({ chat, isChildNode }) => { Archive agent - {chat.workspace_id && ( + {workspaceId && ( onArchiveAndDeleteWorkspace(chat.id)} + onSelect={() => + onArchiveAndDeleteWorkspace(chat.id, workspaceId) + } > + {" "} Archive & delete workspace