From 29d4e37f6b92b613fe61f01983ca49f0d594253a Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Tue, 19 Aug 2025 15:38:03 +0800 Subject: [PATCH] feat(Sidebar): add 'code_tools' icon and route; enhance CodeToolsPage layout with Navbar and improved provider filtering --- src/renderer/src/components/app/Sidebar.tsx | 7 +- src/renderer/src/pages/code/CodeToolsPage.tsx | 250 ++++++++++-------- .../src/pages/launchpad/LaunchpadPage.tsx | 4 +- src/renderer/src/store/index.ts | 2 +- src/renderer/src/store/migrate.ts | 9 + src/renderer/src/store/settings.ts | 10 +- 6 files changed, 169 insertions(+), 113 deletions(-) diff --git a/src/renderer/src/components/app/Sidebar.tsx b/src/renderer/src/components/app/Sidebar.tsx index eb67cf16f9..b39ca72bd1 100644 --- a/src/renderer/src/components/app/Sidebar.tsx +++ b/src/renderer/src/components/app/Sidebar.tsx @@ -16,6 +16,7 @@ import { isEmoji } from '@renderer/utils' import { Avatar, Tooltip } from 'antd' import { CircleHelp, + Code, FileSearch, Folder, Languages, @@ -153,7 +154,8 @@ const MainMenus: FC = () => { translate: , minapp: , knowledge: , - files: + files: , + code_tools: } const pathMap = { @@ -163,7 +165,8 @@ const MainMenus: FC = () => { translate: '/translate', minapp: '/apps', knowledge: '/knowledge', - files: '/files' + files: '/files', + code_tools: '/code' } return sidebarIcons.visible.map((icon) => { diff --git a/src/renderer/src/pages/code/CodeToolsPage.tsx b/src/renderer/src/pages/code/CodeToolsPage.tsx index c6d0b05977..fec6f20672 100644 --- a/src/renderer/src/pages/code/CodeToolsPage.tsx +++ b/src/renderer/src/pages/code/CodeToolsPage.tsx @@ -1,4 +1,5 @@ import AiProvider from '@renderer/aiCore' +import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import ModelSelector from '@renderer/components/ModelSelector' import { isEmbeddingModel, isRerankModel, isTextToImageModel } from '@renderer/config/models' import { useCodeTools } from '@renderer/hooks/useCodeTools' @@ -22,6 +23,8 @@ const CLI_TOOLS = [ { value: 'gemini-cli', label: 'Gemini CLI' } ] +const SUPPORTED_PROVIDERS = ['aihubmix', 'dmxapi', 'new-api'] + const logger = loggerService.withContext('CodeToolsPage') const CodeToolsPage: FC = () => { @@ -54,12 +57,23 @@ const CodeToolsPage: FC = () => { } const openAiProviders = providers.filter((p) => p.type.includes('openai')) - const geminiProviders = providers.filter((p) => p.type === 'gemini') - const claudeProviders = providers.filter((p) => p.type === 'anthropic') + const geminiProviders = providers.filter((p) => p.type === 'gemini' || SUPPORTED_PROVIDERS.includes(p.id)) + const claudeProviders = providers.filter((p) => p.type === 'anthropic' || SUPPORTED_PROVIDERS.includes(p.id)) const modelPredicate = useCallback( - (m: Model) => !isEmbeddingModel(m) && !isRerankModel(m) && !isTextToImageModel(m), - [] + (m: Model) => { + if (isEmbeddingModel(m) || isRerankModel(m) || isTextToImageModel(m)) { + return false + } + if (selectedCliTool === 'claude-code') { + return m.id.includes('claude') + } + if (selectedCliTool === 'gemini-cli') { + return m.id.includes('gemini') + } + return true + }, + [selectedCliTool] ) const availableProviders = @@ -176,13 +190,19 @@ const CodeToolsPage: FC = () => { if (selectedCliTool === 'claude-code') { env = { ANTHROPIC_API_KEY: apiKey, + ANTHROPIC_BASE_URL: modelProvider.apiHost, ANTHROPIC_MODEL: selectedModel.id } } if (selectedCliTool === 'gemini-cli') { + const apiSuffix = modelProvider.id === 'aihubmix' ? '/gemini' : '' + const apiBaseUrl = modelProvider.apiHost + apiSuffix env = { - GEMINI_API_KEY: apiKey + GEMINI_API_KEY: apiKey, + GEMINI_BASE_URL: apiBaseUrl, + GOOGLE_GEMINI_BASE_URL: apiBaseUrl, + GEMINI_MODEL: selectedModel.id } } @@ -228,117 +248,134 @@ const CodeToolsPage: FC = () => { return ( - {t('code.title')} - {t('code.description')} + + {t('code.title')} + + + + {t('code.title')} + {t('code.description')} - {/* Bun 安装状态提示 */} - {!isBunInstalled && ( - - - {t('code.bun_required_message')} - - - } - /> - - )} - - - -
{t('code.cli_tool')}
- { - const label = typeof option?.label === 'string' ? option.label : String(option?.value || '') - return label.toLowerCase().includes(input.toLowerCase()) - }} - options={directories.map((dir) => ({ - value: dir, - label: ( + {/* Bun 安装状态提示 */} + {!isBunInstalled && ( + + - {dir} - handleRemoveDirectory(dir, e)} - /> + {t('code.bun_required_message')} + - ) - }))} - /> - - -
+ } + /> + + )} - -
{t('code.update_options')}
- setAutoUpdateToLatest(e.target.checked)}> - {t('code.auto_update_to_latest')} - -
-
+ + +
{t('code.cli_tool')}
+ { + const label = typeof option?.label === 'string' ? option.label : String(option?.value || '') + return label.toLowerCase().includes(input.toLowerCase()) + }} + options={directories.map((dir) => ({ + value: dir, + label: ( +
+ {dir} + handleRemoveDirectory(dir, e)} + /> +
+ ) + }))} + /> + + +
+ + +
{t('code.update_options')}
+ setAutoUpdateToLatest(e.target.checked)}> + {t('code.auto_update_to_latest')} + +
+
+ + +
+
) } -// 样式组件 const Container = styled.div` + display: flex; + flex: 1; + flex-direction: column; +` + +const ContentContainer = styled.div` + display: flex; + flex: 1; +` + +const MainContent = styled.div` width: 600px; margin: auto; ` @@ -347,7 +384,6 @@ const Title = styled.h1` font-size: 24px; font-weight: 600; margin-bottom: 8px; - margin-top: -50px; color: var(--color-text-1); ` diff --git a/src/renderer/src/pages/launchpad/LaunchpadPage.tsx b/src/renderer/src/pages/launchpad/LaunchpadPage.tsx index 870ca0d263..def90a4a46 100644 --- a/src/renderer/src/pages/launchpad/LaunchpadPage.tsx +++ b/src/renderer/src/pages/launchpad/LaunchpadPage.tsx @@ -3,7 +3,7 @@ import { useMinapps } from '@renderer/hooks/useMinapps' import { useRuntime } from '@renderer/hooks/useRuntime' import { useSettings } from '@renderer/hooks/useSettings' import tabsService from '@renderer/services/TabsService' -import { FileSearch, Folder, Languages, LayoutGrid, Palette, Sparkle, Terminal } from 'lucide-react' +import { Code, FileSearch, Folder, Languages, LayoutGrid, Palette, Sparkle } from 'lucide-react' import { FC, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useNavigate } from 'react-router-dom' @@ -54,7 +54,7 @@ const LaunchpadPage: FC = () => { bgColor: 'linear-gradient(135deg, #F59E0B, #FBBF24)' // 文件:金色,代表资源和重要性 }, { - icon: , + icon: , text: t('title.code'), path: '/code', bgColor: 'linear-gradient(135deg, #1F2937, #374151)' // Code CLI:高级暗黑色,代表专业和技术 diff --git a/src/renderer/src/store/index.ts b/src/renderer/src/store/index.ts index 0f8e88cd3f..c328f8b6c3 100644 --- a/src/renderer/src/store/index.ts +++ b/src/renderer/src/store/index.ts @@ -62,7 +62,7 @@ const persistedReducer = persistReducer( { key: 'cherry-studio', storage, - version: 132, + version: 133, blacklist: ['runtime', 'messages', 'messageBlocks', 'tabs'], migrate }, diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts index dc799b0d48..a22619254a 100644 --- a/src/renderer/src/store/migrate.ts +++ b/src/renderer/src/store/migrate.ts @@ -2119,6 +2119,15 @@ const migrateConfig = { logger.error('migrate 132 error', error as Error) return state } + }, + '133': (state: RootState) => { + try { + state.settings.sidebarIcons.visible.push('code_tools') + return state + } catch (error) { + logger.error('migrate 133 error', error as Error) + return state + } } } diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts index aecd4311bc..fd2853360f 100644 --- a/src/renderer/src/store/settings.ts +++ b/src/renderer/src/store/settings.ts @@ -21,7 +21,15 @@ import { RemoteSyncState } from './backup' export type SendMessageShortcut = 'Enter' | 'Shift+Enter' | 'Ctrl+Enter' | 'Command+Enter' | 'Alt+Enter' -export type SidebarIcon = 'assistants' | 'agents' | 'paintings' | 'translate' | 'minapp' | 'knowledge' | 'files' +export type SidebarIcon = + | 'assistants' + | 'agents' + | 'paintings' + | 'translate' + | 'minapp' + | 'knowledge' + | 'files' + | 'code_tools' export const DEFAULT_SIDEBAR_ICONS: SidebarIcon[] = [ 'assistants',