refactor: update UpgradeChannel handling and improve preference integration

- Commented out the UpgradeChannel enum in constant.ts and moved it to preferenceTypes.ts for better organization.
- Updated various components to utilize the new UpgradeChannel type from preferenceTypes, enhancing type safety and consistency.
- Refactored preference handling across multiple files to streamline the use of the usePreference hook, replacing previous settings references.
- Cleaned up unused code and comments related to previous settings for improved maintainability.
- Updated auto-generated preference mappings to reflect recent changes in preference structure.
This commit is contained in:
fullex 2025-09-03 14:31:15 +08:00
parent 1b57ffeb56
commit 68cd87e069
20 changed files with 241 additions and 262 deletions

View File

@ -197,11 +197,11 @@ export enum FeedUrl {
GITHUB_LATEST = 'https://github.com/CherryHQ/cherry-studio/releases/latest/download' GITHUB_LATEST = 'https://github.com/CherryHQ/cherry-studio/releases/latest/download'
} }
export enum UpgradeChannel { // export enum UpgradeChannel {
LATEST = 'latest', // 最新稳定版本 // LATEST = 'latest', // 最新稳定版本
RC = 'rc', // 公测版本 // RC = 'rc', // 公测版本
BETA = 'beta' // 预览版本 // BETA = 'beta' // 预览版本
} // }
export const defaultTimeout = 10 * 1000 * 60 export const defaultTimeout = 10 * 1000 * 60

View File

@ -59,3 +59,9 @@ export type AssistantIconType = 'model' | 'emoji' | 'none'
export type ProxyMode = 'system' | 'custom' | 'none' export type ProxyMode = 'system' | 'custom' | 'none'
export type MultiModelFoldDisplayMode = 'expanded' | 'compact' export type MultiModelFoldDisplayMode = 'expanded' | 'compact'
export enum UpgradeChannel {
LATEST = 'latest', // 最新稳定版本
RC = 'rc', // 公测版本
BETA = 'beta' // 预览版本
}

View File

@ -1,6 +1,6 @@
/** /**
* Auto-generated preferences configuration * Auto-generated preferences configuration
* Generated at: 2025-09-02T11:59:32.955Z * Generated at: 2025-09-03T04:46:03.708Z
* *
* This file is automatically generated from classification.json * This file is automatically generated from classification.json
* To update this file, modify classification.json and run: * To update this file, modify classification.json and run:
@ -22,7 +22,7 @@ import type {
SidebarIcon, SidebarIcon,
WindowStyle WindowStyle
} from '@shared/data/preferenceTypes' } from '@shared/data/preferenceTypes'
import { LanguageVarious, ThemeMode } from '@shared/data/preferenceTypes' import { LanguageVarious, ThemeMode, UpgradeChannel } from '@shared/data/preferenceTypes'
/* eslint @typescript-eslint/member-ordering: ["error", { /* eslint @typescript-eslint/member-ordering: ["error", {
"interfaces": { "order": "alphabetically" }, "interfaces": { "order": "alphabetically" },
@ -38,7 +38,7 @@ export interface PreferencesType {
// redux/settings/autoCheckUpdate // redux/settings/autoCheckUpdate
'app.dist.auto_update.enabled': boolean 'app.dist.auto_update.enabled': boolean
// redux/settings/testChannel // redux/settings/testChannel
'app.dist.test_plan.channel': string 'app.dist.test_plan.channel': UpgradeChannel
// redux/settings/testPlan // redux/settings/testPlan
'app.dist.test_plan.enabled': boolean 'app.dist.test_plan.enabled': boolean
// redux/settings/language // redux/settings/language
@ -180,17 +180,17 @@ export interface PreferencesType {
// redux/settings/localBackupSyncInterval // redux/settings/localBackupSyncInterval
'data.backup.local.sync_interval': number 'data.backup.local.sync_interval': number
// redux/nutstore/nutstoreAutoSync // redux/nutstore/nutstoreAutoSync
'data.backup.nutstore.auto_sync': boolean | null 'data.backup.nutstore.auto_sync': boolean
// redux/nutstore/nutstoreMaxBackups
'data.backup.nutstore.max_backups': number
// redux/nutstore/nutstorePath // redux/nutstore/nutstorePath
'data.backup.nutstore.path': string | null 'data.backup.nutstore.path': string
// redux/nutstore/nutstoreSkipBackupFile // redux/nutstore/nutstoreSkipBackupFile
'data.backup.nutstore.skip_backup_file': boolean | null 'data.backup.nutstore.skip_backup_file': boolean
// redux/nutstore/nutstoreSyncInterval // redux/nutstore/nutstoreSyncInterval
'data.backup.nutstore.sync_interval': number | null 'data.backup.nutstore.sync_interval': number
// redux/nutstore/nutstoreSyncState
'data.backup.nutstore.sync_state': Record<string, unknown> | null
// redux/nutstore/nutstoreToken // redux/nutstore/nutstoreToken
'data.backup.nutstore.token': string | null 'data.backup.nutstore.token': string
// redux/settings/s3.accessKeyId // redux/settings/s3.accessKeyId
'data.backup.s3.access_key_id': string 'data.backup.s3.access_key_id': string
// redux/settings/s3.autoSync // redux/settings/s3.autoSync
@ -278,7 +278,7 @@ export interface PreferencesType {
// redux/settings/notionPageNameKey // redux/settings/notionPageNameKey
'data.integration.notion.page_name_key': string 'data.integration.notion.page_name_key': string
// redux/settings/defaultObsidianVault // redux/settings/defaultObsidianVault
'data.integration.obsidian.default_vault': string | null 'data.integration.obsidian.default_vault': string
// redux/settings/siyuanApiUrl // redux/settings/siyuanApiUrl
'data.integration.siyuan.api_url': string | null 'data.integration.siyuan.api_url': string | null
// redux/settings/siyuanBoxId // redux/settings/siyuanBoxId
@ -408,7 +408,7 @@ export const DefaultPreferences: PreferencesType = {
'app.developer_mode.enabled': false, 'app.developer_mode.enabled': false,
'app.disable_hardware_acceleration': false, 'app.disable_hardware_acceleration': false,
'app.dist.auto_update.enabled': true, 'app.dist.auto_update.enabled': true,
'app.dist.test_plan.channel': 'UpgradeChannel.LATEST', 'app.dist.test_plan.channel': UpgradeChannel.LATEST,
'app.dist.test_plan.enabled': false, 'app.dist.test_plan.enabled': false,
'app.language': null, 'app.language': null,
'app.launch_on_boot': false, 'app.launch_on_boot': false,
@ -479,12 +479,12 @@ export const DefaultPreferences: PreferencesType = {
'data.backup.local.max_backups': 0, 'data.backup.local.max_backups': 0,
'data.backup.local.skip_backup_file': false, 'data.backup.local.skip_backup_file': false,
'data.backup.local.sync_interval': 0, 'data.backup.local.sync_interval': 0,
'data.backup.nutstore.auto_sync': null, 'data.backup.nutstore.auto_sync': false,
'data.backup.nutstore.path': null, 'data.backup.nutstore.max_backups': 0,
'data.backup.nutstore.skip_backup_file': null, 'data.backup.nutstore.path': '/cherry-studio',
'data.backup.nutstore.sync_interval': null, 'data.backup.nutstore.skip_backup_file': false,
'data.backup.nutstore.sync_state': null, 'data.backup.nutstore.sync_interval': 0,
'data.backup.nutstore.token': null, 'data.backup.nutstore.token': '',
'data.backup.s3.access_key_id': '', 'data.backup.s3.access_key_id': '',
'data.backup.s3.auto_sync': false, 'data.backup.s3.auto_sync': false,
'data.backup.s3.bucket': '', 'data.backup.s3.bucket': '',
@ -528,7 +528,7 @@ export const DefaultPreferences: PreferencesType = {
'data.integration.notion.database_id': '', 'data.integration.notion.database_id': '',
'data.integration.notion.export_reasoning': false, 'data.integration.notion.export_reasoning': false,
'data.integration.notion.page_name_key': 'Name', 'data.integration.notion.page_name_key': 'Name',
'data.integration.obsidian.default_vault': null, 'data.integration.obsidian.default_vault': '',
'data.integration.siyuan.api_url': null, 'data.integration.siyuan.api_url': null,
'data.integration.siyuan.box_id': null, 'data.integration.siyuan.box_id': null,
'data.integration.siyuan.root_path': null, 'data.integration.siyuan.root_path': null,

View File

@ -157,6 +157,8 @@ if (!app.requestSingleInstanceLock()) {
return return
} }
// DATA REFACTOR USE
// TODO: remove when data refactor is stable
//************FOR TESTING ONLY START****************/ //************FOR TESTING ONLY START****************/
await preferenceService.initialize() await preferenceService.initialize()
@ -177,7 +179,7 @@ if (!app.requestSingleInstanceLock()) {
electronApp.setAppUserModelId(import.meta.env.VITE_MAIN_BUNDLE_ID || 'com.kangfenmao.CherryStudio') electronApp.setAppUserModelId(import.meta.env.VITE_MAIN_BUNDLE_ID || 'com.kangfenmao.CherryStudio')
// Mac: Hide dock icon before window creation when launch to tray is set // Mac: Hide dock icon before window creation when launch to tray is set
const isLaunchToTray = configManager.getLaunchToTray() const isLaunchToTray = preferenceService.get('app.tray.on_launch')
if (isLaunchToTray) { if (isLaunchToTray) {
app.dock?.hide() app.dock?.hide()
} }

View File

@ -3,13 +3,15 @@ import { arch } from 'node:os'
import path from 'node:path' import path from 'node:path'
import { PreferenceService } from '@data/PreferenceService' import { PreferenceService } from '@data/PreferenceService'
import { preferenceService } from '@data/PreferenceService'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { isLinux, isMac, isPortable, isWin } from '@main/constant' import { isLinux, isMac, isPortable, isWin } from '@main/constant'
import { generateSignature } from '@main/integration/cherryin' import { generateSignature } from '@main/integration/cherryin'
import { getBinaryPath, isBinaryExists, runInstallScript } from '@main/utils/process' import { getBinaryPath, isBinaryExists, runInstallScript } from '@main/utils/process'
import { handleZoomFactor } from '@main/utils/zoom' import { handleZoomFactor } from '@main/utils/zoom'
import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core' import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core'
import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, UpgradeChannel } from '@shared/config/constant' import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH } from '@shared/config/constant'
import { UpgradeChannel } from '@shared/data/preferenceTypes'
import { IpcChannel } from '@shared/IpcChannel' import { IpcChannel } from '@shared/IpcChannel'
import { FileMetadata, Provider, Shortcut } from '@types' import { FileMetadata, Provider, Shortcut } from '@types'
import { BrowserWindow, dialog, ipcMain, ProxyConfig, session, shell, systemPreferences, webContents } from 'electron' import { BrowserWindow, dialog, ipcMain, ProxyConfig, session, shell, systemPreferences, webContents } from 'electron'
@ -159,40 +161,38 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
appService.setAppLaunchOnBoot(isLaunchOnBoot) appService.setAppLaunchOnBoot(isLaunchOnBoot)
}) })
// launch to tray // // launch to tray
ipcMain.handle(IpcChannel.App_SetLaunchToTray, (_, isActive: boolean) => { // ipcMain.handle(IpcChannel.App_SetLaunchToTray, (_, isActive: boolean) => {
configManager.setLaunchToTray(isActive) // configManager.setLaunchToTray(isActive)
}) // })
// tray // // tray
ipcMain.handle(IpcChannel.App_SetTray, (_, isActive: boolean) => { // ipcMain.handle(IpcChannel.App_SetTray, (_, isActive: boolean) => {
configManager.setTray(isActive) // configManager.setTray(isActive)
}) // })
// to tray on close // // to tray on close
ipcMain.handle(IpcChannel.App_SetTrayOnClose, (_, isActive: boolean) => { // ipcMain.handle(IpcChannel.App_SetTrayOnClose, (_, isActive: boolean) => {
configManager.setTrayOnClose(isActive) // configManager.setTrayOnClose(isActive)
}) // })
// auto update // // auto update
ipcMain.handle(IpcChannel.App_SetAutoUpdate, (_, isActive: boolean) => { // ipcMain.handle(IpcChannel.App_SetAutoUpdate, (_, isActive: boolean) => {
appUpdater.setAutoUpdate(isActive) // appUpdater.setAutoUpdate(isActive)
configManager.setAutoUpdate(isActive) // configManager.setAutoUpdate(isActive)
}) // })
ipcMain.handle(IpcChannel.App_SetTestPlan, async (_, isActive: boolean) => { ipcMain.handle(IpcChannel.App_SetTestPlan, async (_, isActive: boolean) => {
logger.info(`set test plan: ${isActive}`) logger.info(`set test plan: ${isActive}`)
if (isActive !== configManager.getTestPlan()) { if (isActive !== preferenceService.get('app.dist.test_plan.enabled')) {
appUpdater.cancelDownload() appUpdater.cancelDownload()
configManager.setTestPlan(isActive)
} }
}) })
ipcMain.handle(IpcChannel.App_SetTestChannel, async (_, channel: UpgradeChannel) => { ipcMain.handle(IpcChannel.App_SetTestChannel, async (_, channel: UpgradeChannel) => {
logger.info(`set test channel: ${channel}`) logger.info(`set test channel: ${channel}`)
if (channel !== configManager.getTestChannel()) { if (channel !== preferenceService.get('app.dist.test_plan.channel')) {
appUpdater.cancelDownload() appUpdater.cancelDownload()
configManager.setTestChannel(channel)
} }
}) })

View File

@ -1,9 +1,11 @@
import { preferenceService } from '@data/PreferenceService'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { isWin } from '@main/constant' import { isWin } from '@main/constant'
import { getIpCountry } from '@main/utils/ipService' import { getIpCountry } from '@main/utils/ipService'
import { getI18n } from '@main/utils/language' import { getI18n } from '@main/utils/language'
import { generateUserAgent } from '@main/utils/systemInfo' import { generateUserAgent } from '@main/utils/systemInfo'
import { FeedUrl, UpgradeChannel } from '@shared/config/constant' import { FeedUrl } from '@shared/config/constant'
import { UpgradeChannel } from '@shared/data/preferenceTypes'
import { IpcChannel } from '@shared/IpcChannel' import { IpcChannel } from '@shared/IpcChannel'
import { CancellationToken, UpdateInfo } from 'builder-util-runtime' import { CancellationToken, UpdateInfo } from 'builder-util-runtime'
import { app, BrowserWindow, dialog, net } from 'electron' import { app, BrowserWindow, dialog, net } from 'electron'
@ -12,7 +14,6 @@ import path from 'path'
import semver from 'semver' import semver from 'semver'
import icon from '../../../build/icon.png?asset' import icon from '../../../build/icon.png?asset'
import { configManager } from './ConfigManager'
import { windowService } from './WindowService' import { windowService } from './WindowService'
const logger = loggerService.withContext('AppUpdater') const logger = loggerService.withContext('AppUpdater')
@ -26,8 +27,8 @@ export default class AppUpdater {
constructor() { constructor() {
autoUpdater.logger = logger as Logger autoUpdater.logger = logger as Logger
autoUpdater.forceDevUpdateConfig = !app.isPackaged autoUpdater.forceDevUpdateConfig = !app.isPackaged
autoUpdater.autoDownload = configManager.getAutoUpdate() autoUpdater.autoDownload = preferenceService.get('app.dist.auto_update.enabled')
autoUpdater.autoInstallOnAppQuit = configManager.getAutoUpdate() autoUpdater.autoInstallOnAppQuit = preferenceService.get('app.dist.auto_update.enabled')
autoUpdater.requestHeaders = { autoUpdater.requestHeaders = {
...autoUpdater.requestHeaders, ...autoUpdater.requestHeaders,
'User-Agent': generateUserAgent() 'User-Agent': generateUserAgent()
@ -139,7 +140,7 @@ export default class AppUpdater {
private _getTestChannel() { private _getTestChannel() {
const currentChannel = this._getChannelByVersion(app.getVersion()) const currentChannel = this._getChannelByVersion(app.getVersion())
const savedChannel = configManager.getTestChannel() const savedChannel = preferenceService.get('app.dist.test_plan.channel')
if (currentChannel === UpgradeChannel.LATEST) { if (currentChannel === UpgradeChannel.LATEST) {
return savedChannel || UpgradeChannel.RC return savedChannel || UpgradeChannel.RC
@ -164,7 +165,7 @@ export default class AppUpdater {
} }
private async _setFeedUrl() { private async _setFeedUrl() {
const testPlan = configManager.getTestPlan() const testPlan = preferenceService.get('app.dist.test_plan.enabled')
if (testPlan) { if (testPlan) {
const channel = this._getTestChannel() const channel = this._getTestChannel()

View File

@ -1,4 +1,4 @@
import { UpgradeChannel, ZOOM_SHORTCUTS } from '@shared/config/constant' import { ZOOM_SHORTCUTS } from '@shared/config/constant'
import { Shortcut } from '@types' import { Shortcut } from '@types'
import Store from 'electron-store' import Store from 'electron-store'
@ -52,29 +52,29 @@ export class ConfigManager {
// this.set(ConfigKeys.Theme, theme) // this.set(ConfigKeys.Theme, theme)
// } // }
getLaunchToTray(): boolean { // getLaunchToTray(): boolean {
return !!this.get(ConfigKeys.LaunchToTray, false) // return !!this.get(ConfigKeys.LaunchToTray, false)
} // }
setLaunchToTray(value: boolean) { // setLaunchToTray(value: boolean) {
this.set(ConfigKeys.LaunchToTray, value) // this.set(ConfigKeys.LaunchToTray, value)
} // }
getTray(): boolean { // getTray(): boolean {
return !!this.get(ConfigKeys.Tray, true) // return !!this.get(ConfigKeys.Tray, true)
} // }
setTray(value: boolean) { // setTray(value: boolean) {
this.setAndNotify(ConfigKeys.Tray, value) // this.setAndNotify(ConfigKeys.Tray, value)
} // }
getTrayOnClose(): boolean { // getTrayOnClose(): boolean {
return !!this.get(ConfigKeys.TrayOnClose, true) // return !!this.get(ConfigKeys.TrayOnClose, true)
} // }
setTrayOnClose(value: boolean) { // setTrayOnClose(value: boolean) {
this.set(ConfigKeys.TrayOnClose, value) // this.set(ConfigKeys.TrayOnClose, value)
} // }
getZoomFactor(): number { getZoomFactor(): number {
return this.get<number>(ConfigKeys.ZoomFactor, 1) return this.get<number>(ConfigKeys.ZoomFactor, 1)
@ -119,104 +119,104 @@ export class ConfigManager {
) )
} }
getClickTrayToShowQuickAssistant(): boolean { // getClickTrayToShowQuickAssistant(): boolean {
return this.get<boolean>(ConfigKeys.ClickTrayToShowQuickAssistant, false) // return this.get<boolean>(ConfigKeys.ClickTrayToShowQuickAssistant, false)
} // }
setClickTrayToShowQuickAssistant(value: boolean) { // setClickTrayToShowQuickAssistant(value: boolean) {
this.set(ConfigKeys.ClickTrayToShowQuickAssistant, value) // this.set(ConfigKeys.ClickTrayToShowQuickAssistant, value)
} // }
getEnableQuickAssistant(): boolean { // getEnableQuickAssistant(): boolean {
return this.get(ConfigKeys.EnableQuickAssistant, false) // return this.get(ConfigKeys.EnableQuickAssistant, false)
} // }
setEnableQuickAssistant(value: boolean) { // setEnableQuickAssistant(value: boolean) {
this.setAndNotify(ConfigKeys.EnableQuickAssistant, value) // this.setAndNotify(ConfigKeys.EnableQuickAssistant, value)
} // }
getAutoUpdate(): boolean { // getAutoUpdate(): boolean {
return this.get<boolean>(ConfigKeys.AutoUpdate, true) // return this.get<boolean>(ConfigKeys.AutoUpdate, true)
} // }
setAutoUpdate(value: boolean) { // setAutoUpdate(value: boolean) {
this.set(ConfigKeys.AutoUpdate, value) // this.set(ConfigKeys.AutoUpdate, value)
} // }
getTestPlan(): boolean { // getTestPlan(): boolean {
return this.get<boolean>(ConfigKeys.TestPlan, false) // return this.get<boolean>(ConfigKeys.TestPlan, false)
} // }
setTestPlan(value: boolean) { // setTestPlan(value: boolean) {
this.set(ConfigKeys.TestPlan, value) // this.set(ConfigKeys.TestPlan, value)
} // }
getTestChannel(): UpgradeChannel { // getTestChannel(): UpgradeChannel {
return this.get<UpgradeChannel>(ConfigKeys.TestChannel) // return this.get<UpgradeChannel>(ConfigKeys.TestChannel)
} // }
setTestChannel(value: UpgradeChannel) { // setTestChannel(value: UpgradeChannel) {
this.set(ConfigKeys.TestChannel, value) // this.set(ConfigKeys.TestChannel, value)
} // }
getEnableDataCollection(): boolean { // getEnableDataCollection(): boolean {
return this.get<boolean>(ConfigKeys.EnableDataCollection, true) // return this.get<boolean>(ConfigKeys.EnableDataCollection, true)
} // }
setEnableDataCollection(value: boolean) { // setEnableDataCollection(value: boolean) {
this.set(ConfigKeys.EnableDataCollection, value) // this.set(ConfigKeys.EnableDataCollection, value)
} // }
// Selection Assistant: is enabled the selection assistant // // Selection Assistant: is enabled the selection assistant
getSelectionAssistantEnabled(): boolean { // getSelectionAssistantEnabled(): boolean {
return this.get<boolean>(ConfigKeys.SelectionAssistantEnabled, false) // return this.get<boolean>(ConfigKeys.SelectionAssistantEnabled, false)
} // }
setSelectionAssistantEnabled(value: boolean) { // setSelectionAssistantEnabled(value: boolean) {
this.setAndNotify(ConfigKeys.SelectionAssistantEnabled, value) // this.setAndNotify(ConfigKeys.SelectionAssistantEnabled, value)
} // }
// Selection Assistant: trigger mode (selected, ctrlkey) // // Selection Assistant: trigger mode (selected, ctrlkey)
getSelectionAssistantTriggerMode(): string { // getSelectionAssistantTriggerMode(): string {
return this.get<string>(ConfigKeys.SelectionAssistantTriggerMode, 'selected') // return this.get<string>(ConfigKeys.SelectionAssistantTriggerMode, 'selected')
} // }
setSelectionAssistantTriggerMode(value: string) { // setSelectionAssistantTriggerMode(value: string) {
this.setAndNotify(ConfigKeys.SelectionAssistantTriggerMode, value) // this.setAndNotify(ConfigKeys.SelectionAssistantTriggerMode, value)
} // }
// Selection Assistant: if action window position follow toolbar // // Selection Assistant: if action window position follow toolbar
getSelectionAssistantFollowToolbar(): boolean { // getSelectionAssistantFollowToolbar(): boolean {
return this.get<boolean>(ConfigKeys.SelectionAssistantFollowToolbar, true) // return this.get<boolean>(ConfigKeys.SelectionAssistantFollowToolbar, true)
} // }
setSelectionAssistantFollowToolbar(value: boolean) { // setSelectionAssistantFollowToolbar(value: boolean) {
this.setAndNotify(ConfigKeys.SelectionAssistantFollowToolbar, value) // this.setAndNotify(ConfigKeys.SelectionAssistantFollowToolbar, value)
} // }
getSelectionAssistantRemeberWinSize(): boolean { // getSelectionAssistantRemeberWinSize(): boolean {
return this.get<boolean>(ConfigKeys.SelectionAssistantRemeberWinSize, false) // return this.get<boolean>(ConfigKeys.SelectionAssistantRemeberWinSize, false)
} // }
setSelectionAssistantRemeberWinSize(value: boolean) { // setSelectionAssistantRemeberWinSize(value: boolean) {
this.setAndNotify(ConfigKeys.SelectionAssistantRemeberWinSize, value) // this.setAndNotify(ConfigKeys.SelectionAssistantRemeberWinSize, value)
} // }
getSelectionAssistantFilterMode(): string { // getSelectionAssistantFilterMode(): string {
return this.get<string>(ConfigKeys.SelectionAssistantFilterMode, 'default') // return this.get<string>(ConfigKeys.SelectionAssistantFilterMode, 'default')
} // }
setSelectionAssistantFilterMode(value: string) { // setSelectionAssistantFilterMode(value: string) {
this.setAndNotify(ConfigKeys.SelectionAssistantFilterMode, value) // this.setAndNotify(ConfigKeys.SelectionAssistantFilterMode, value)
} // }
getSelectionAssistantFilterList(): string[] { // getSelectionAssistantFilterList(): string[] {
return this.get<string[]>(ConfigKeys.SelectionAssistantFilterList, []) // return this.get<string[]>(ConfigKeys.SelectionAssistantFilterList, [])
} // }
setSelectionAssistantFilterList(value: string[]) { // setSelectionAssistantFilterList(value: string[]) {
this.setAndNotify(ConfigKeys.SelectionAssistantFilterList, value) // this.setAndNotify(ConfigKeys.SelectionAssistantFilterList, value)
} // }
getDisableHardwareAcceleration(): boolean { getDisableHardwareAcceleration(): boolean {
return this.get<boolean>(ConfigKeys.DisableHardwareAcceleration, false) return this.get<boolean>(ConfigKeys.DisableHardwareAcceleration, false)
@ -230,13 +230,13 @@ export class ConfigManager {
this.set(key, value, true) this.set(key, value, true)
} }
getEnableDeveloperMode(): boolean { // getEnableDeveloperMode(): boolean {
return this.get<boolean>(ConfigKeys.EnableDeveloperMode, false) // return this.get<boolean>(ConfigKeys.EnableDeveloperMode, false)
} // }
setEnableDeveloperMode(value: boolean) { // setEnableDeveloperMode(value: boolean) {
this.set(ConfigKeys.EnableDeveloperMode, value) // this.set(ConfigKeys.EnableDeveloperMode, value)
} // }
set(key: string, value: unknown, isNotify: boolean = false) { set(key: string, value: unknown, isNotify: boolean = false) {
this.store.set(key, value) this.store.set(key, value)

View File

@ -1,3 +1,4 @@
import { preferenceService } from '@data/PreferenceService'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { handleZoomFactor } from '@main/utils/zoom' import { handleZoomFactor } from '@main/utils/zoom'
import { Shortcut } from '@types' import { Shortcut } from '@types'
@ -6,7 +7,6 @@ import { BrowserWindow, globalShortcut } from 'electron'
import { configManager } from './ConfigManager' import { configManager } from './ConfigManager'
import selectionService from './SelectionService' import selectionService from './SelectionService'
import { windowService } from './WindowService' import { windowService } from './WindowService'
const logger = loggerService.withContext('ShortcutService') const logger = loggerService.withContext('ShortcutService')
let showAppAccelerator: string | null = null let showAppAccelerator: string | null = null
@ -137,7 +137,7 @@ const convertShortcutFormat = (shortcut: string | string[]): string => {
export function registerShortcuts(window: BrowserWindow) { export function registerShortcuts(window: BrowserWindow) {
if (isRegisterOnBoot) { if (isRegisterOnBoot) {
window.once('ready-to-show', () => { window.once('ready-to-show', () => {
if (configManager.getLaunchToTray()) { if (preferenceService.get('app.tray.on_launch')) {
registerOnlyUniversalShortcuts() registerOnlyUniversalShortcuts()
} }
}) })
@ -190,7 +190,7 @@ export function registerShortcuts(window: BrowserWindow) {
case 'mini_window': case 'mini_window':
//available only when QuickAssistant enabled //available only when QuickAssistant enabled
if (!configManager.getEnableQuickAssistant()) { if (!preferenceService.get('feature.quick_assistant.enabled')) {
return return
} }
showMiniWindowAccelerator = formatShortcutKey(shortcut.shortcut) showMiniWindowAccelerator = formatShortcutKey(shortcut.shortcut)

View File

@ -1,3 +1,4 @@
import { preferenceService } from '@data/PreferenceService'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { Attributes, convertSpanToSpanEntity, SpanEntity, TokenUsage, TraceCache } from '@mcp-trace/trace-core' import { Attributes, convertSpanToSpanEntity, SpanEntity, TokenUsage, TraceCache } from '@mcp-trace/trace-core'
import { SpanStatusCode } from '@opentelemetry/api' import { SpanStatusCode } from '@opentelemetry/api'
@ -6,8 +7,6 @@ import fs from 'fs/promises'
import * as os from 'os' import * as os from 'os'
import * as path from 'path' import * as path from 'path'
import { configManager } from './ConfigManager'
const logger = loggerService.withContext('SpanCacheService') const logger = loggerService.withContext('SpanCacheService')
class SpanCacheService implements TraceCache { class SpanCacheService implements TraceCache {
@ -21,7 +20,7 @@ class SpanCacheService implements TraceCache {
} }
createSpan: (span: ReadableSpan) => void = (span: ReadableSpan) => { createSpan: (span: ReadableSpan) => void = (span: ReadableSpan) => {
if (!configManager.getEnableDeveloperMode()) { if (!preferenceService.get('app.developer_mode.enabled')) {
return return
} }
const spanEntity = convertSpanToSpanEntity(span) const spanEntity = convertSpanToSpanEntity(span)
@ -31,7 +30,7 @@ class SpanCacheService implements TraceCache {
} }
endSpan: (span: ReadableSpan) => void = (span: ReadableSpan) => { endSpan: (span: ReadableSpan) => void = (span: ReadableSpan) => {
if (!configManager.getEnableDeveloperMode()) { if (!preferenceService.get('app.developer_mode.enabled')) {
return return
} }
const spanId = span.spanContext().spanId const spanId = span.spanContext().spanId
@ -87,7 +86,7 @@ class SpanCacheService implements TraceCache {
} }
async saveSpans(topicId: string) { async saveSpans(topicId: string) {
if (!configManager.getEnableDeveloperMode()) { if (!preferenceService.get('app.developer_mode.enabled')) {
return return
} }
let traceId: string | undefined let traceId: string | undefined
@ -138,7 +137,7 @@ class SpanCacheService implements TraceCache {
} }
saveEntity(entity: SpanEntity) { saveEntity(entity: SpanEntity) {
if (!configManager.getEnableDeveloperMode()) { if (!preferenceService.get('app.developer_mode.enabled')) {
return return
} }
if (this.cache.has(entity.id)) { if (this.cache.has(entity.id)) {

View File

@ -1,6 +1,7 @@
// just import the themeService to ensure the theme is initialized // just import the themeService to ensure the theme is initialized
import './ThemeService' import './ThemeService'
import { preferenceService } from '@data/PreferenceService'
import { is } from '@electron-toolkit/utils' import { is } from '@electron-toolkit/utils'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { isDev, isLinux, isMac, isWin } from '@main/constant' import { isDev, isLinux, isMac, isWin } from '@main/constant'
@ -86,7 +87,7 @@ export class WindowService {
this.setupMainWindow(this.mainWindow, mainWindowState) this.setupMainWindow(this.mainWindow, mainWindowState)
//preload miniWindow to resolve series of issues about miniWindow in Mac //preload miniWindow to resolve series of issues about miniWindow in Mac
const enableQuickAssistant = configManager.getEnableQuickAssistant() const enableQuickAssistant = preferenceService.get('feature.quick_assistant.enabled')
if (enableQuickAssistant && !this.miniWindow) { if (enableQuickAssistant && !this.miniWindow) {
this.miniWindow = this.createMiniWindow(true) this.miniWindow = this.createMiniWindow(true)
} }
@ -141,7 +142,7 @@ export class WindowService {
private setupMaximize(mainWindow: BrowserWindow, isMaximized: boolean) { private setupMaximize(mainWindow: BrowserWindow, isMaximized: boolean) {
if (isMaximized) { if (isMaximized) {
// 如果是从托盘启动,则需要延迟最大化,否则显示的就不是重启前的最大化窗口了 // 如果是从托盘启动,则需要延迟最大化,否则显示的就不是重启前的最大化窗口了
configManager.getLaunchToTray() preferenceService.get('app.tray.on_launch')
? mainWindow.once('show', () => { ? mainWindow.once('show', () => {
mainWindow.maximize() mainWindow.maximize()
}) })
@ -169,7 +170,7 @@ export class WindowService {
mainWindow.webContents.setZoomFactor(configManager.getZoomFactor()) mainWindow.webContents.setZoomFactor(configManager.getZoomFactor())
// show window only when laucn to tray not set // show window only when laucn to tray not set
const isLaunchToTray = configManager.getLaunchToTray() const isLaunchToTray = preferenceService.get('app.tray.on_launch')
if (!isLaunchToTray) { if (!isLaunchToTray) {
//[mac]hacky-fix: miniWindow set visibleOnFullScreen:true will cause dock icon disappeared //[mac]hacky-fix: miniWindow set visibleOnFullScreen:true will cause dock icon disappeared
app.dock?.show() app.dock?.show()
@ -342,8 +343,8 @@ export class WindowService {
} }
// 托盘及关闭行为设置 // 托盘及关闭行为设置
const isShowTray = configManager.getTray() const isShowTray = preferenceService.get('app.tray.enabled')
const isTrayOnClose = configManager.getTrayOnClose() const isTrayOnClose = preferenceService.get('app.tray.on_close')
// 没有开启托盘,或者开启了托盘,但设置了直接关闭,应执行直接退出 // 没有开启托盘,或者开启了托盘,但设置了直接关闭,应执行直接退出
if (!isShowTray || (isShowTray && !isTrayOnClose)) { if (!isShowTray || (isShowTray && !isTrayOnClose)) {
@ -444,7 +445,7 @@ export class WindowService {
if (this.mainWindow && !this.mainWindow.isDestroyed() && this.mainWindow.isVisible()) { if (this.mainWindow && !this.mainWindow.isDestroyed() && this.mainWindow.isVisible()) {
if (this.mainWindow.isFocused()) { if (this.mainWindow.isFocused()) {
// if tray is enabled, hide the main window, else do nothing // if tray is enabled, hide the main window, else do nothing
if (configManager.getTray()) { if (preferenceService.get('app.tray.on_close')) {
this.mainWindow.hide() this.mainWindow.hide()
app.dock?.hide() app.dock?.hide()
} }
@ -547,7 +548,7 @@ export class WindowService {
} }
public showMiniWindow() { public showMiniWindow() {
const enableQuickAssistant = configManager.getEnableQuickAssistant() const enableQuickAssistant = preferenceService.get('feature.quick_assistant.enabled')
if (!enableQuickAssistant) { if (!enableQuickAssistant) {
return return

View File

@ -2,10 +2,10 @@ import type { ExtractChunkData } from '@cherrystudio/embedjs-interfaces'
import { electronAPI } from '@electron-toolkit/preload' import { electronAPI } from '@electron-toolkit/preload'
import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core' import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core'
import { SpanContext } from '@opentelemetry/api' import { SpanContext } from '@opentelemetry/api'
import { UpgradeChannel } from '@shared/config/constant'
import type { LogLevel, LogSourceWithContext } from '@shared/config/logger' import type { LogLevel, LogSourceWithContext } from '@shared/config/logger'
import type { FileChangeEvent } from '@shared/config/types' import type { FileChangeEvent } from '@shared/config/types'
import type { PreferenceDefaultScopeType, PreferenceKeyType, SelectionActionItem } from '@shared/data/preferenceTypes' import type { PreferenceDefaultScopeType, PreferenceKeyType, SelectionActionItem } from '@shared/data/preferenceTypes'
import { UpgradeChannel } from '@shared/data/preferenceTypes'
import { IpcChannel } from '@shared/IpcChannel' import { IpcChannel } from '@shared/IpcChannel'
import { import {
AddMemoryOptions, AddMemoryOptions,

View File

@ -10,7 +10,7 @@ import i18n from '@renderer/i18n'
import { handleSaveData, useAppDispatch } from '@renderer/store' import { handleSaveData, useAppDispatch } from '@renderer/store'
import { setUpdateState } from '@renderer/store/runtime' import { setUpdateState } from '@renderer/store/runtime'
import { runAsyncFunction } from '@renderer/utils' import { runAsyncFunction } from '@renderer/utils'
import { UpgradeChannel } from '@shared/config/constant' import { UpgradeChannel } from '@shared/data/preferenceTypes'
import { ThemeMode } from '@shared/data/preferenceTypes' import { ThemeMode } from '@shared/data/preferenceTypes'
import { Avatar, Button, Progress, Radio, Row, Switch, Tag, Tooltip } from 'antd' import { Avatar, Button, Progress, Radio, Row, Switch, Tag, Tooltip } from 'antd'
import { debounce } from 'lodash' import { debounce } from 'lodash'

View File

@ -5,6 +5,7 @@ import {
LoadingOutlined, LoadingOutlined,
YuqueOutlined YuqueOutlined
} from '@ant-design/icons' } from '@ant-design/icons'
import { usePreference } from '@data/hooks/usePreference'
import DividerWithText from '@renderer/components/DividerWithText' import DividerWithText from '@renderer/components/DividerWithText'
import { NutstoreIcon } from '@renderer/components/Icons/NutstoreIcons' import { NutstoreIcon } from '@renderer/components/Icons/NutstoreIcons'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
@ -15,8 +16,6 @@ import { useTheme } from '@renderer/context/ThemeProvider'
import { useKnowledgeFiles } from '@renderer/hooks/useKnowledgeFiles' import { useKnowledgeFiles } from '@renderer/hooks/useKnowledgeFiles'
import { useTimer } from '@renderer/hooks/useTimer' import { useTimer } from '@renderer/hooks/useTimer'
import { reset } from '@renderer/services/BackupService' import { reset } from '@renderer/services/BackupService'
import store, { useAppDispatch } from '@renderer/store'
import { setSkipBackupFile as _setSkipBackupFile } from '@renderer/store/settings'
import { AppInfo } from '@renderer/types' import { AppInfo } from '@renderer/types'
import { formatFileSize } from '@renderer/utils' import { formatFileSize } from '@renderer/utils'
import { occupiedDirs } from '@shared/config/constant' import { occupiedDirs } from '@shared/config/constant'
@ -49,6 +48,8 @@ import WebDavSettings from './WebDavSettings'
import YuqueSettings from './YuqueSettings' import YuqueSettings from './YuqueSettings'
const DataSettings: FC = () => { const DataSettings: FC = () => {
const [skipBackupFile, setSkipBackupFile] = usePreference('data.backup.general.skip_backup_file')
const { t } = useTranslation() const { t } = useTranslation()
const [appInfo, setAppInfo] = useState<AppInfo>() const [appInfo, setAppInfo] = useState<AppInfo>()
const [cacheSize, setCacheSize] = useState<string>('') const [cacheSize, setCacheSize] = useState<string>('')
@ -57,11 +58,6 @@ const DataSettings: FC = () => {
const [menu, setMenu] = useState<string>('data') const [menu, setMenu] = useState<string>('data')
const { setTimeoutTimer } = useTimer() const { setTimeoutTimer } = useTimer()
const _skipBackupFile = store.getState().settings.skipBackupFile
const [skipBackupFile, setSkipBackupFile] = useState<boolean>(_skipBackupFile)
const dispatch = useAppDispatch()
//joplin icon needs to be updated into iconfont //joplin icon needs to be updated into iconfont
const JoplinIcon = () => ( const JoplinIcon = () => (
<svg viewBox="0 0 24 24" width="16" height="16" fill="var(--color-icon)" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 24 24" width="16" height="16" fill="var(--color-icon)" xmlns="http://www.w3.org/2000/svg">
@ -578,7 +574,6 @@ const DataSettings: FC = () => {
const onSkipBackupFilesChange = (value: boolean) => { const onSkipBackupFilesChange = (value: boolean) => {
setSkipBackupFile(value) setSkipBackupFile(value)
dispatch(_setSkipBackupFile(value))
} }
return ( return (

View File

@ -1,4 +1,5 @@
import { CheckOutlined, FolderOutlined, LoadingOutlined, SyncOutlined, WarningOutlined } from '@ant-design/icons' import { CheckOutlined, FolderOutlined, LoadingOutlined, SyncOutlined, WarningOutlined } from '@ant-design/icons'
import { usePreference } from '@data/hooks/usePreference'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import NutstorePathPopup from '@renderer/components/Popups/NutsorePathPopup' import NutstorePathPopup from '@renderer/components/Popups/NutsorePathPopup'
import Selector from '@renderer/components/Selector' import Selector from '@renderer/components/Selector'
@ -15,15 +16,7 @@ import {
startNutstoreAutoSync, startNutstoreAutoSync,
stopNutstoreAutoSync stopNutstoreAutoSync
} from '@renderer/services/NutstoreService' } from '@renderer/services/NutstoreService'
import { useAppDispatch, useAppSelector } from '@renderer/store' import { useAppSelector } from '@renderer/store'
import {
setNutstoreAutoSync,
setNutstoreMaxBackups,
setNutstorePath,
setNutstoreSkipBackupFile,
setNutstoreSyncInterval,
setNutstoreToken
} from '@renderer/store/nutstore'
import { modalConfirm } from '@renderer/utils' import { modalConfirm } from '@renderer/utils'
import { NUTSTORE_HOST } from '@shared/config/nutstore' import { NUTSTORE_HOST } from '@shared/config/nutstore'
import { Button, Input, Switch, Tooltip, Typography } from 'antd' import { Button, Input, Switch, Tooltip, Typography } from 'antd'
@ -37,25 +30,24 @@ import { SettingDivider, SettingGroup, SettingHelpText, SettingRow, SettingRowTi
const NutstoreSettings: FC = () => { const NutstoreSettings: FC = () => {
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation() const { t } = useTranslation()
const { const { nutstoreSyncState } = useAppSelector((state) => state.nutstore)
nutstoreToken,
nutstorePath,
nutstoreSyncInterval,
nutstoreAutoSync,
nutstoreSyncState,
nutstoreSkipBackupFile,
nutstoreMaxBackups
} = useAppSelector((state) => state.nutstore)
const dispatch = useAppDispatch() const [nutstoreAutoSync, setNutstoreAutoSync] = usePreference('data.backup.nutstore.auto_sync')
const [nutstoreMaxBackups, setNutstoreMaxBackups] = usePreference('data.backup.nutstore.max_backups')
const [nutstorePath, setNutstorePath] = usePreference('data.backup.nutstore.path')
const [nutstoreSkipBackupFile, setNutstoreSkipBackupFile] = usePreference('data.backup.nutstore.skip_backup_file')
const [nutstoreSyncInterval, setNutstoreSyncInterval] = usePreference('data.backup.nutstore.sync_interval')
const [nutstoreToken, setNutstoreToken] = usePreference('data.backup.nutstore.token')
const [nutstoreUsername, setNutstoreUsername] = useState<string | undefined>(undefined) const [nutstoreUsername, setNutstoreUsername] = useState<string | undefined>(undefined)
const [nutstorePass, setNutstorePass] = useState<string | undefined>(undefined) const [nutstorePass, setNutstorePass] = useState<string | undefined>(undefined)
const [storagePath, setStoragePath] = useState<string | undefined>(nutstorePath) // const [storagePath, setStoragePath] = useState<string | undefined>(nutstorePath)
const [checkConnectionLoading, setCheckConnectionLoading] = useState(false) const [checkConnectionLoading, setCheckConnectionLoading] = useState(false)
const [nsConnected, setNsConnected] = useState<boolean>(false) const [nsConnected, setNsConnected] = useState<boolean>(false)
const [syncInterval, setSyncInterval] = useState<number>(nutstoreSyncInterval)
const [nutSkipBackupFile, setNutSkipBackupFile] = useState<boolean>(nutstoreSkipBackupFile) // const [syncInterval, setSyncInterval] = useState<number>(nutstoreSyncInterval)
// const [nutSkipBackupFile, setNutSkipBackupFile] = useState<boolean>(nutstoreSkipBackupFile)
const [backupManagerVisible, setBackupManagerVisible] = useState(false) const [backupManagerVisible, setBackupManagerVisible] = useState(false)
const nutstoreSSOHandler = useNutstoreSSO() const nutstoreSSOHandler = useNutstoreSSO()
@ -66,8 +58,8 @@ const NutstoreSettings: FC = () => {
window.open(ssoUrl, '_blank') window.open(ssoUrl, '_blank')
const nutstoreToken = await nutstoreSSOHandler() const nutstoreToken = await nutstoreSSOHandler()
dispatch(setNutstoreToken(nutstoreToken)) setNutstoreToken(nutstoreToken)
}, [dispatch, nutstoreSSOHandler]) }, [nutstoreSSOHandler, setNutstoreToken])
useEffect(() => { useEffect(() => {
async function decryptTokenEffect() { async function decryptTokenEffect() {
@ -78,14 +70,14 @@ const NutstoreSettings: FC = () => {
setNutstoreUsername(decrypted.username) setNutstoreUsername(decrypted.username)
setNutstorePass(decrypted.access_token) setNutstorePass(decrypted.access_token)
if (!nutstorePath) { if (!nutstorePath) {
dispatch(setNutstorePath('/cherry-studio')) setNutstorePath('/cherry-studio')
setStoragePath('/cherry-studio') // setStoragePath('/cherry-studio')
} }
} }
} }
} }
decryptTokenEffect() decryptTokenEffect()
}, [nutstoreToken, dispatch, nutstorePath]) }, [nutstoreToken, setNutstorePath, nutstorePath])
const handleLayout = useCallback(async () => { const handleLayout = useCallback(async () => {
const confirmedLogout = await modalConfirm({ const confirmedLogout = await modalConfirm({
@ -93,13 +85,12 @@ const NutstoreSettings: FC = () => {
content: t('settings.data.nutstore.logout.content') content: t('settings.data.nutstore.logout.content')
}) })
if (confirmedLogout) { if (confirmedLogout) {
dispatch(setNutstoreToken('')) setNutstoreToken('')
dispatch(setNutstorePath('')) setNutstorePath('')
dispatch(setNutstoreAutoSync(false)) setNutstoreAutoSync(false)
setNutstoreUsername('') setNutstoreUsername('')
setStoragePath(undefined)
} }
}, [dispatch, t]) }, [setNutstorePath, setNutstoreToken, setNutstoreAutoSync, t])
const handleCheckConnection = async () => { const handleCheckConnection = async () => {
if (!nutstoreToken) return if (!nutstoreToken) return
@ -126,25 +117,23 @@ const NutstoreSettings: FC = () => {
backupMethod: backupToNutstore backupMethod: backupToNutstore
}) })
const onSyncIntervalChange = (value: number) => { const onSyncIntervalChange = async (value: number) => {
setSyncInterval(value) await setNutstoreSyncInterval(value)
dispatch(setNutstoreSyncInterval(value))
if (value === 0) { if (value === 0) {
dispatch(setNutstoreAutoSync(false)) await setNutstoreAutoSync(false)
stopNutstoreAutoSync() stopNutstoreAutoSync()
} else { } else {
dispatch(setNutstoreAutoSync(true)) await setNutstoreAutoSync(true)
startNutstoreAutoSync() startNutstoreAutoSync()
} }
} }
const onSkipBackupFilesChange = (value: boolean) => { const onSkipBackupFilesChange = (value: boolean) => {
setNutSkipBackupFile(value) setNutstoreSkipBackupFile(value)
dispatch(setNutstoreSkipBackupFile(value))
} }
const onMaxBackupsChange = (value: number) => { const onMaxBackupsChange = (value: number) => {
dispatch(setNutstoreMaxBackups(value)) setNutstoreMaxBackups(value)
} }
const handleClickPathChange = async () => { const handleClickPathChange = async () => {
@ -174,8 +163,7 @@ const NutstoreSettings: FC = () => {
return return
} }
setStoragePath(targetPath) setNutstorePath(targetPath)
dispatch(setNutstorePath(targetPath))
} }
const renderSyncStatus = () => { const renderSyncStatus = () => {
@ -260,8 +248,7 @@ const NutstoreSettings: FC = () => {
style={{ width: 250 }} style={{ width: 250 }}
value={nutstorePath} value={nutstorePath}
onChange={(e) => { onChange={(e) => {
setStoragePath(e.target.value) setNutstorePath(e.target.value)
dispatch(setNutstorePath(e.target.value))
}} }}
/> />
<Button type="default" onClick={handleClickPathChange}> <Button type="default" onClick={handleClickPathChange}>
@ -286,7 +273,7 @@ const NutstoreSettings: FC = () => {
<SettingRowTitle>{t('settings.data.webdav.autoSync.label')}</SettingRowTitle> <SettingRowTitle>{t('settings.data.webdav.autoSync.label')}</SettingRowTitle>
<Selector <Selector
size={14} size={14}
value={syncInterval} value={nutstoreSyncInterval}
onChange={onSyncIntervalChange} onChange={onSyncIntervalChange}
options={[ options={[
{ label: t('settings.data.webdav.autoSync.off'), value: 0 }, { label: t('settings.data.webdav.autoSync.off'), value: 0 },
@ -302,7 +289,7 @@ const NutstoreSettings: FC = () => {
]} ]}
/> />
</SettingRow> </SettingRow>
{nutstoreAutoSync && syncInterval > 0 && ( {nutstoreAutoSync && nutstoreSyncInterval > 0 && (
<> <>
<SettingDivider /> <SettingDivider />
<SettingRow> <SettingRow>
@ -333,7 +320,7 @@ const NutstoreSettings: FC = () => {
<SettingDivider /> <SettingDivider />
<SettingRow> <SettingRow>
<SettingRowTitle>{t('settings.data.backup.skip_file_data_title')}</SettingRowTitle> <SettingRowTitle>{t('settings.data.backup.skip_file_data_title')}</SettingRowTitle>
<Switch checked={nutSkipBackupFile} onChange={onSkipBackupFilesChange} /> <Switch checked={nutstoreSkipBackupFile} onChange={onSkipBackupFilesChange} />
</SettingRow> </SettingRow>
<SettingRow> <SettingRow>
<SettingHelpText>{t('settings.data.backup.skip_file_data_help')}</SettingHelpText> <SettingHelpText>{t('settings.data.backup.skip_file_data_help')}</SettingHelpText>
@ -361,7 +348,7 @@ const NutstoreSettings: FC = () => {
webdavHost: NUTSTORE_HOST, webdavHost: NUTSTORE_HOST,
webdavUser: nutstoreUsername, webdavUser: nutstoreUsername,
webdavPass: nutstorePass, webdavPass: nutstorePass,
webdavPath: storagePath webdavPath: nutstorePath
}} }}
restoreMethod={restoreFromNutstore} restoreMethod={restoreFromNutstore}
customLabels={{ customLabels={{

View File

@ -1,8 +1,6 @@
import { usePreference } from '@data/hooks/usePreference'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import { setDefaultObsidianVault } from '@renderer/store/settings'
import { Empty, Select, Spin } from 'antd' import { Empty, Select, Spin } from 'antd'
import { FC, useEffect, useState } from 'react' import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -15,8 +13,8 @@ const { Option } = Select
const ObsidianSettings: FC = () => { const ObsidianSettings: FC = () => {
const { t } = useTranslation() const { t } = useTranslation()
const { defaultObsidianVault } = useSettings()
const dispatch = useAppDispatch() const [defaultObsidianVault, setDefaultObsidianVault] = usePreference('data.integration.obsidian.default_vault')
const [vaults, setVaults] = useState<Array<{ path: string; name: string }>>([]) const [vaults, setVaults] = useState<Array<{ path: string; name: string }>>([])
const [loading, setLoading] = useState<boolean>(false) const [loading, setLoading] = useState<boolean>(false)
@ -40,7 +38,7 @@ const ObsidianSettings: FC = () => {
// 如果没有设置默认vault则选择第一个 // 如果没有设置默认vault则选择第一个
if (!defaultObsidianVault && vaultsData.length > 0) { if (!defaultObsidianVault && vaultsData.length > 0) {
dispatch(setDefaultObsidianVault(vaultsData[0].name)) setDefaultObsidianVault(vaultsData[0].name)
} }
} catch (error) { } catch (error) {
logger.error('获取Obsidian Vault失败:', error as Error) logger.error('获取Obsidian Vault失败:', error as Error)
@ -51,10 +49,10 @@ const ObsidianSettings: FC = () => {
} }
fetchVaults() fetchVaults()
}, [dispatch, defaultObsidianVault, t]) }, [defaultObsidianVault, setDefaultObsidianVault, t])
const handleChange = (value: string) => { const handleChange = (value: string) => {
dispatch(setDefaultObsidianVault(value)) setDefaultObsidianVault(value)
} }
return ( return (

View File

@ -8,8 +8,6 @@ import {
DropResult DropResult
} from '@hello-pangea/dnd' } from '@hello-pangea/dnd'
import { getSidebarIconLabel } from '@renderer/i18n/label' import { getSidebarIconLabel } from '@renderer/i18n/label'
// import { useAppDispatch } from '@renderer/store'
// import { setSidebarIcons } from '@renderer/store/settings'
import { SidebarIcon } from '@shared/data/preferenceTypes' import { SidebarIcon } from '@shared/data/preferenceTypes'
import { message } from 'antd' import { message } from 'antd'
import { import {
@ -42,8 +40,6 @@ const SidebarIconsManager: FC<SidebarIconsManagerProps> = ({
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
// const dispatch = useAppDispatch()
const onDragEnd = useCallback( const onDragEnd = useCallback(
(result: DropResult) => { (result: DropResult) => {
if (!result.destination) return if (!result.destination) return

View File

@ -1,4 +1,5 @@
import { RedoOutlined } from '@ant-design/icons' import { RedoOutlined } from '@ant-design/icons'
import { usePreference } from '@data/hooks/usePreference'
import InfoTooltip from '@renderer/components/InfoTooltip' import InfoTooltip from '@renderer/components/InfoTooltip'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import ModelSelector from '@renderer/components/ModelSelector' import ModelSelector from '@renderer/components/ModelSelector'
@ -6,10 +7,7 @@ import { isEmbeddingModel, isRerankModel, isTextToImageModel } from '@renderer/c
import { useTheme } from '@renderer/context/ThemeProvider' import { useTheme } from '@renderer/context/ThemeProvider'
import { useDefaultModel } from '@renderer/hooks/useAssistant' import { useDefaultModel } from '@renderer/hooks/useAssistant'
import { useProviders } from '@renderer/hooks/useProvider' import { useProviders } from '@renderer/hooks/useProvider'
import { useSettings } from '@renderer/hooks/useSettings'
import { getModelUniqId, hasModel } from '@renderer/services/ModelService' import { getModelUniqId, hasModel } from '@renderer/services/ModelService'
import { useAppDispatch } from '@renderer/store'
import { setTranslateModelPrompt } from '@renderer/store/settings'
import { Model } from '@renderer/types' import { Model } from '@renderer/types'
import { TRANSLATE_PROMPT } from '@shared/config/prompts' import { TRANSLATE_PROMPT } from '@shared/config/prompts'
import { Button, Tooltip } from 'antd' import { Button, Tooltip } from 'antd'
@ -30,9 +28,8 @@ const ModelSettings: FC = () => {
const allModels = providers.map((p) => p.models).flat() const allModels = providers.map((p) => p.models).flat()
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation() const { t } = useTranslation()
const { translateModelPrompt } = useSettings()
const dispatch = useAppDispatch() const [translateModelPrompt, setTranslateModelPrompt] = usePreference('feature.translate.model_prompt')
const modelPredicate = useCallback( const modelPredicate = useCallback(
(m: Model) => !isEmbeddingModel(m) && !isRerankModel(m) && !isTextToImageModel(m), (m: Model) => !isEmbeddingModel(m) && !isRerankModel(m) && !isTextToImageModel(m),
@ -52,7 +49,7 @@ const ModelSettings: FC = () => {
) )
const onResetTranslatePrompt = () => { const onResetTranslatePrompt = () => {
dispatch(setTranslateModelPrompt(TRANSLATE_PROMPT)) setTranslateModelPrompt(TRANSLATE_PROMPT)
} }
return ( return (

View File

@ -1,9 +1,7 @@
import { RedoOutlined } from '@ant-design/icons' import { RedoOutlined } from '@ant-design/icons'
import { usePreference } from '@data/hooks/usePreference'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import { useTheme } from '@renderer/context/ThemeProvider' import { useTheme } from '@renderer/context/ThemeProvider'
import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import { setTranslateModelPrompt } from '@renderer/store/settings'
import { TRANSLATE_PROMPT } from '@shared/config/prompts' import { TRANSLATE_PROMPT } from '@shared/config/prompts'
import { Input, Tooltip } from 'antd' import { Input, Tooltip } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@ -15,15 +13,13 @@ import { SettingGroup, SettingTitle } from '..'
const TranslatePromptSettings = () => { const TranslatePromptSettings = () => {
const { t } = useTranslation() const { t } = useTranslation()
const { theme } = useTheme() const { theme } = useTheme()
const { translateModelPrompt } = useSettings() const [translateModelPrompt, setTranslateModelPrompt] = usePreference('feature.translate.model_prompt')
const [localPrompt, setLocalPrompt] = useState(translateModelPrompt) const [localPrompt, setLocalPrompt] = useState(translateModelPrompt)
const dispatch = useAppDispatch()
const onResetTranslatePrompt = () => { const onResetTranslatePrompt = () => {
setLocalPrompt(TRANSLATE_PROMPT) setLocalPrompt(TRANSLATE_PROMPT)
dispatch(setTranslateModelPrompt(TRANSLATE_PROMPT)) setTranslateModelPrompt(TRANSLATE_PROMPT)
} }
return ( return (
@ -43,7 +39,7 @@ const TranslatePromptSettings = () => {
<Input.TextArea <Input.TextArea
value={localPrompt} value={localPrompt}
onChange={(e) => setLocalPrompt(e.target.value)} onChange={(e) => setLocalPrompt(e.target.value)}
onBlur={(e) => dispatch(setTranslateModelPrompt(e.target.value))} onBlur={(e) => setTranslateModelPrompt(e.target.value)}
autoSize={{ minRows: 4, maxRows: 10 }} autoSize={{ minRows: 4, maxRows: 10 }}
placeholder={t('settings.models.translate_model_prompt_message')} placeholder={t('settings.models.translate_model_prompt_message')}
/> />

View File

@ -31,9 +31,10 @@ import {
WebSearchProvider WebSearchProvider
} from '@renderer/types' } from '@renderer/types'
import { getDefaultGroupName, getLeadingEmoji, runAsyncFunction, uuid } from '@renderer/utils' import { getDefaultGroupName, getLeadingEmoji, runAsyncFunction, uuid } from '@renderer/utils'
import { defaultByPassRules, UpgradeChannel } from '@shared/config/constant' import { defaultByPassRules } from '@shared/config/constant'
import { TRANSLATE_PROMPT } from '@shared/config/prompts' import { TRANSLATE_PROMPT } from '@shared/config/prompts'
import { DefaultPreferences } from '@shared/data/preferences' import { DefaultPreferences } from '@shared/data/preferences'
import { UpgradeChannel } from '@shared/data/preferenceTypes'
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
import { createMigrate } from 'redux-persist' import { createMigrate } from 'redux-persist'

View File

@ -11,7 +11,6 @@ import {
TranslateLanguageCode TranslateLanguageCode
} from '@renderer/types' } from '@renderer/types'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import { UpgradeChannel } from '@shared/config/constant'
import { TRANSLATE_PROMPT } from '@shared/config/prompts' import { TRANSLATE_PROMPT } from '@shared/config/prompts'
import { DefaultPreferences } from '@shared/data/preferences' import { DefaultPreferences } from '@shared/data/preferences'
import type { import type {
@ -21,6 +20,7 @@ import type {
SendMessageShortcut, SendMessageShortcut,
SidebarIcon SidebarIcon
} from '@shared/data/preferenceTypes' } from '@shared/data/preferenceTypes'
import { UpgradeChannel } from '@shared/data/preferenceTypes'
import { ThemeMode } from '@shared/data/preferenceTypes' import { ThemeMode } from '@shared/data/preferenceTypes'
import { OpenAIVerbosity } from '@types' import { OpenAIVerbosity } from '@types'
@ -899,7 +899,7 @@ export const {
// setTestChannel, // setTestChannel,
// setRenderInputMessageAsMarkdown, // setRenderInputMessageAsMarkdown,
// setClickAssistantToShowTopic, // setClickAssistantToShowTopic,
setSkipBackupFile, // setSkipBackupFile,
// setWebdavHost, // setWebdavHost,
// setWebdavUser, // setWebdavUser,
// setWebdavPass, // setWebdavPass,
@ -922,7 +922,7 @@ export const {
// setGridColumns, // setGridColumns,
// setGridPopoverTrigger, // setGridPopoverTrigger,
// setMessageStyle, // setMessageStyle,
setTranslateModelPrompt, // setTranslateModelPrompt,
// setAutoTranslateWithSpace, // setAutoTranslateWithSpace,
// setShowTranslateConfirm, // setShowTranslateConfirm,
// setEnableTopicNaming, // setEnableTopicNaming,
@ -951,8 +951,8 @@ export const {
// setJoplinToken, // setJoplinToken,
// setJoplinUrl, // setJoplinUrl,
// setJoplinExportReasoning, // setJoplinExportReasoning,
setMessageNavigation, // setMessageNavigation,
setDefaultObsidianVault, // setDefaultObsidianVault,
setDefaultAgent, setDefaultAgent,
// setSiyuanApiUrl, // setSiyuanApiUrl,
// setSiyuanToken, // setSiyuanToken,
@ -986,9 +986,9 @@ export const {
// setNavbarPosition, // setNavbarPosition,
// setShowMessageOutline, // setShowMessageOutline,
// API Server actions // API Server actions
setApiServerEnabled, // setApiServerEnabled,
setApiServerPort, // setApiServerPort,
setApiServerApiKey, // setApiServerApiKey,
// setShowWorkspace, // setShowWorkspace,
toggleShowWorkspace toggleShowWorkspace
} = settingsSlice.actions } = settingsSlice.actions