diff --git a/frontend/src/app/agents/page.tsx b/frontend/src/app/agents/page.tsx index c8c31952..b08219f5 100644 --- a/frontend/src/app/agents/page.tsx +++ b/frontend/src/app/agents/page.tsx @@ -20,14 +20,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { StatusPill } from "@/components/atoms/StatusPill"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { Button, buttonVariants } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; +import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { TableEmptyStateRow, TableLoadingRow } from "@/components/ui/table-state"; import { ApiError } from "@/api/mutator"; @@ -341,37 +334,25 @@ export default function AgentsPage() { ) : null} - + ariaLabel="Delete agent" + title="Delete agent" + description={ + <> + This will remove {deleteTarget?.name}. This action cannot be + undone. + > + } + errorMessage={deleteMutation.error?.message} + onConfirm={handleDelete} + isConfirming={deleteMutation.isPending} + /> > ); } diff --git a/frontend/src/app/board-groups/page.tsx b/frontend/src/app/board-groups/page.tsx index 6959acb9..ae75da63 100644 --- a/frontend/src/app/board-groups/page.tsx +++ b/frontend/src/app/board-groups/page.tsx @@ -24,14 +24,7 @@ import { import type { BoardGroupRead } from "@/api/generated/model"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { Button, buttonVariants } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; +import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { formatTimestamp } from "@/lib/formatters"; import { TableEmptyStateRow, TableLoadingRow } from "@/components/ui/table-state"; @@ -268,37 +261,25 @@ export default function BoardGroupsPage() {
{groupsQuery.error.message}
) : null} - + ariaLabel="Delete board group" + title="Delete board group" + description={ + <> + This will remove {deleteTarget?.name}. Boards will be ungrouped. + This action cannot be undone. + > + } + errorMessage={deleteMutation.error?.message} + onConfirm={handleDelete} + isConfirming={deleteMutation.isPending} + /> > ); } diff --git a/frontend/src/app/boards/page.tsx b/frontend/src/app/boards/page.tsx index 0e30bf23..26196be8 100644 --- a/frontend/src/app/boards/page.tsx +++ b/frontend/src/app/boards/page.tsx @@ -30,14 +30,7 @@ import { useOrganizationMembership } from "@/lib/use-organization-membership"; import type { BoardGroupRead, BoardRead } from "@/api/generated/model"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { Button, buttonVariants } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; +import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { TableEmptyStateRow, TableLoadingRow } from "@/components/ui/table-state"; const compactId = (value: string) => @@ -322,37 +315,25 @@ export default function BoardsPage() {{boardsQuery.error.message}
) : null} - + ariaLabel="Delete board" + title="Delete board" + description={ + <> + This will remove {deleteTarget?.name}. This action cannot be + undone. + > + } + errorMessage={deleteMutation.error?.message} + onConfirm={handleDelete} + isConfirming={deleteMutation.isPending} + /> > ); } diff --git a/frontend/src/app/gateways/page.tsx b/frontend/src/app/gateways/page.tsx index ba1685db..16be10c4 100644 --- a/frontend/src/app/gateways/page.tsx +++ b/frontend/src/app/gateways/page.tsx @@ -18,14 +18,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { Button, buttonVariants } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; +import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { TableEmptyStateRow, TableLoadingRow } from "@/components/ui/table-state"; import { ApiError } from "@/api/mutator"; @@ -294,33 +287,22 @@ export default function GatewaysPage() { ) : null} - + title="Delete gateway?" + description={ + <> + This removes the gateway connection from Mission Control. Boards + using it will need a new gateway assigned. + > + } + errorMessage={deleteMutation.error?.message} + errorStyle="text" + cancelVariant="ghost" + onConfirm={handleDelete} + isConfirming={deleteMutation.isPending} + /> > ); } diff --git a/frontend/src/components/ui/confirm-action-dialog.tsx b/frontend/src/components/ui/confirm-action-dialog.tsx new file mode 100644 index 00000000..3814ddac --- /dev/null +++ b/frontend/src/components/ui/confirm-action-dialog.tsx @@ -0,0 +1,71 @@ +import type { ReactNode } from "react"; + +import { Button, type ButtonProps } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; + +type ConfirmActionDialogProps = { + open: boolean; + onOpenChange: (open: boolean) => void; + title: string; + description: ReactNode; + onConfirm: () => void; + isConfirming: boolean; + errorMessage?: string | null; + confirmLabel?: string; + confirmingLabel?: string; + cancelLabel?: string; + cancelVariant?: NonNullable