diff --git a/Changelog.md b/Changelog.md
index ff4584007..085296fc8 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -8,6 +8,7 @@
✨ 新增功能
- 允许代理页面允许高级过滤搜索
+- 备份设置页面新增导入备份按钮
diff --git a/src-tauri/src/cmd/backup.rs b/src-tauri/src/cmd/backup.rs
index eecb6d733..fc80bc9b4 100644
--- a/src-tauri/src/cmd/backup.rs
+++ b/src-tauri/src/cmd/backup.rs
@@ -27,6 +27,12 @@ pub async fn restore_local_backup(filename: String) -> CmdResult<()> {
feat::restore_local_backup(filename).await.stringify_err()
}
+/// Import local backup into the app's backup directory
+#[tauri::command]
+pub async fn import_local_backup(source: String) -> CmdResult {
+ feat::import_local_backup(source).await.stringify_err()
+}
+
/// Export local backup to a user selected destination
#[tauri::command]
pub async fn export_local_backup(filename: String, destination: String) -> CmdResult<()> {
diff --git a/src-tauri/src/feat/backup.rs b/src-tauri/src/feat/backup.rs
index 23d906081..9b4d187bd 100644
--- a/src-tauri/src/feat/backup.rs
+++ b/src-tauri/src/feat/backup.rs
@@ -158,6 +158,53 @@ where
Ok(final_name)
}
+/// Import an existing backup file into the local backup directory
+pub async fn import_local_backup(source: String) -> Result {
+ let source_path = PathBuf::from(source.as_str());
+ if !source_path.exists() {
+ return Err(anyhow!("Backup file not found: {source}"));
+ }
+ if !source_path.is_file() {
+ return Err(anyhow!("Backup path is not a file: {source}"));
+ }
+
+ let ext = source_path
+ .extension()
+ .and_then(|ext| ext.to_str())
+ .map(|ext| ext.to_ascii_lowercase())
+ .unwrap_or_default();
+ if ext != "zip" {
+ return Err(anyhow!("Only .zip backup files are supported"));
+ }
+
+ let file_name = source_path
+ .file_name()
+ .and_then(|name| name.to_str())
+ .ok_or_else(|| anyhow!("Invalid backup file name"))?;
+
+ let backup_dir = local_backup_dir()?;
+ let target_path = backup_dir.join(file_name);
+
+ if target_path == source_path {
+ // Already located in the backup directory
+ return Ok(file_name.to_string().into());
+ }
+
+ if let Some(parent) = target_path.parent() {
+ fs::create_dir_all(parent).await?;
+ }
+
+ if target_path.exists() {
+ return Err(anyhow!("Backup file already exists: {file_name}"));
+ }
+
+ fs::copy(&source_path, &target_path)
+ .await
+ .map_err(|err| anyhow!("Failed to import backup file: {err:#?}"))?;
+
+ Ok(file_name.to_string().into())
+}
+
async fn move_file(from: PathBuf, to: PathBuf) -> Result<()> {
if let Some(parent) = to.parent() {
fs::create_dir_all(parent).await?;
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 42d33c9ed..a81f292cd 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -210,6 +210,7 @@ mod app_init {
cmd::list_local_backup,
cmd::delete_local_backup,
cmd::restore_local_backup,
+ cmd::import_local_backup,
cmd::export_local_backup,
cmd::create_webdav_backup,
cmd::save_webdav_config,
diff --git a/src/components/setting/mods/backup-history-viewer.tsx b/src/components/setting/mods/backup-history-viewer.tsx
index d1be64b35..ee3956378 100644
--- a/src/components/setting/mods/backup-history-viewer.tsx
+++ b/src/components/setting/mods/backup-history-viewer.tsx
@@ -57,7 +57,9 @@ interface BackupHistoryViewerProps {
interface BackupRow {
filename: string;
platform: string;
- backup_time: dayjs.Dayjs;
+ backup_time: dayjs.Dayjs | null;
+ display_time: string;
+ sort_value: number;
}
const confirmAsync = async (message: string) => {
@@ -86,16 +88,44 @@ export const BackupHistoryViewer = ({
const pageSize = 8;
const isBusy = loading || isRestarting;
- const buildRow = useCallback((filename: string): BackupRow | null => {
- const platform = filename.split("-")[0];
- const match = filename.match(FILENAME_PATTERN);
- if (!match) return null;
- return {
- filename,
- platform,
- backup_time: dayjs(match[0], DATE_FORMAT),
- };
- }, []);
+ const buildRow = useCallback(
+ (item: ILocalBackupFile | IWebDavFile): BackupRow | null => {
+ const { filename, last_modified } = item;
+ if (!filename.toLowerCase().endsWith(".zip")) return null;
+
+ const platform =
+ (filename.includes("-") && filename.split("-")[0]) ||
+ t("settings.modals.backup.history.unknownPlatform", {
+ defaultValue: "unknown",
+ });
+ const match = filename.match(FILENAME_PATTERN);
+ const parsedFromName = match ? dayjs(match[0], DATE_FORMAT, true) : null;
+ const parsedFromModified =
+ last_modified && dayjs(last_modified).isValid()
+ ? dayjs(last_modified)
+ : null;
+ const backupTime = parsedFromName?.isValid()
+ ? parsedFromName
+ : parsedFromModified;
+
+ return {
+ filename,
+ platform,
+ backup_time: backupTime ?? null,
+ display_time:
+ backupTime?.format("YYYY-MM-DD HH:mm") ??
+ parsedFromModified?.format("YYYY-MM-DD HH:mm") ??
+ t("settings.modals.backup.history.unknownTime", {
+ defaultValue: "Unknown time",
+ }),
+ sort_value:
+ backupTime?.valueOf() ??
+ parsedFromModified?.valueOf() ??
+ Number.NEGATIVE_INFINITY,
+ };
+ },
+ [t],
+ );
const fetchRows = useCallback(async () => {
if (!open) return;
@@ -108,9 +138,13 @@ export const BackupHistoryViewer = ({
const list = isLocal ? await listLocalBackup() : await listWebDavBackup();
setRows(
list
- .map((item) => buildRow(item.filename))
+ .map((item) => buildRow(item))
.filter((item): item is BackupRow => item !== null)
- .sort((a, b) => (a.backup_time.isAfter(b.backup_time) ? -1 : 1)),
+ .sort((a, b) =>
+ a.sort_value === b.sort_value
+ ? b.filename.localeCompare(a.filename)
+ : b.sort_value - a.sort_value,
+ ),
);
} catch (error) {
console.error(error);
@@ -138,7 +172,8 @@ export const BackupHistoryViewer = ({
return t("settings.modals.backup.manual.webdav");
}
if (!total) return t("settings.modals.backup.history.empty");
- const recent = rows[0]?.backup_time.fromNow();
+ const recent =
+ rows[0]?.backup_time?.fromNow() ?? rows[0]?.display_time ?? "";
return t("settings.modals.backup.history.summary", {
count: total,
recent,
@@ -283,7 +318,7 @@ export const BackupHistoryViewer = ({
spacing={1.5}
>
- {`${row.platform} · ${row.backup_time.format("YYYY-MM-DD HH:mm")}`}
+ {`${row.platform} · ${row.display_time}`}
}) {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const [busyAction, setBusyAction] = useState(null);
+ const [localImporting, setLocalImporting] = useState(false);
const [historyOpen, setHistoryOpen] = useState(false);
const [historySource, setHistorySource] = useState("local");
const [historyPage, setHistoryPage] = useState(0);
@@ -67,6 +73,28 @@ export function BackupViewer({ ref }: { ref?: Ref }) {
}
});
+ const handleImport = useLockFn(async () => {
+ const selected = await openDialog({
+ multiple: false,
+ filters: [{ name: "Backup File", extensions: ["zip"] }],
+ });
+ if (!selected || Array.isArray(selected)) return;
+ try {
+ setLocalImporting(true);
+ await importLocalBackup(selected);
+ showNotice.success("settings.modals.backup.messages.localBackupImported");
+ openHistory("local");
+ } catch (error) {
+ console.error(error);
+ showNotice.error(
+ "settings.modals.backup.messages.localBackupImportFailed",
+ { error },
+ );
+ } finally {
+ setLocalImporting(false);
+ }
+ });
+
const setWebdavBusy = useCallback(
(loading: boolean) => {
setBusyAction(loading ? "webdav" : null);
@@ -74,6 +102,8 @@ export function BackupViewer({ ref }: { ref?: Ref }) {
[setBusyAction],
);
+ const isLocalBusy = busyAction === "local" || localImporting;
+
return (
}) {
variant="contained"
size="small"
loading={busyAction === "local"}
+ disabled={localImporting}
onClick={() => handleBackup("local")}
>
{t("settings.modals.backup.actions.backup")}
@@ -133,10 +164,21 @@ export function BackupViewer({ ref }: { ref?: Ref }) {
key="history"
variant="outlined"
size="small"
+ disabled={isLocalBusy}
onClick={() => openHistory("local")}
>
{t("settings.modals.backup.actions.viewHistory")}
,
+ handleImport()}
+ >
+ {t("settings.modals.backup.actions.importBackup")}
+ ,
],
},
{
diff --git a/src/locales/ar/settings.json b/src/locales/ar/settings.json
index dab0b65c2..e4cf82fb1 100644
--- a/src/locales/ar/settings.json
+++ b/src/locales/ar/settings.json
@@ -283,6 +283,7 @@
"backup": "نسخ احتياطي",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "حذف النسخة الاحتياطية",
"restore": "استعادة",
"restoreBackup": "استعادة النسخة الاحتياطية",
@@ -307,6 +308,8 @@
"restoreSuccess": "تمت الاستعادة بنجاح، سيعاد تشغيل التطبيق خلال ثانية واحدة",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Failed to import local backup: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "هل تريد بالتأكيد حذف ملف النسخة الاحتياطية هذا؟",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/de/settings.json b/src/locales/de/settings.json
index 0409abf00..42166e2f3 100644
--- a/src/locales/de/settings.json
+++ b/src/locales/de/settings.json
@@ -283,6 +283,7 @@
"backup": "Sichern",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "Sicherung löschen",
"restore": "Wiederherstellen",
"restoreBackup": "Sicherung wiederherstellen",
@@ -307,6 +308,8 @@
"restoreSuccess": "Wiederherstellung erfolgreich. Die App wird in 1 Sekunde neu starten.",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Failed to import local backup: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "Confirm to delete this backup file?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/en/settings.json b/src/locales/en/settings.json
index 24e821b1c..997de9b25 100644
--- a/src/locales/en/settings.json
+++ b/src/locales/en/settings.json
@@ -283,6 +283,7 @@
"backup": "Backup",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "Delete Backup",
"restore": "Restore",
"restoreBackup": "Restore Backup",
@@ -307,6 +308,8 @@
"restoreSuccess": "Restore Success, App will restart in 1s",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Failed to import local backup: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "Confirm to delete this backup file?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/es/settings.json b/src/locales/es/settings.json
index 39692beea..3ed6245f1 100644
--- a/src/locales/es/settings.json
+++ b/src/locales/es/settings.json
@@ -283,6 +283,7 @@
"backup": "Copia de seguridad",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "Eliminar copia de seguridad",
"restore": "Restaurar",
"restoreBackup": "Restaurar copia de seguridad",
@@ -307,6 +308,8 @@
"restoreSuccess": "Restauración exitosa. La aplicación se reiniciará en 1 segundo",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Failed to import local backup: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "Confirm to delete this backup file?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/fa/settings.json b/src/locales/fa/settings.json
index 23153f62c..984312f8a 100644
--- a/src/locales/fa/settings.json
+++ b/src/locales/fa/settings.json
@@ -283,6 +283,7 @@
"backup": "پشتیبانگیری",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "حذف پشتیبان",
"restore": "بازیابی",
"restoreBackup": "بازیابی پشتیبان",
@@ -307,6 +308,8 @@
"restoreSuccess": "بازیابی با موفقیت انجام شد، برنامه در 1 ثانیه راهاندازی مجدد میشود",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Failed to import local backup: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "آیا از حذف این فایل پشتیبان اطمینان دارید؟",
@@ -333,7 +336,9 @@
"history": {
"title": "تاریخچه پشتیبان گیری",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "هیچ نسخه پشتیبان در دسترس نیست"
+ "empty": "هیچ نسخه پشتیبان در دسترس نیست",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "پیکربندی WebDAV"
diff --git a/src/locales/id/settings.json b/src/locales/id/settings.json
index c32b3f8ba..b74cece79 100644
--- a/src/locales/id/settings.json
+++ b/src/locales/id/settings.json
@@ -283,6 +283,7 @@
"backup": "Cadangan",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "Hapus Cadangan",
"restore": "Pulihkan",
"restoreBackup": "Pulihkan Cadangan",
@@ -307,6 +308,8 @@
"restoreSuccess": "Pemulihan Berhasil, Aplikasi akan dimulai ulang dalam 1 detik",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Failed to import local backup: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "Konfirmasi untuk menghapus file cadangan ini?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/jp/settings.json b/src/locales/jp/settings.json
index b0cb62d44..817947041 100644
--- a/src/locales/jp/settings.json
+++ b/src/locales/jp/settings.json
@@ -283,6 +283,7 @@
"backup": "バックアップ",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "バックアップをインポート",
"deleteBackup": "バックアップを削除",
"restore": "復元",
"restoreBackup": "バックアップを復元",
@@ -307,6 +308,8 @@
"restoreSuccess": "復元に成功しました。アプリケーションは1秒後に再起動します。",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "ローカルバックアップのインポートに成功しました",
+ "localBackupImportFailed": "ローカルバックアップのインポートに失敗しました: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "Confirm to delete this backup file?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/ko/settings.json b/src/locales/ko/settings.json
index 7c0096030..898af32f6 100644
--- a/src/locales/ko/settings.json
+++ b/src/locales/ko/settings.json
@@ -283,6 +283,7 @@
"backup": "백업",
"export": "내보내기",
"exportBackup": "백업 내보내기",
+ "importBackup": "백업 가져오기",
"deleteBackup": "백업 삭제",
"restore": "복원",
"restoreBackup": "백업 복원",
@@ -307,6 +308,8 @@
"restoreSuccess": "복원 성공, 1초 후 앱이 재시작됩니다",
"localBackupExported": "로컬 백업이 내보내졌습니다",
"localBackupExportFailed": "로컬 백업 내보내기 실패",
+ "localBackupImported": "로컬 백업을 가져왔습니다",
+ "localBackupImportFailed": "로컬 백업 가져오기 실패: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "이 백업 파일을 삭제하시겠습니까?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "알 수 없음",
+ "unknownTime": "시간 정보 없음"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/ru/settings.json b/src/locales/ru/settings.json
index f2da50b19..96506ca70 100644
--- a/src/locales/ru/settings.json
+++ b/src/locales/ru/settings.json
@@ -283,6 +283,7 @@
"backup": "Резервное копирование",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "Удалить резервную копию",
"restore": "Восстановить",
"restoreBackup": "Восстановить резервную копию",
@@ -307,6 +308,8 @@
"restoreSuccess": "Восстановление успешно выполнено, приложение перезапустится через 1 секунду",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Не удалось импортировать локальную резервную копию: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "Вы уверены, что хотите удалить этот файл резервной копии?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "неизвестно",
+ "unknownTime": "Неизвестное время"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/tr/settings.json b/src/locales/tr/settings.json
index db7798988..e79318c17 100644
--- a/src/locales/tr/settings.json
+++ b/src/locales/tr/settings.json
@@ -283,6 +283,7 @@
"backup": "Yedekle",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "Yedeği Sil",
"restore": "Geri Yükle",
"restoreBackup": "Yedeği Geri Yükle",
@@ -307,6 +308,8 @@
"restoreSuccess": "Geri Yükleme Başarılı, Uygulama 1 saniye içinde yeniden başlatılacak",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Failed to import local backup: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "Bu yedek dosyasını silmeyi onaylıyor musunuz?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/tt/settings.json b/src/locales/tt/settings.json
index fee717492..1504aaf68 100644
--- a/src/locales/tt/settings.json
+++ b/src/locales/tt/settings.json
@@ -283,6 +283,7 @@
"backup": "Резерв копия",
"export": "Export",
"exportBackup": "Export Backup",
+ "importBackup": "Import Backup",
"deleteBackup": "Резерв копияне бетерү",
"restore": "Кайтару",
"restoreBackup": "Резерв копияне кайтару",
@@ -307,6 +308,8 @@
"restoreSuccess": "Уңышлы кайтарылды, кушымта 1 секундтан яңадан башланачак",
"localBackupExported": "Local backup exported successfully",
"localBackupExportFailed": "Failed to export local backup",
+ "localBackupImported": "Local backup imported successfully",
+ "localBackupImportFailed": "Failed to import local backup: {{error}}",
"webdavRefreshSuccess": "WebDAV refresh succeeded",
"webdavRefreshFailed": "WebDAV refresh failed: {{error}}",
"confirmDelete": "Бу резерв копия файлын бетерергә телисезме?",
@@ -333,7 +336,9 @@
"history": {
"title": "Backup history",
"summary": "{{count}} backups • latest {{recent}}",
- "empty": "No backups available"
+ "empty": "No backups available",
+ "unknownPlatform": "unknown",
+ "unknownTime": "Unknown time"
},
"webdav": {
"title": "WebDAV settings"
diff --git a/src/locales/zh/settings.json b/src/locales/zh/settings.json
index 8ab74085c..9d0611fcc 100644
--- a/src/locales/zh/settings.json
+++ b/src/locales/zh/settings.json
@@ -283,6 +283,7 @@
"backup": "备份",
"export": "导出",
"exportBackup": "导出备份",
+ "importBackup": "导入备份",
"deleteBackup": "删除备份",
"restore": "恢复",
"restoreBackup": "恢复备份",
@@ -307,6 +308,8 @@
"restoreSuccess": "恢复成功,应用将在 1 秒后重启",
"localBackupExported": "本地备份导出成功",
"localBackupExportFailed": "本地备份导出失败",
+ "localBackupImported": "本地备份导入成功",
+ "localBackupImportFailed": "本地备份导入失败:{{error}}",
"webdavRefreshSuccess": "WebDAV 刷新成功",
"webdavRefreshFailed": "WebDAV 刷新失败: {{error}}",
"confirmDelete": "确认删除此备份文件吗?",
@@ -333,7 +336,9 @@
"history": {
"title": "备份记录",
"summary": "共 {{count}} 份备份 · 最近 {{recent}}",
- "empty": "暂无备份记录"
+ "empty": "暂无备份记录",
+ "unknownPlatform": "未知",
+ "unknownTime": "未知时间"
},
"webdav": {
"title": "WebDAV 设置"
diff --git a/src/locales/zhtw/settings.json b/src/locales/zhtw/settings.json
index a2b716f40..b829656c0 100644
--- a/src/locales/zhtw/settings.json
+++ b/src/locales/zhtw/settings.json
@@ -283,6 +283,7 @@
"backup": "備份",
"export": "匯出",
"exportBackup": "匯出備份",
+ "importBackup": "匯入備份",
"deleteBackup": "刪除備份",
"restore": "還原",
"restoreBackup": "還原備份",
@@ -307,6 +308,8 @@
"restoreSuccess": "還原成功,應用程式將在 1 秒後重啟",
"localBackupExported": "本機備份匯出成功",
"localBackupExportFailed": "本機備份匯出失敗",
+ "localBackupImported": "本機備份匯入成功",
+ "localBackupImportFailed": "本機備份匯入失敗:{{error}}",
"webdavRefreshSuccess": "WebDAV 更新成功",
"webdavRefreshFailed": "WebDAV 更新失敗: {{error}}",
"confirmDelete": "確認是否刪除此備份檔案嗎?",
@@ -333,7 +336,9 @@
"history": {
"title": "備份紀錄",
"summary": "共 {{count}} 份備份 · 最近 {{recent}}",
- "empty": "尚無備份紀錄"
+ "empty": "尚無備份紀錄",
+ "unknownPlatform": "未知",
+ "unknownTime": "未知時間"
},
"webdav": {
"title": "WebDAV 設定"
diff --git a/src/services/cmds.ts b/src/services/cmds.ts
index 1c227acfc..cd34ecfc6 100644
--- a/src/services/cmds.ts
+++ b/src/services/cmds.ts
@@ -455,6 +455,10 @@ export async function restoreLocalBackup(filename: string) {
return invoke("restore_local_backup", { filename });
}
+export async function importLocalBackup(source: string) {
+ return invoke("import_local_backup", { source });
+}
+
export async function exportLocalBackup(filename: string, destination: string) {
return invoke("export_local_backup", { filename, destination });
}
diff --git a/src/types/generated/i18n-keys.ts b/src/types/generated/i18n-keys.ts
index 4d0fdad7f..166828f85 100644
--- a/src/types/generated/i18n-keys.ts
+++ b/src/types/generated/i18n-keys.ts
@@ -464,6 +464,7 @@ export const translationKeys = [
"settings.modals.backup.actions.backup",
"settings.modals.backup.actions.export",
"settings.modals.backup.actions.exportBackup",
+ "settings.modals.backup.actions.importBackup",
"settings.modals.backup.actions.deleteBackup",
"settings.modals.backup.actions.restore",
"settings.modals.backup.actions.restoreBackup",
@@ -484,6 +485,8 @@ export const translationKeys = [
"settings.modals.backup.messages.restoreSuccess",
"settings.modals.backup.messages.localBackupExported",
"settings.modals.backup.messages.localBackupExportFailed",
+ "settings.modals.backup.messages.localBackupImported",
+ "settings.modals.backup.messages.localBackupImportFailed",
"settings.modals.backup.messages.webdavRefreshSuccess",
"settings.modals.backup.messages.webdavRefreshFailed",
"settings.modals.backup.messages.confirmDelete",
@@ -503,6 +506,8 @@ export const translationKeys = [
"settings.modals.backup.history.title",
"settings.modals.backup.history.summary",
"settings.modals.backup.history.empty",
+ "settings.modals.backup.history.unknownPlatform",
+ "settings.modals.backup.history.unknownTime",
"settings.modals.backup.webdav.title",
"settings.modals.backup.table.filename",
"settings.modals.backup.table.backupTime",
diff --git a/src/types/generated/i18n-resources.ts b/src/types/generated/i18n-resources.ts
index 2700b138c..f21552073 100644
--- a/src/types/generated/i18n-resources.ts
+++ b/src/types/generated/i18n-resources.ts
@@ -694,6 +694,7 @@ export interface TranslationResources {
deleteBackup: string;
export: string;
exportBackup: string;
+ importBackup: string;
restore: string;
restoreBackup: string;
selectTarget: string;
@@ -720,6 +721,8 @@ export interface TranslationResources {
empty: string;
summary: string;
title: string;
+ unknownPlatform: string;
+ unknownTime: string;
};
manual: {
configureWebdav: string;
@@ -737,6 +740,8 @@ export interface TranslationResources {
localBackupExported: string;
localBackupExportFailed: string;
localBackupFailed: string;
+ localBackupImported: string;
+ localBackupImportFailed: string;
passwordRequired: string;
restoreSuccess: string;
usernameRequired: string;