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.

<img width="450" height="242" alt="image"
src="https://github.com/user-attachments/assets/98ce6978-d2d6-440b-9841-3806038556ee"
/>
This commit is contained in:
Ethan
2026-04-01 15:34:21 +11:00
committed by GitHub
parent 5cba59af79
commit 153a66b579
+36 -2
View File
@@ -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<TypesGen.Chat>(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}
/>
<ConfirmDialog
open={pendingArchiveChatId !== null}
onClose={() => 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."
/>
<DeleteDialog
key={pendingWorkspaceName}
isOpen={deleteDialogOpen}