| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- import { PermissionAction, SupportCategories } from '@supabase/shared-types/out/constants'
- import { useParams } from 'common'
- import { Download, MoreVertical, Trash } from 'lucide-react'
- import { useState } from 'react'
- import {
- Button,
- CriticalIcon,
- Dialog,
- DialogContent,
- DialogHeader,
- DialogSection,
- DialogTitle,
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuTrigger,
- } from 'ui'
- import { DeleteProjectModal } from '@/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectModal'
- import { SupportLink } from '@/components/interfaces/Support/SupportLink'
- import { LogicalBackupCliInstructions } from '@/components/layouts/ProjectLayout/LogicalBackupCliInstructions'
- import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
- import { DropdownMenuItemTooltip } from '@/components/ui/DropdownMenuItemTooltip'
- import { InlineLink } from '@/components/ui/InlineLink'
- import { useBackupDownloadMutation } from '@/data/database/backup-download-mutation'
- import { useDownloadableBackupQuery } from '@/data/database/backup-query'
- import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
- import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
- export const RestoreFailedState = () => {
- const { ref } = useParams()
- const { data: project } = useSelectedProjectQuery()
- const [visible, setVisible] = useState(false)
- const [showCliBackup, setShowCliBackup] = useState(false)
- const { can: canDeleteProject } = useAsyncCheckPermissions(PermissionAction.UPDATE, 'projects', {
- resource: { project_id: project?.id },
- })
- const { data, isPending: isLoadingBackups } = useDownloadableBackupQuery({ projectRef: ref })
- const backups = data?.backups ?? []
- const { mutate: downloadBackup, isPending: isDownloading } = useBackupDownloadMutation({
- onSuccess: (res) => {
- const { fileUrl } = res
- // Trigger browser download by create,trigger and remove tempLink
- const tempLink = document.createElement('a')
- tempLink.href = fileUrl
- document.body.appendChild(tempLink)
- tempLink.click()
- document.body.removeChild(tempLink)
- },
- })
- const onClickDownloadBackup = () => {
- if (!ref) return console.error('Project ref is required')
- if (backups.length === 0 || data?.status === 'physical-backups-enabled')
- return setShowCliBackup(true)
- downloadBackup({ ref, backup: backups[0] })
- }
- const downloadBackupTooltipText = isLoadingBackups
- ? undefined
- : data?.status === 'physical-backups-enabled'
- ? 'Project uses physical backups — click to see CLI backup instructions'
- : backups.length === 0
- ? 'No downloadable backup available — click to see CLI backup instructions'
- : undefined
- return (
- <>
- <div className="flex items-center justify-center h-full">
- <div className="bg-surface-100 border border-overlay rounded-md w-3/4 lg:w-1/2">
- <div className="space-y-6 pt-6">
- <div className="flex px-8 space-x-8">
- <div className="mt-1">
- <CriticalIcon className="w-5 h-5" />
- </div>
- <div className="space-y-1">
- <p>Something went wrong while restoring your project</p>
- <p className="text-sm text-foreground-light">
- Your project's data is intact, but your project is inaccessible due to a
- restoration failure. Database backups for this project can still be accessed{' '}
- <InlineLink href={`/project/${ref}/database/backups/scheduled`}>here</InlineLink>.
- </p>
- <p className="text-sm text-foreground-light">
- Please contact support for assistance.
- </p>
- </div>
- </div>
- <div className="border-t border-overlay flex items-center justify-end py-4 px-8 gap-x-2">
- <Button asChild type="default">
- <SupportLink
- queryParams={{
- category: SupportCategories.DATABASE_UNRESPONSIVE,
- projectRef: project?.ref,
- subject: 'Restoration failed for project',
- }}
- >
- Contact support
- </SupportLink>
- </Button>
- <ButtonTooltip
- type="default"
- icon={<Download />}
- disabled={isLoadingBackups}
- loading={isDownloading || isLoadingBackups}
- tooltip={{
- content: {
- side: 'bottom',
- text: downloadBackupTooltipText,
- },
- }}
- onClick={onClickDownloadBackup}
- >
- Download backup
- </ButtonTooltip>
- <DropdownMenu>
- <DropdownMenuTrigger>
- <Button type="default" className="w-7" icon={<MoreVertical />} />
- </DropdownMenuTrigger>
- <DropdownMenuContent className="w-72" align="end">
- <DropdownMenuItemTooltip
- onClick={() => setVisible(true)}
- className="items-start gap-x-2"
- disabled={!canDeleteProject}
- tooltip={{
- content: {
- side: 'right',
- text: !canDeleteProject
- ? 'You need additional permissions to delete this project'
- : undefined,
- },
- }}
- >
- <div className="translate-y-0.5">
- <Trash size={14} />
- </div>
- <div className="">
- <p>Delete project</p>
- <p className="text-foreground-lighter">
- Project cannot be restored once it is deleted
- </p>
- </div>
- </DropdownMenuItemTooltip>
- </DropdownMenuContent>
- </DropdownMenu>
- </div>
- </div>
- </div>
- </div>
- <Dialog open={showCliBackup} onOpenChange={setShowCliBackup}>
- <DialogContent size="medium">
- <DialogHeader>
- <DialogTitle>Back up your database</DialogTitle>
- </DialogHeader>
- <DialogSection>
- <LogicalBackupCliInstructions showResetPassword={false} />
- </DialogSection>
- </DialogContent>
- </Dialog>
- <DeleteProjectModal visible={visible} onClose={() => setVisible(false)} />
- </>
- )
- }
|