DeleteSecretModal.tsx77 lines · main
1import { parseAsString, useQueryState } from 'nuqs'
2import { useEffect } from 'react'
3import { toast } from 'sonner'
4import { Modal } from 'ui'
5
6import { useVaultSecretDeleteMutation } from '@/data/vault/vault-secret-delete-mutation'
7import { useVaultSecretsQuery } from '@/data/vault/vault-secrets-query'
8import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
9
10export const DeleteSecretModal = () => {
11 const { data: project } = useSelectedProjectQuery()
12
13 const { data: secrets = [], isSuccess } = useVaultSecretsQuery({
14 projectRef: project?.ref,
15 connectionString: project?.connectionString,
16 })
17
18 const [secretIdToDelete, setSelectedSecretToDelete] = useQueryState('delete', parseAsString)
19 const selectedSecret = secrets.find((secret) => secret.id === secretIdToDelete)
20
21 const {
22 mutate: deleteSecret,
23 isPending: isDeleting,
24 isSuccess: isSuccessDelete,
25 } = useVaultSecretDeleteMutation({
26 onSuccess: () => {
27 toast.success(`Successfully deleted secret ${selectedSecret?.name}`)
28 setSelectedSecretToDelete(null)
29 },
30 onError: (error) => {
31 toast.error(`Failed to delete secret: ${error.message}`)
32 },
33 })
34
35 const onConfirmDeleteSecret = async () => {
36 if (!project) return console.error('Project is required')
37 if (!selectedSecret) return
38
39 deleteSecret({
40 projectRef: project.ref,
41 connectionString: project?.connectionString,
42 id: selectedSecret.id,
43 })
44 }
45
46 useEffect(() => {
47 if (isSuccess && !!secretIdToDelete && !selectedSecret && !isSuccessDelete) {
48 toast('Secret not found')
49 setSelectedSecretToDelete(null)
50 }
51 }, [isSuccess, isSuccessDelete, secretIdToDelete, selectedSecret, setSelectedSecretToDelete])
52
53 return (
54 <Modal
55 size="small"
56 variant="danger"
57 alignFooter="right"
58 header="Confirm to delete secret"
59 visible={!!selectedSecret}
60 loading={isDeleting}
61 onCancel={() => setSelectedSecretToDelete(null)}
62 onConfirm={onConfirmDeleteSecret}
63 >
64 <Modal.Content className="space-y-4">
65 <p className="text-sm">
66 The following secret will be permanently removed and cannot be recovered. Are you sure?
67 </p>
68 <div className="space-y-1">
69 <p className="text-sm">{selectedSecret?.description}</p>
70 <p className="text-sm text-foreground-light">
71 ID: <code className="text-code-inline">{selectedSecret?.id}</code>
72 </p>
73 </div>
74 </Modal.Content>
75 </Modal>
76 )
77}