import React, { useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Error } from 'App/State/AppSectionState'; import AppState from 'App/State/AppState'; import TextInput from 'Components/Form/TextInput'; import Icon, { IconName, IconProps } from 'Components/Icon'; import Button from 'Components/Link/Button'; import SpinnerButton from 'Components/Link/SpinnerButton'; import ModalBody from 'Components/Modal/ModalBody'; import ModalContent from 'Components/Modal/ModalContent'; import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; import usePrevious from 'Helpers/Hooks/usePrevious'; import { icons, kinds } from 'Helpers/Props'; import { useRestart } from 'System/useSystem'; import { FileInputChanged } from 'typings/inputs'; import translate from 'Utilities/String/translate'; import { useRestoreBackup, useRestoreBackupUpload } from './useBackups'; import styles from './RestoreBackupModalContent.css'; function getErrorMessage(error: Error) { if ( !error || !error.responseJSON || !('message' in error.responseJSON) || !error.responseJSON.message ) { return translate('ErrorRestoringBackup'); } return error.responseJSON.message; } function getStepIconProps( isExecuting: boolean, hasExecuted: boolean, error?: Error ): { name: IconName; kind?: IconProps['kind']; title?: string; isSpinning?: boolean; } { if (isExecuting) { return { name: icons.SPINNER, isSpinning: true, }; } if (hasExecuted) { return { name: icons.CHECK, kind: 'success', }; } if (error) { return { name: icons.FATAL, kind: 'danger', title: getErrorMessage(error), }; } return { name: icons.PENDING, }; } export interface RestoreBackupModalContentProps { id?: number; name?: string; onModalClose: () => void; } function RestoreBackupModalContent({ id, name, onModalClose, }: RestoreBackupModalContentProps) { const { isRestarting } = useSelector((state: AppState) => state.app); const dispatch = useDispatch(); const { restoreBackupById, isRestoringBackup, restoreBackupError } = useRestoreBackup(id || 0); const { uploadBackup, isUploadingBackup, uploadBackupError } = useRestoreBackupUpload(); const { mutate: restart } = useRestart(); const [path, setPath] = useState(''); const [file, setFile] = useState(null); const [isRestored, setIsRestored] = useState(false); const [isRestarted, setIsRestarted] = useState(false); const [isReloading, setIsReloading] = useState(false); const isRestoring = isRestoringBackup || isUploadingBackup; const restoreError = restoreBackupError || uploadBackupError; const wasRestoring = usePrevious(isRestoring); const wasRestarting = usePrevious(isRestarting); const isRestoreDisabled = (!id && !path) || isRestoring || isRestarting || isReloading; const handlePathChange = useCallback(({ value, files }: FileInputChanged) => { if (!files?.length) { return; } setPath(value); setFile(files[0]); }, []); const handleRestorePress = useCallback(() => { if (id) { restoreBackupById(); } else if (file) { const formData = new FormData(); formData.append('restore', file); uploadBackup(formData); } }, [id, file, restoreBackupById, uploadBackup]); useEffect(() => { if (wasRestoring && !isRestoring && !restoreError) { setIsRestored(true); restart(); } }, [isRestoring, wasRestoring, restoreError, restart]); useEffect(() => { if (wasRestarting && !isRestarting) { setIsRestarted(true); setIsReloading(true); window.location.reload(); } }, [isRestarting, wasRestarting, dispatch]); return ( Restore Backup {id && name ? ( translate('WouldYouLikeToRestoreBackup', { name, }) ) : ( )}
{translate('Restore')}
{translate('Restart')}
{translate('Reload')}
{translate('RestartReloadNote')}
{translate('Restore')}
); } export default RestoreBackupModalContent;