feat: 优化webdav备份文件恢复管理功能 (#4699)

* feat: 优化webdav备份文件恢复管理功能

* fix: 恢复和删除操作更改为文字而非图标

* feat: 统一坚果云与webdav备份恢复功能
This commit is contained in:
africa1207 2025-04-13 21:52:16 +08:00 committed by GitHub
parent 88cbb27557
commit a54360cc69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 466 additions and 63 deletions

10
.vscode/settings.json vendored
View File

@ -31,5 +31,13 @@
"[markdown]": {
"files.trimTrailingWhitespace": false
},
"i18n-ally.localesPaths": ["src/renderer/src/i18n"]
"i18n-ally.localesPaths": ["src/renderer/src/i18n/locales"],
"i18n-ally.enabledFrameworks": ["react-i18next", "i18next"],
"i18n-ally.keystyle": "nested", //
"i18n-ally.sortKeys": true, //
"i18n-ally.namespace": true, //
"i18n-ally.enabledParsers": ["ts", "js", "json"], //
"i18n-ally.sourceLanguage": "en-us", //
"i18n-ally.displayLanguage": "zh-cn",
"i18n-ally.fullReloadOnChanged": true //
}

View File

@ -120,6 +120,7 @@ export enum IpcChannel {
Backup_ListWebdavFiles = 'backup:listWebdavFiles',
Backup_CheckConnection = 'backup:checkConnection',
Backup_CreateDirectory = 'backup:createDirectory',
Backup_DeleteWebdavFile = 'backup:deleteWebdavFile',
// zip
Zip_Compress = 'zip:compress',

View File

@ -182,6 +182,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
ipcMain.handle(IpcChannel.Backup_ListWebdavFiles, backupManager.listWebdavFiles)
ipcMain.handle(IpcChannel.Backup_CheckConnection, backupManager.checkConnection)
ipcMain.handle(IpcChannel.Backup_CreateDirectory, backupManager.createDirectory)
ipcMain.handle(IpcChannel.Backup_DeleteWebdavFile, backupManager.deleteWebdavFile)
// file
ipcMain.handle(IpcChannel.File_Open, fileManager.open)

View File

@ -22,6 +22,7 @@ class BackupManager {
this.backupToWebdav = this.backupToWebdav.bind(this)
this.restoreFromWebdav = this.restoreFromWebdav.bind(this)
this.listWebdavFiles = this.listWebdavFiles.bind(this)
this.deleteWebdavFile = this.deleteWebdavFile.bind(this)
}
private async setWritableRecursive(dirPath: string): Promise<void> {
@ -309,6 +310,16 @@ class BackupManager {
const webdavClient = new WebDav(webdavConfig)
return await webdavClient.createDirectory(path, options)
}
async deleteWebdavFile(_: Electron.IpcMainInvokeEvent, fileName: string, webdavConfig: WebDavConfig) {
try {
const webdavClient = new WebDav(webdavConfig)
return await webdavClient.deleteFile(fileName)
} catch (error: any) {
Logger.error('Failed to delete WebDAV file:', error)
throw new Error(error.message || 'Failed to delete backup file')
}
}
}
export default BackupManager

View File

@ -26,6 +26,7 @@ export default class WebDav {
this.putFileContents = this.putFileContents.bind(this)
this.getFileContents = this.getFileContents.bind(this)
this.createDirectory = this.createDirectory.bind(this)
this.deleteFile = this.deleteFile.bind(this)
}
public putFileContents = async (
@ -98,4 +99,19 @@ export default class WebDav {
throw error
}
}
public deleteFile = async (filename: string) => {
if (!this.instance) {
throw new Error('WebDAV client not initialized')
}
const remoteFilePath = `${this.webdavPath}/${filename}`
try {
return await this.instance.deleteFile(remoteFilePath)
} catch (error) {
Logger.error('[WebDAV] Error deleting file on WebDAV:', error)
throw error
}
}
}

View File

@ -46,6 +46,7 @@ declare global {
listWebdavFiles: (webdavConfig: WebDavConfig) => Promise<BackupFile[]>
checkConnection: (webdavConfig: WebDavConfig) => Promise<boolean>
createDirectory: (webdavConfig: WebDavConfig, path: string, options?: CreateDirectoryOptions) => Promise<void>
deleteWebdavFile: (fileName: string, webdavConfig: WebDavConfig) => Promise<boolean>
}
file: {
select: (options?: OpenDialogOptions) => Promise<FileType[] | null>

View File

@ -41,7 +41,9 @@ const api = {
checkConnection: (webdavConfig: WebDavConfig) =>
ipcRenderer.invoke(IpcChannel.Backup_CheckConnection, webdavConfig),
createDirectory: (webdavConfig: WebDavConfig, path: string, options?: CreateDirectoryOptions) =>
ipcRenderer.invoke(IpcChannel.Backup_CreateDirectory, webdavConfig, path, options)
ipcRenderer.invoke(IpcChannel.Backup_CreateDirectory, webdavConfig, path, options),
deleteWebdavFile: (fileName: string, webdavConfig: WebDavConfig) =>
ipcRenderer.invoke(IpcChannel.Backup_DeleteWebdavFile, fileName, webdavConfig)
},
file: {
select: (options?: OpenDialogOptions) => ipcRenderer.invoke(IpcChannel.File_Select, options),

View File

@ -0,0 +1,283 @@
import { DeleteOutlined, ExclamationCircleOutlined, ReloadOutlined } from '@ant-design/icons'
import { restoreFromWebdav } from '@renderer/services/BackupService'
import { formatFileSize } from '@renderer/utils'
import { Button, message, Modal, Table, Tooltip } from 'antd'
import dayjs from 'dayjs'
import { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
interface BackupFile {
fileName: string
modifiedTime: string
size: number
}
interface WebdavConfig {
webdavHost: string
webdavUser: string
webdavPass: string
webdavPath: string
}
interface WebdavBackupManagerProps {
visible: boolean
onClose: () => void
webdavConfig: {
webdavHost?: string
webdavUser?: string
webdavPass?: string
webdavPath?: string
}
restoreMethod?: (fileName: string) => Promise<void>
}
export function WebdavBackupManager({ visible, onClose, webdavConfig, restoreMethod }: WebdavBackupManagerProps) {
const { t } = useTranslation()
const [backupFiles, setBackupFiles] = useState<BackupFile[]>([])
const [loading, setLoading] = useState(false)
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
const [deleting, setDeleting] = useState(false)
const [restoring, setRestoring] = useState(false)
const [pagination, setPagination] = useState({
current: 1,
pageSize: 5,
total: 0
})
const { webdavHost, webdavUser, webdavPass, webdavPath } = webdavConfig
const fetchBackupFiles = useCallback(async () => {
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
message.error(t('message.error.invalid.webdav'))
return
}
setLoading(true)
try {
const files = await window.api.backup.listWebdavFiles({
webdavHost,
webdavUser,
webdavPass,
webdavPath
} as WebdavConfig)
setBackupFiles(files)
setPagination((prev) => ({
...prev,
total: files.length
}))
} catch (error: any) {
message.error(`${t('settings.data.webdav.backup.manager.fetch.error')}: ${error.message}`)
} finally {
setLoading(false)
}
}, [webdavHost, webdavUser, webdavPass, webdavPath, t])
useEffect(() => {
if (visible) {
fetchBackupFiles()
setSelectedRowKeys([])
setPagination((prev) => ({
...prev,
current: 1
}))
}
}, [visible, fetchBackupFiles])
const handleTableChange = (pagination: any) => {
setPagination(pagination)
}
const handleDeleteSelected = async () => {
if (selectedRowKeys.length === 0) {
message.warning(t('settings.data.webdav.backup.manager.select.files.delete'))
return
}
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
message.error(t('message.error.invalid.webdav'))
return
}
Modal.confirm({
title: t('settings.data.webdav.backup.manager.delete.confirm.title'),
icon: <ExclamationCircleOutlined />,
content: t('settings.data.webdav.backup.manager.delete.confirm.multiple', { count: selectedRowKeys.length }),
okText: t('common.confirm'),
cancelText: t('common.cancel'),
onOk: async () => {
setDeleting(true)
try {
// 依次删除选中的文件
for (const key of selectedRowKeys) {
await window.api.backup.deleteWebdavFile(key.toString(), {
webdavHost,
webdavUser,
webdavPass,
webdavPath
} as WebdavConfig)
}
message.success(
t('settings.data.webdav.backup.manager.delete.success.multiple', { count: selectedRowKeys.length })
)
setSelectedRowKeys([])
await fetchBackupFiles()
} catch (error: any) {
message.error(`${t('settings.data.webdav.backup.manager.delete.error')}: ${error.message}`)
} finally {
setDeleting(false)
}
}
})
}
const handleDeleteSingle = async (fileName: string) => {
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
message.error(t('message.error.invalid.webdav'))
return
}
Modal.confirm({
title: t('settings.data.webdav.backup.manager.delete.confirm.title'),
icon: <ExclamationCircleOutlined />,
content: t('settings.data.webdav.backup.manager.delete.confirm.single', { fileName }),
okText: t('common.confirm'),
cancelText: t('common.cancel'),
onOk: async () => {
setDeleting(true)
try {
await window.api.backup.deleteWebdavFile(fileName, {
webdavHost,
webdavUser,
webdavPass,
webdavPath
} as WebdavConfig)
message.success(t('settings.data.webdav.backup.manager.delete.success.single'))
await fetchBackupFiles()
} catch (error: any) {
message.error(`${t('settings.data.webdav.backup.manager.delete.error')}: ${error.message}`)
} finally {
setDeleting(false)
}
}
})
}
const handleRestore = async (fileName: string) => {
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
message.error(t('message.error.invalid.webdav'))
return
}
Modal.confirm({
title: t('settings.data.webdav.restore.confirm.title'),
icon: <ExclamationCircleOutlined />,
content: t('settings.data.webdav.restore.confirm.content'),
okText: t('common.confirm'),
cancelText: t('common.cancel'),
onOk: async () => {
setRestoring(true)
try {
await (restoreMethod || restoreFromWebdav)(fileName)
message.success(t('settings.data.webdav.backup.manager.restore.success'))
onClose() // 关闭模态框
} catch (error: any) {
message.error(`${t('settings.data.webdav.backup.manager.restore.error')}: ${error.message}`)
} finally {
setRestoring(false)
}
}
})
}
const columns = [
{
title: t('settings.data.webdav.backup.manager.columns.fileName'),
dataIndex: 'fileName',
key: 'fileName',
ellipsis: {
showTitle: false
},
render: (fileName: string) => (
<Tooltip placement="topLeft" title={fileName}>
{fileName}
</Tooltip>
)
},
{
title: t('settings.data.webdav.backup.manager.columns.modifiedTime'),
dataIndex: 'modifiedTime',
key: 'modifiedTime',
width: 180,
render: (time: string) => dayjs(time).format('YYYY-MM-DD HH:mm:ss')
},
{
title: t('settings.data.webdav.backup.manager.columns.size'),
dataIndex: 'size',
key: 'size',
width: 120,
render: (size: number) => formatFileSize(size)
},
{
title: t('settings.data.webdav.backup.manager.columns.actions'),
key: 'action',
width: 160,
render: (_: any, record: BackupFile) => (
<>
<Button type="link" onClick={() => handleRestore(record.fileName)} disabled={restoring || deleting}>
{t('settings.data.webdav.backup.manager.restore.text')}
</Button>
<Button
type="link"
danger
onClick={() => handleDeleteSingle(record.fileName)}
disabled={deleting || restoring}>
{t('settings.data.webdav.backup.manager.delete.text')}
</Button>
</>
)
}
]
const rowSelection = {
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[]) => {
setSelectedRowKeys(selectedRowKeys)
}
}
return (
<Modal
title={t('settings.data.webdav.backup.manager.title')}
open={visible}
onCancel={onClose}
width={800}
footer={[
<Button key="refresh" icon={<ReloadOutlined />} onClick={fetchBackupFiles} disabled={loading}>
{t('settings.data.webdav.backup.manager.refresh')}
</Button>,
<Button
key="delete"
danger
icon={<DeleteOutlined />}
onClick={handleDeleteSelected}
disabled={selectedRowKeys.length === 0 || deleting}
loading={deleting}>
{t('settings.data.webdav.backup.manager.delete.selected')} ({selectedRowKeys.length})
</Button>,
<Button key="close" onClick={onClose}>
{t('common.close')}
</Button>
]}>
<Table
rowKey="fileName"
columns={columns}
dataSource={backupFiles}
rowSelection={rowSelection}
pagination={pagination}
loading={loading}
onChange={handleTableChange}
size="middle"
/>
</Modal>
)
}

View File

@ -879,6 +879,25 @@
"backup.button": "Backup to WebDAV",
"backup.modal.filename.placeholder": "Please enter backup filename",
"backup.modal.title": "Backup to WebDAV",
"backup.manager.title": "Backup Data Management",
"backup.manager.refresh": "Refresh",
"backup.manager.delete.selected": "Delete Selected",
"backup.manager.delete.text": "Delete",
"backup.manager.restore.text": "Restore",
"backup.manager.restore.success": "Restore successful, application will refresh shortly",
"backup.manager.restore.error": "Restore failed",
"backup.manager.delete.confirm.title": "Confirm Delete",
"backup.manager.delete.confirm.single": "Are you sure you want to delete backup file \"{{fileName}}\"? This action cannot be undone.",
"backup.manager.delete.confirm.multiple": "Are you sure you want to delete {{count}} selected backup files? This action cannot be undone.",
"backup.manager.delete.success.single": "Deleted successfully",
"backup.manager.delete.success.multiple": "Successfully deleted {{count}} backup files",
"backup.manager.delete.error": "Delete failed",
"backup.manager.fetch.error": "Failed to get backup files",
"backup.manager.select.files.delete": "Please select backup files to delete",
"backup.manager.columns.fileName": "Filename",
"backup.manager.columns.modifiedTime": "Modified Time",
"backup.manager.columns.size": "Size",
"backup.manager.columns.actions": "Actions",
"host": "WebDAV Host",
"host.placeholder": "http://localhost:8080",
"hour_interval_one": "{{count}} hour",

View File

@ -879,6 +879,25 @@
"backup.button": "WebDAVにバックアップ",
"backup.modal.filename.placeholder": "バックアップファイル名を入力してください",
"backup.modal.title": "WebDAV にバックアップ",
"backup.manager.title": "バックアップデータ管理",
"backup.manager.refresh": "更新",
"backup.manager.delete.selected": "選択したものを ",
"backup.manager.delete.text": "削除",
"backup.manager.restore.text": "復元",
"backup.manager.restore.success": "復元が成功しました、アプリケーションは間もなく更新されます",
"backup.manager.restore.error": "復元に失敗しました",
"backup.manager.delete.confirm.title": "削除の確認",
"backup.manager.delete.confirm.single": "バックアップファイル \"{{fileName}}\" を削除してもよろしいですか?この操作は元に戻せません。",
"backup.manager.delete.confirm.multiple": "選択した {{count}} 個のバックアップファイルを削除してもよろしいですか?この操作は元に戻せません。",
"backup.manager.delete.success.single": "削除が成功しました",
"backup.manager.delete.success.multiple": "{{count}} 個のバックアップファイルを削除しました",
"backup.manager.delete.error": "削除に失敗しました",
"backup.manager.fetch.error": "バックアップファイルの取得に失敗しました",
"backup.manager.select.files.delete": "削除するバックアップファイルを選択してください",
"backup.manager.columns.fileName": "ファイル名",
"backup.manager.columns.modifiedTime": "更新日時",
"backup.manager.columns.size": "サイズ",
"backup.manager.columns.actions": "操作",
"host": "WebDAVホスト",
"host.placeholder": "http://localhost:8080",
"hour_interval_one": "{{count}} 時間",

View File

@ -879,6 +879,25 @@
"backup.button": "Резервное копирование на WebDAV",
"backup.modal.filename.placeholder": "Введите имя файла резервной копии",
"backup.modal.title": "Резервное копирование на WebDAV",
"backup.manager.title": "Управление резервными копиями",
"backup.manager.refresh": "Обновить",
"backup.manager.delete.selected": "Удалить выбранные",
"backup.manager.delete.text": "Удалить",
"backup.manager.restore.text": "Восстановить",
"backup.manager.restore.success": "Восстановление прошло успешно, приложение скоро обновится",
"backup.manager.restore.error": "Ошибка восстановления",
"backup.manager.delete.confirm.title": "Подтверждение удаления",
"backup.manager.delete.confirm.single": "Вы уверены, что хотите удалить резервную копию \"{{fileName}}\"? Это действие нельзя отменить.",
"backup.manager.delete.confirm.multiple": "Вы уверены, что хотите удалить {{count}} выбранных резервных копий? Это действие нельзя отменить.",
"backup.manager.delete.success.single": "Успешно удалено",
"backup.manager.delete.success.multiple": "Успешно удалено {{count}} резервных копий",
"backup.manager.delete.error": "Ошибка удаления",
"backup.manager.fetch.error": "Ошибка получения файлов резервных копий",
"backup.manager.select.files.delete": "Выберите файлы резервных копий для удаления",
"backup.manager.columns.fileName": "Имя файла",
"backup.manager.columns.modifiedTime": "Время изменения",
"backup.manager.columns.size": "Размер",
"backup.manager.columns.actions": "Действия",
"host": "Хост WebDAV",
"host.placeholder": "http://localhost:8080",
"hour_interval_one": "{{count}} час",

View File

@ -881,6 +881,25 @@
"backup.button": "备份到 WebDAV",
"backup.modal.filename.placeholder": "请输入备份文件名",
"backup.modal.title": "备份到 WebDAV",
"backup.manager.title": "备份数据管理",
"backup.manager.refresh": "刷新",
"backup.manager.delete.selected": "删除选中",
"backup.manager.delete.text": "删除",
"backup.manager.restore.text": "恢复",
"backup.manager.restore.success": "恢复成功,应用将在几秒后刷新",
"backup.manager.restore.error": "恢复失败",
"backup.manager.delete.confirm.title": "确认删除",
"backup.manager.delete.confirm.single": "确定要删除备份文件 \"{{fileName}}\" 吗?此操作不可恢复。",
"backup.manager.delete.confirm.multiple": "确定要删除选中的 {{count}} 个备份文件吗?此操作不可恢复。",
"backup.manager.delete.success.single": "删除成功",
"backup.manager.delete.success.multiple": "成功删除 {{count}} 个备份文件",
"backup.manager.delete.error": "删除失败",
"backup.manager.fetch.error": "获取备份文件失败",
"backup.manager.select.files.delete": "请选择要删除的备份文件",
"backup.manager.columns.fileName": "文件名",
"backup.manager.columns.modifiedTime": "修改时间",
"backup.manager.columns.size": "大小",
"backup.manager.columns.actions": "操作",
"host": "WebDAV 地址",
"host.placeholder": "http://localhost:8080",
"hour_interval_one": "{{count}} 小时",

View File

@ -879,6 +879,25 @@
"backup.button": "備份到 WebDAV",
"backup.modal.filename.placeholder": "請輸入備份文件名",
"backup.modal.title": "備份到 WebDAV",
"backup.manager.title": "備份數據管理",
"backup.manager.refresh": "刷新",
"backup.manager.delete.selected": "刪除選中",
"backup.manager.delete.text": "刪除",
"backup.manager.restore.text": "恢復",
"backup.manager.restore.success": "恢復成功,應用將在幾秒後刷新",
"backup.manager.restore.error": "恢復失敗",
"backup.manager.delete.confirm.title": "確認刪除",
"backup.manager.delete.confirm.single": "確定要刪除備份文件 \"{{fileName}}\" 嗎?此操作不可恢復。",
"backup.manager.delete.confirm.multiple": "確定要刪除選中的 {{count}} 個備份文件嗎?此操作不可恢復。",
"backup.manager.delete.success.single": "刪除成功",
"backup.manager.delete.success.multiple": "成功刪除 {{count}} 個備份文件",
"backup.manager.delete.error": "刪除失敗",
"backup.manager.fetch.error": "獲取備份文件失敗",
"backup.manager.select.files.delete": "請選擇要刪除的備份文件",
"backup.manager.columns.fileName": "文件名",
"backup.manager.columns.modifiedTime": "修改時間",
"backup.manager.columns.size": "大小",
"backup.manager.columns.actions": "操作",
"host": "WebDAV 主機位址",
"host.placeholder": "http://localhost:8080",
"hour_interval_one": "{{count}} 小時",

View File

@ -1,12 +1,8 @@
import { CheckOutlined, FolderOutlined, LoadingOutlined, SyncOutlined, WarningOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout'
import NutstorePathPopup from '@renderer/components/Popups/NutsorePathPopup'
import {
useWebdavBackupModal,
useWebdavRestoreModal,
WebdavBackupModal,
WebdavRestoreModal
} from '@renderer/components/WebdavModals'
import { WebdavBackupManager } from '@renderer/components/WebdavBackupManager'
import { useWebdavBackupModal, WebdavBackupModal } from '@renderer/components/WebdavModals'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useNutstoreSSO } from '@renderer/hooks/useNutstoreSSO'
import {
@ -54,6 +50,8 @@ const NutstoreSettings: FC = () => {
const nutstoreSSOHandler = useNutstoreSSO()
const [backupManagerVisible, setBackupManagerVisible] = useState(false)
const handleClickNutstoreSSO = useCallback(async () => {
const ssoUrl = await window.api.nutstore.getSSOUrl()
window.open(ssoUrl, '_blank')
@ -118,24 +116,6 @@ const NutstoreSettings: FC = () => {
backupMethod: backupToNutstore
})
const {
isRestoreModalVisible,
handleRestore,
handleCancel: handleCancelRestore,
restoring,
selectedFile,
setSelectedFile,
loadingFiles,
backupFiles,
showRestoreModal
} = useWebdavRestoreModal({
restoreMethod: restoreFromNutstore,
webdavHost: NUTSTORE_HOST,
webdavUser: nutstoreUsername,
webdavPass: nutstorePass,
webdavPath: storagePath
})
const onSyncIntervalChange = (value: number) => {
setSyncInterval(value)
dispatch(setNutstoreSyncInterval(value))
@ -205,6 +185,14 @@ const NutstoreSettings: FC = () => {
const isLogin = nutstoreToken && nutstoreUsername
const showBackupManager = () => {
setBackupManagerVisible(true)
}
const closeBackupManager = () => {
setBackupManagerVisible(false)
}
return (
<SettingGroup theme={theme}>
<SettingTitle>{t('settings.data.nutstore.title')}</SettingTitle>
@ -269,7 +257,7 @@ const NutstoreSettings: FC = () => {
<Button onClick={showBackupModal} loading={backuping}>
{t('settings.data.nutstore.backup.button')}
</Button>
<Button onClick={showRestoreModal} loading={restoring}>
<Button onClick={showBackupManager} disabled={!nutstoreToken}>
{t('settings.data.nutstore.restore.button')}
</Button>
</HStack>
@ -311,15 +299,16 @@ const NutstoreSettings: FC = () => {
setCustomFileName={setCustomFileName}
/>
<WebdavRestoreModal
isRestoreModalVisible={isRestoreModalVisible}
handleRestore={handleRestore}
handleCancel={handleCancelRestore}
restoring={restoring}
selectedFile={selectedFile}
setSelectedFile={setSelectedFile}
loadingFiles={loadingFiles}
backupFiles={backupFiles}
<WebdavBackupManager
visible={backupManagerVisible}
onClose={closeBackupManager}
webdavConfig={{
webdavHost: NUTSTORE_HOST,
webdavUser: nutstoreUsername,
webdavPass: nutstorePass,
webdavPath: storagePath
}}
restoreMethod={restoreFromNutstore}
/>
</>
</SettingGroup>

View File

@ -1,11 +1,7 @@
import { FolderOpenOutlined, SaveOutlined, SyncOutlined, WarningOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout'
import {
useWebdavBackupModal,
useWebdavRestoreModal,
WebdavBackupModal,
WebdavRestoreModal
} from '@renderer/components/WebdavModals'
import { WebdavBackupManager } from '@renderer/components/WebdavBackupManager'
import { useWebdavBackupModal, WebdavBackupModal } from '@renderer/components/WebdavModals'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useSettings } from '@renderer/hooks/useSettings'
import { startAutoSync, stopAutoSync } from '@renderer/services/BackupService'
@ -38,6 +34,7 @@ const WebDavSettings: FC = () => {
const [webdavUser, setWebdavUser] = useState<string | undefined>(webDAVUser)
const [webdavPass, setWebdavPass] = useState<string | undefined>(webDAVPass)
const [webdavPath, setWebdavPath] = useState<string | undefined>(webDAVPath)
const [backupManagerVisible, setBackupManagerVisible] = useState(false)
const [syncInterval, setSyncInterval] = useState<number>(webDAVSyncInterval)
@ -89,17 +86,13 @@ const WebDavSettings: FC = () => {
const { isModalVisible, handleBackup, handleCancel, backuping, customFileName, setCustomFileName, showBackupModal } =
useWebdavBackupModal()
const {
isRestoreModalVisible,
handleRestore,
handleCancel: handleCancelRestore,
restoring,
selectedFile,
setSelectedFile,
loadingFiles,
backupFiles,
showRestoreModal
} = useWebdavRestoreModal({ webdavHost, webdavUser, webdavPass, webdavPath })
const showBackupManager = () => {
setBackupManagerVisible(true)
}
const closeBackupManager = () => {
setBackupManagerVisible(false)
}
return (
<SettingGroup theme={theme}>
@ -156,7 +149,10 @@ const WebDavSettings: FC = () => {
<Button onClick={showBackupModal} icon={<SaveOutlined />} loading={backuping}>
{t('settings.data.webdav.backup.button')}
</Button>
<Button onClick={showRestoreModal} icon={<FolderOpenOutlined />} loading={restoring}>
<Button
onClick={showBackupManager}
icon={<FolderOpenOutlined />}
disabled={!webdavHost || !webdavUser || !webdavPass || !webdavPath}>
{t('settings.data.webdav.restore.button')}
</Button>
</HStack>
@ -196,15 +192,15 @@ const WebDavSettings: FC = () => {
setCustomFileName={setCustomFileName}
/>
<WebdavRestoreModal
isRestoreModalVisible={isRestoreModalVisible}
handleRestore={handleRestore}
handleCancel={handleCancelRestore}
restoring={restoring}
selectedFile={selectedFile}
setSelectedFile={setSelectedFile}
loadingFiles={loadingFiles}
backupFiles={backupFiles}
<WebdavBackupManager
visible={backupManagerVisible}
onClose={closeBackupManager}
webdavConfig={{
webdavHost,
webdavUser,
webdavPass,
webdavPath
}}
/>
</>
</SettingGroup>