mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-14 22:10:32 +08:00
* feat(auto-backup): implement centralized auto-backup manager and UI - Introduced AutoBackupManager to handle verge settings, run a background scheduler, debounce change-driven backups, and trim auto-labeled archives (keeps 20); wired into startup and config refresh hooks (src-tauri/src/module/auto_backup.rs:28-209, src-tauri/src/utils/resolve/mod.rs:64-136, src-tauri/src/feat/config.rs:102-238) - Extended verge schema and backup helpers so scheduled/change-based settings persist, create_local_backup can rename archives, and profile/global-extend mutations now trigger backups (src-tauri/src/config/verge.rs:162-536, src/types/types.d.ts:857-859, src-tauri/src/feat/backup.rs:125-189, src-tauri/src/cmd/profile.rs:66-476, src-tauri/src/cmd/save_profile.rs:21-82) - Added Auto Backup settings panel in backup dialog with dual toggles + interval selector; localized new strings across all locales (src/components/setting/mods/auto-backup-settings.tsx:1-138, src/components/setting/mods/backup-viewer.tsx:28-309, src/locales/en/settings.json:312-326 and mirrored entries) - Regenerated typed i18n resources for strong typing in React (src/types/generated/i18n-keys.ts, src/types/generated/i18n-resources.ts) * refactor(setting/backup): restructure backup dialog for consistent layout * refactor(ui): unify settings dialog style * fix(backup): only trigger auto-backup on valid saves & restore restarts app safely * fix(backup): scrub console.log leak and rewire WebDAV dialog to actually probe server * refactor: rename SubscriptionChange to ProfileChange * chore: update i18n * chore: WebDAV i18n improvements * refactor(backup): error handling * refactor(auto-backup): wrap scheduler startup with maybe_start_runner * refactor: remove the redundant throw in handleExport * feat(backup-history-viewer): improve WebDAV handling and UI fallback * feat(auto-backup): trigger backups on all profile edits & improve interval input UX * refactor: use InputAdornment * docs: Changelog.md
88 lines
2.2 KiB
TypeScript
88 lines
2.2 KiB
TypeScript
import { Box } from "@mui/material";
|
|
import { useCallback, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import { BaseDialog, BaseLoadingOverlay } from "@/components/base";
|
|
import { listWebDavBackup } from "@/services/cmds";
|
|
import { showNotice } from "@/services/noticeService";
|
|
|
|
import { BackupConfigViewer } from "./backup-config-viewer";
|
|
|
|
interface BackupWebdavDialogProps {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
onBackupSuccess?: () => void;
|
|
setBusy?: (loading: boolean) => void;
|
|
}
|
|
|
|
export const BackupWebdavDialog = ({
|
|
open,
|
|
onClose,
|
|
onBackupSuccess,
|
|
setBusy,
|
|
}: BackupWebdavDialogProps) => {
|
|
const { t } = useTranslation();
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const handleLoading = useCallback(
|
|
(value: boolean) => {
|
|
setLoading(value);
|
|
setBusy?.(value);
|
|
},
|
|
[setBusy],
|
|
);
|
|
|
|
const refreshWebdav = useCallback(
|
|
async (options?: { silent?: boolean }) => {
|
|
handleLoading(true);
|
|
try {
|
|
await listWebDavBackup();
|
|
if (!options?.silent) {
|
|
showNotice.success(
|
|
"settings.modals.backup.messages.webdavRefreshSuccess",
|
|
);
|
|
}
|
|
} catch (error) {
|
|
showNotice.error(
|
|
"settings.modals.backup.messages.webdavRefreshFailed",
|
|
{ error },
|
|
);
|
|
} finally {
|
|
handleLoading(false);
|
|
}
|
|
},
|
|
[handleLoading],
|
|
);
|
|
|
|
const refreshSilently = useCallback(
|
|
() => refreshWebdav({ silent: true }),
|
|
[refreshWebdav],
|
|
);
|
|
|
|
return (
|
|
<BaseDialog
|
|
open={open}
|
|
title={t("settings.modals.backup.webdav.title")}
|
|
contentSx={{ width: { xs: 360, sm: 520 } }}
|
|
disableOk
|
|
cancelBtn={t("shared.actions.close")}
|
|
onCancel={onClose}
|
|
onClose={onClose}
|
|
>
|
|
<Box sx={{ position: "relative" }}>
|
|
<BaseLoadingOverlay isLoading={loading} />
|
|
<BackupConfigViewer
|
|
setLoading={handleLoading}
|
|
onBackupSuccess={async () => {
|
|
await refreshSilently();
|
|
onBackupSuccess?.();
|
|
}}
|
|
onSaveSuccess={refreshSilently}
|
|
onRefresh={refreshWebdav}
|
|
onInit={refreshSilently}
|
|
/>
|
|
</Box>
|
|
</BaseDialog>
|
|
);
|
|
};
|