Files
suwayomi-material-you-webui/src/screens/settings/Backup.tsx

149 lines
5.4 KiB
TypeScript
Raw Normal View History

2021-04-10 00:44:13 +04:30
/*
* 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/.
*/
2021-04-10 00:44:13 +04:30
import { useContext, useEffect, useRef, useState } from 'react';
2021-09-09 17:51:22 +04:30
import List from '@mui/material/List';
import ListItemText from '@mui/material/ListItemText';
2021-04-10 00:44:13 +04:30
import { fromEvent } from 'file-selector';
import { useTranslation } from 'react-i18next';
import { ListItemButton } from '@mui/material';
import ListItemIcon from '@mui/material/ListItemIcon';
2023-10-28 00:32:02 +02:00
import { requestManager } from '@/lib/requests/RequestManager.ts';
import { makeToast } from '@/components/util/Toast';
import { ListItemLink } from '@/components/util/ListItemLink';
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext';
import { BackupRestoreState, GetRestoreStatusQuery } from '@/lib/graphql/generated/graphql.ts';
import { Progress } from '@/components/util/Progress.tsx';
2021-04-10 00:44:13 +04:30
2023-10-28 00:32:02 +02:00
export function Backup() {
const { t } = useTranslation();
2023-10-28 00:32:02 +02:00
const { setTitle, setAction } = useContext(NavBarContext);
useEffect(() => {
setTitle(t('settings.backup.title'));
setAction(null);
}, [t]);
2021-04-10 00:44:13 +04:30
useSetDefaultBackTo('settings');
const [isRestoring, setIsRestoring] = useState<boolean | null>(null);
const { data } = requestManager.useGetBackupRestoreStatus({
skip: isRestoring !== null ? !isRestoring : false,
pollInterval: 1000,
});
const prevRestoreStatusRef = useRef<GetRestoreStatusQuery['restoreStatus'] | null>(null);
const restoreProgress = (() => {
if (!isRestoring || !data) {
return 0;
}
const progress = 100 * (data.restoreStatus.mangaProgress / data.restoreStatus.totalManga);
return Number.isNaN(progress) ? 0 : progress;
})();
useEffect(() => {
if (!data || isRestoring !== null) {
return;
}
const isRestoreInProgress = data?.restoreStatus.state !== BackupRestoreState.Idle;
setIsRestoring(isRestoreInProgress);
}, [data?.restoreStatus.state]);
useEffect(() => {
if (!data) {
return;
}
const isRestoreFinished =
isRestoring &&
data.restoreStatus.mangaProgress === data.restoreStatus.totalManga &&
prevRestoreStatusRef.current?.state !== BackupRestoreState.Idle;
if (isRestoreFinished) {
setIsRestoring(false);
makeToast(t('settings.backup.label.restored_backup'), 'success');
}
prevRestoreStatusRef.current = data.restoreStatus;
}, [data?.restoreStatus.state]);
const submitBackup = async (file: File) => {
if (file.name.toLowerCase().match(/proto\.gz$|tachibk$/g)) {
makeToast(t('settings.backup.label.restoring_backup'), 'info');
try {
await requestManager.restoreBackupFile(file).response;
setIsRestoring(true);
} catch (e) {
makeToast(t('settings.backup.label.backup_restore_failed'), 'error');
}
2021-08-19 20:42:28 +04:30
} else if (file.name.toLowerCase().endsWith('json')) {
makeToast(t('settings.backup.label.legacy_backup_unsupported'), 'error');
2021-08-19 20:42:28 +04:30
} else {
makeToast(t('global.error.label.invalid_file_type'), 'error');
2021-08-19 20:42:28 +04:30
}
2021-04-10 00:44:13 +04:30
};
const dropHandler = async (e: Event) => {
e.preventDefault();
const files = await fromEvent(e);
submitBackup(files[0] as File);
};
const dragOverHandler = (e: Event) => {
e.preventDefault();
};
useEffect(() => {
document.addEventListener('drop', dropHandler);
document.addEventListener('dragover', dragOverHandler);
const handleFileSelection = async (event: Event) => {
const files = await fromEvent(event);
2021-04-10 00:44:13 +04:30
submitBackup(files[0] as File);
};
const input = document.getElementById('backup-file');
input?.addEventListener('change', handleFileSelection);
2021-04-10 00:44:13 +04:30
return () => {
document.removeEventListener('drop', dropHandler);
document.removeEventListener('dragover', dragOverHandler);
input?.removeEventListener('change', handleFileSelection);
2021-04-10 00:44:13 +04:30
};
}, []);
return (
2021-08-19 20:42:28 +04:30
<>
2021-11-15 18:55:50 +03:30
<List sx={{ padding: 0 }}>
<ListItemLink to={requestManager.getExportBackupUrl()} directLink>
<ListItemText
primary={t('settings.backup.label.create_backup')}
secondary={t('settings.backup.label.create_backup_info')}
/>
2021-08-19 20:42:28 +04:30
</ListItemLink>
<ListItemButton
onClick={() => document.getElementById('backup-file')?.click()}
disabled={!!isRestoring}
>
2021-08-19 20:42:28 +04:30
<ListItemText
primary={t('settings.backup.label.restore_backup')}
secondary={t('settings.backup.label.restore_backup_info')}
2021-08-19 20:42:28 +04:30
/>
{isRestoring ? (
<ListItemIcon>
<Progress progress={restoreProgress} />
</ListItemIcon>
) : null}
</ListItemButton>
2021-08-19 20:42:28 +04:30
</List>
<input type="file" id="backup-file" style={{ display: 'none' }} />
2021-08-19 20:42:28 +04:30
</>
2021-04-10 00:44:13 +04:30
);
}