mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-02 02:09:03 +08:00
add autoSync in WebDav
This commit is contained in:
parent
f8fd1f1c5e
commit
8fad34968d
@ -222,6 +222,7 @@
|
|||||||
"assistant.added.content": "Assistant added successfully",
|
"assistant.added.content": "Assistant added successfully",
|
||||||
"backup.failed": "Backup failed",
|
"backup.failed": "Backup failed",
|
||||||
"backup.success": "Backup successful",
|
"backup.success": "Backup successful",
|
||||||
|
"backup.start.success": "Backup started",
|
||||||
"chat.completion.paused": "Chat completion paused",
|
"chat.completion.paused": "Chat completion paused",
|
||||||
"copied": "Copied!",
|
"copied": "Copied!",
|
||||||
"error.enter.api.host": "Please enter your API host first",
|
"error.enter.api.host": "Please enter your API host first",
|
||||||
@ -363,6 +364,8 @@
|
|||||||
"webdav.password": "WebDAV Password",
|
"webdav.password": "WebDAV Password",
|
||||||
"webdav.path": "WebDAV Path",
|
"webdav.path": "WebDAV Path",
|
||||||
"webdav.path.placeholder": "/backup",
|
"webdav.path.placeholder": "/backup",
|
||||||
|
"webdav.autoSync": "Auto Sync",
|
||||||
|
"webdav.minutes": "Minutes",
|
||||||
"webdav.restore.button": "Restore from WebDAV",
|
"webdav.restore.button": "Restore from WebDAV",
|
||||||
"webdav.title": "WebDAV",
|
"webdav.title": "WebDAV",
|
||||||
"webdav.user": "WebDAV User"
|
"webdav.user": "WebDAV User"
|
||||||
|
|||||||
@ -222,6 +222,7 @@
|
|||||||
"assistant.added.content": "Ассистент успешно добавлен",
|
"assistant.added.content": "Ассистент успешно добавлен",
|
||||||
"backup.failed": "Создание резервной копии не удалось",
|
"backup.failed": "Создание резервной копии не удалось",
|
||||||
"backup.success": "Резервная копия успешно создана",
|
"backup.success": "Резервная копия успешно создана",
|
||||||
|
"backup.start.success": "Создание резервной копии начато",
|
||||||
"chat.completion.paused": "Завершение чата приостановлено",
|
"chat.completion.paused": "Завершение чата приостановлено",
|
||||||
"copied": "Скопировано!",
|
"copied": "Скопировано!",
|
||||||
"error.enter.api.host": "Пожалуйста, введите ваш API хост",
|
"error.enter.api.host": "Пожалуйста, введите ваш API хост",
|
||||||
@ -363,6 +364,8 @@
|
|||||||
"webdav.password": "Пароль WebDAV",
|
"webdav.password": "Пароль WebDAV",
|
||||||
"webdav.path": "Путь WebDAV",
|
"webdav.path": "Путь WebDAV",
|
||||||
"webdav.path.placeholder": "/backup",
|
"webdav.path.placeholder": "/backup",
|
||||||
|
"webdav.autoSync": "Автоматическая синхронизация",
|
||||||
|
"webdav.minutes": "минут",
|
||||||
"webdav.restore.button": "Восстановление с WebDAV",
|
"webdav.restore.button": "Восстановление с WebDAV",
|
||||||
"webdav.title": "WebDAV",
|
"webdav.title": "WebDAV",
|
||||||
"webdav.user": "Пользователь WebDAV"
|
"webdav.user": "Пользователь WebDAV"
|
||||||
|
|||||||
@ -222,6 +222,7 @@
|
|||||||
"assistant.added.content": "智能体添加成功",
|
"assistant.added.content": "智能体添加成功",
|
||||||
"backup.failed": "备份失败",
|
"backup.failed": "备份失败",
|
||||||
"backup.success": "备份成功",
|
"backup.success": "备份成功",
|
||||||
|
"backup.start.success": "开始备份",
|
||||||
"chat.completion.paused": "会话已停止",
|
"chat.completion.paused": "会话已停止",
|
||||||
"copied": "已复制",
|
"copied": "已复制",
|
||||||
"error.enter.api.host": "请输入您的 API 地址",
|
"error.enter.api.host": "请输入您的 API 地址",
|
||||||
@ -363,6 +364,8 @@
|
|||||||
"webdav.password": "WebDAV 密码",
|
"webdav.password": "WebDAV 密码",
|
||||||
"webdav.path": "WebDAV 路径",
|
"webdav.path": "WebDAV 路径",
|
||||||
"webdav.path.placeholder": "/backup",
|
"webdav.path.placeholder": "/backup",
|
||||||
|
"webdav.autoSync": "自动同步",
|
||||||
|
"webdav.minutes": "分钟",
|
||||||
"webdav.restore.button": "从 WebDAV 恢复",
|
"webdav.restore.button": "从 WebDAV 恢复",
|
||||||
"webdav.title": "WebDAV",
|
"webdav.title": "WebDAV",
|
||||||
"webdav.user": "WebDAV 用户名"
|
"webdav.user": "WebDAV 用户名"
|
||||||
@ -513,4 +516,4 @@
|
|||||||
"visualization": "可视化"
|
"visualization": "可视化"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,6 +222,7 @@
|
|||||||
"assistant.added.content": "智能體添加成功",
|
"assistant.added.content": "智能體添加成功",
|
||||||
"backup.failed": "備份失敗",
|
"backup.failed": "備份失敗",
|
||||||
"backup.success": "備份成功",
|
"backup.success": "備份成功",
|
||||||
|
"backup.start.success": "開始備份",
|
||||||
"chat.completion.paused": "聊天完成已暫停",
|
"chat.completion.paused": "聊天完成已暫停",
|
||||||
"copied": "已複製",
|
"copied": "已複製",
|
||||||
"error.enter.api.host": "請先輸入您的 API 主機地址",
|
"error.enter.api.host": "請先輸入您的 API 主機地址",
|
||||||
@ -363,6 +364,8 @@
|
|||||||
"webdav.password": "WebDAV 密碼",
|
"webdav.password": "WebDAV 密碼",
|
||||||
"webdav.path": "WebDAV Path",
|
"webdav.path": "WebDAV Path",
|
||||||
"webdav.path.placeholder": "/backup",
|
"webdav.path.placeholder": "/backup",
|
||||||
|
"webdav.autoSync": "自動同步",
|
||||||
|
"webdav.minutes": "分鐘",
|
||||||
"webdav.restore.button": "從 WebDAV 恢復",
|
"webdav.restore.button": "從 WebDAV 恢復",
|
||||||
"webdav.title": "WebDAV",
|
"webdav.title": "WebDAV",
|
||||||
"webdav.user": "WebDAV 使用者名稱"
|
"webdav.user": "WebDAV 使用者名稱"
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
import { FolderOpenOutlined, SaveOutlined } from '@ant-design/icons'
|
import { FolderOpenOutlined, SaveOutlined } from '@ant-design/icons'
|
||||||
import { HStack } from '@renderer/components/Layout'
|
import { HStack } from '@renderer/components/Layout'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { backupToWebdav, restoreFromWebdav } from '@renderer/services/BackupService'
|
import { backupToWebdav, restoreFromWebdav, startAutoSync, stopAutoSync } from '@renderer/services/BackupService'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import {
|
import {
|
||||||
|
setWebdavAutoSync,
|
||||||
setWebdavHost as _setWebdavHost,
|
setWebdavHost as _setWebdavHost,
|
||||||
setWebdavPass as _setWebdavPass,
|
setWebdavPass as _setWebdavPass,
|
||||||
setWebdavPath as _setWebdavPath,
|
setWebdavPath as _setWebdavPath,
|
||||||
|
setWebdavSyncInterval as _setWebdavSyncInterval,
|
||||||
setWebdavUser as _setWebdavUser
|
setWebdavUser as _setWebdavUser
|
||||||
} from '@renderer/store/settings'
|
} from '@renderer/store/settings'
|
||||||
import { Button, Input } from 'antd'
|
import { Button, Input, Select, Switch } from 'antd'
|
||||||
import { FC, useState } from 'react'
|
import { FC, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
@ -20,7 +22,9 @@ const WebDavSettings: FC = () => {
|
|||||||
webdavHost: webDAVHost,
|
webdavHost: webDAVHost,
|
||||||
webdavUser: webDAVUser,
|
webdavUser: webDAVUser,
|
||||||
webdavPass: webDAVPass,
|
webdavPass: webDAVPass,
|
||||||
webdavPath: webDAVPath
|
webdavPath: webDAVPath,
|
||||||
|
webdavAutoSync: webDAVAutoSync,
|
||||||
|
webdavSyncInterval: webDAVSyncInterval
|
||||||
} = useSettings()
|
} = useSettings()
|
||||||
|
|
||||||
const [webdavHost, setWebdavHost] = useState<string | undefined>(webDAVHost)
|
const [webdavHost, setWebdavHost] = useState<string | undefined>(webDAVHost)
|
||||||
@ -28,6 +32,9 @@ const WebDavSettings: FC = () => {
|
|||||||
const [webdavPass, setWebdavPass] = useState<string | undefined>(webDAVPass)
|
const [webdavPass, setWebdavPass] = useState<string | undefined>(webDAVPass)
|
||||||
const [webdavPath, setWebdavPath] = useState<string | undefined>(webDAVPath)
|
const [webdavPath, setWebdavPath] = useState<string | undefined>(webDAVPath)
|
||||||
|
|
||||||
|
const [autoSync, setAutoSync] = useState<boolean>(webDAVAutoSync)
|
||||||
|
const [syncInterval, setSyncInterval] = useState<number>(webDAVSyncInterval)
|
||||||
|
|
||||||
const [backuping, setBackuping] = useState(false)
|
const [backuping, setBackuping] = useState(false)
|
||||||
const [restoring, setRestoring] = useState(false)
|
const [restoring, setRestoring] = useState(false)
|
||||||
|
|
||||||
@ -56,6 +63,19 @@ const WebDavSettings: FC = () => {
|
|||||||
await restoreFromWebdav()
|
await restoreFromWebdav()
|
||||||
setRestoring(false)
|
setRestoring(false)
|
||||||
}
|
}
|
||||||
|
const onToggleAutoSync = (checked: boolean) => {
|
||||||
|
dispatch(setWebdavAutoSync(checked))
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
startAutoSync()
|
||||||
|
} else {
|
||||||
|
stopAutoSync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onSyncIntervalChange = (value: number) => {
|
||||||
|
setSyncInterval(value)
|
||||||
|
dispatch(_setWebdavSyncInterval(value))
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -106,6 +126,32 @@ const WebDavSettings: FC = () => {
|
|||||||
/>
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
|
<SettingRow>
|
||||||
|
<SettingRowTitle>{t('settings.data.webdav.autoSync')}</SettingRowTitle>
|
||||||
|
<HStack gap="10px" alignItems="center">
|
||||||
|
<Switch
|
||||||
|
checked={autoSync}
|
||||||
|
onChange={(checked) => {
|
||||||
|
setAutoSync(checked)
|
||||||
|
onToggleAutoSync(checked)
|
||||||
|
}}
|
||||||
|
disabled={!webdavHost}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
value={syncInterval}
|
||||||
|
onChange={onSyncIntervalChange}
|
||||||
|
disabled={!webdavHost || !autoSync}
|
||||||
|
style={{ width: 120 }}>
|
||||||
|
<Select.Option value={1}>1 {t('settings.data.webdav.minutes')}</Select.Option>
|
||||||
|
<Select.Option value={5}>5 {t('settings.data.webdav.minutes')}</Select.Option>
|
||||||
|
<Select.Option value={15}>15 {t('settings.data.webdav.minutes')}</Select.Option>
|
||||||
|
<Select.Option value={30}>30 {t('settings.data.webdav.minutes')}</Select.Option>
|
||||||
|
<Select.Option value={60}>60 {t('settings.data.webdav.minutes')}</Select.Option>
|
||||||
|
<Select.Option value={120}>120 {t('settings.data.webdav.minutes')}</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</HStack>
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitle>{t('settings.general.backup.title')}</SettingRowTitle>
|
<SettingRowTitle>{t('settings.general.backup.title')}</SettingRowTitle>
|
||||||
<HStack gap="5px" justifyContent="space-between">
|
<HStack gap="5px" justifyContent="space-between">
|
||||||
|
|||||||
@ -108,6 +108,49 @@ export async function restoreFromWebdav() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let syncInterval: NodeJS.Timeout | null = null
|
||||||
|
export function startAutoSync() {
|
||||||
|
const { webdavAutoSync, webdavHost, webdavSyncInterval } = store.getState().settings
|
||||||
|
|
||||||
|
if (syncInterval) {
|
||||||
|
stopAutoSync()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webdavAutoSync && webdavHost) {
|
||||||
|
console.log('[AutoSync] Starting auto sync with interval:', webdavSyncInterval, 'minutes')
|
||||||
|
|
||||||
|
const performBackup = async () => {
|
||||||
|
try {
|
||||||
|
console.log('[AutoSync] Performing backup...')
|
||||||
|
await backupToWebdav()
|
||||||
|
window.message.success({
|
||||||
|
content: i18n.t('message.backup.start.success'),
|
||||||
|
key: 'webdav-sync'
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[AutoSync] Backup failed:', error)
|
||||||
|
window.message.error({
|
||||||
|
content: i18n.t('message.backup.failed'),
|
||||||
|
key: 'webdav-sync'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
performBackup()
|
||||||
|
|
||||||
|
syncInterval = setInterval(performBackup, webdavSyncInterval * 60 * 1000)
|
||||||
|
console.log('[AutoSync] Sync interval set up:', syncInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopAutoSync() {
|
||||||
|
if (syncInterval) {
|
||||||
|
console.log('[AutoSync] Stopping auto sync')
|
||||||
|
clearInterval(syncInterval)
|
||||||
|
syncInterval = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getBackupData() {
|
async function getBackupData() {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
time: new Date().getTime(),
|
time: new Date().getTime(),
|
||||||
|
|||||||
@ -36,6 +36,8 @@ export interface SettingsState {
|
|||||||
webdavUser: string
|
webdavUser: string
|
||||||
webdavPass: string
|
webdavPass: string
|
||||||
webdavPath: string
|
webdavPath: string
|
||||||
|
webdavAutoSync: boolean
|
||||||
|
webdavSyncInterval: number
|
||||||
translateModelPrompt: string
|
translateModelPrompt: string
|
||||||
autoTranslateWithSpace: boolean
|
autoTranslateWithSpace: boolean
|
||||||
enableTopicNaming: boolean
|
enableTopicNaming: boolean
|
||||||
@ -75,6 +77,8 @@ const initialState: SettingsState = {
|
|||||||
webdavUser: '',
|
webdavUser: '',
|
||||||
webdavPass: '',
|
webdavPass: '',
|
||||||
webdavPath: '/cherry-studio',
|
webdavPath: '/cherry-studio',
|
||||||
|
webdavAutoSync: false,
|
||||||
|
webdavSyncInterval: 5,
|
||||||
translateModelPrompt: TRANSLATE_PROMPT,
|
translateModelPrompt: TRANSLATE_PROMPT,
|
||||||
autoTranslateWithSpace: false,
|
autoTranslateWithSpace: false,
|
||||||
enableTopicNaming: true,
|
enableTopicNaming: true,
|
||||||
@ -165,6 +169,12 @@ const settingsSlice = createSlice({
|
|||||||
setWebdavPath: (state, action: PayloadAction<string>) => {
|
setWebdavPath: (state, action: PayloadAction<string>) => {
|
||||||
state.webdavPath = action.payload
|
state.webdavPath = action.payload
|
||||||
},
|
},
|
||||||
|
setWebdavAutoSync: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.webdavAutoSync = action.payload
|
||||||
|
},
|
||||||
|
setWebdavSyncInterval: (state, action: PayloadAction<number>) => {
|
||||||
|
state.webdavSyncInterval = action.payload
|
||||||
|
},
|
||||||
setCodeShowLineNumbers: (state, action: PayloadAction<boolean>) => {
|
setCodeShowLineNumbers: (state, action: PayloadAction<boolean>) => {
|
||||||
state.codeShowLineNumbers = action.payload
|
state.codeShowLineNumbers = action.payload
|
||||||
},
|
},
|
||||||
@ -228,6 +238,8 @@ export const {
|
|||||||
setWebdavUser,
|
setWebdavUser,
|
||||||
setWebdavPass,
|
setWebdavPass,
|
||||||
setWebdavPath,
|
setWebdavPath,
|
||||||
|
setWebdavAutoSync,
|
||||||
|
setWebdavSyncInterval,
|
||||||
setCodeShowLineNumbers,
|
setCodeShowLineNumbers,
|
||||||
setCodeCollapsible,
|
setCodeCollapsible,
|
||||||
setMathEngine,
|
setMathEngine,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user