DeleteSecretModal.tsx 2.5 KB

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