diff --git a/packages/shared/IpcChannel.ts b/packages/shared/IpcChannel.ts index b77fd5d430..8da9a67429 100644 --- a/packages/shared/IpcChannel.ts +++ b/packages/shared/IpcChannel.ts @@ -15,7 +15,8 @@ export enum IpcChannel { App_SetTrayOnClose = 'app:set-tray-on-close', App_SetTheme = 'app:set-theme', App_SetAutoUpdate = 'app:set-auto-update', - App_SetFeedUrl = 'app:set-feed-url', + App_SetEnableEarlyAccess = 'app:set-enable-early-access', + App_SetUpgradeChannel = 'app:set-upgrade-channel', App_HandleZoomFactor = 'app:handle-zoom-factor', App_Select = 'app:select', App_HasWritePermission = 'app:has-write-permission', diff --git a/packages/shared/config/constant.ts b/packages/shared/config/constant.ts index 0b568461ea..975767fefa 100644 --- a/packages/shared/config/constant.ts +++ b/packages/shared/config/constant.ts @@ -406,8 +406,15 @@ export const defaultLanguage = 'en-US' export enum FeedUrl { PRODUCTION = 'https://releases.cherry-ai.com', - EARLY_ACCESS = 'https://github.com/CherryHQ/cherry-studio/releases/latest/download' + GITHUB_LATEST = 'https://github.com/CherryHQ/cherry-studio/releases/latest/download' } + +export enum UpgradeChannel { + LATEST = 'latest', // 最新稳定版本 + RC = 'rc', // 公测版本 + BETA = 'beta' // 预览版本 +} + export const defaultTimeout = 5 * 1000 * 60 export const occupiedDirs = ['logs', 'Network', 'Partitions/webview/Network'] diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 8d8690a54e..b2003f8db8 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -5,7 +5,7 @@ import path from 'node:path' import { isMac, isWin } from '@main/constant' import { getBinaryPath, isBinaryExists, runInstallScript } from '@main/utils/process' import { handleZoomFactor } from '@main/utils/zoom' -import { FeedUrl } from '@shared/config/constant' +import { UpgradeChannel } from '@shared/config/constant' import { IpcChannel } from '@shared/IpcChannel' import { Shortcut, ThemeMode } from '@types' import { BrowserWindow, dialog, ipcMain, session, shell } from 'electron' @@ -141,8 +141,14 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { configManager.setAutoUpdate(isActive) }) - ipcMain.handle(IpcChannel.App_SetFeedUrl, (_, feedUrl: FeedUrl) => { - appUpdater.setFeedUrl(feedUrl) + ipcMain.handle(IpcChannel.App_SetEnableEarlyAccess, async (_, isActive: boolean) => { + appUpdater.cancelDownload() + configManager.setEnableEarlyAccess(isActive) + }) + + ipcMain.handle(IpcChannel.App_SetUpgradeChannel, async (_, channel: UpgradeChannel) => { + appUpdater.cancelDownload() + configManager.setUpgradeChannel(channel) }) ipcMain.handle(IpcChannel.Config_Set, (_, key: string, value: any, isNotify: boolean = false) => { diff --git a/src/main/services/AppUpdater.ts b/src/main/services/AppUpdater.ts index 4c71a05556..e26a779d59 100644 --- a/src/main/services/AppUpdater.ts +++ b/src/main/services/AppUpdater.ts @@ -1,8 +1,8 @@ import { isWin } from '@main/constant' import { locales } from '@main/utils/locales' -import { FeedUrl } from '@shared/config/constant' +import { FeedUrl, UpgradeChannel } from '@shared/config/constant' import { IpcChannel } from '@shared/IpcChannel' -import { UpdateInfo } from 'builder-util-runtime' +import { CancellationToken, UpdateInfo } from 'builder-util-runtime' import { app, BrowserWindow, dialog } from 'electron' import logger from 'electron-log' import { AppUpdater as _AppUpdater, autoUpdater, NsisUpdater } from 'electron-updater' @@ -14,6 +14,7 @@ import { configManager } from './ConfigManager' export default class AppUpdater { autoUpdater: _AppUpdater = autoUpdater private releaseInfo: UpdateInfo | undefined + private cancellationToken: CancellationToken = new CancellationToken() constructor(mainWindow: BrowserWindow) { logger.transports.file.level = 'info' @@ -22,9 +23,7 @@ export default class AppUpdater { autoUpdater.forceDevUpdateConfig = !app.isPackaged autoUpdater.autoDownload = configManager.getAutoUpdate() autoUpdater.autoInstallOnAppQuit = configManager.getAutoUpdate() - autoUpdater.setFeedURL(configManager.getFeedUrl()) - // 检测下载错误 autoUpdater.on('error', (error) => { // 简单记录错误信息和时间戳 logger.error('更新异常', { @@ -64,6 +63,33 @@ export default class AppUpdater { this.autoUpdater = autoUpdater } + private async _getPreReleaseVersionFromGithub(channel: UpgradeChannel) { + try { + const responses = await fetch('https://api.github.com/repos/CherryHQ/cherry-studio/releases?per_page=8', { + headers: { + Accept: 'application/vnd.github+json', + 'X-GitHub-Api-Version': '2022-11-28', + 'Accept-Language': 'en-US,en;q=0.9' + } + }) + const data = (await responses.json()) as GithubReleaseInfo[] + logger.debug('github release data', data) + const release: GithubReleaseInfo | undefined = data.find((item: GithubReleaseInfo) => { + return item.prerelease && item.tag_name.includes(`-${channel}.`) + }) + + if (!release) { + return null + } + + logger.info('release info', release.tag_name) + return `https://github.com/CherryHQ/cherry-studio/releases/download/${release.tag_name}` + } catch (error) { + logger.error('Failed to get latest not draft version from github:', error) + return null + } + } + private async _getIpCountry() { try { // add timeout using AbortController @@ -93,9 +119,44 @@ export default class AppUpdater { autoUpdater.autoInstallOnAppQuit = isActive } - public setFeedUrl(feedUrl: FeedUrl) { - autoUpdater.setFeedURL(feedUrl) - configManager.setFeedUrl(feedUrl) + private async _setFeedUrl() { + // disable downgrade and differential download + // github and gitcode don't support multiple range download + this.autoUpdater.allowDowngrade = false + this.autoUpdater.disableDifferentialDownload = true + + if (configManager.getEnableEarlyAccess()) { + const channel = configManager.getUpgradeChannel() + if (channel === UpgradeChannel.LATEST) { + this.autoUpdater.setFeedURL(FeedUrl.GITHUB_LATEST) + this.autoUpdater.channel = UpgradeChannel.LATEST + return true + } + + const preReleaseUrl = await this._getPreReleaseVersionFromGithub(channel) + if (preReleaseUrl) { + this.autoUpdater.setFeedURL(preReleaseUrl) + this.autoUpdater.channel = channel + return true + } + return false + } + + // no early access, use latest version + this.autoUpdater.channel = 'latest' + this.autoUpdater.setFeedURL(FeedUrl.PRODUCTION) + + const ipCountry = await this._getIpCountry() + logger.info('ipCountry', ipCountry) + if (ipCountry.toLowerCase() !== 'cn') { + this.autoUpdater.setFeedURL(FeedUrl.GITHUB_LATEST) + } + return true + } + + public cancelDownload() { + this.cancellationToken.cancel() + this.cancellationToken = new CancellationToken() } public async checkForUpdates() { @@ -106,10 +167,12 @@ export default class AppUpdater { } } - const ipCountry = await this._getIpCountry() - logger.info('ipCountry', ipCountry) - if (ipCountry !== 'CN') { - this.autoUpdater.setFeedURL(FeedUrl.EARLY_ACCESS) + const isSetFeedUrl = await this._setFeedUrl() + if (!isSetFeedUrl) { + return { + currentVersion: app.getVersion(), + updateInfo: null + } } try { @@ -117,7 +180,8 @@ export default class AppUpdater { if (update?.isUpdateAvailable && !this.autoUpdater.autoDownload) { // 如果 autoDownload 为 false,则需要再调用下面的函数触发下 // do not use await, because it will block the return of this function - this.autoUpdater.downloadUpdate() + logger.info('downloadUpdate manual by check for updates', this.cancellationToken) + this.autoUpdater.downloadUpdate(this.cancellationToken) } return { @@ -178,7 +242,11 @@ export default class AppUpdater { return releaseNotes.map((note) => note.note).join('\n') } } - +interface GithubReleaseInfo { + draft: boolean + prerelease: boolean + tag_name: string +} interface ReleaseNoteInfo { readonly version: string readonly note: string | null diff --git a/src/main/services/ConfigManager.ts b/src/main/services/ConfigManager.ts index 573674bd70..6d33b6e3dd 100644 --- a/src/main/services/ConfigManager.ts +++ b/src/main/services/ConfigManager.ts @@ -1,4 +1,4 @@ -import { defaultLanguage, FeedUrl, ZOOM_SHORTCUTS } from '@shared/config/constant' +import { defaultLanguage, UpgradeChannel, ZOOM_SHORTCUTS } from '@shared/config/constant' import { LanguageVarious, Shortcut, ThemeMode } from '@types' import { app } from 'electron' import Store from 'electron-store' @@ -16,7 +16,8 @@ export enum ConfigKeys { ClickTrayToShowQuickAssistant = 'clickTrayToShowQuickAssistant', EnableQuickAssistant = 'enableQuickAssistant', AutoUpdate = 'autoUpdate', - FeedUrl = 'feedUrl', + EnableEarlyAccess = 'enableEarlyAccess', + UpgradeChannel = 'upgradeChannel', EnableDataCollection = 'enableDataCollection', SelectionAssistantEnabled = 'selectionAssistantEnabled', SelectionAssistantTriggerMode = 'selectionAssistantTriggerMode', @@ -142,12 +143,20 @@ export class ConfigManager { this.set(ConfigKeys.AutoUpdate, value) } - getFeedUrl(): string { - return this.get(ConfigKeys.FeedUrl, FeedUrl.PRODUCTION) + getEnableEarlyAccess(): boolean { + return this.get(ConfigKeys.EnableEarlyAccess, false) } - setFeedUrl(value: FeedUrl) { - this.set(ConfigKeys.FeedUrl, value) + setEnableEarlyAccess(value: boolean) { + this.set(ConfigKeys.EnableEarlyAccess, value) + } + + getUpgradeChannel(): UpgradeChannel { + return this.get(ConfigKeys.UpgradeChannel, UpgradeChannel.LATEST) + } + + setUpgradeChannel(value: UpgradeChannel) { + this.set(ConfigKeys.UpgradeChannel, value) } getEnableDataCollection(): boolean { diff --git a/src/preload/index.ts b/src/preload/index.ts index 3e9ae532b2..ed2a2042e0 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -1,6 +1,6 @@ import type { ExtractChunkData } from '@cherrystudio/embedjs-interfaces' import { electronAPI } from '@electron-toolkit/preload' -import { FeedUrl } from '@shared/config/constant' +import { UpgradeChannel } from '@shared/config/constant' import { IpcChannel } from '@shared/IpcChannel' import { FileType, KnowledgeBaseParams, KnowledgeItem, MCPServer, Shortcut, ThemeMode, WebDavConfig } from '@types' import { contextBridge, ipcRenderer, OpenDialogOptions, shell, webUtils } from 'electron' @@ -23,7 +23,8 @@ const api = { setLaunchToTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetLaunchToTray, isActive), setTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTray, isActive), setTrayOnClose: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTrayOnClose, isActive), - setFeedUrl: (feedUrl: FeedUrl) => ipcRenderer.invoke(IpcChannel.App_SetFeedUrl, feedUrl), + setEnableEarlyAccess: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetEnableEarlyAccess, isActive), + setUpgradeChannel: (channel: UpgradeChannel) => ipcRenderer.invoke(IpcChannel.App_SetUpgradeChannel, channel), setTheme: (theme: ThemeMode) => ipcRenderer.invoke(IpcChannel.App_SetTheme, theme), handleZoomFactor: (delta: number, reset: boolean = false) => ipcRenderer.invoke(IpcChannel.App_HandleZoomFactor, delta, reset), diff --git a/src/renderer/src/hooks/useSettings.ts b/src/renderer/src/hooks/useSettings.ts index 10f9ee9001..72560706e6 100644 --- a/src/renderer/src/hooks/useSettings.ts +++ b/src/renderer/src/hooks/useSettings.ts @@ -17,10 +17,11 @@ import { setTopicPosition, setTray as _setTray, setTrayOnClose, + setUpgradeChannel as _setUpgradeChannel, setWindowStyle } from '@renderer/store/settings' import { SidebarIcon, ThemeMode, TranslateLanguageVarious } from '@renderer/types' -import { FeedUrl } from '@shared/config/constant' +import { UpgradeChannel } from '@shared/config/constant' export function useSettings() { const settings = useAppSelector((state) => state.settings) @@ -62,7 +63,12 @@ export function useSettings() { setEarlyAccess(isEarlyAccess: boolean) { dispatch(_setEarlyAccess(isEarlyAccess)) - window.api.setFeedUrl(isEarlyAccess ? FeedUrl.EARLY_ACCESS : FeedUrl.PRODUCTION) + window.api.setEnableEarlyAccess(isEarlyAccess) + }, + + setUpgradeChannel(channel: UpgradeChannel) { + dispatch(_setUpgradeChannel(channel)) + window.api.setUpgradeChannel(channel) }, setTheme(theme: ThemeMode) { diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 303899f2e8..b58056ae92 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -1385,7 +1385,14 @@ "general.image_upload": "Image Upload", "general.auto_check_update.title": "Auto Update", "general.early_access.title": "Early Access", - "general.early_access.tooltip": "Enable to use the latest version from GitHub, which may be slower. Please backup your data in advance.", + "general.early_access.tooltip": "Updating to test versions cannot be downgraded, there is a risk of data loss, please backup your data in advance", + "general.early_access.beta_version": "Beta Version", + "general.early_access.rc_version": "RC Version", + "general.early_access.latest_version": "Latest Version", + "general.early_access.latest_version_tooltip": "github latest version, latest stable version", + "general.early_access.version_options": "Version Options", + "general.early_access.rc_version_tooltip": "More stable, please backup your data", + "general.early_access.beta_version_tooltip": "Latest features but unstable, use with caution", "general.reset.button": "Reset", "general.reset.title": "Data Reset", "general.restore.button": "Restore", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index bd20c61ead..64f6a98475 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -1830,7 +1830,14 @@ }, "general.auto_check_update.title": "自動更新", "general.early_access.title": "早期アクセス", - "general.early_access.tooltip": "有効にすると、GitHub の最新バージョンを使用します。ダウンロード速度が遅く、不安定な場合があります。データを事前にバックアップしてください。", + "general.early_access.tooltip": "更新すると、データが失われる可能性があります。データを事前にバックアップしてください。", + "general.early_access.beta_version": "ベータ版", + "general.early_access.rc_version": "RC版", + "general.early_access.latest_version": "最新版", + "general.early_access.latest_version_tooltip": "github latest バージョン, 最新安定版", + "general.early_access.version_options": "バージョンオプション", + "general.early_access.rc_version_tooltip": "より安定しています。データを事前にバックアップしてください。", + "general.early_access.beta_version_tooltip": "最新の機能ですが、不安定な場合があります。使用には注意してください。", "quickPhrase": { "title": "クイックフレーズ", "add": "フレーズを追加", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index fcd5487b92..e027e7270d 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -1830,7 +1830,14 @@ }, "general.auto_check_update.title": "Автоматическое обновление", "general.early_access.title": "Ранний доступ", - "general.early_access.tooltip": "Включить для использования последней версии из GitHub, что может быть медленнее и нестабильно. Пожалуйста, сделайте резервную копию данных заранее.", + "general.early_access.tooltip": "Обновление до тестовых версий не может быть откачено, существует риск потери данных, пожалуйста, сделайте резервную копию данных заранее", + "general.early_access.beta_version": "Бета версия", + "general.early_access.rc_version": "RC версия", + "general.early_access.latest_version": "Стабильная версия", + "general.early_access.latest_version_tooltip": "github latest версия, стабильная версия", + "general.early_access.version_options": "Варианты версии", + "general.early_access.rc_version_tooltip": "Более стабильно, пожалуйста, сделайте резервную копию данных заранее", + "general.early_access.beta_version_tooltip": "Самые последние функции, но нестабильно, используйте с осторожностью", "quickPhrase": { "title": "Быстрые фразы", "add": "Добавить фразу", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 9bc4201f71..894d53c2be 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -1385,7 +1385,14 @@ "general.image_upload": "图片上传", "general.auto_check_update.title": "自动更新", "general.early_access.title": "抢先体验", - "general.early_access.tooltip": "开启后,将使用 GitHub 的最新版本,下载速度可能较慢,请务必提前备份数据", + "general.early_access.tooltip": "更新到测试版本不能降级,有数据丢失风险,请务必提前备份数据", + "general.early_access.beta_version": "预览版本", + "general.early_access.rc_version": "公测版本", + "general.early_access.latest_version": "稳定版本", + "general.early_access.version_options": "版本选择", + "general.early_access.rc_version_tooltip": "相对稳定,请备份数据", + "general.early_access.beta_version_tooltip": "功能最新但不稳定,谨慎使用", + "general.early_access.latest_version_tooltip": "github latest 版本, 最新稳定版本", "general.reset.button": "重置", "general.reset.title": "重置数据", "general.restore.button": "恢复", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index e99c57e170..65a3a3f58c 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -1833,7 +1833,14 @@ }, "general.auto_check_update.title": "自動更新", "general.early_access.title": "搶先體驗", - "general.early_access.tooltip": "開啟後,將使用 GitHub 的最新版本,下載速度可能較慢,請務必提前備份數據", + "general.early_access.tooltip": "更新到測試版本不能降級,有數據丟失風險,請務必提前備份數據", + "general.early_access.beta_version": "預覽版本", + "general.early_access.rc_version": "公測版本", + "general.early_access.latest_version": "穩定版本", + "general.early_access.latest_version_tooltip": "github latest 版本, 最新穩定版本", + "general.early_access.version_options": "版本選項", + "general.early_access.rc_version_tooltip": "相對穩定,請務必提前備份數據", + "general.early_access.beta_version_tooltip": "功能最新但不穩定,謹慎使用", "quickPhrase": { "title": "快捷短語", "add": "新增短語", diff --git a/src/renderer/src/pages/settings/AboutSettings.tsx b/src/renderer/src/pages/settings/AboutSettings.tsx index 82f11ec7d4..9bf65e4489 100644 --- a/src/renderer/src/pages/settings/AboutSettings.tsx +++ b/src/renderer/src/pages/settings/AboutSettings.tsx @@ -10,7 +10,8 @@ import { useAppDispatch } from '@renderer/store' import { setUpdateState } from '@renderer/store/runtime' import { ThemeMode } from '@renderer/types' import { compareVersions, runAsyncFunction } from '@renderer/utils' -import { Avatar, Button, Progress, Row, Switch, Tag, Tooltip } from 'antd' +import { UpgradeChannel } from '@shared/config/constant' +import { Avatar, Button, Progress, Radio, Row, Switch, Tag, Tooltip } from 'antd' import { debounce } from 'lodash' import { Bug, FileCheck, Github, Globe, Mail, Rss } from 'lucide-react' import { FC, useEffect, useState } from 'react' @@ -25,7 +26,8 @@ const AboutSettings: FC = () => { const [version, setVersion] = useState('') const [isPortable, setIsPortable] = useState(false) const { t } = useTranslation() - const { autoCheckUpdate, setAutoCheckUpdate, earlyAccess, setEarlyAccess } = useSettings() + const { autoCheckUpdate, setAutoCheckUpdate, earlyAccess, setEarlyAccess, upgradeChannel, setUpgradeChannel } = + useSettings() const { theme } = useTheme() const dispatch = useAppDispatch() const { update } = useRuntime() @@ -95,15 +97,65 @@ const AboutSettings: FC = () => { const hasNewVersion = update?.info?.version && version ? compareVersions(update.info.version, version) > 0 : false + const handleUpgradeChannelChange = async (value: UpgradeChannel) => { + setUpgradeChannel(value) + // Clear update info when switching upgrade channel + dispatch( + setUpdateState({ + available: false, + info: null, + downloaded: false, + checking: false, + downloading: false, + downloadProgress: 0 + }) + ) + } + + // Get available test version options based on current version + const getAvailableTestChannels = () => { + return [ + { + tooltip: t('settings.general.early_access.latest_version_tooltip'), + label: t('settings.general.early_access.latest_version'), + value: UpgradeChannel.LATEST + }, + { + tooltip: t('settings.general.early_access.rc_version_tooltip'), + label: t('settings.general.early_access.rc_version'), + value: UpgradeChannel.RC + }, + { + tooltip: t('settings.general.early_access.beta_version_tooltip'), + label: t('settings.general.early_access.beta_version'), + value: UpgradeChannel.BETA + } + ] + } + + const handlerSetEarlyAccess = (value: boolean) => { + setEarlyAccess(value) + dispatch( + setUpdateState({ + available: false, + info: null, + downloaded: false, + checking: false, + downloading: false, + downloadProgress: 0 + }) + ) + if (value === false) setUpgradeChannel(UpgradeChannel.LATEST) + } + useEffect(() => { runAsyncFunction(async () => { const appInfo = await window.api.getAppInfo() setVersion(appInfo.version) setIsPortable(appInfo.isPortable) }) - setEarlyAccess(earlyAccess) setAutoCheckUpdate(autoCheckUpdate) - }, [autoCheckUpdate, earlyAccess, setAutoCheckUpdate, setEarlyAccess]) + }, [autoCheckUpdate, setAutoCheckUpdate, setEarlyAccess]) return ( @@ -167,9 +219,29 @@ const AboutSettings: FC = () => { {t('settings.general.early_access.title')} - setEarlyAccess(v)} /> + handlerSetEarlyAccess(v)} /> + {earlyAccess && getAvailableTestChannels().length > 0 && ( + <> + + + {t('settings.general.early_access.version_options')} + handleUpgradeChannelChange(e.target.value)}> + {getAvailableTestChannels().map((option) => ( + + {option.label} + + ))} + + + + )} )} diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts index df89be66b8..0e9385de0c 100644 --- a/src/renderer/src/store/migrate.ts +++ b/src/renderer/src/store/migrate.ts @@ -7,6 +7,7 @@ import db from '@renderer/databases' import i18n from '@renderer/i18n' import { Assistant, Provider, WebSearchProvider } from '@renderer/types' import { getDefaultGroupName, getLeadingEmoji, runAsyncFunction, uuid } from '@renderer/utils' +import { UpgradeChannel } from '@shared/config/constant' import { isEmpty } from 'lodash' import { createMigrate } from 'redux-persist' @@ -1627,6 +1628,9 @@ const migrateConfig = { } } }) + if (state.settings) { + state.settings.upgradeChannel = UpgradeChannel.LATEST + } return state } catch (error) { return state diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts index d4014adf25..ee991556f7 100644 --- a/src/renderer/src/store/settings.ts +++ b/src/renderer/src/store/settings.ts @@ -11,6 +11,7 @@ import { ThemeMode, TranslateLanguageVarious } from '@renderer/types' +import { UpgradeChannel } from '@shared/config/constant' import { WebDAVSyncState } from './backup' @@ -68,6 +69,7 @@ export interface SettingsState { clickAssistantToShowTopic: boolean autoCheckUpdate: boolean earlyAccess: boolean + upgradeChannel: UpgradeChannel renderInputMessageAsMarkdown: boolean // 代码执行 codeExecution: { @@ -221,6 +223,7 @@ export const initialState: SettingsState = { clickAssistantToShowTopic: true, autoCheckUpdate: true, earlyAccess: false, + upgradeChannel: UpgradeChannel.LATEST, renderInputMessageAsMarkdown: false, codeExecution: { enabled: false, @@ -429,6 +432,9 @@ const settingsSlice = createSlice({ setEarlyAccess: (state, action: PayloadAction) => { state.earlyAccess = action.payload }, + setUpgradeChannel: (state, action: PayloadAction) => { + state.upgradeChannel = action.payload + }, setRenderInputMessageAsMarkdown: (state, action: PayloadAction) => { state.renderInputMessageAsMarkdown = action.payload }, @@ -725,6 +731,7 @@ export const { setPasteLongTextAsFile, setAutoCheckUpdate, setEarlyAccess, + setUpgradeChannel, setRenderInputMessageAsMarkdown, setClickAssistantToShowTopic, setSkipBackupFile,