fix: enhance backup and restore functionality with skip option (#6294)

* fix: enhance backup and restore functionality with skip option

- Updated `restore` and `restoreFromWebdav` methods in `BackupManager` to include a `skipBackupFile` parameter, allowing users to skip restoring the Data directory if desired.
- Modified corresponding IPC calls in `preload` and `BackupService` to support the new parameter.
- Added success message translations in multiple languages for improved user feedback.

* fix: integrate skipBackupFile option in RestorePopup for enhanced restore functionality

* refactor: remove skipBackupFile parameter from restore methods for simplified usage

- Updated `restore` and `restoreFromWebdav` methods in `BackupManager`, `BackupService`, and `NutstoreService` to remove the `skipBackupFile` parameter, streamlining the restore process.
- Adjusted corresponding IPC calls in `preload` and `RestorePopup` to reflect the changes, ensuring consistent functionality across the application.
This commit is contained in:
SuYao 2025-05-22 19:38:34 +08:00 committed by GitHub
parent fc5209723f
commit e162da55bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 39 additions and 37 deletions

View File

@ -255,19 +255,26 @@ class BackupManager {
const sourcePath = path.join(this.tempDir, 'Data') const sourcePath = path.join(this.tempDir, 'Data')
const destPath = path.join(app.getPath('userData'), 'Data') const destPath = path.join(app.getPath('userData'), 'Data')
// 获取源目录总大小 const dataExists = await fs.pathExists(sourcePath)
const totalSize = await this.getDirSize(sourcePath) const dataFiles = dataExists ? await fs.readdir(sourcePath) : []
let copiedSize = 0
await this.setWritableRecursive(destPath) if (dataExists && dataFiles.length > 0) {
await fs.remove(destPath) // 获取源目录总大小
const totalSize = await this.getDirSize(sourcePath)
let copiedSize = 0
// 使用流式复制 await this.setWritableRecursive(destPath)
await this.copyDirWithProgress(sourcePath, destPath, (size) => { await fs.remove(destPath)
copiedSize += size
const progress = Math.min(85, 35 + Math.floor((copiedSize / totalSize) * 50)) // 使用流式复制
onProgress({ stage: 'copying_files', progress, total: 100 }) await this.copyDirWithProgress(sourcePath, destPath, (size) => {
}) copiedSize += size
const progress = Math.min(85, 35 + Math.floor((copiedSize / totalSize) * 50))
onProgress({ stage: 'copying_files', progress, total: 100 })
})
} else {
Logger.log('[backup] skipBackupFile is true, skip restoring Data directory')
}
Logger.log('[backup] step 4: clean up temp directory') Logger.log('[backup] step 4: clean up temp directory')
// 清理临时目录 // 清理临时目录

View File

@ -2,12 +2,12 @@ import ZhinaoProviderLogo from '@renderer/assets/images/models/360.png'
import HunyuanProviderLogo from '@renderer/assets/images/models/hunyuan.png' import HunyuanProviderLogo from '@renderer/assets/images/models/hunyuan.png'
import AzureProviderLogo from '@renderer/assets/images/models/microsoft.png' import AzureProviderLogo from '@renderer/assets/images/models/microsoft.png'
import AiHubMixProviderLogo from '@renderer/assets/images/providers/aihubmix.webp' import AiHubMixProviderLogo from '@renderer/assets/images/providers/aihubmix.webp'
import BurnCloudProviderLogo from '@renderer/assets/images/providers/burncloud.png'
import AlayaNewProviderLogo from '@renderer/assets/images/providers/alayanew.webp' import AlayaNewProviderLogo from '@renderer/assets/images/providers/alayanew.webp'
import AnthropicProviderLogo from '@renderer/assets/images/providers/anthropic.png' import AnthropicProviderLogo from '@renderer/assets/images/providers/anthropic.png'
import BaichuanProviderLogo from '@renderer/assets/images/providers/baichuan.png' import BaichuanProviderLogo from '@renderer/assets/images/providers/baichuan.png'
import BaiduCloudProviderLogo from '@renderer/assets/images/providers/baidu-cloud.svg' import BaiduCloudProviderLogo from '@renderer/assets/images/providers/baidu-cloud.svg'
import BailianProviderLogo from '@renderer/assets/images/providers/bailian.png' import BailianProviderLogo from '@renderer/assets/images/providers/bailian.png'
import BurnCloudProviderLogo from '@renderer/assets/images/providers/burncloud.png'
import DeepSeekProviderLogo from '@renderer/assets/images/providers/deepseek.png' import DeepSeekProviderLogo from '@renderer/assets/images/providers/deepseek.png'
import DmxapiProviderLogo from '@renderer/assets/images/providers/DMXAPI.png' import DmxapiProviderLogo from '@renderer/assets/images/providers/DMXAPI.png'
import FireworksProviderLogo from '@renderer/assets/images/providers/fireworks.png' import FireworksProviderLogo from '@renderer/assets/images/providers/fireworks.png'

View File

@ -396,6 +396,7 @@
"search": "Search", "search": "Search",
"select": "Select", "select": "Select",
"selectedMessages": "Selected {{count}} messages", "selectedMessages": "Selected {{count}} messages",
"success": "Success",
"topics": "Topics", "topics": "Topics",
"warning": "Warning", "warning": "Warning",
"you": "You", "you": "You",

View File

@ -396,6 +396,7 @@
"search": "検索", "search": "検索",
"select": "選択", "select": "選択",
"selectedMessages": "{{count}}件のメッセージを選択しました", "selectedMessages": "{{count}}件のメッセージを選択しました",
"success": "成功",
"topics": "トピック", "topics": "トピック",
"warning": "警告", "warning": "警告",
"you": "あなた", "you": "あなた",

View File

@ -396,6 +396,7 @@
"search": "Поиск", "search": "Поиск",
"select": "Выбрать", "select": "Выбрать",
"selectedMessages": "Выбрано {{count}} сообщений", "selectedMessages": "Выбрано {{count}} сообщений",
"success": "Успешно",
"topics": "Топики", "topics": "Топики",
"warning": "Предупреждение", "warning": "Предупреждение",
"you": "Вы", "you": "Вы",

View File

@ -396,6 +396,7 @@
"search": "搜索", "search": "搜索",
"select": "选择", "select": "选择",
"selectedMessages": "选中 {{count}} 条消息", "selectedMessages": "选中 {{count}} 条消息",
"success": "成功",
"topics": "话题", "topics": "话题",
"warning": "警告", "warning": "警告",
"you": "用户", "you": "用户",

View File

@ -395,7 +395,8 @@
"save": "儲存", "save": "儲存",
"search": "搜尋", "search": "搜尋",
"select": "選擇", "select": "選擇",
"selectedMessages": "选中 {{count}} 条消息", "selectedMessages": "選中 {{count}} 條訊息",
"success": "成功",
"topics": "話題", "topics": "話題",
"warning": "警告", "warning": "警告",
"you": "您", "you": "您",

View File

@ -138,10 +138,6 @@ export async function backupToWebdav({
source: 'backup' source: 'backup'
}) })
if (showMessage && !autoBackupProcess) {
window.message.success({ content: i18n.t('message.backup.success'), key: 'backup' })
}
// 清理旧备份文件 // 清理旧备份文件
if (webdavMaxBackups > 0) { if (webdavMaxBackups > 0) {
try { try {
@ -199,19 +195,14 @@ export async function backupToWebdav({
notificationService.send({ notificationService.send({
id: uuid(), id: uuid(),
type: 'error', type: 'error',
title: i18n.t('common.error'), title: i18n.t('message.backup.failed'),
message: i18n.t('message.backup.failed'), message: error.message,
silent: false, silent: false,
timestamp: Date.now(), timestamp: Date.now(),
source: 'backup' source: 'backup'
}) })
store.dispatch(setWebDAVSyncState({ lastSyncError: error.message })) store.dispatch(setWebDAVSyncState({ lastSyncError: error.message }))
console.error('[Backup] backupToWebdav: Error uploading file to WebDAV:', error) console.error('[Backup] backupToWebdav: Error uploading file to WebDAV:', error)
showMessage &&
window.modal.error({
title: i18n.t('message.backup.failed'),
content: error.message
})
throw error throw error
} finally { } finally {
if (!autoBackupProcess) { if (!autoBackupProcess) {

View File

@ -34,7 +34,6 @@ import {
createTranslationBlock, createTranslationBlock,
resetAssistantMessage resetAssistantMessage
} from '@renderer/utils/messageUtils/create' } from '@renderer/utils/messageUtils/create'
import { getMainTextContent } from '@renderer/utils/messageUtils/find'
import { getTopicQueue, waitForTopicQueue } from '@renderer/utils/queue' import { getTopicQueue, waitForTopicQueue } from '@renderer/utils/queue'
import { isOnHomePage } from '@renderer/utils/window' import { isOnHomePage } from '@renderer/utils/window'
import { t } from 'i18next' import { t } from 'i18next'
@ -652,18 +651,18 @@ const fetchAndProcessAssistantResponseImpl = async (
saveUpdatedBlockToDB(lastBlockId, assistantMsgId, topicId, getState) saveUpdatedBlockToDB(lastBlockId, assistantMsgId, topicId, getState)
} }
const content = getMainTextContent(finalAssistantMsg) // const content = getMainTextContent(finalAssistantMsg)
if (!isOnHomePage()) { // if (!isOnHomePage()) {
await notificationService.send({ // await notificationService.send({
id: uuid(), // id: uuid(),
type: 'success', // type: 'success',
title: t('notification.assistant'), // title: t('notification.assistant'),
message: content.length > 50 ? content.slice(0, 47) + '...' : content, // message: content.length > 50 ? content.slice(0, 47) + '...' : content,
silent: false, // silent: false,
timestamp: Date.now(), // timestamp: Date.now(),
source: 'assistant' // source: 'assistant'
}) // })
} // }
// 更新topic的name // 更新topic的name
autoRenameTopic(assistant, topicId) autoRenameTopic(assistant, topicId)