import { forwardRef, useImperativeHandle, useState, useRef, SVGProps, } from "react"; import { useTranslation } from "react-i18next"; import { useLockFn } from "ahooks"; import { Typography } from "@mui/material"; import { useForm } from "react-hook-form"; import { useVerge } from "@/hooks/use-verge"; import { BaseDialog, DialogRef, Notice } from "@/components/base"; import { isValidUrl } from "@/utils/helper"; import getSystem from "@/utils/get-system"; import { BaseLoadingOverlay } from "@/components/base"; import dayjs, { Dayjs } from "dayjs"; import customParseFormat from "dayjs/plugin/customParseFormat"; dayjs.extend(customParseFormat); import { TextField, Button, Grid, Box, Paper, Stack, IconButton, InputAdornment, Divider, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TablePagination, } from "@mui/material"; import Visibility from "@mui/icons-material/Visibility"; import VisibilityOff from "@mui/icons-material/VisibilityOff"; import DeleteIcon from "@mui/icons-material/Delete"; import RestoreIcon from "@mui/icons-material/Restore"; import { createWebdavBackup, listWebDavBackup, saveWebdavConfig, } from "@/services/cmds"; type BackupFile = IWebDavFile & { platform: string; backup_time: Dayjs; allow_apply: boolean; }; export const BackupViewer = forwardRef((props, ref) => { const { t } = useTranslation(); const [open, setOpen] = useState(false); const { verge, mutateVerge } = useVerge(); const { webdav_url, webdav_username, webdav_password } = verge || {}; const [showPassword, setShowPassword] = useState(false); const usernameRef = useRef(null); const passwordRef = useRef(null); const [backupFiles, setBackupFiles] = useState([]); const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(5); const OS = getSystem(); const urlRef = useRef(null); const [isLoading, setIsLoading] = useState(false); const { register, handleSubmit, watch } = useForm({ defaultValues: { url: webdav_url, username: webdav_username, password: webdav_password, }, }); const url = watch("url"); const username = watch("username"); const password = watch("password"); const webdavChanged = webdav_url !== url || webdav_username !== username || webdav_password !== password; useImperativeHandle(ref, () => ({ open: () => { setOpen(true); if (webdav_url && webdav_username && webdav_password) { fetchAndSetBackupFiles(); } }, close: () => setOpen(false), })); // Handle page change const handleChangePage = ( _: React.MouseEvent | null, page: number ) => { console.log(page); setPage(page); }; // Handle rows per page change const handleChangeRowsPerPage = (event: any) => { setRowsPerPage(parseInt(event.target.value, 10)); setPage(0); // Reset to the first page }; const fetchAndSetBackupFiles = () => { setIsLoading(true); // Assuming setIsLoading is defined in your component or context to manage loading state getAllBackupFiles() .then((files: BackupFile[]) => { console.log(files); setBackupFiles(files); // Assuming setBackupFiles is a state setter function in your component or context }) .catch((e) => { console.error(e); }) .finally(() => { setIsLoading(false); }); }; const checkForm = () => { const username = usernameRef.current?.value; const password = passwordRef.current?.value; const url = urlRef.current?.value; if (!url) { Notice.error(t("Webdav url cannot be empty")); urlRef.current?.focus(); return; } else if (!isValidUrl(url)) { Notice.error(t("Webdav address must be url")); urlRef.current?.focus(); return; } if (!username) { Notice.error(t("Username cannot be empty")); usernameRef.current?.focus(); return; } if (!password) { Notice.error(t("Password cannot be empty")); passwordRef.current?.focus(); return; } }; const submit = async (data: IWebDavConfig) => { checkForm(); setIsLoading(true); await saveWebdavConfig(data.url, data.username, data.password) .then(() => { mutateVerge( { webdav_url: data.url, webdav_username: data.username, webdav_password: data.password, }, false ); Notice.success(t("Webdav Config Saved Successfully"), 1500); }) .catch((e) => { Notice.error(t("Webdav Config Save Failed", { error: e }), 3000); }) .finally(() => { setIsLoading(false); fetchAndSetBackupFiles(); }); }; const handleClickShowPassword = () => { setShowPassword(!showPassword); }; const handleBackup = useLockFn(async () => { checkForm(); setIsLoading(true); await createWebdavBackup() .then(() => { Notice.success(t("Backup Successfully"), 1500); }) .finally(() => { setIsLoading(false); fetchAndSetBackupFiles(); }) .catch((e) => { console.log(e, "backup failed"); Notice.error(t("Backup Failed", { error: e }), 3000); }); }); const getAllBackupFiles = async () => { const files = await listWebDavBackup(); return files .map((file) => { const platform = file.filename.split("-")[0]; const fileBackupTimeStr = file.filename.match( /\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}/ )!; const backupTime = dayjs(fileBackupTimeStr[0], "YYYY-MM-DD_HH-mm-ss"); const allowApply = OS === platform; return { ...file, platform, backup_time: backupTime, allow_apply: allowApply, } as BackupFile; }) .sort((a, b) => (a.backup_time.isAfter(b.backup_time) ? -1 : 1)); }; const datasource = backupFiles.slice( page * rowsPerPage, page * rowsPerPage + rowsPerPage ); return ( setOpen(false)} onCancel={() => setOpen(false)} >
{/* WebDAV Server Address */} {/* Username and Password */} {showPassword ? ( ) : ( )} ), }} /> {webdavChanged || webdav_url === null || webdav_username == null || webdav_password == null ? ( ) : ( )}
文件名称 时间 操作 {datasource.length > 0 ? ( datasource?.map((file, index) => ( {file.platform === "windows" ? ( ) : file.platform === "linux" ? ( ) : ( )} {file.filename} {file.backup_time.fromNow()} )) ) : ( 暂无备份 )}
); }); export function LinuxIcon(props: SVGProps) { return ( ); } export function WindowsIcon(props: SVGProps) { return ( ); } export function MacIcon(props: SVGProps) { return ( ); }