import { ApiError } from "../../api/client"; import type { BulkRemoveItem } from "../../api/types"; import { ConfirmDialog } from "../../components/ui/ConfirmDialog"; import { useToast } from "../../components/ui/toast-context"; import { useBulkRemoveMachines } from "./hooks"; interface BulkRemoveMachinesDialogProps { /** Selected agent_ids to remove, or empty when the dialog is closed. */ agentIds: string[]; /** Whether the dialog is open. Kept explicit so an empty list can stay open. */ open: boolean; onClose: () => void; /** Called after a successful batch so the page can clear its selection. */ onRemoved: () => void; } /** Count outcomes by status for a compact "12 removed, 1 not found" summary. */ function summarize(results: BulkRemoveItem[]): string { const counts = new Map(); for (const r of results) counts.set(r.status, (counts.get(r.status) ?? 0) + 1); const order = ["removed", "not_found", "invalid", "error"]; const labels: Record = { removed: "removed", not_found: "not found", invalid: "invalid", error: "errored", }; const parts: string[] = []; for (const status of order) { const n = counts.get(status); if (n) parts.push(`${n} ${labels[status] ?? status}`); } // Surface any unexpected status the server may add in the future. for (const [status, n] of counts) { if (!order.includes(status)) parts.push(`${n} ${status}`); } return parts.join(", "); } /** * Confirm + bulk-remove the selected machines (Task 5). On confirm the selected * agent_ids are purged in one request; the per-id summary the server returns is * surfaced as a toast (e.g. "12 removed, 1 not found") so a partial outcome is * visible rather than silently swallowed. */ export function BulkRemoveMachinesDialog({ agentIds, open, onClose, onRemoved, }: BulkRemoveMachinesDialogProps) { const toast = useToast(); const bulkRemove = useBulkRemoveMachines(); const count = agentIds.length; function onConfirm() { if (count === 0) { onClose(); return; } bulkRemove.mutate(agentIds, { onSuccess: (res) => { const summary = summarize(res.results); if (res.removed === res.requested) { toast.success( `Removed ${res.removed} ${res.removed === 1 ? "machine" : "machines"}`, summary || undefined, ); } else { // Partial: some ids were not found / invalid. Report as info, not an // error — the requested removals that could happen, did. toast.info( `Removed ${res.removed} of ${res.requested}`, summary || undefined, ); } onRemoved(); onClose(); }, onError: (err) => { toast.error( "Could not remove machines", err instanceof ApiError ? `${err.message}${err.code ? ` (${err.code})` : ""}` : "The server did not respond. No machines were removed.", ); }, }); } return ( Remove the {count} selected{" "} {count === 1 ? "machine" : "machines"} from the GuruConnect console. Their live sessions are dropped and the rows disappear from the list. Any that are genuinely still in service re-appear when their agents next check in.

} /> ); }