mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 18:50:56 +08:00
fix: v2 merge error (#10658)
* fix: v2 merge error * fix: review improve * fix: ci error * fix: review * Update index.tsx * Update index.tsx
This commit is contained in:
parent
06b6f2b9d8
commit
cb12bb5137
@ -1,5 +1,5 @@
|
||||
import { CacheService } from '@main/services/CacheService'
|
||||
import { loggerService } from '@main/services/LoggerService'
|
||||
import { cacheService } from '@data/CacheService'
|
||||
import { loggerService } from '@logger'
|
||||
import { reduxService } from '@main/services/ReduxService'
|
||||
import type { ApiModel, Model, Provider } from '@types'
|
||||
|
||||
@ -12,7 +12,7 @@ const PROVIDERS_CACHE_TTL = 10 * 1000 // 10 seconds
|
||||
export async function getAvailableProviders(): Promise<Provider[]> {
|
||||
try {
|
||||
// Try to get from cache first (faster)
|
||||
const cachedSupportedProviders = CacheService.get<Provider[]>(PROVIDERS_CACHE_KEY)
|
||||
const cachedSupportedProviders = cacheService.get<Provider[]>(PROVIDERS_CACHE_KEY)
|
||||
if (cachedSupportedProviders && cachedSupportedProviders.length > 0) {
|
||||
logger.debug('Providers resolved from cache', {
|
||||
count: cachedSupportedProviders.length
|
||||
@ -33,7 +33,7 @@ export async function getAvailableProviders(): Promise<Provider[]> {
|
||||
)
|
||||
|
||||
// Cache the filtered results
|
||||
CacheService.set(PROVIDERS_CACHE_KEY, supportedProviders, PROVIDERS_CACHE_TTL)
|
||||
cacheService.set(PROVIDERS_CACHE_KEY, supportedProviders, PROVIDERS_CACHE_TTL)
|
||||
|
||||
logger.info('Providers filtered', {
|
||||
supported: supportedProviders.length,
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
import { CacheService } from '@main/services/CacheService'
|
||||
import { cacheService } from '@data/CacheService'
|
||||
import { loggerService } from '@logger'
|
||||
import mcpService from '@main/services/MCPService'
|
||||
import { reduxService } from '@main/services/ReduxService'
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
|
||||
import type { ListToolsResult } from '@modelcontextprotocol/sdk/types.js'
|
||||
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'
|
||||
import type { MCPServer } from '@types'
|
||||
|
||||
import { loggerService } from '../../services/LoggerService'
|
||||
import { reduxService } from '../../services/ReduxService'
|
||||
|
||||
const logger = loggerService.withContext('MCPApiService')
|
||||
|
||||
// Cache configuration
|
||||
@ -51,7 +50,7 @@ export async function getMCPServersFromRedux(): Promise<MCPServer[]> {
|
||||
logger.debug('Getting servers from Redux store')
|
||||
|
||||
// Try to get from cache first (faster)
|
||||
const cachedServers = CacheService.get<MCPServer[]>(MCP_SERVERS_CACHE_KEY)
|
||||
const cachedServers = cacheService.get<MCPServer[]>(MCP_SERVERS_CACHE_KEY)
|
||||
if (cachedServers) {
|
||||
logger.debug('MCP servers resolved from cache', { count: cachedServers.length })
|
||||
return cachedServers
|
||||
@ -62,7 +61,7 @@ export async function getMCPServersFromRedux(): Promise<MCPServer[]> {
|
||||
const serverList = servers || []
|
||||
|
||||
// Cache the results
|
||||
CacheService.set(MCP_SERVERS_CACHE_KEY, serverList, MCP_SERVERS_CACHE_TTL)
|
||||
cacheService.set(MCP_SERVERS_CACHE_KEY, serverList, MCP_SERVERS_CACHE_TTL)
|
||||
|
||||
logger.debug('Fetched servers from Redux store', { count: serverList.length })
|
||||
return serverList
|
||||
|
||||
@ -21,7 +21,8 @@ import type {
|
||||
OcrProvider,
|
||||
Provider,
|
||||
Shortcut,
|
||||
SupportedOcrFile} from '@types'
|
||||
SupportedOcrFile
|
||||
} from '@types'
|
||||
import checkDiskSpace from 'check-disk-space'
|
||||
import type { ProxyConfig } from 'electron'
|
||||
import { BrowserWindow, dialog, ipcMain, session, shell, systemPreferences, webContents } from 'electron'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { RowFlex } from '@cherrystudio/ui'
|
||||
import { FreeTrialModelTag } from '@renderer/components/FreeTrialModelTag'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import ModelTagsWithLabel from '@renderer/components/ModelTagsWithLabel'
|
||||
import { TopView } from '@renderer/components/TopView'
|
||||
import { DynamicVirtualList, type DynamicVirtualListRef } from '@renderer/components/VirtualList'
|
||||
@ -105,7 +105,7 @@ const PopupContainer: React.FC<Props> = ({ model, apiFilter, modelFilter, showTa
|
||||
type: 'model',
|
||||
name: (
|
||||
<ModelName>
|
||||
<HStack alignItems="center">{model.name}</HStack>
|
||||
<RowFlex className="items-center">{model.name}</RowFlex>
|
||||
{isCherryAi && <FreeTrialModelTag model={model} showLabel={false} />}
|
||||
</ModelName>
|
||||
),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, ScrollShadow } from '@heroui/react'
|
||||
import { loggerService } from '@logger'
|
||||
import { handleSaveData } from '@renderer/store'
|
||||
import { ReleaseNoteInfo, UpdateInfo } from 'builder-util-runtime'
|
||||
import type { ReleaseNoteInfo, UpdateInfo } from 'builder-util-runtime'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Markdown from 'react-markdown'
|
||||
|
||||
@ -290,9 +290,11 @@ const AgentSessionInputbar: FC<Props> = ({ agentId, sessionId }) => {
|
||||
<SendMessageButton sendMessage={sendMessage} disabled={sendDisabled} />
|
||||
{canAbort && (
|
||||
<Tooltip placement="top" content={t('chat.input.pause')}>
|
||||
<ActionIconButton onClick={abortAgentSession} style={{ marginRight: -2 }}>
|
||||
<CirclePause size={20} color="var(--color-error)" />
|
||||
</ActionIconButton>
|
||||
<ActionIconButton
|
||||
onClick={abortAgentSession}
|
||||
className="-mr-0.5"
|
||||
icon={<CirclePause size={20} color="var(--color-error)" />}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Button, DescriptionSwitch, HelpTooltip, RowFlex, Selector, type SelectorItem } from '@cherrystudio/ui'
|
||||
import { Button, DescriptionSwitch, HelpTooltip, RowFlex, Selector, type SelectorItem, Switch } from '@cherrystudio/ui'
|
||||
import { useMultiplePreferences, usePreference } from '@data/hooks/usePreference'
|
||||
import EditableNumber from '@renderer/components/EditableNumber'
|
||||
import Scrollbar from '@renderer/components/Scrollbar'
|
||||
@ -19,7 +19,7 @@ import { modalConfirm } from '@renderer/utils'
|
||||
import { getSendMessageShortcutLabel } from '@renderer/utils/input'
|
||||
import type { MultiModelMessageStyle, SendMessageShortcut } from '@shared/data/preference/preferenceTypes'
|
||||
import { ThemeMode } from '@shared/data/preference/preferenceTypes'
|
||||
import { Col, InputNumber, Row, Slider, Switch } from 'antd'
|
||||
import { Col, InputNumber, Row, Slider } from 'antd'
|
||||
import { Settings2 } from 'lucide-react'
|
||||
import type { FC } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
@ -245,10 +245,10 @@ const SettingsTab: FC<Props> = (props) => {
|
||||
<HelpTooltip title={t('chat.settings.temperature.tip')} />
|
||||
</SettingRowTitleSmall>
|
||||
<Switch
|
||||
size="small"
|
||||
size="sm"
|
||||
style={{ marginLeft: 'auto' }}
|
||||
checked={enableTemperature}
|
||||
onChange={(enabled) => {
|
||||
isSelected={enableTemperature}
|
||||
onValueChange={(enabled) => {
|
||||
setEnableTemperature(enabled)
|
||||
onUpdateAssistantSettings({ enableTemperature: enabled })
|
||||
}}
|
||||
@ -292,9 +292,9 @@ const SettingsTab: FC<Props> = (props) => {
|
||||
<SettingRow>
|
||||
<SettingRowTitleSmall>{t('models.stream_output')}</SettingRowTitleSmall>
|
||||
<Switch
|
||||
size="small"
|
||||
checked={streamOutput}
|
||||
onChange={(checked) => {
|
||||
size="sm"
|
||||
isSelected={streamOutput}
|
||||
onValueChange={(checked) => {
|
||||
setStreamOutput(checked)
|
||||
onUpdateAssistantSettings({ streamOutput: checked })
|
||||
}}
|
||||
@ -309,9 +309,9 @@ const SettingsTab: FC<Props> = (props) => {
|
||||
</SettingRowTitleSmall>
|
||||
</Row>
|
||||
<Switch
|
||||
size="small"
|
||||
checked={enableMaxTokens}
|
||||
onChange={async (enabled) => {
|
||||
size="sm"
|
||||
isSelected={enableMaxTokens}
|
||||
onValueChange={async (enabled) => {
|
||||
if (enabled) {
|
||||
const confirmed = await modalConfirm({
|
||||
title: t('chat.settings.max_tokens.confirm'),
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { SyncOutlined } from '@ant-design/icons'
|
||||
import { Button } from '@cherrystudio/ui'
|
||||
import { usePreference } from '@data/hooks/usePreference'
|
||||
import { useDisclosure } from '@heroui/react'
|
||||
import UpdateDialog from '@renderer/components/UpdateDialog'
|
||||
import { usePreference } from '@data/hooks/usePreference'
|
||||
import { useAppUpdateState } from '@renderer/hooks/useAppUpdate'
|
||||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
@ -2,7 +2,8 @@ import { Button, Input } from '@heroui/react'
|
||||
import { loggerService } from '@logger'
|
||||
import type { WebviewTag } from 'electron'
|
||||
import { ChevronDown, ChevronUp, X } from 'lucide-react'
|
||||
import { FC, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import type { FC } from 'react'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type FoundInPageResult = Electron.FoundInPageResult
|
||||
@ -121,7 +122,7 @@ const WebviewSearch: FC<WebviewSearchProps> = ({ webviewRef, isWebviewReady, app
|
||||
const nextWebview = webviewRef.current ?? null
|
||||
if (currentWebview === nextWebview) return
|
||||
setCurrentWebview(nextWebview)
|
||||
})
|
||||
}, [webviewRef, currentWebview])
|
||||
|
||||
useEffect(() => {
|
||||
const target = currentWebview
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { SpaceBetweenRowFlex } from '@cherrystudio/ui'
|
||||
import { SpaceBetweenRowFlex, Tooltip } from '@cherrystudio/ui'
|
||||
import { usePreference } from '@data/hooks/usePreference'
|
||||
import ActionIconButton from '@renderer/components/Buttons/ActionIconButton'
|
||||
import CodeEditor from '@renderer/components/CodeEditor'
|
||||
@ -6,9 +6,8 @@ import RichEditor from '@renderer/components/RichEditor'
|
||||
import type { RichEditorRef } from '@renderer/components/RichEditor/types'
|
||||
import Selector from '@renderer/components/Selector'
|
||||
import { useNotesSettings } from '@renderer/hooks/useNotesSettings'
|
||||
import { useAppDispatch } from '@renderer/store'
|
||||
import type { EditorView } from '@renderer/types'
|
||||
import { Empty, Tooltip } from 'antd'
|
||||
import { Empty } from 'antd'
|
||||
import { SpellCheck } from 'lucide-react'
|
||||
import type { FC, RefObject } from 'react'
|
||||
import { memo, useCallback, useMemo, useState } from 'react'
|
||||
@ -26,8 +25,6 @@ interface NotesEditorProps {
|
||||
const NotesEditor: FC<NotesEditorProps> = memo(
|
||||
({ activeNodeId, currentContent, tokenCount, onMarkdownChange, editorRef }) => {
|
||||
const { t } = useTranslation()
|
||||
// oxlint-disable-next-line no-unused-vars
|
||||
const dispatch = useAppDispatch()
|
||||
const { settings } = useNotesSettings()
|
||||
const [enableSpellCheck, setEnableSpellCheck] = usePreference('app.spell_check.enabled')
|
||||
const currentViewMode = useMemo(() => {
|
||||
@ -103,8 +100,7 @@ const NotesEditor: FC<NotesEditorProps> = memo(
|
||||
gap: 12
|
||||
}}>
|
||||
{tmpViewMode === 'preview' && (
|
||||
// oxlint-disable-next-line no-undef
|
||||
<Tooltip placement="top" title={t('notes.spell_check_tooltip')} mouseLeaveDelay={0} arrow>
|
||||
<Tooltip placement="top" content={t('notes.spell_check_tooltip')} closeDelay={0}>
|
||||
<ActionIconButton
|
||||
active={enableSpellCheck}
|
||||
onClick={() => {
|
||||
@ -115,7 +111,6 @@ const NotesEditor: FC<NotesEditorProps> = memo(
|
||||
icon={<SpellCheck size={18} />}>
|
||||
<SpellCheck size={18} />
|
||||
</ActionIconButton>
|
||||
{/* oxlint-disable-next-line no-undef */}
|
||||
</Tooltip>
|
||||
)}
|
||||
<Selector
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { GithubOutlined } from '@ant-design/icons'
|
||||
import { RowFlex, Switch, Tooltip, Avatar, Button } from '@cherrystudio/ui'
|
||||
import { Avatar, Button, RowFlex, Switch, Tooltip } from '@cherrystudio/ui'
|
||||
import { usePreference } from '@data/hooks/usePreference'
|
||||
import { Radio, RadioGroup, useDisclosure } from '@heroui/react'
|
||||
import IndicatorLight from '@renderer/components/IndicatorLight'
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { Button } from '@cherrystudio/ui'
|
||||
import { Button, SpaceBetweenRowFlex } from '@cherrystudio/ui'
|
||||
import CodeEditor from '@renderer/components/CodeEditor'
|
||||
import { HSpaceBetweenStack } from '@renderer/components/Layout'
|
||||
import type { RichEditorRef } from '@renderer/components/RichEditor/types'
|
||||
import type { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent'
|
||||
import type { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
|
||||
@ -83,14 +82,12 @@ const PromptSettings: FC<AgentPromptSettingsProps> = ({ agentBase, update }) =>
|
||||
onChange={setInstructions}
|
||||
height="100%"
|
||||
expanded={false}
|
||||
style={{
|
||||
height: '100%'
|
||||
}}
|
||||
className="h-full"
|
||||
/>
|
||||
)}
|
||||
</RichEditorContainer>
|
||||
</TextAreaContainer>
|
||||
<HSpaceBetweenStack width="100%" justifyContent="flex-end" mt="10px">
|
||||
<SpaceBetweenRowFlex className="mt-2.5 w-full justify-end">
|
||||
<TokenCount>Tokens: {tokenCount}</TokenCount>
|
||||
<Button
|
||||
variant="solid"
|
||||
@ -111,7 +108,7 @@ const PromptSettings: FC<AgentPromptSettingsProps> = ({ agentBase, update }) =>
|
||||
}}>
|
||||
{showPreview ? t('common.edit') : t('common.save')}
|
||||
</Button>
|
||||
</HSpaceBetweenStack>
|
||||
</SpaceBetweenRowFlex>
|
||||
</SettingsItem>
|
||||
</SettingsContainer>
|
||||
)
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { Button, RowFlex } from '@cherrystudio/ui'
|
||||
import { loggerService } from '@logger'
|
||||
import { TopView } from '@renderer/components/TopView'
|
||||
import { useTimer } from '@renderer/hooks/useTimer'
|
||||
import type { Provider } from '@renderer/types'
|
||||
import type { FormProps } from 'antd'
|
||||
import { AutoComplete, Button, Flex, Form, Input, Modal, Progress, Select } from 'antd'
|
||||
import { AutoComplete, Form, Input, Modal, Progress, Select } from 'antd'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { useTimer } from '../../../../hooks/useTimer'
|
||||
|
||||
const logger = loggerService.withContext('OVMSClient')
|
||||
|
||||
interface ShowParams {
|
||||
@ -233,7 +233,7 @@ const PopupContainer: React.FC<Props> = ({ title, resolve }) => {
|
||||
labelCol={{ flex: '110px' }}
|
||||
labelAlign="left"
|
||||
colon={false}
|
||||
style={{ marginTop: 25 }}
|
||||
className="mt-[25px]"
|
||||
onFinish={onFinish}
|
||||
disabled={false}>
|
||||
<Form.Item
|
||||
@ -299,7 +299,7 @@ const PopupContainer: React.FC<Props> = ({ title, resolve }) => {
|
||||
/>
|
||||
</Form.Item>
|
||||
{loading && (
|
||||
<Form.Item style={{ marginBottom: 16 }}>
|
||||
<Form.Item className="mb-4">
|
||||
<Progress
|
||||
percent={Math.round(progress)}
|
||||
status={progress === 100 ? 'success' : 'active'}
|
||||
@ -310,22 +310,21 @@ const PopupContainer: React.FC<Props> = ({ title, resolve }) => {
|
||||
showInfo={true}
|
||||
format={(percent) => `${percent}%`}
|
||||
/>
|
||||
<div style={{ textAlign: 'center', marginTop: 8, color: '#666', fontSize: '14px' }}>
|
||||
{t('ovms.download.tip')}
|
||||
</div>
|
||||
<div className="mt-2 text-center text-[#666] text-sm">{t('ovms.download.tip')}</div>
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item style={{ marginBottom: 8, textAlign: 'center' }}>
|
||||
<Flex justify="end" align="center" style={{ position: 'relative' }}>
|
||||
<Form.Item className="mb-2 text-center">
|
||||
<RowFlex className="relative items-center justify-end">
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType={loading ? 'button' : 'submit'}
|
||||
size="middle"
|
||||
loading={false}
|
||||
onClick={loading ? onCancel : undefined}>
|
||||
color="primary"
|
||||
variant="solid"
|
||||
type={loading ? 'button' : 'submit'}
|
||||
size="md"
|
||||
isLoading={false}
|
||||
onPress={loading ? onCancel : undefined}>
|
||||
{loading ? t('common.cancel') : t('ovms.download.button')}
|
||||
</Button>
|
||||
</Flex>
|
||||
</RowFlex>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { VStack } from '@renderer/components/Layout'
|
||||
import { Alert, Button } from 'antd'
|
||||
import { Button, ColFlex } from '@cherrystudio/ui'
|
||||
import { Alert } from 'antd'
|
||||
import type { FC } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -109,52 +109,55 @@ const OVMSSettings: FC = () => {
|
||||
banner
|
||||
style={{ borderRadius: 'var(--list-item-border-radius)' }}
|
||||
description={
|
||||
<VStack>
|
||||
<ColFlex>
|
||||
<SettingRow style={{ width: '100%' }}>
|
||||
<SettingSubtitle style={{ margin: 0, fontWeight: 'normal' }}>{getStatusMessage()}</SettingSubtitle>
|
||||
{ovmsStatus === 'not-installed' && (
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={installOvms}
|
||||
loading={isInstallingOvms}
|
||||
disabled={isInstallingOvms}
|
||||
size="small">
|
||||
color="primary"
|
||||
variant="solid"
|
||||
onPress={installOvms}
|
||||
isLoading={isInstallingOvms}
|
||||
isDisabled={isInstallingOvms}
|
||||
size="sm">
|
||||
{isInstallingOvms ? t('ovms.action.installing') : t('ovms.action.install')}
|
||||
</Button>
|
||||
)}
|
||||
{ovmsStatus === 'not-running' && (
|
||||
<div style={{ display: 'flex', gap: '8px' }}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={installOvms}
|
||||
loading={isInstallingOvms}
|
||||
disabled={isInstallingOvms || isRunningOvms}
|
||||
size="small">
|
||||
color="primary"
|
||||
variant="solid"
|
||||
onPress={installOvms}
|
||||
isLoading={isInstallingOvms}
|
||||
isDisabled={isInstallingOvms || isRunningOvms}
|
||||
size="sm">
|
||||
{isInstallingOvms ? t('ovms.action.installing') : t('ovms.action.reinstall')}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={runOvms}
|
||||
loading={isRunningOvms}
|
||||
disabled={isRunningOvms}
|
||||
size="small">
|
||||
color="primary"
|
||||
variant="solid"
|
||||
onPress={runOvms}
|
||||
isLoading={isRunningOvms}
|
||||
isDisabled={isRunningOvms}
|
||||
size="sm">
|
||||
{isRunningOvms ? t('ovms.action.starting') : t('ovms.action.run')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{ovmsStatus === 'running' && (
|
||||
<Button
|
||||
type="primary"
|
||||
danger
|
||||
onClick={stopOvms}
|
||||
loading={isStoppingOvms}
|
||||
disabled={isStoppingOvms}
|
||||
size="small">
|
||||
color="danger"
|
||||
variant="solid"
|
||||
onPress={stopOvms}
|
||||
isLoading={isStoppingOvms}
|
||||
isDisabled={isStoppingOvms}
|
||||
size="sm">
|
||||
{isStoppingOvms ? t('ovms.action.stopping') : t('ovms.action.stop')}
|
||||
</Button>
|
||||
)}
|
||||
</SettingRow>
|
||||
</VStack>
|
||||
</ColFlex>
|
||||
}
|
||||
/>
|
||||
<Alert
|
||||
|
||||
Loading…
Reference in New Issue
Block a user