diff --git a/src/features/backup/component/BackupValidationDialog.tsx b/src/features/backup/component/BackupValidationDialog.tsx
new file mode 100644
index 00000000..9321a3b9
--- /dev/null
+++ b/src/features/backup/component/BackupValidationDialog.tsx
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) Contributors to the Suwayomi project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+import List from '@mui/material/List';
+import { useTranslation } from 'react-i18next';
+import Dialog from '@mui/material/Dialog';
+import DialogTitle from '@mui/material/DialogTitle';
+import DialogContent from '@mui/material/DialogContent';
+import DialogActions from '@mui/material/DialogActions';
+import Button from '@mui/material/Button';
+import ListItem from '@mui/material/ListItem';
+import { Link } from 'react-router-dom';
+import Stack from '@mui/material/Stack';
+import { BrowseTab } from '@/features/browse/Browse.types.ts';
+import { AppRoutes } from '@/base/AppRoute.constants.ts';
+import { DialogProps } from '@/base/global-dialog/GlobalDialogManager.tsx';
+import { ValidateBackupResult } from '@/lib/graphql/generated/graphql.ts';
+
+export const BackupValidationDialog = ({
+ validationResult,
+ onCancel,
+ onConfirm,
+}: DialogProps & { validationResult: ValidateBackupResult }) => {
+ const { t } = useTranslation();
+
+ return (
+
+ );
+};
diff --git a/src/features/backup/screens/Backup.tsx b/src/features/backup/screens/Backup.tsx
index d1d9fb29..a135ad87 100644
--- a/src/features/backup/screens/Backup.tsx
+++ b/src/features/backup/screens/Backup.tsx
@@ -15,18 +15,10 @@ import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListSubheader from '@mui/material/ListSubheader';
import { t as translate } from 'i18next';
-import Dialog from '@mui/material/Dialog';
-import DialogTitle from '@mui/material/DialogTitle';
-import DialogContent from '@mui/material/DialogContent';
-import DialogActions from '@mui/material/DialogActions';
-import Button from '@mui/material/Button';
-import ListItem from '@mui/material/ListItem';
-import { Link } from 'react-router-dom';
-import Stack from '@mui/material/Stack';
import { useEventListener, useMergedRef, useWindowEvent } from '@mantine/hooks';
import { requestManager } from '@/lib/requests/RequestManager.ts';
import { makeToast } from '@/base/utils/Toast.ts';
-import { BackupRestoreState, ValidateBackupQuery } from '@/lib/graphql/generated/graphql.ts';
+import { BackupRestoreState } from '@/lib/graphql/generated/graphql.ts';
import { Progress } from '@/base/components/feedback/Progress.tsx';
import { TextSetting } from '@/base/components/settings/text/TextSetting.tsx';
import { NumberSetting } from '@/base/components/settings/NumberSetting.tsx';
@@ -35,12 +27,11 @@ import { LoadingPlaceholder } from '@/base/components/feedback/LoadingPlaceholde
import { EmptyViewAbsoluteCentered } from '@/base/components/feedback/EmptyViewAbsoluteCentered.tsx';
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import { ServerSettings } from '@/features/settings/Settings.types.ts';
-import { AppRoutes } from '@/base/AppRoute.constants.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
-import { BrowseTab } from '@/features/browse/Browse.types.ts';
import { GlobalDialogManager } from '@/base/global-dialog/GlobalDialogManager.tsx';
import { BackupFlagInclusionDialog } from '@/features/backup/component/BackupFlagInclusionDialog.tsx';
+import { BackupValidationDialog } from '@/features/backup/component/BackupValidationDialog.tsx';
type BackupSettingsType = Pick;
@@ -72,10 +63,6 @@ export function Backup() {
pollInterval: 1000,
});
- const [currentBackupFile, setCurrentBackupFile] = useState(null);
- const [isInvalidBackupDialogOpen, setIsInvalidBackupDialogOpen] = useState(false);
- const [validationResult, setValidationResult] = useState();
-
const [, setTriggerReRender] = useState(0);
const inputRef = useRef(null);
@@ -123,8 +110,6 @@ export function Backup() {
}, [data?.restoreStatus?.state]);
const resetBackupState = () => {
- setCurrentBackupFile(null);
-
const input = document.getElementById('backup-file') as HTMLInputElement;
if (input) {
input.value = '';
@@ -167,14 +152,19 @@ export function Backup() {
} = await requestManager.validateBackupFile(file, { fetchPolicy: 'network-only' }).response;
if (validateBackupData.missingSources.length || validateBackupData.missingTrackers.length) {
- setValidationResult(validateBackupData);
- setIsInvalidBackupDialogOpen(true);
- return false;
+ try {
+ await GlobalDialogManager.show(`backup-validate-${file.name}`, BackupValidationDialog, {
+ validationResult: validateBackupData,
+ });
+ } catch (_) {
+ return false;
+ }
}
return true;
} catch (e) {
makeToast(t('settings.backup.action.validate.error.label.failure'), 'error', getErrorMessage(e));
+ } finally {
resetBackupState();
}
@@ -207,18 +197,12 @@ export function Backup() {
return;
}
- setCurrentBackupFile(file);
const isBackupValid = await validateBackup(file);
if (isBackupValid) {
await restoreBackup(file);
}
};
- const closeInvalidBackupDialog = () => {
- setIsInvalidBackupDialogOpen(false);
- resetBackupState();
- };
-
useWindowEvent('drop', async (e) => {
e.preventDefault();
const files = await fromEvent(e);
@@ -322,88 +306,6 @@ export function Backup() {
-
>
);
}