From bc2d7cadc4f42937f21840af88b86c2f5b9e8684 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 4 Oct 2025 16:36:30 +0200 Subject: [PATCH] Use "GlobalDialogManager" for backup validation --- .../component/BackupValidationDialog.tsx | 110 ++++++++++++++++ src/features/backup/screens/Backup.tsx | 118 ++---------------- 2 files changed, 120 insertions(+), 108 deletions(-) create mode 100644 src/features/backup/component/BackupValidationDialog.tsx 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 ( + + {t('settings.backup.action.validate.dialog.title')} + + {!!validationResult?.missingSources.length && ( + + {validationResult?.missingSources.map(({ id, name }) => ( + + {`${name} (${id})`} + + ))} + + )} + {!!validationResult?.missingTrackers.length && ( + + {validationResult?.missingTrackers.map(({ name }) => ( + + {`${name}`} + + ))} + + )} + + + + {!!validationResult?.missingSources.length && ( + + )} + {!!validationResult?.missingTrackers.length && ( + + )} + + + + + + + + ); +}; 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() { - - {t('settings.backup.action.validate.dialog.title')} - - {!!validationResult?.missingSources.length && ( - - {validationResult?.missingSources.map(({ id, name }) => ( - - {`${name} (${id})`} - - ))} - - )} - {!!validationResult?.missingTrackers.length && ( - - {validationResult?.missingTrackers.map(({ name }) => ( - - {`${name}`} - - ))} - - )} - - - - {!!validationResult?.missingSources.length && ( - - )} - {!!validationResult?.missingTrackers.length && ( - - )} - - - - - - - ); }