mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-08 14:29:15 +08:00
211 lines
8.0 KiB
TypeScript
211 lines
8.0 KiB
TypeScript
import { FolderOpenOutlined, SaveOutlined, SyncOutlined, WarningOutlined } from '@ant-design/icons'
|
||
import { HStack } from '@renderer/components/Layout'
|
||
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'
|
||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||
import {
|
||
setWebdavAutoSync,
|
||
setWebdavHost as _setWebdavHost,
|
||
setWebdavPass as _setWebdavPass,
|
||
setWebdavPath as _setWebdavPath,
|
||
setWebdavSyncInterval as _setWebdavSyncInterval,
|
||
setWebdavUser as _setWebdavUser
|
||
} from '@renderer/store/settings'
|
||
import { Button, Input, Select, Tooltip } from 'antd'
|
||
import dayjs from 'dayjs'
|
||
import { FC, useState } from 'react'
|
||
import { useTranslation } from 'react-i18next'
|
||
|
||
import { SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '..'
|
||
|
||
const WebDavSettings: FC = () => {
|
||
const {
|
||
webdavHost: webDAVHost,
|
||
webdavUser: webDAVUser,
|
||
webdavPass: webDAVPass,
|
||
webdavPath: webDAVPath,
|
||
webdavSyncInterval: webDAVSyncInterval
|
||
} = useSettings()
|
||
|
||
const [webdavHost, setWebdavHost] = useState<string | undefined>(webDAVHost)
|
||
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)
|
||
|
||
const dispatch = useAppDispatch()
|
||
const { theme } = useTheme()
|
||
|
||
const { t } = useTranslation()
|
||
|
||
const { webdavSync } = useAppSelector((state) => state.backup)
|
||
|
||
// 把之前备份的文件定时上传到 webdav,首先先配置 webdav 的 host, port, user, pass, path
|
||
|
||
const onSyncIntervalChange = (value: number) => {
|
||
setSyncInterval(value)
|
||
dispatch(_setWebdavSyncInterval(value))
|
||
if (value === 0) {
|
||
dispatch(setWebdavAutoSync(false))
|
||
stopAutoSync()
|
||
} else {
|
||
dispatch(setWebdavAutoSync(true))
|
||
startAutoSync()
|
||
}
|
||
}
|
||
|
||
const renderSyncStatus = () => {
|
||
if (!webdavHost) return null
|
||
|
||
if (!webdavSync.lastSyncTime && !webdavSync.syncing && !webdavSync.lastSyncError) {
|
||
return <span style={{ color: 'var(--text-secondary)' }}>{t('settings.data.webdav.noSync')}</span>
|
||
}
|
||
|
||
return (
|
||
<HStack gap="5px" alignItems="center">
|
||
{webdavSync.syncing && <SyncOutlined spin />}
|
||
{!webdavSync.syncing && webdavSync.lastSyncError && (
|
||
<Tooltip title={`${t('settings.data.webdav.syncError')}: ${webdavSync.lastSyncError}`}>
|
||
<WarningOutlined style={{ color: 'red' }} />
|
||
</Tooltip>
|
||
)}
|
||
{webdavSync.lastSyncTime && (
|
||
<span style={{ color: 'var(--text-secondary)' }}>
|
||
{t('settings.data.webdav.lastSync')}: {dayjs(webdavSync.lastSyncTime).format('HH:mm:ss')}
|
||
</span>
|
||
)}
|
||
</HStack>
|
||
)
|
||
}
|
||
|
||
const { isModalVisible, handleBackup, handleCancel, backuping, customFileName, setCustomFileName, showBackupModal } =
|
||
useWebdavBackupModal()
|
||
|
||
const showBackupManager = () => {
|
||
setBackupManagerVisible(true)
|
||
}
|
||
|
||
const closeBackupManager = () => {
|
||
setBackupManagerVisible(false)
|
||
}
|
||
|
||
return (
|
||
<SettingGroup theme={theme}>
|
||
<SettingTitle>{t('settings.data.webdav.title')}</SettingTitle>
|
||
<SettingDivider />
|
||
<SettingRow>
|
||
<SettingRowTitle>{t('settings.data.webdav.host')}</SettingRowTitle>
|
||
<Input
|
||
placeholder={t('settings.data.webdav.host.placeholder')}
|
||
value={webdavHost}
|
||
onChange={(e) => setWebdavHost(e.target.value)}
|
||
style={{ width: 250 }}
|
||
type="url"
|
||
onBlur={() => dispatch(_setWebdavHost(webdavHost || ''))}
|
||
/>
|
||
</SettingRow>
|
||
<SettingDivider />
|
||
<SettingRow>
|
||
<SettingRowTitle>{t('settings.data.webdav.user')}</SettingRowTitle>
|
||
<Input
|
||
placeholder={t('settings.data.webdav.user')}
|
||
value={webdavUser}
|
||
onChange={(e) => setWebdavUser(e.target.value)}
|
||
style={{ width: 250 }}
|
||
onBlur={() => dispatch(_setWebdavUser(webdavUser || ''))}
|
||
/>
|
||
</SettingRow>
|
||
<SettingDivider />
|
||
<SettingRow>
|
||
<SettingRowTitle>{t('settings.data.webdav.password')}</SettingRowTitle>
|
||
<Input.Password
|
||
placeholder={t('settings.data.webdav.password')}
|
||
value={webdavPass}
|
||
onChange={(e) => setWebdavPass(e.target.value)}
|
||
style={{ width: 250 }}
|
||
onBlur={() => dispatch(_setWebdavPass(webdavPass || ''))}
|
||
/>
|
||
</SettingRow>
|
||
<SettingDivider />
|
||
<SettingRow>
|
||
<SettingRowTitle>{t('settings.data.webdav.path')}</SettingRowTitle>
|
||
<Input
|
||
placeholder={t('settings.data.webdav.path.placeholder')}
|
||
value={webdavPath}
|
||
onChange={(e) => setWebdavPath(e.target.value)}
|
||
style={{ width: 250 }}
|
||
onBlur={() => dispatch(_setWebdavPath(webdavPath || ''))}
|
||
/>
|
||
</SettingRow>
|
||
<SettingDivider />
|
||
<SettingRow>
|
||
<SettingRowTitle>{t('settings.general.backup.title')}</SettingRowTitle>
|
||
<HStack gap="5px" justifyContent="space-between">
|
||
<Button onClick={showBackupModal} icon={<SaveOutlined />} loading={backuping}>
|
||
{t('settings.data.webdav.backup.button')}
|
||
</Button>
|
||
<Button
|
||
onClick={showBackupManager}
|
||
icon={<FolderOpenOutlined />}
|
||
disabled={!webdavHost || !webdavUser || !webdavPass || !webdavPath}>
|
||
{t('settings.data.webdav.restore.button')}
|
||
</Button>
|
||
</HStack>
|
||
</SettingRow>
|
||
<SettingDivider />
|
||
<SettingRow>
|
||
<SettingRowTitle>{t('settings.data.webdav.autoSync')}</SettingRowTitle>
|
||
<Select value={syncInterval} onChange={onSyncIntervalChange} disabled={!webdavHost} style={{ width: 120 }}>
|
||
<Select.Option value={0}>{t('settings.data.webdav.autoSync.off')}</Select.Option>
|
||
<Select.Option value={1}>{t('settings.data.webdav.minute_interval', { count: 1 })}</Select.Option>
|
||
<Select.Option value={5}>{t('settings.data.webdav.minute_interval', { count: 5 })}</Select.Option>
|
||
<Select.Option value={15}>{t('settings.data.webdav.minute_interval', { count: 15 })}</Select.Option>
|
||
<Select.Option value={30}>{t('settings.data.webdav.minute_interval', { count: 30 })}</Select.Option>
|
||
<Select.Option value={60}>{t('settings.data.webdav.hour_interval', { count: 1 })}</Select.Option>
|
||
<Select.Option value={120}>{t('settings.data.webdav.hour_interval', { count: 2 })}</Select.Option>
|
||
<Select.Option value={360}>{t('settings.data.webdav.hour_interval', { count: 6 })}</Select.Option>
|
||
<Select.Option value={720}>{t('settings.data.webdav.hour_interval', { count: 12 })}</Select.Option>
|
||
<Select.Option value={1440}>{t('settings.data.webdav.hour_interval', { count: 24 })}</Select.Option>
|
||
</Select>
|
||
</SettingRow>
|
||
{webdavSync && syncInterval > 0 && (
|
||
<>
|
||
<SettingDivider />
|
||
<SettingRow>
|
||
<SettingRowTitle>{t('settings.data.webdav.syncStatus')}</SettingRowTitle>
|
||
{renderSyncStatus()}
|
||
</SettingRow>
|
||
</>
|
||
)}
|
||
<>
|
||
<WebdavBackupModal
|
||
isModalVisible={isModalVisible}
|
||
handleBackup={handleBackup}
|
||
handleCancel={handleCancel}
|
||
backuping={backuping}
|
||
customFileName={customFileName}
|
||
setCustomFileName={setCustomFileName}
|
||
/>
|
||
|
||
<WebdavBackupManager
|
||
visible={backupManagerVisible}
|
||
onClose={closeBackupManager}
|
||
webdavConfig={{
|
||
webdavHost,
|
||
webdavUser,
|
||
webdavPass,
|
||
webdavPath
|
||
}}
|
||
/>
|
||
</>
|
||
</SettingGroup>
|
||
)
|
||
}
|
||
|
||
export default WebDavSettings
|