import { SupportCategories } from '@supabase/shared-types/out/constants' import { LOCAL_STORAGE_KEYS, useParams } from 'common' import { CheckCircle, Download, Loader } from 'lucide-react' import { useEffect, useState } from 'react' import { Button } from 'ui' import { Admonition } from 'ui-patterns/admonition' import { SupportLink } from '@/components/interfaces/Support/SupportLink' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { useBackupDownloadMutation } from '@/data/database/backup-download-mutation' import { useDownloadableBackupQuery } from '@/data/database/backup-query' import { useInvalidateProjectDetailsQuery } from '@/data/projects/project-detail-query' import { useProjectStatusQuery } from '@/data/projects/project-status-query' import { useLongRunningTransitionState } from '@/hooks/misc/useLongRunningTransitionState' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { PROJECT_STATUS } from '@/lib/constants' import { clearPersistedTransitionStartTime, minutesToMilliseconds, } from '@/lib/project-transition-state' import { getRestoreLongRunningThresholdMinutes } from '@/lib/restore-estimate' export const RestoringState = () => { const { ref } = useParams() const { data: project } = useSelectedProjectQuery() const [loading, setLoading] = useState(false) const [isCompleted, setIsCompleted] = useState(false) const restoreStateStartStorageKey = ref ? LOCAL_STORAGE_KEYS.PROJECT_RESTORING_STARTED_AT(ref) : null const { data } = useDownloadableBackupQuery({ projectRef: ref }) const backups = data?.backups ?? [] const logicalBackups = backups.filter((b) => !b.isPhysicalBackup) const longRunningThresholdMinutes = getRestoreLongRunningThresholdMinutes(project?.volumeSizeGb) const longRunningThresholdMs = minutesToMilliseconds(longRunningThresholdMinutes) const isTakingLongerThanExpected = useLongRunningTransitionState({ storageKey: restoreStateStartStorageKey, thresholdMs: longRunningThresholdMs, }) const { invalidateProjectDetailsQuery } = useInvalidateProjectDetailsQuery() const { data: projectStatusData, isSuccess: isProjectStatusSuccess } = useProjectStatusQuery( { projectRef: ref }, { enabled: project?.status !== PROJECT_STATUS.ACTIVE_HEALTHY, refetchInterval: (query) => { const data = query.state.data return data?.status === PROJECT_STATUS.ACTIVE_HEALTHY || data?.status === PROJECT_STATUS.RESTORE_FAILED ? false : 4000 }, } ) 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 (logicalBackups.length === 0) return console.error('No available backups to download') downloadBackup({ ref, backup: logicalBackups[0] }) } const onConfirm = async () => { if (!project) return console.error('Project is required') setLoading(true) if (ref) await invalidateProjectDetailsQuery(ref) } useEffect(() => { if (!isProjectStatusSuccess) return if (projectStatusData.status === PROJECT_STATUS.ACTIVE_HEALTHY) { if (restoreStateStartStorageKey) { clearPersistedTransitionStartTime(restoreStateStartStorageKey) } setIsCompleted(true) } else if (projectStatusData.status === PROJECT_STATUS.RESTORE_FAILED) { if (restoreStateStartStorageKey) { clearPersistedTransitionStartTime(restoreStateStartStorageKey) } if (ref) void invalidateProjectDetailsQuery(ref) } }, [ isProjectStatusSuccess, projectStatusData, restoreStateStartStorageKey, ref, invalidateProjectDetailsQuery, ]) return (
{isCompleted ? (

Restoration complete!

Your project has been successfully restored and is now back online.

) : ( <>

Restoration in progress

Restoration can take from a few minutes up to several hours depending on the size of your database. Your project will be offline while the restoration is running.

{isTakingLongerThanExpected && ( Contact support } className="mt-5!" /> )}
} loading={isDownloading} disabled={logicalBackups.length === 0} tooltip={{ content: { side: 'bottom', text: logicalBackups.length === 0 ? 'No available backups to download' : undefined, }, }} onClick={onClickDownloadBackup} > Download latest backup
)}
) }