feat(backup): add local backup import flow (#5669)

* feat(backup): add local backup import flow

* refactor(backup): robustify history listing and propagate import error details

* docs: Changelog.md
This commit is contained in:
Sline
2025-12-19 17:46:31 +08:00
committed by GitHub
parent b4e25951b4
commit bd8eccdcea
22 changed files with 240 additions and 29 deletions

View File

@@ -8,6 +8,7 @@
<summary><strong> ✨ 新增功能 </strong></summary>
- 允许代理页面允许高级过滤搜索
- 备份设置页面新增导入备份按钮
</details>

View File

@@ -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<String> {
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<()> {

View File

@@ -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<String> {
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?;

View File

@@ -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,

View File

@@ -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 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);
if (!match) return null;
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: dayjs(match[0], DATE_FORMAT),
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}
>
<Typography variant="caption" color="text.secondary">
{`${row.platform} · ${row.backup_time.format("YYYY-MM-DD HH:mm")}`}
{`${row.platform} · ${row.display_time}`}
</Typography>
<Stack
direction="row"

View File

@@ -7,13 +7,18 @@ import {
Stack,
Typography,
} from "@mui/material";
import { open as openDialog } from "@tauri-apps/plugin-dialog";
import { useLockFn } from "ahooks";
import type { ReactNode, Ref } from "react";
import { useCallback, useImperativeHandle, useState } from "react";
import { useTranslation } from "react-i18next";
import { BaseDialog, DialogRef } from "@/components/base";
import { createLocalBackup, createWebdavBackup } from "@/services/cmds";
import {
createLocalBackup,
createWebdavBackup,
importLocalBackup,
} from "@/services/cmds";
import { showNotice } from "@/services/notice-service";
import { AutoBackupSettings } from "./auto-backup-settings";
@@ -26,6 +31,7 @@ export function BackupViewer({ ref }: { ref?: Ref<DialogRef> }) {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const [busyAction, setBusyAction] = useState<BackupSource | null>(null);
const [localImporting, setLocalImporting] = useState(false);
const [historyOpen, setHistoryOpen] = useState(false);
const [historySource, setHistorySource] = useState<BackupSource>("local");
const [historyPage, setHistoryPage] = useState(0);
@@ -67,6 +73,28 @@ export function BackupViewer({ ref }: { ref?: Ref<DialogRef> }) {
}
});
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<DialogRef> }) {
[setBusyAction],
);
const isLocalBusy = busyAction === "local" || localImporting;
return (
<BaseDialog
open={open}
@@ -125,6 +155,7 @@ export function BackupViewer({ ref }: { ref?: Ref<DialogRef> }) {
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<DialogRef> }) {
key="history"
variant="outlined"
size="small"
disabled={isLocalBusy}
onClick={() => openHistory("local")}
>
{t("settings.modals.backup.actions.viewHistory")}
</Button>,
<LoadingButton
key="import"
variant="text"
size="small"
loading={localImporting}
disabled={busyAction === "local"}
onClick={() => handleImport()}
>
{t("settings.modals.backup.actions.importBackup")}
</LoadingButton>,
],
},
{

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 设置"

View File

@@ -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 設定"

View File

@@ -455,6 +455,10 @@ export async function restoreLocalBackup(filename: string) {
return invoke<void>("restore_local_backup", { filename });
}
export async function importLocalBackup(source: string) {
return invoke<string>("import_local_backup", { source });
}
export async function exportLocalBackup(filename: string, destination: string) {
return invoke<void>("export_local_backup", { filename, destination });
}

View File

@@ -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",

View File

@@ -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;