|
| 1 | +import { useRouter } from 'next/router' |
| 2 | +import { toast } from 'sonner' |
| 3 | + |
| 4 | +import { useParams } from 'common' |
| 5 | +import { useContentDeleteMutation } from 'data/content/content-delete-mutation' |
| 6 | +import { Snippet } from 'data/content/sql-folders-query' |
| 7 | +import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2' |
| 8 | +import { createTabId, useTabsStateSnapshot } from 'state/tabs' |
| 9 | +import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' |
| 10 | + |
| 11 | +export const DeleteSnippetsModal = ({ |
| 12 | + snippets, |
| 13 | + visible, |
| 14 | + onClose, |
| 15 | +}: { |
| 16 | + visible: boolean |
| 17 | + snippets: Snippet[] |
| 18 | + onClose: () => void |
| 19 | +}) => { |
| 20 | + const router = useRouter() |
| 21 | + const { ref: projectRef, id } = useParams() |
| 22 | + const tabs = useTabsStateSnapshot() |
| 23 | + const snapV2 = useSqlEditorV2StateSnapshot() |
| 24 | + |
| 25 | + const postDeleteCleanup = (ids: string[]) => { |
| 26 | + if (!!id && ids.includes(id)) { |
| 27 | + const openedSQLTabs = tabs.openTabs.filter((x) => x.startsWith('sql-') && !x.includes(id)) |
| 28 | + if (openedSQLTabs.length > 0) { |
| 29 | + // [Joshen] For simplicity, just opening the first tab for now |
| 30 | + const firstTabId = openedSQLTabs[0].split('sql-')[1] |
| 31 | + router.push(`/project/${projectRef}/sql/${firstTabId}`) |
| 32 | + } else { |
| 33 | + router.push(`/project/${projectRef}/sql/new`) |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + if (ids.length > 0) ids.forEach((id) => snapV2.removeSnippet(id)) |
| 38 | + } |
| 39 | + |
| 40 | + const { mutate: deleteContent, isLoading: isDeleting } = useContentDeleteMutation({ |
| 41 | + onSuccess: (data) => { |
| 42 | + toast.success( |
| 43 | + `Successfully deleted ${snippets.length.toLocaleString()} quer${snippets.length > 1 ? 'ies' : 'y'}` |
| 44 | + ) |
| 45 | + |
| 46 | + // Update Tabs state - currently unknown how to differentiate between sql and non-sql content |
| 47 | + // so we're just deleting all tabs for with matching IDs |
| 48 | + const tabIds = data.map((id) => createTabId('sql', { id })) |
| 49 | + tabs.removeTabs(tabIds) |
| 50 | + |
| 51 | + postDeleteCleanup(data) |
| 52 | + onClose() |
| 53 | + }, |
| 54 | + onError: (error, data) => { |
| 55 | + if (error.message.includes('Contents not found')) { |
| 56 | + postDeleteCleanup(data.ids) |
| 57 | + onClose() |
| 58 | + } else { |
| 59 | + toast.error(`Failed to delete query: ${error.message}`) |
| 60 | + } |
| 61 | + }, |
| 62 | + }) |
| 63 | + |
| 64 | + const onConfirmDelete = () => { |
| 65 | + if (!projectRef) return console.error('Project ref is required') |
| 66 | + deleteContent({ projectRef, ids: snippets.map((x) => x.id) }) |
| 67 | + } |
| 68 | + |
| 69 | + return ( |
| 70 | + <ConfirmationModal |
| 71 | + size="small" |
| 72 | + visible={visible} |
| 73 | + title={`Confirm to delete ${snippets.length === 1 ? 'query' : `${snippets.length.toLocaleString()} quer${snippets.length > 1 ? 'ies' : 'y'}`}`} |
| 74 | + confirmLabel={`Delete ${snippets.length.toLocaleString()} quer${snippets.length > 1 ? 'ies' : 'y'}`} |
| 75 | + confirmLabelLoading="Deleting query" |
| 76 | + loading={isDeleting} |
| 77 | + variant="destructive" |
| 78 | + onCancel={onClose} |
| 79 | + onConfirm={onConfirmDelete} |
| 80 | + alert={ |
| 81 | + (snippets[0]?.visibility as unknown as string) === 'project' |
| 82 | + ? { |
| 83 | + title: 'This SQL snippet will be lost forever', |
| 84 | + description: |
| 85 | + 'Deleting this query will remove it for all members of the project team.', |
| 86 | + } |
| 87 | + : undefined |
| 88 | + } |
| 89 | + > |
| 90 | + <p className="text-sm"> |
| 91 | + This action cannot be undone.{' '} |
| 92 | + {snippets.length === 1 |
| 93 | + ? `Are you sure you want to delete '${snippets[0]?.name}'?` |
| 94 | + : `Are you sure you want to delete the selected ${snippets.length} quer${snippets.length > 1 ? 'ies' : 'y'}?`} |
| 95 | + </p> |
| 96 | + </ConfirmationModal> |
| 97 | + ) |
| 98 | +} |
0 commit comments