feat: add data settings

This commit is contained in:
kangfenmao 2024-10-15 18:56:09 +08:00
parent 303a0e20a0
commit 90fec317e5
8 changed files with 267 additions and 238 deletions

View File

@ -188,6 +188,7 @@
"settings": {
"title": "Settings",
"general": "General Settings",
"data": "Data Settings",
"provider": "Model Provider",
"model": "Default Model",
"assistant": "Default Assistant",
@ -208,15 +209,15 @@
"general.backup.button": "Backup",
"general.restore.button": "Restore",
"general.view_webdav_settings": "View WebDAV settings",
"general.webdav.title": "WebDAV",
"general.webdav.host": "WebDAV Host",
"general.webdav.host.placeholder": "http://localhost:8080",
"general.webdav.user": "WebDAV User",
"general.webdav.password": "WebDAV Password",
"general.webdav.path": "WebDAV Path",
"general.webdav.path.placeholder": "/backup",
"general.webdav.backup.button": "Backup to WebDAV",
"general.webdav.restore.button": "Restore from WebDAV",
"data.webdav.title": "WebDAV",
"data.webdav.host": "WebDAV Host",
"data.webdav.host.placeholder": "http://localhost:8080",
"data.webdav.user": "WebDAV User",
"data.webdav.password": "WebDAV Password",
"data.webdav.path": "WebDAV Path",
"data.webdav.path.placeholder": "/backup",
"data.webdav.backup.button": "Backup to WebDAV",
"data.webdav.restore.button": "Restore from WebDAV",
"general.reset.title": "Data Reset",
"general.reset.button": "Reset",
"general.check_update_setting": "Check for updates",

View File

@ -188,6 +188,7 @@
"settings": {
"title": "设置",
"general": "常规设置",
"data": "数据设置",
"provider": "模型服务",
"model": "默认模型",
"assistant": "默认助手",
@ -210,15 +211,15 @@
"general.reset.title": "重置数据",
"general.reset.button": "重置",
"general.view_webdav_settings": "查看 WebDAV 设置",
"general.webdav.title": "WebDAV",
"general.webdav.host": "WebDAV 地址",
"general.webdav.host.placeholder": "http://localhost:8080",
"general.webdav.user": "WebDAV 用户名",
"general.webdav.password": "WebDAV 密码",
"general.webdav.path": "WebDAV 路径",
"general.webdav.path.placeholder": "/backup",
"general.webdav.backup.button": "备份到 WebDAV",
"general.webdav.restore.button": "从 WebDAV 恢复",
"data.webdav.title": "WebDAV",
"data.webdav.host": "WebDAV 地址",
"data.webdav.host.placeholder": "http://localhost:8080",
"data.webdav.user": "WebDAV 用户名",
"data.webdav.password": "WebDAV 密码",
"data.webdav.path": "WebDAV 路径",
"data.webdav.path.placeholder": "/backup",
"data.webdav.backup.button": "备份到 WebDAV",
"data.webdav.restore.button": "从 WebDAV 恢复",
"general.check_update_setting": "更新设置",
"general.manual_update_check": "手动检查更新",
"general.auto_update_check": "自动检查更新",

View File

@ -188,6 +188,7 @@
"settings": {
"title": "設定",
"general": "一般設定",
"data": "數據設定",
"provider": "模型提供者",
"model": "預設模型",
"assistant": "預設助手",
@ -208,15 +209,15 @@
"general.backup.button": "備份",
"general.restore.button": "復原",
"general.view_webdav_settings": "查看 WebDAV 設定",
"general.webdav.title": "WebDAV",
"general.webdav.host": "WebDAV 主機位址",
"general.webdav.host.placeholder": "http://localhost:8080",
"general.webdav.user": "WebDAV 使用者名稱",
"general.webdav.password": "WebDAV 密碼",
"general.webdav.path": "WebDAV Path",
"general.webdav.path.placeholder": "/backup",
"general.webdav.backup.button": "從 WebDAV 備份",
"general.webdav.restore.button": "從 WebDAV 恢復",
"data.webdav.title": "WebDAV",
"data.webdav.host": "WebDAV 主機位址",
"data.webdav.host.placeholder": "http://localhost:8080",
"data.webdav.user": "WebDAV 使用者名稱",
"data.webdav.password": "WebDAV 密碼",
"data.webdav.path": "WebDAV Path",
"data.webdav.path.placeholder": "/backup",
"data.webdav.backup.button": "從 WebDAV 備份",
"data.webdav.restore.button": "從 WebDAV 恢復",
"general.reset.title": "資料重置",
"general.reset.button": "重置",
"general.check_update_setting": "更新設定",

View File

@ -0,0 +1,61 @@
import { FolderOpenOutlined, SaveOutlined } from '@ant-design/icons'
import { HStack, VStack } from '@renderer/components/Layout'
import { backup, reset, restore } from '@renderer/services/backup'
import { Button } from 'antd'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { Link, Route, Routes } from 'react-router-dom'
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from '..'
import WebDavSettings from './WebDavSettings'
const DataSettings: FC = () => {
const { t } = useTranslation()
return (
<Routes>
<Route
path="/"
element={
<SettingContainer>
<SettingTitle>{t('settings.data')}</SettingTitle>
<SettingDivider />
<SettingRow style={{ minHeight: 32 }}>
<SettingRowTitle>{t('settings.data.webdav.title')}</SettingRowTitle>
<VStack gap="5px">
<Link to="/settings/data/webdav" style={{ color: 'var(--color-text-2)' }}>
{t('settings.general.view_webdav_settings')}
</Link>
</VStack>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.backup.title')}</SettingRowTitle>
<HStack gap="5px" justifyContent="space-between">
<Button onClick={backup} icon={<SaveOutlined />}>
{t('settings.general.backup.button')}
</Button>
<Button onClick={restore} icon={<FolderOpenOutlined />}>
{t('settings.general.restore.button')}
</Button>
</HStack>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.reset.title')}</SettingRowTitle>
<HStack gap="5px">
<Button onClick={reset} danger>
{t('settings.general.reset.button')}
</Button>
</HStack>
</SettingRow>
<SettingDivider />
</SettingContainer>
}
/>
<Route path="webdav" element={<WebDavSettings />} />
</Routes>
)
}
export default DataSettings

View File

@ -62,20 +62,20 @@ const WebDavSettings: FC = () => {
<Breadcrumb
items={[
{
title: t('settings.general.title'),
href: '#/settings/general'
title: t('settings.data'),
href: '#/settings/data'
},
{
title: t('settings.general.webdav.title')
title: t('settings.data.webdav.title')
}
]}
/>
<SettingTitle style={{ marginTop: 20 }}>{t('settings.general.webdav.title')}</SettingTitle>
<SettingTitle style={{ marginTop: 20 }}>{t('settings.data.webdav.title')}</SettingTitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.webdav.host')}</SettingRowTitle>
<SettingRowTitle>{t('settings.data.webdav.host')}</SettingRowTitle>
<Input
placeholder={t('settings.general.webdav.host.placeholder')}
placeholder={t('settings.data.webdav.host.placeholder')}
value={webdavHost}
onChange={(e) => setWebdavHost(e.target.value)}
style={{ width: 250 }}
@ -85,9 +85,9 @@ const WebDavSettings: FC = () => {
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.webdav.user')}</SettingRowTitle>
<SettingRowTitle>{t('settings.data.webdav.user')}</SettingRowTitle>
<Input
placeholder={t('settings.general.webdav.user')}
placeholder={t('settings.data.webdav.user')}
value={webdavUser}
onChange={(e) => setWebdavUser(e.target.value)}
style={{ width: 250 }}
@ -96,9 +96,9 @@ const WebDavSettings: FC = () => {
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.webdav.password')}</SettingRowTitle>
<SettingRowTitle>{t('settings.data.webdav.password')}</SettingRowTitle>
<Input.Password
placeholder={t('settings.general.webdav.password')}
placeholder={t('settings.data.webdav.password')}
value={webdavPass}
onChange={(e) => setWebdavPass(e.target.value)}
style={{ width: 250 }}
@ -107,9 +107,9 @@ const WebDavSettings: FC = () => {
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.webdav.path')}</SettingRowTitle>
<SettingRowTitle>{t('settings.data.webdav.path')}</SettingRowTitle>
<Input
placeholder={t('settings.general.webdav.path.placeholder')}
placeholder={t('settings.data.webdav.path.placeholder')}
value={webdavPath}
onChange={(e) => setWebdavPath(e.target.value)}
style={{ width: 250 }}
@ -122,10 +122,10 @@ const WebDavSettings: FC = () => {
<HStack gap="5px" justifyContent="space-between">
{/* 添加 在线备份 在线还原 按钮 */}
<Button onClick={onBackup} icon={<SaveOutlined />} loading={backuping}>
{t('settings.general.webdav.backup.button')}
{t('settings.data.webdav.backup.button')}
</Button>
<Button onClick={onRestore} icon={<FolderOpenOutlined />} loading={restoring}>
{t('settings.general.webdav.restore.button')}
{t('settings.data.webdav.restore.button')}
</Button>
</HStack>
</SettingRow>

View File

@ -0,0 +1,152 @@
import { isMac } from '@renderer/config/constant'
import { useSettings } from '@renderer/hooks/useSettings'
import i18n from '@renderer/i18n'
import { useAppDispatch } from '@renderer/store'
import { setClickAssistantToShowTopic, setLanguage, setManualUpdateCheck } from '@renderer/store/settings'
import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings'
import { ThemeMode } from '@renderer/types'
import { isValidProxyUrl } from '@renderer/utils'
import { Input, Select, Switch } from 'antd'
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from '.'
const GeneralSettings: FC = () => {
const {
language,
proxyUrl: storeProxyUrl,
theme,
windowStyle,
topicPosition,
clickAssistantToShowTopic,
manualUpdateCheck,
setTheme,
setWindowStyle,
setTopicPosition
} = useSettings()
const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl)
const dispatch = useAppDispatch()
const { t } = useTranslation()
const onSelectLanguage = (value: string) => {
dispatch(setLanguage(value))
localStorage.setItem('language', value)
i18n.changeLanguage(value)
}
const onSetProxyUrl = () => {
if (proxyUrl && !isValidProxyUrl(proxyUrl)) {
window.message.error({ content: t('message.error.invalid.proxy.url'), key: 'proxy-error' })
return
}
dispatch(_setProxyUrl(proxyUrl))
window.api.setProxy(proxyUrl)
}
return (
<SettingContainer>
<SettingTitle>{t('settings.general.title')}</SettingTitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('common.language')}</SettingRowTitle>
<Select
defaultValue={language || 'en-US'}
style={{ width: 180 }}
onChange={onSelectLanguage}
options={[
{ value: 'zh-CN', label: '中文' },
{ value: 'zh-TW', label: '中文(繁体)' },
{ value: 'en-US', label: 'English' }
]}
/>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.theme.title')}</SettingRowTitle>
<Select
defaultValue={theme}
style={{ width: 180 }}
onChange={setTheme}
options={[
{ value: ThemeMode.light, label: t('settings.theme.light') },
{ value: ThemeMode.dark, label: t('settings.theme.dark') },
{ value: ThemeMode.auto, label: t('settings.theme.auto') }
]}
/>
</SettingRow>
{isMac && (
<>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.theme.window.style.title')}</SettingRowTitle>
<Select
defaultValue={windowStyle || 'opaque'}
style={{ width: 180 }}
onChange={setWindowStyle}
options={[
{ value: 'transparent', label: t('settings.theme.window.style.transparent') },
{ value: 'opaque', label: t('settings.theme.window.style.opaque') }
]}
/>
</SettingRow>
</>
)}
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.check_update_setting')}</SettingRowTitle>
<Select
defaultValue={manualUpdateCheck ?? false}
style={{ width: 180 }}
onChange={(v) => dispatch(setManualUpdateCheck(v))}
options={[
{ value: false, label: t('settings.general.auto_update_check') },
{ value: true, label: t('settings.general.manual_update_check') }
]}
/>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.proxy.title')}</SettingRowTitle>
<Input
placeholder="socks5://127.0.0.1:6153"
value={proxyUrl}
onChange={(e) => setProxyUrl(e.target.value)}
style={{ width: 180 }}
onBlur={() => onSetProxyUrl()}
type="url"
/>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.topic.position')}</SettingRowTitle>
<Select
defaultValue={topicPosition || 'right'}
style={{ width: 180 }}
onChange={setTopicPosition}
options={[
{ value: 'left', label: t('settings.topic.position.left') },
{ value: 'right', label: t('settings.topic.position.right') }
]}
/>
</SettingRow>
<SettingDivider />
{topicPosition === 'left' && (
<>
<SettingRow style={{ minHeight: 32 }}>
<SettingRowTitle>{t('settings.advanced.click_assistant_switch_to_topics')}</SettingRowTitle>
<Switch
checked={clickAssistantToShowTopic}
onChange={(checked) => dispatch(setClickAssistantToShowTopic(checked))}
/>
</SettingRow>
<SettingDivider />
</>
)}
</SettingContainer>
)
}
export default GeneralSettings

View File

@ -1,195 +0,0 @@
import { FolderOpenOutlined, SaveOutlined } from '@ant-design/icons'
import { HStack, VStack } from '@renderer/components/Layout'
import { isMac } from '@renderer/config/constant'
import { useSettings } from '@renderer/hooks/useSettings'
import i18n from '@renderer/i18n'
import { backup, reset, restore } from '@renderer/services/backup'
import { useAppDispatch } from '@renderer/store'
import { setClickAssistantToShowTopic, setLanguage, setManualUpdateCheck } from '@renderer/store/settings'
import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings'
import { ThemeMode } from '@renderer/types'
import { isValidProxyUrl } from '@renderer/utils'
import { Button, Input, Select, Switch } from 'antd'
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Link, Route, Routes } from 'react-router-dom'
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from '..'
import WebDavSettings from './WebDavSettings'
const GeneralSettings: FC = () => {
const {
language,
proxyUrl: storeProxyUrl,
theme,
windowStyle,
topicPosition,
clickAssistantToShowTopic,
manualUpdateCheck,
setTheme,
setWindowStyle,
setTopicPosition
} = useSettings()
const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl)
const dispatch = useAppDispatch()
const { t } = useTranslation()
const onSelectLanguage = (value: string) => {
dispatch(setLanguage(value))
localStorage.setItem('language', value)
i18n.changeLanguage(value)
}
const onSetProxyUrl = () => {
if (proxyUrl && !isValidProxyUrl(proxyUrl)) {
window.message.error({ content: t('message.error.invalid.proxy.url'), key: 'proxy-error' })
return
}
dispatch(_setProxyUrl(proxyUrl))
window.api.setProxy(proxyUrl)
}
return (
<Routes>
<Route
path="/"
element={
<SettingContainer>
<SettingTitle>{t('settings.general.title')}</SettingTitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('common.language')}</SettingRowTitle>
<Select
defaultValue={language || 'en-US'}
style={{ width: 180 }}
onChange={onSelectLanguage}
options={[
{ value: 'zh-CN', label: '中文' },
{ value: 'zh-TW', label: '中文(繁体)' },
{ value: 'en-US', label: 'English' }
]}
/>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.theme.title')}</SettingRowTitle>
<Select
defaultValue={theme}
style={{ width: 180 }}
onChange={setTheme}
options={[
{ value: ThemeMode.light, label: t('settings.theme.light') },
{ value: ThemeMode.dark, label: t('settings.theme.dark') },
{ value: ThemeMode.auto, label: t('settings.theme.auto') }
]}
/>
</SettingRow>
{isMac && (
<>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.theme.window.style.title')}</SettingRowTitle>
<Select
defaultValue={windowStyle || 'opaque'}
style={{ width: 180 }}
onChange={setWindowStyle}
options={[
{ value: 'transparent', label: t('settings.theme.window.style.transparent') },
{ value: 'opaque', label: t('settings.theme.window.style.opaque') }
]}
/>
</SettingRow>
</>
)}
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.topic.position')}</SettingRowTitle>
<Select
defaultValue={topicPosition || 'right'}
style={{ width: 180 }}
onChange={setTopicPosition}
options={[
{ value: 'left', label: t('settings.topic.position.left') },
{ value: 'right', label: t('settings.topic.position.right') }
]}
/>
</SettingRow>
<SettingDivider />
{topicPosition === 'left' && (
<>
<SettingRow style={{ minHeight: 32 }}>
<SettingRowTitle>{t('settings.advanced.click_assistant_switch_to_topics')}</SettingRowTitle>
<Switch
checked={clickAssistantToShowTopic}
onChange={(checked) => dispatch(setClickAssistantToShowTopic(checked))}
/>
</SettingRow>
<SettingDivider />
</>
)}
<SettingRow>
<SettingRowTitle>{t('settings.general.check_update_setting')}</SettingRowTitle>
<Select
defaultValue={manualUpdateCheck ?? false}
style={{ width: 180 }}
onChange={(v) => dispatch(setManualUpdateCheck(v))}
options={[
{ value: false, label: t('settings.general.auto_update_check') },
{ value: true, label: t('settings.general.manual_update_check') }
]}
/>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.proxy.title')}</SettingRowTitle>
<Input
placeholder="socks5://127.0.0.1:6153"
value={proxyUrl}
onChange={(e) => setProxyUrl(e.target.value)}
style={{ width: 180 }}
onBlur={() => onSetProxyUrl()}
type="url"
/>
</SettingRow>
<SettingDivider />
<SettingRow style={{ minHeight: 32 }}>
<SettingRowTitle>{t('settings.general.webdav.title')}</SettingRowTitle>
<VStack gap="5px">
<Link to="/settings/general/webdav" style={{ color: 'var(--color-text-2)' }}>
{t('settings.general.view_webdav_settings')}
</Link>
</VStack>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.backup.title')}</SettingRowTitle>
<HStack gap="5px" justifyContent="space-between">
<Button onClick={backup} icon={<SaveOutlined />}>
{t('settings.general.backup.button')}
</Button>
<Button onClick={restore} icon={<FolderOpenOutlined />}>
{t('settings.general.restore.button')}
</Button>
</HStack>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.reset.title')}</SettingRowTitle>
<HStack gap="5px">
<Button onClick={reset} danger>
{t('settings.general.reset.button')}
</Button>
</HStack>
</SettingRow>
<SettingDivider />
</SettingContainer>
}
/>
<Route path="webdav" element={<WebDavSettings />} />
</Routes>
)
}
export default GeneralSettings

View File

@ -1,4 +1,4 @@
import { CloudOutlined, InfoCircleOutlined, MessageOutlined, SettingOutlined } from '@ant-design/icons'
import { CloudOutlined, InfoCircleOutlined, MessageOutlined, SaveOutlined, SettingOutlined } from '@ant-design/icons'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import { isLocalAi } from '@renderer/config/env'
import { FC } from 'react'
@ -8,7 +8,8 @@ import styled from 'styled-components'
import AboutSettings from './AboutSettings'
import AssistantSettings from './AssistantSettings'
import GeneralSettings from './GeneralSettings/GeneralSettings'
import DataSettings from './DataSettings/DataSettings'
import GeneralSettings from './GeneralSettings'
import ModelSettings from './ModelSettings'
import ProvidersList from './ProviderSettings'
@ -53,6 +54,12 @@ const SettingsPage: FC = () => {
{t('settings.general')}
</MenuItem>
</MenuItemLink>
<MenuItemLink to="/settings/data">
<MenuItem className={isRoute('/settings/data')}>
<SaveOutlined />
{t('settings.data')}
</MenuItem>
</MenuItemLink>
<MenuItemLink to="/settings/about">
<MenuItem className={isRoute('/settings/about')}>
<InfoCircleOutlined />
@ -66,6 +73,7 @@ const SettingsPage: FC = () => {
<Route path="model" element={<ModelSettings />} />
<Route path="assistant" element={<AssistantSettings />} />
<Route path="general/*" element={<GeneralSettings />} />
<Route path="data/*" element={<DataSettings />} />
<Route path="about" element={<AboutSettings />} />
</Routes>
</SettingContent>