From 153a66b579fe07e20ff46387e2e29294427c0a0e Mon Sep 17 00:00:00 2001 From: Ethan <39577870+ethanndickson@users.noreply.github.com> Date: Wed, 1 Apr 2026 15:34:21 +1100 Subject: [PATCH] fix(site/src/pages/AgentsPage): confirm active agent archive (#23887) Add a confirmation dialog before archiving an agent that is actively running from the Agents UI. This PR came about as feedback on PR 23758: https://github.com/coder/coder/pull/23758#issuecomment-4160424938. Active agents now require confirmation before archive interrupts the current run, while inactive agents keep the existing one-click archive behavior. image --- site/src/pages/AgentsPage/AgentsPage.tsx | 38 ++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/site/src/pages/AgentsPage/AgentsPage.tsx b/site/src/pages/AgentsPage/AgentsPage.tsx index 0277cb8379..8214b5de33 100644 --- a/site/src/pages/AgentsPage/AgentsPage.tsx +++ b/site/src/pages/AgentsPage/AgentsPage.tsx @@ -29,6 +29,7 @@ import { } from "#/api/queries/chats"; import { workspaceById } from "#/api/queries/workspaces"; import type * as TypesGen from "#/api/typesGenerated"; +import { ConfirmDialog } from "#/components/Dialogs/ConfirmDialog/ConfirmDialog"; import { DeleteDialog } from "#/components/Dialogs/DeleteDialog/DeleteDialog"; import { useAuthenticated } from "#/hooks/useAuthenticated"; import { useDashboard } from "#/modules/dashboard/useDashboard"; @@ -187,6 +188,9 @@ const AgentsPage: FC = () => { toast.error(getErrorMessage(error, "Failed to archive agent.")); }, }); + const [pendingArchiveChatId, setPendingArchiveChatId] = useState< + string | null + >(null); const [pendingArchiveAndDelete, setPendingArchiveAndDelete] = useState<{ chatId: string; workspaceId: string; @@ -282,10 +286,30 @@ const AgentsPage: FC = () => { (archiveAndDeleteMutation.isPending ? archiveAndDeleteMutation.variables?.chatId : undefined); + const isActiveChat = (chat: TypesGen.Chat | undefined) => + chat?.status === "pending" || chat?.status === "running"; const requestArchiveAgent = (chatId: string) => { - if (!isArchiving) { - archiveAgentMutation.mutate(chatId); + if (isArchiving) { + return; } + const chat = + queryClient.getQueryData(chatKey(chatId)) ?? + chatList.find((candidate) => candidate.id === chatId); + if (chat === undefined || isActiveChat(chat)) { + setPendingArchiveChatId(chatId); + return; + } + archiveAgentMutation.mutate(chatId); + }; + const handleConfirmArchiveAgent = () => { + if (!pendingArchiveChatId || isArchiving) { + return; + } + archiveAgentMutation.mutate(pendingArchiveChatId, { + onSettled: () => { + setPendingArchiveChatId(null); + }, + }); }; const requestArchiveAndDeleteWorkspace = async ( chatId: string, @@ -699,6 +723,16 @@ const AgentsPage: FC = () => { archivedFilter={archivedFilter} onArchivedFilterChange={setArchivedFilter} /> + setPendingArchiveChatId(null)} + onConfirm={handleConfirmArchiveAgent} + type="delete" + confirmText="Archive" + confirmLoading={archiveAgentMutation.isPending} + title="Archive agent?" + description="This agent is currently running. Archiving it will interrupt the current run." + />