import { ExternalLink } from 'lucide-react' import Link from 'next/link' import { toast } from 'sonner' import { Alert, AlertDescription, AlertTitle, Button, Checkbox } from 'ui' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { useTableFilter } from '@/components/grid/hooks/useTableFilter' import type { SupaRow } from '@/components/grid/types' import { useDatabaseColumnDeleteMutation } from '@/data/database-columns/database-column-delete-mutation' import { TableLike } from '@/data/table-editor/table-editor-types' import { useTableRowDeleteAllMutation } from '@/data/table-rows/table-row-delete-all-mutation' import { useTableRowDeleteMutation } from '@/data/table-rows/table-row-delete-mutation' import { useTableRowTruncateMutation } from '@/data/table-rows/table-row-truncate-mutation' import { useTableDeleteMutation } from '@/data/tables/table-delete-mutation' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { useGetImpersonatedRoleState } from '@/state/role-impersonation-state' import { useTableEditorStateSnapshot } from '@/state/table-editor' export type DeleteConfirmationDialogsProps = { selectedTable?: TableLike onTableDeleted?: () => void } const DeleteConfirmationDialogs = ({ selectedTable, onTableDeleted, }: DeleteConfirmationDialogsProps) => { const { data: project } = useSelectedProjectQuery() const snap = useTableEditorStateSnapshot() const { filters, setFilters } = useTableFilter() const removeDeletedColumnFromFiltersAndSorts = ({ columnName, }: { ref?: string tableName?: string schema?: string columnName: string }) => { setFilters(filters.filter((filter) => filter.column !== columnName)) } const { mutate: deleteColumn } = useDatabaseColumnDeleteMutation({ onSuccess: () => { if (!(snap.confirmationDialog?.type === 'column')) return const selectedColumnToDelete = snap.confirmationDialog.column removeDeletedColumnFromFiltersAndSorts({ columnName: selectedColumnToDelete.name }) toast.success(`Successfully deleted column "${selectedColumnToDelete.name}"`) }, onError: (error) => { if (!(snap.confirmationDialog?.type === 'column')) return const selectedColumnToDelete = snap.confirmationDialog.column toast.error(`Failed to delete ${selectedColumnToDelete!.name}: ${error.message}`) }, onSettled: () => { snap.closeConfirmationDialog() }, }) const { mutate: deleteTable } = useTableDeleteMutation({ onSuccess: async () => { toast.success(`Successfully deleted table "${selectedTable?.name}"`) onTableDeleted?.() }, onError: (error) => { toast.error(`Failed to delete ${selectedTable?.name}: ${error.message}`) }, onSettled: () => { snap.closeConfirmationDialog() }, }) const { mutate: deleteRows, isPending: isDeletingRows } = useTableRowDeleteMutation({ onSuccess: () => { if (snap.confirmationDialog?.type === 'row') { snap.confirmationDialog.callback?.() } toast.success(`Successfully deleted selected row(s)`) }, onSettled: () => { snap.closeConfirmationDialog() }, }) const { mutate: deleteAllRows, isPending: isDeletingAllRows } = useTableRowDeleteAllMutation({ onSuccess: () => { if (snap.confirmationDialog?.type === 'row') { snap.confirmationDialog.callback?.() } toast.success(`Successfully deleted selected rows`) }, onError: (error) => { toast.error(`Failed to delete rows: ${error.message}`) }, onSettled: () => { snap.closeConfirmationDialog() }, }) const { mutate: truncateRows, isPending: isTruncatingRows } = useTableRowTruncateMutation({ onSuccess: () => { if (snap.confirmationDialog?.type === 'row') { snap.confirmationDialog.callback?.() } toast.success(`Successfully deleted all rows from table`) }, onError: (error) => { toast.error(`Failed to delete rows: ${error.message}`) }, onSettled: () => { snap.closeConfirmationDialog() }, }) const isAllRowsSelected = snap.confirmationDialog?.type === 'row' ? snap.confirmationDialog.allRowsSelected : false const numRows = snap.confirmationDialog?.type === 'row' ? snap.confirmationDialog.allRowsSelected ? (snap.confirmationDialog.numRows ?? 0) : snap.confirmationDialog.rows.length : 0 const isDeleteWithCascade = snap.confirmationDialog?.type === 'column' || snap.confirmationDialog?.type === 'table' ? snap.confirmationDialog.isDeleteWithCascade : false const onConfirmDeleteColumn = async () => { if (!(snap.confirmationDialog?.type === 'column')) return if (project === undefined) return const selectedColumnToDelete = snap.confirmationDialog.column if (selectedColumnToDelete === undefined) return deleteColumn({ column: selectedColumnToDelete, cascade: isDeleteWithCascade, projectRef: project.ref, connectionString: project?.connectionString, }) } const onConfirmDeleteTable = async () => { if (!(snap.confirmationDialog?.type === 'table')) return const selectedTableToDelete = selectedTable if (selectedTableToDelete === undefined) return deleteTable({ projectRef: project?.ref!, connectionString: project?.connectionString, id: selectedTableToDelete.id, name: selectedTableToDelete.name, schema: selectedTableToDelete.schema, cascade: isDeleteWithCascade, }) } const getImpersonatedRoleState = useGetImpersonatedRoleState() const onConfirmDeleteRow = async () => { if (!project) return console.error('Project ref is required') if (!selectedTable) return console.error('Selected table required') if (snap.confirmationDialog?.type !== 'row') return const selectedRowsToDelete = snap.confirmationDialog.rows if (snap.confirmationDialog.allRowsSelected) { if (filters.length === 0) { if (getImpersonatedRoleState().role !== undefined) { snap.closeConfirmationDialog() return toast.error('Table truncation is not supported when impersonating a role') } truncateRows({ projectRef: project.ref, connectionString: project.connectionString, table: selectedTable, }) } else { deleteAllRows({ projectRef: project.ref, connectionString: project.connectionString, table: selectedTable, filters, roleImpersonationState: getImpersonatedRoleState(), }) } } else { deleteRows({ projectRef: project.ref, connectionString: project.connectionString, table: selectedTable, rows: selectedRowsToDelete as SupaRow[], roleImpersonationState: getImpersonatedRoleState(), }) } } return ( <> { snap.closeConfirmationDialog() }} onConfirm={onConfirmDeleteColumn} >

Are you sure you want to delete the selected column? This action cannot be undone.

snap.toggleConfirmationIsWithCascade()} />

Deletes the column and its dependent objects

{isDeleteWithCascade && ( All dependent objects will be removed, as will any objects that depend on them, recursively. )}
{`Confirm deletion of table "${selectedTable?.name}"`} } confirmLabel="Delete" confirmLabelLoading="Deleting" onCancel={() => { snap.closeConfirmationDialog() }} onConfirm={onConfirmDeleteTable} >

Are you sure you want to delete the selected table? This action cannot be undone.

snap.toggleConfirmationIsWithCascade(!isDeleteWithCascade)} />

Deletes the table and its dependent objects

{isDeleteWithCascade && ( Warning: Dropping with cascade may result in unintended consequences All dependent objects will be removed, as will any objects that depend on them, recursively. )}
Confirm to delete the selected row {numRows > 1 && 's'}

} confirmLabel="Delete" confirmLabelLoading="Deleting" onCancel={() => snap.closeConfirmationDialog()} onConfirm={() => onConfirmDeleteRow()} loading={isTruncatingRows || isDeletingRows || isDeletingAllRows} >

Are you sure you want to delete {isAllRowsSelected ? 'all' : 'the selected'} {numRows > 1 && `${numRows} `} row {numRows > 1 && 's'} ? This action cannot be undone.

) } export default DeleteConfirmationDialogs