mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-09 14:59:27 +08:00
feat(provider-settings): add option to hide disabled providers
- Add hide disabled providers toggle in provider settings - Update preference schema to store the setting - Refactor provider list layout to accommodate new toggle
This commit is contained in:
parent
736aef22c4
commit
b6fa2583d1
@ -47,6 +47,7 @@ export interface PreferenceSchemas {
|
|||||||
'app.proxy.mode': PreferenceTypes.ProxyMode
|
'app.proxy.mode': PreferenceTypes.ProxyMode
|
||||||
// redux/settings/proxyUrl
|
// redux/settings/proxyUrl
|
||||||
'app.proxy.url': string
|
'app.proxy.url': string
|
||||||
|
'app.settings.provider.hide_disabled': boolean
|
||||||
// redux/settings/enableSpellCheck
|
// redux/settings/enableSpellCheck
|
||||||
'app.spell_check.enabled': boolean
|
'app.spell_check.enabled': boolean
|
||||||
// redux/settings/spellCheckLanguages
|
// redux/settings/spellCheckLanguages
|
||||||
@ -433,6 +434,7 @@ export const DefaultPreferences: PreferenceSchemas = {
|
|||||||
'app.proxy.bypass_rules': '',
|
'app.proxy.bypass_rules': '',
|
||||||
'app.proxy.mode': 'system',
|
'app.proxy.mode': 'system',
|
||||||
'app.proxy.url': '',
|
'app.proxy.url': '',
|
||||||
|
'app.settings.provider.hide_disabled': false,
|
||||||
'app.spell_check.enabled': false,
|
'app.spell_check.enabled': false,
|
||||||
'app.spell_check.languages': [],
|
'app.spell_check.languages': [],
|
||||||
'app.tray.enabled': true,
|
'app.tray.enabled': true,
|
||||||
|
|||||||
@ -4176,6 +4176,11 @@
|
|||||||
"docs_check": "Check",
|
"docs_check": "Check",
|
||||||
"docs_more_details": "for more details",
|
"docs_more_details": "for more details",
|
||||||
"get_api_key": "Get API Key",
|
"get_api_key": "Get API Key",
|
||||||
|
"list": {
|
||||||
|
"settings": {
|
||||||
|
"hide_disabled": "Hide disabled providers"
|
||||||
|
}
|
||||||
|
},
|
||||||
"misc": "Other",
|
"misc": "Other",
|
||||||
"no_models_for_check": "No models available for checking (e.g. chat models)",
|
"no_models_for_check": "No models available for checking (e.g. chat models)",
|
||||||
"not_checked": "Not Checked",
|
"not_checked": "Not Checked",
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { Button } from '@cherrystudio/ui'
|
import { Button, Popover, PopoverContent, PopoverTrigger, Switch } from '@cherrystudio/ui'
|
||||||
|
import { usePreference } from '@data/hooks/usePreference'
|
||||||
import type { DropResult } from '@hello-pangea/dnd'
|
import type { DropResult } from '@hello-pangea/dnd'
|
||||||
import { loggerService } from '@logger'
|
import { loggerService } from '@logger'
|
||||||
import {
|
import {
|
||||||
@ -16,7 +17,7 @@ import { isSystemProvider } from '@renderer/types'
|
|||||||
import { getFancyProviderName, matchKeywordsInModel, matchKeywordsInProvider, uuid } from '@renderer/utils'
|
import { getFancyProviderName, matchKeywordsInModel, matchKeywordsInProvider, uuid } from '@renderer/utils'
|
||||||
import type { MenuProps } from 'antd'
|
import type { MenuProps } from 'antd'
|
||||||
import { Dropdown, Input, Tag } from 'antd'
|
import { Dropdown, Input, Tag } from 'antd'
|
||||||
import { GripVertical, PlusIcon, Search, UserPen } from 'lucide-react'
|
import { GripVertical, PlusIcon, Search, SettingsIcon, UserPen } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { startTransition, useCallback, useEffect, useRef, useState } from 'react'
|
import { startTransition, useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -30,7 +31,6 @@ import UrlSchemaInfoPopup from './UrlSchemaInfoPopup'
|
|||||||
|
|
||||||
const logger = loggerService.withContext('ProviderList')
|
const logger = loggerService.withContext('ProviderList')
|
||||||
|
|
||||||
const BUTTON_WRAPPER_HEIGHT = 50
|
|
||||||
const systemType = await window.api.system.getDeviceType()
|
const systemType = await window.api.system.getDeviceType()
|
||||||
const cpuName = await window.api.system.getCpuName()
|
const cpuName = await window.api.system.getCpuName()
|
||||||
|
|
||||||
@ -45,6 +45,7 @@ const ProviderList: FC = () => {
|
|||||||
const [dragging, setDragging] = useState(false)
|
const [dragging, setDragging] = useState(false)
|
||||||
const [providerLogos, setProviderLogos] = useState<Record<string, string>>({})
|
const [providerLogos, setProviderLogos] = useState<Record<string, string>>({})
|
||||||
const listRef = useRef<DraggableVirtualListRef>(null)
|
const listRef = useRef<DraggableVirtualListRef>(null)
|
||||||
|
const [hideDisabled, setHideDisabled] = usePreference('app.settings.provider.hide_disabled')
|
||||||
|
|
||||||
const setSelectedProvider = useCallback((provider: Provider) => {
|
const setSelectedProvider = useCallback((provider: Provider) => {
|
||||||
startTransition(() => _setSelectedProvider(provider))
|
startTransition(() => _setSelectedProvider(provider))
|
||||||
@ -283,6 +284,10 @@ const ProviderList: FC = () => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hideDisabled && !provider.enabled) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
const keywords = searchText.toLowerCase().split(/\s+/).filter(Boolean)
|
const keywords = searchText.toLowerCase().split(/\s+/).filter(Boolean)
|
||||||
const isProviderMatch = matchKeywordsInProvider(keywords, provider)
|
const isProviderMatch = matchKeywordsInProvider(keywords, provider)
|
||||||
const isModelMatch = provider.models.some((model) => matchKeywordsInModel(keywords, model))
|
const isModelMatch = provider.models.some((model) => matchKeywordsInModel(keywords, model))
|
||||||
@ -311,12 +316,12 @@ const ProviderList: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<Container className="selectable">
|
<Container className="selectable">
|
||||||
<ProviderListContainer>
|
<ProviderListContainer>
|
||||||
<AddButtonWrapper>
|
<header className="flex h-11 gap-1 p-1">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={t('settings.provider.search')}
|
placeholder={t('settings.provider.search')}
|
||||||
value={searchText}
|
value={searchText}
|
||||||
style={{ borderRadius: 'var(--list-item-border-radius)', height: 35 }}
|
style={{ borderRadius: 'var(--list-item-border-radius)' }}
|
||||||
suffix={<Search size={14} />}
|
suffix={<Search size={14} />}
|
||||||
onChange={(e) => setSearchText(e.target.value)}
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
@ -328,7 +333,29 @@ const ProviderList: FC = () => {
|
|||||||
allowClear
|
allowClear
|
||||||
disabled={dragging}
|
disabled={dragging}
|
||||||
/>
|
/>
|
||||||
</AddButtonWrapper>
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
startContent={<SettingsIcon size={18} />}
|
||||||
|
isIconOnly
|
||||||
|
className="h-full min-h-0 w-9 min-w-0"
|
||||||
|
/>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent>
|
||||||
|
<ul className="flex h-full w-full flex-col">
|
||||||
|
<li className="flex flex-row items-center justify-between">
|
||||||
|
<Switch
|
||||||
|
isSelected={hideDisabled}
|
||||||
|
onValueChange={setHideDisabled}
|
||||||
|
classNames={{ base: 'flex-1 flex-row-reverse justify-between max-w-full' }}>
|
||||||
|
{t('settings.provider.list.settings.hide_disabled')}
|
||||||
|
</Switch>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</header>
|
||||||
<DraggableVirtualList
|
<DraggableVirtualList
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
list={filteredProviders}
|
list={filteredProviders}
|
||||||
@ -338,7 +365,8 @@ const ProviderList: FC = () => {
|
|||||||
itemKey={itemKey}
|
itemKey={itemKey}
|
||||||
overscan={3}
|
overscan={3}
|
||||||
style={{
|
style={{
|
||||||
height: `calc(100% - 2 * ${BUTTON_WRAPPER_HEIGHT}px)`
|
flex: 1,
|
||||||
|
overflow: 'hidden'
|
||||||
}}
|
}}
|
||||||
scrollerStyle={{
|
scrollerStyle={{
|
||||||
padding: 8,
|
padding: 8,
|
||||||
@ -372,7 +400,7 @@ const ProviderList: FC = () => {
|
|||||||
</Dropdown>
|
</Dropdown>
|
||||||
)}
|
)}
|
||||||
</DraggableVirtualList>
|
</DraggableVirtualList>
|
||||||
<AddButtonWrapper>
|
<footer className="h-12">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
style={{ width: '100%', borderRadius: 'var(--list-item-border-radius)' }}
|
style={{ width: '100%', borderRadius: 'var(--list-item-border-radius)' }}
|
||||||
@ -381,7 +409,7 @@ const ProviderList: FC = () => {
|
|||||||
isDisabled={dragging}>
|
isDisabled={dragging}>
|
||||||
{t('button.add')}
|
{t('button.add')}
|
||||||
</Button>
|
</Button>
|
||||||
</AddButtonWrapper>
|
</footer>
|
||||||
</ProviderListContainer>
|
</ProviderListContainer>
|
||||||
<ProviderSetting providerId={selectedProvider.id} key={selectedProvider.id} />
|
<ProviderSetting providerId={selectedProvider.id} key={selectedProvider.id} />
|
||||||
</Container>
|
</Container>
|
||||||
@ -451,12 +479,4 @@ const ProviderItemName = styled.div`
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
`
|
`
|
||||||
|
|
||||||
const AddButtonWrapper = styled.div`
|
|
||||||
height: ${BUTTON_WRAPPER_HEIGHT}px;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 10px 8px;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default ProviderList
|
export default ProviderList
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export { default as ProviderList } from './ProviderList'
|
|
||||||
@ -33,7 +33,7 @@ import GeneralSettings from './GeneralSettings'
|
|||||||
import MCPSettings from './MCPSettings'
|
import MCPSettings from './MCPSettings'
|
||||||
import MemorySettings from './MemorySettings'
|
import MemorySettings from './MemorySettings'
|
||||||
import NotesSettings from './NotesSettings'
|
import NotesSettings from './NotesSettings'
|
||||||
import { ProviderList } from './ProviderSettings'
|
import ProviderList from './ProviderSettings/ProviderList'
|
||||||
import QuickAssistantSettings from './QuickAssistantSettings'
|
import QuickAssistantSettings from './QuickAssistantSettings'
|
||||||
import QuickPhraseSettings from './QuickPhraseSettings'
|
import QuickPhraseSettings from './QuickPhraseSettings'
|
||||||
import SelectionAssistantSettings from './SelectionAssistantSettings/SelectionAssistantSettings'
|
import SelectionAssistantSettings from './SelectionAssistantSettings/SelectionAssistantSettings'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user