mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 17:15:38 +08:00
feat(auto-backup): implement centralized auto-backup manager and UI (#5374)
* 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
This commit is contained in:
@@ -11,6 +11,7 @@ use crate::{
|
||||
},
|
||||
core::{CoreManager, handle, timer::Timer, tray::Tray},
|
||||
feat, logging,
|
||||
module::auto_backup::{AutoBackupManager, AutoBackupTrigger},
|
||||
process::AsyncHandler,
|
||||
ret_err,
|
||||
utils::{dirs, help, logging::Type},
|
||||
@@ -90,6 +91,7 @@ pub async fn import_profile(url: std::string::String, option: Option<PrfOption>)
|
||||
}
|
||||
|
||||
logging!(info, Type::Cmd, "[导入订阅] 导入完成: {}", url);
|
||||
AutoBackupManager::trigger_backup(AutoBackupTrigger::ProfileChange);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -122,6 +124,7 @@ pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResu
|
||||
handle::Handle::notify_profile_changed(uid.clone());
|
||||
}
|
||||
Config::profiles().await.apply();
|
||||
AutoBackupManager::trigger_backup(AutoBackupTrigger::ProfileChange);
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -164,6 +167,7 @@ pub async fn delete_profile(index: String) -> CmdResult {
|
||||
// 发送配置变更通知
|
||||
logging!(info, Type::Cmd, "[删除订阅] 发送配置变更通知: {}", index);
|
||||
handle::Handle::notify_profile_changed(index);
|
||||
AutoBackupManager::trigger_backup(AutoBackupTrigger::ProfileChange);
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Cmd, "{}", e);
|
||||
@@ -460,6 +464,7 @@ pub async fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
|
||||
});
|
||||
}
|
||||
|
||||
AutoBackupManager::trigger_backup(AutoBackupTrigger::ProfileChange);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
config::{Config, PrfItem},
|
||||
core::{CoreManager, handle, validate::CoreConfigValidator},
|
||||
logging,
|
||||
module::auto_backup::{AutoBackupManager, AutoBackupTrigger},
|
||||
utils::{dirs, logging::Type},
|
||||
};
|
||||
use smartstring::alias::String;
|
||||
@@ -17,6 +18,12 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
let backup_trigger = match index.as_str() {
|
||||
"Merge" => Some(AutoBackupTrigger::GlobalMerge),
|
||||
"Script" => Some(AutoBackupTrigger::GlobalScript),
|
||||
_ => Some(AutoBackupTrigger::ProfileChange),
|
||||
};
|
||||
|
||||
// 在异步操作前获取必要元数据并释放锁
|
||||
let (rel_path, is_merge_file) = {
|
||||
let profiles = Config::profiles().await;
|
||||
@@ -51,11 +58,17 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
||||
is_merge_file
|
||||
);
|
||||
|
||||
if is_merge_file {
|
||||
return handle_merge_file(&file_path_str, &file_path, &original_content).await;
|
||||
let changes_applied = if is_merge_file {
|
||||
handle_merge_file(&file_path_str, &file_path, &original_content).await?
|
||||
} else {
|
||||
handle_full_validation(&file_path_str, &file_path, &original_content).await?
|
||||
};
|
||||
|
||||
if changes_applied && let Some(trigger) = backup_trigger {
|
||||
AutoBackupManager::trigger_backup(trigger);
|
||||
}
|
||||
|
||||
handle_full_validation(&file_path_str, &file_path, &original_content).await
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn restore_original(
|
||||
@@ -76,7 +89,7 @@ async fn handle_merge_file(
|
||||
file_path_str: &str,
|
||||
file_path: &std::path::Path,
|
||||
original_content: &str,
|
||||
) -> CmdResult {
|
||||
) -> CmdResult<bool> {
|
||||
logging!(
|
||||
info,
|
||||
Type::Config,
|
||||
@@ -96,7 +109,7 @@ async fn handle_merge_file(
|
||||
} else {
|
||||
handle::Handle::refresh_clash();
|
||||
}
|
||||
Ok(())
|
||||
Ok(true)
|
||||
}
|
||||
Ok((false, error_msg)) => {
|
||||
logging!(
|
||||
@@ -108,7 +121,7 @@ async fn handle_merge_file(
|
||||
restore_original(file_path, original_content).await?;
|
||||
let result = (false, error_msg.clone());
|
||||
crate::cmd::validate::handle_yaml_validation_notice(&result, "合并配置文件");
|
||||
Ok(())
|
||||
Ok(false)
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Config, "[cmd配置save] 验证过程发生错误: {}", e);
|
||||
@@ -122,11 +135,11 @@ async fn handle_full_validation(
|
||||
file_path_str: &str,
|
||||
file_path: &std::path::Path,
|
||||
original_content: &str,
|
||||
) -> CmdResult {
|
||||
) -> CmdResult<bool> {
|
||||
match CoreConfigValidator::validate_config_file(file_path_str, None).await {
|
||||
Ok((true, _)) => {
|
||||
logging!(info, Type::Config, "[cmd配置save] 验证成功");
|
||||
Ok(())
|
||||
Ok(true)
|
||||
}
|
||||
Ok((false, error_msg)) => {
|
||||
logging!(warn, Type::Config, "[cmd配置save] 验证失败: {}", error_msg);
|
||||
@@ -160,7 +173,7 @@ async fn handle_full_validation(
|
||||
handle::Handle::notice_message("config_validate::error", error_msg.to_owned());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(false)
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Config, "[cmd配置save] 验证过程发生错误: {}", e);
|
||||
|
||||
Reference in New Issue
Block a user