Compare commits

...

4 Commits

Author SHA1 Message Date
icarus
d8b841c386 Merge branch 'feat/show-enabled-provider-only' of github.com:CherryHQ/cherry-studio into feat/show-enabled-provider-only 2025-10-24 21:09:45 +08:00
icarus
5ee120db7c refactor(provider): change hide disabled providers to show disabled providers
Update the provider settings to use a more intuitive "show disabled" toggle instead of "hide disabled". This includes updating the preference schema, default value, and UI components to reflect this change.
2025-10-24 21:09:22 +08:00
GitHub Action
c22034080c fix(i18n): Auto update translations for PR #10933 2025-10-23 20:13:41 +00:00
icarus
b6fa2583d1 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
2025-10-24 04:10:02 +08:00
13 changed files with 113 additions and 87 deletions

View File

@@ -399,6 +399,7 @@ export interface PreferenceSchemas {
'ui.custom_css': string
// redux/settings/navbarPosition
'ui.navbar.position': 'left' | 'top'
'ui.provider.show_disabled': boolean
// redux/settings/sidebarIcons.disabled
'ui.sidebar.icons.invisible': PreferenceTypes.SidebarIcon[]
// redux/settings/sidebarIcons.visible
@@ -656,6 +657,7 @@ export const DefaultPreferences: PreferenceSchemas = {
'topic.tab.show_time': false,
'ui.custom_css': '',
'ui.navbar.position': 'top',
'ui.provider.show_disabled': true,
'ui.sidebar.icons.invisible': [],
'ui.sidebar.icons.visible': [
'assistants',

View File

@@ -4176,6 +4176,11 @@
"docs_check": "Check",
"docs_more_details": "for more details",
"get_api_key": "Get API Key",
"list": {
"settings": {
"show_disabled": "Show disabled providers"
}
},
"misc": "Other",
"no_models_for_check": "No models available for checking (e.g. chat models)",
"not_checked": "Not Checked",
@@ -4230,7 +4235,7 @@
"system": "System Proxy",
"title": "Proxy Mode"
},
"tip": "[to be translated]:支持模糊匹配(*.test.com,192.168.0.0/16)"
"tip": "Supports fuzzy matching (*.test.com, 192.168.0.0/16)"
},
"quickAssistant": {
"click_tray_to_show": "Click the tray icon to start",

View File

@@ -538,7 +538,7 @@
"context": "清除上下文 {{Command}}"
},
"new_topic": "新話題 {{Command}}",
"paste_text_file_confirm": "[to be translated]:粘贴到输入框?",
"paste_text_file_confirm": "貼到輸入框?",
"pause": "暫停",
"placeholder": "在此輸入您的訊息,按 {{key}} 傳送 - @ 選擇模型,/ 包含工具",
"placeholder_without_triggers": "在此輸入您的訊息,按 {{key}} 傳送",
@@ -4230,7 +4230,7 @@
"system": "系統代理伺服器",
"title": "代理伺服器模式"
},
"tip": "[to be translated]:支持模糊匹配(*.test.com,192.168.0.0/16)"
"tip": "支援模糊匹配*.test.com,192.168.0.0/16"
},
"quickAssistant": {
"click_tray_to_show": "點選工具列圖示啟動",

View File

@@ -2656,11 +2656,11 @@
"go_to_settings": "Zu Einstellungen",
"open_accessibility_settings": "Bedienungshilfen-Einstellungen öffnen"
},
"description": [
"Der Textauswahl-Assistent benötigt <strong>Bedienungshilfen-Berechtigungen</strong>, um ordnungsgemäß zu funktionieren.",
"Klicken Sie auf <strong>Zu Einstellungen</strong> und anschließend im Berechtigungsdialog auf <strong>Systemeinstellungen öffnen</strong>. Suchen Sie danach in der App-Liste <strong>Cherry Studio</strong> und aktivieren Sie den Schalter.",
"Nach Abschluss der Einrichtung Textauswahl-Assistent erneut aktivieren."
],
"description": {
"0": "Der Textauswahl-Assistent benötigt <strong>Bedienungshilfen-Berechtigungen</strong>, um ordnungsgemäß zu funktionieren.",
"1": "Klicken Sie auf <strong>Zu Einstellungen</strong> und anschließend im Berechtigungsdialog auf <strong>Systemeinstellungen öffnen</strong>. Suchen Sie danach in der App-Liste <strong>Cherry Studio</strong> und aktivieren Sie den Schalter.",
"2": "Nach Abschluss der Einrichtung Textauswahl-Assistent erneut aktivieren."
},
"title": "Bedienungshilfen-Berechtigung"
},
"title": "Aktivieren"

View File

@@ -538,7 +538,7 @@
"context": "Καθαρισμός ενδιάμεσων {{Command}}"
},
"new_topic": "Νέο θέμα {{Command}}",
"paste_text_file_confirm": "[to be translated]:粘贴到输入框?",
"paste_text_file_confirm": "Επικόλληση στο πλαίσιο εισόδου;",
"pause": "Παύση",
"placeholder": "Εισάγετε μήνυμα εδώ...",
"placeholder_without_triggers": "Γράψτε το μήνυμά σας εδώ, πατήστε {{key}} για αποστολή",
@@ -1962,12 +1962,12 @@
"rename_changed": "Λόγω πολιτικής ασφάλειας, το όνομα του αρχείου έχει αλλάξει από {{original}} σε {{final}}",
"save": "αποθήκευση στις σημειώσεις",
"search": {
"both": "[to be translated]:名称+内容",
"content": "[to be translated]:内容",
"found_results": "[to be translated]:找到 {{count}} 个结果 (名称: {{nameCount}}, 内容: {{contentCount}})",
"more_matches": "[to be translated]:个匹配",
"searching": "[to be translated]:搜索中...",
"show_less": "[to be translated]:收起"
"both": "Όνομα + περιεχόμενο",
"content": "περιεχόμενο",
"found_results": "Βρέθηκαν {{count}} αποτελέσματα (όνομα: {{nameCount}}, περιεχόμενο: {{contentCount}})",
"more_matches": "ένας αγώνας",
"searching": "Αναζήτηση...",
"show_less": "κλείσιμο"
},
"settings": {
"data": {
@@ -2117,8 +2117,8 @@
"install_code_103": "Η λήψη του OVMS runtime απέτυχε",
"install_code_104": "Η αποσυμπίεση του OVMS runtime απέτυχε",
"install_code_105": "Ο καθαρισμός του OVMS runtime απέτυχε",
"install_code_106": "[to be translated]:创建 run.bat 失败",
"install_code_110": "[to be translated]:清理旧 OVMS runtime 失败",
"install_code_106": "Η δημιουργία του run.bat απέτυχε",
"install_code_110": "Η διαγραφή του παλιού χρόνου εκτέλεσης OVMS απέτυχε",
"run": "Η εκτέλεση του OVMS απέτυχε:",
"stop": "Η διακοπή του OVMS απέτυχε:"
},
@@ -4230,7 +4230,7 @@
"system": "συστηματική προξενική",
"title": "κλίμακα προξενικής"
},
"tip": "[to be translated]:支持模糊匹配(*.test.com,192.168.0.0/16)"
"tip": "υποστηρίζει ασαφή αντιστοίχιση (*.test.com,192.168.0.0/16)"
},
"quickAssistant": {
"click_tray_to_show": "Επιλέξτε την εικόνα στο πίνακα για να ενεργοποιήσετε",

View File

@@ -538,7 +538,7 @@
"context": "Limpiar contexto {{Command}}"
},
"new_topic": "Nuevo tema {{Command}}",
"paste_text_file_confirm": "[to be translated]:粘贴到输入框?",
"paste_text_file_confirm": "¿Pegar en el cuadro de entrada?",
"pause": "Pausar",
"placeholder": "Escribe aquí tu mensaje...",
"placeholder_without_triggers": "Escribe tu mensaje aquí, presiona {{key}} para enviar",
@@ -1962,12 +1962,12 @@
"rename_changed": "Debido a políticas de seguridad, el nombre del archivo ha cambiado de {{original}} a {{final}}",
"save": "Guardar en notas",
"search": {
"both": "[to be translated]:名称+内容",
"content": "[to be translated]:内容",
"found_results": "[to be translated]:找到 {{count}} 个结果 (名称: {{nameCount}}, 内容: {{contentCount}})",
"more_matches": "[to be translated]:个匹配",
"searching": "[to be translated]:搜索中...",
"show_less": "[to be translated]:收起"
"both": "nombre+contenido",
"content": "contenido",
"found_results": "encontrados {{count}} resultados (nombre: {{nameCount}}, contenido: {{contentCount}})",
"more_matches": "una coincidencia",
"searching": "Buscando...",
"show_less": "Recoger"
},
"settings": {
"data": {
@@ -2117,8 +2117,8 @@
"install_code_103": "Error al descargar el tiempo de ejecución de OVMS",
"install_code_104": "Error al descomprimir el tiempo de ejecución de OVMS",
"install_code_105": "Error al limpiar el tiempo de ejecución de OVMS",
"install_code_106": "[to be translated]:创建 run.bat 失败",
"install_code_110": "[to be translated]:清理旧 OVMS runtime 失败",
"install_code_106": "Error al crear run.bat",
"install_code_110": "Error al limpiar el antiguo runtime de OVMS",
"run": "Error al ejecutar OVMS:",
"stop": "Error al detener OVMS:"
},
@@ -4230,7 +4230,7 @@
"system": "Proxy del sistema",
"title": "Modo de proxy"
},
"tip": "[to be translated]:支持模糊匹配(*.test.com,192.168.0.0/16)"
"tip": "Admite coincidencia difusa (*.test.com,192.168.0.0/16)"
},
"quickAssistant": {
"click_tray_to_show": "Haz clic en el icono de la bandeja para iniciar",

View File

@@ -538,7 +538,7 @@
"context": "Effacer le contexte {{Command}}"
},
"new_topic": "Nouveau sujet {{Command}}",
"paste_text_file_confirm": "[to be translated]:粘贴到输入框?",
"paste_text_file_confirm": "Coller dans la zone de saisie ?",
"pause": "Pause",
"placeholder": "Entrez votre message ici...",
"placeholder_without_triggers": "Tapez votre message ici, appuyez sur {{key}} pour envoyer",
@@ -1962,12 +1962,12 @@
"rename_changed": "En raison de la politique de sécurité, le nom du fichier a été changé de {{original}} à {{final}}",
"save": "sauvegarder dans les notes",
"search": {
"both": "[to be translated]:名称+内容",
"content": "[to be translated]:内容",
"found_results": "[to be translated]:找到 {{count}} 个结果 (名称: {{nameCount}}, 内容: {{contentCount}})",
"more_matches": "[to be translated]:个匹配",
"searching": "[to be translated]:搜索中...",
"show_less": "[to be translated]:收起"
"both": "Nom + contenu",
"content": "suivre linstruction du système",
"found_results": "{{count}} résultats trouvés (nom : {{nameCount}}, contenu : {{contentCount}})",
"more_matches": "une correspondance",
"searching": "Recherche en cours...",
"show_less": "Replier"
},
"settings": {
"data": {
@@ -2117,8 +2117,8 @@
"install_code_103": "Échec du téléchargement du runtime OVMS",
"install_code_104": "Échec de la décompression du runtime OVMS",
"install_code_105": "Échec du nettoyage du runtime OVMS",
"install_code_106": "[to be translated]:创建 run.bat 失败",
"install_code_110": "[to be translated]:清理旧 OVMS runtime 失败",
"install_code_106": "Échec de la création de run.bat",
"install_code_110": "Échec du nettoyage de l'ancien runtime OVMS",
"run": "Échec de l'exécution d'OVMS :",
"stop": "Échec de l'arrêt d'OVMS :"
},
@@ -4230,7 +4230,7 @@
"system": "Proxy système",
"title": "Mode de proxy"
},
"tip": "[to be translated]:支持模糊匹配(*.test.com,192.168.0.0/16)"
"tip": "Prise en charge de la correspondance floue (*.test.com, 192.168.0.0/16)"
},
"quickAssistant": {
"click_tray_to_show": "Cliquez sur l'icône dans la barre d'état système pour démarrer",

View File

@@ -538,7 +538,7 @@
"context": "コンテキストをクリア {{Command}}"
},
"new_topic": "新しいトピック {{Command}}",
"paste_text_file_confirm": "[to be translated]:粘贴到输入框",
"paste_text_file_confirm": "入力ボックスに貼り付けますか",
"pause": "一時停止",
"placeholder": "ここにメッセージを入力し、{{key}} を押して送信...",
"placeholder_without_triggers": "ここにメッセージを入力し、{{key}} を押して送信...",
@@ -1962,12 +1962,12 @@
"rename_changed": "セキュリティポリシーにより、ファイル名は{{original}}から{{final}}に変更されました",
"save": "メモに保存する",
"search": {
"both": "[to be translated]:名称+内容",
"content": "[to be translated]:内容",
"found_results": "[to be translated]:找到 {{count}} 个结果 (名称: {{nameCount}}, 内容: {{contentCount}})",
"more_matches": "[to be translated]:个匹配",
"searching": "[to be translated]:搜索中...",
"show_less": "[to be translated]:收起"
"both": "名称+内容",
"content": "内容",
"found_results": "{{count}} 件の結果が見つかりました(名称: {{nameCount}}内容: {{contentCount}}",
"more_matches": "個マッチ",
"searching": "索中...",
"show_less": "閉じる"
},
"settings": {
"data": {
@@ -2117,8 +2117,8 @@
"install_code_103": "OVMSランタイムのダウンロードに失敗しました",
"install_code_104": "OVMSランタイムの解凍に失敗しました",
"install_code_105": "OVMSランタイムのクリーンアップに失敗しました",
"install_code_106": "[to be translated]:创建 run.bat 失败",
"install_code_110": "[to be translated]:清理旧 OVMS runtime 失败",
"install_code_106": "run.batの作成に失敗しました",
"install_code_110": "古いOVMSランタイムのクリーンアップに失敗しました",
"run": "OVMSの実行に失敗しました:",
"stop": "OVMSの停止に失敗しました:"
},
@@ -4230,7 +4230,7 @@
"system": "システムプロキシ",
"title": "プロキシモード"
},
"tip": "[to be translated]:支持模糊匹配(*.test.com,192.168.0.0/16)"
"tip": "ワイルドカード一致をサポート (*.test.com, 192.168.0.0/16)"
},
"quickAssistant": {
"click_tray_to_show": "トレイアイコンをクリックして起動",

View File

@@ -538,7 +538,7 @@
"context": "Limpar contexto {{Command}}"
},
"new_topic": "Novo tópico {{Command}}",
"paste_text_file_confirm": "[to be translated]:粘贴到输入框?",
"paste_text_file_confirm": "Colar na caixa de entrada?",
"pause": "Pausar",
"placeholder": "Digite sua mensagem aqui...",
"placeholder_without_triggers": "Escreve a tua mensagem aqui, pressiona {{key}} para enviar",
@@ -1962,12 +1962,12 @@
"rename_changed": "Devido às políticas de segurança, o nome do arquivo foi alterado de {{original}} para {{final}}",
"save": "salvar em notas",
"search": {
"both": "[to be translated]:名称+内容",
"content": "[to be translated]:内容",
"found_results": "[to be translated]:找到 {{count}} 个结果 (名称: {{nameCount}}, 内容: {{contentCount}})",
"more_matches": "[to be translated]:个匹配",
"searching": "[to be translated]:搜索中...",
"show_less": "[to be translated]:收起"
"both": "nome+conteúdo",
"content": "conteúdo",
"found_results": "Encontrados {{count}} resultados (nome: {{nameCount}}, conteúdo: {{contentCount}})",
"more_matches": "个匹配",
"searching": "Procurando...",
"show_less": "Recolher"
},
"settings": {
"data": {
@@ -2117,8 +2117,8 @@
"install_code_103": "Falha ao baixar o tempo de execução do OVMS",
"install_code_104": "Falha ao descompactar o tempo de execução do OVMS",
"install_code_105": "Falha ao limpar o tempo de execução do OVMS",
"install_code_106": "[to be translated]:创建 run.bat 失败",
"install_code_110": "[to be translated]:清理旧 OVMS runtime 失败",
"install_code_106": "Falha ao criar run.bat",
"install_code_110": "Falha ao limpar o antigo runtime OVMS",
"run": "Falha ao executar o OVMS:",
"stop": "Falha ao parar o OVMS:"
},
@@ -4230,7 +4230,7 @@
"system": "Proxy do Sistema",
"title": "Modo de Proxy"
},
"tip": "[to be translated]:支持模糊匹配(*.test.com,192.168.0.0/16)"
"tip": "Suporta correspondência difusa (*.test.com, 192.168.0.0/16)"
},
"quickAssistant": {
"click_tray_to_show": "Clique no ícone da bandeja para iniciar",

View File

@@ -538,7 +538,7 @@
"context": "Очистить контекст {{Command}}"
},
"new_topic": "Новый топик {{Command}}",
"paste_text_file_confirm": "[to be translated]:粘贴到输入框?",
"paste_text_file_confirm": "Вставить в поле ввода?",
"pause": "Остановить",
"placeholder": "Введите ваше сообщение здесь, нажмите {{key}} для отправки...",
"placeholder_without_triggers": "Напишите сообщение здесь, нажмите {{key}} для отправки",
@@ -1962,12 +1962,12 @@
"rename_changed": "В связи с политикой безопасности имя файла было изменено с {{Original}} на {{final}}",
"save": "Сохранить в заметки",
"search": {
"both": "[to be translated]:名称+内容",
"content": "[to be translated]:内容",
"found_results": "[to be translated]:找到 {{count}} 个结果 (名称: {{nameCount}}, 内容: {{contentCount}})",
"more_matches": "[to be translated]:个匹配",
"searching": "[to be translated]:搜索中...",
"show_less": "[to be translated]:收起"
"both": "Название+содержание",
"content": "содержание",
"found_results": "Найдено результатов: {{count}} (название: {{nameCount}}, содержание: {{contentCount}})",
"more_matches": "соответствие",
"searching": "Поиск...",
"show_less": "Свернуть"
},
"settings": {
"data": {
@@ -2117,8 +2117,8 @@
"install_code_103": "Ошибка загрузки среды выполнения OVMS",
"install_code_104": "Ошибка распаковки среды выполнения OVMS",
"install_code_105": "Ошибка очистки среды выполнения OVMS",
"install_code_106": "[to be translated]:创建 run.bat 失败",
"install_code_110": "[to be translated]:清理旧 OVMS runtime 失败",
"install_code_106": "Создание run.bat не удалось",
"install_code_110": "Очистка старой среды выполнения OVMS не удалась",
"run": "Ошибка запуска OVMS:",
"stop": "Ошибка остановки OVMS:"
},
@@ -4230,7 +4230,7 @@
"system": "Системный прокси",
"title": "Режим прокси"
},
"tip": "[to be translated]:支持模糊匹配(*.test.com,192.168.0.0/16)"
"tip": "Поддержка нечеткого соответствия (*.test.com, 192.168.0.0/16)"
},
"quickAssistant": {
"click_tray_to_show": "Нажмите на иконку трея для запуска",

View File

@@ -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 { loggerService } from '@logger'
import {
@@ -16,7 +17,7 @@ import { isSystemProvider } from '@renderer/types'
import { getFancyProviderName, matchKeywordsInModel, matchKeywordsInProvider, uuid } from '@renderer/utils'
import type { MenuProps } 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 { startTransition, useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -30,7 +31,6 @@ import UrlSchemaInfoPopup from './UrlSchemaInfoPopup'
const logger = loggerService.withContext('ProviderList')
const BUTTON_WRAPPER_HEIGHT = 50
const systemType = await window.api.system.getDeviceType()
const cpuName = await window.api.system.getCpuName()
@@ -45,6 +45,7 @@ const ProviderList: FC = () => {
const [dragging, setDragging] = useState(false)
const [providerLogos, setProviderLogos] = useState<Record<string, string>>({})
const listRef = useRef<DraggableVirtualListRef>(null)
const [showDisabled, setShowDisabled] = usePreference('ui.provider.show_disabled')
const setSelectedProvider = useCallback((provider: Provider) => {
startTransition(() => _setSelectedProvider(provider))
@@ -283,6 +284,10 @@ const ProviderList: FC = () => {
return false
}
if (!showDisabled && !provider.enabled) {
return false
}
const keywords = searchText.toLowerCase().split(/\s+/).filter(Boolean)
const isProviderMatch = matchKeywordsInProvider(keywords, provider)
const isModelMatch = provider.models.some((model) => matchKeywordsInModel(keywords, model))
@@ -311,12 +316,12 @@ const ProviderList: FC = () => {
return (
<Container className="selectable">
<ProviderListContainer>
<AddButtonWrapper>
<header className="flex h-11 gap-1 p-1">
<Input
type="text"
placeholder={t('settings.provider.search')}
value={searchText}
style={{ borderRadius: 'var(--list-item-border-radius)', height: 35 }}
style={{ borderRadius: 'var(--list-item-border-radius)' }}
suffix={<Search size={14} />}
onChange={(e) => setSearchText(e.target.value)}
onKeyDown={(e) => {
@@ -328,7 +333,29 @@ const ProviderList: FC = () => {
allowClear
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={showDisabled}
onValueChange={setShowDisabled}
classNames={{ base: 'flex-1 flex-row-reverse justify-between max-w-full' }}>
{t('settings.provider.list.settings.show_disabled')}
</Switch>
</li>
</ul>
</PopoverContent>
</Popover>
</header>
<DraggableVirtualList
ref={listRef}
list={filteredProviders}
@@ -338,7 +365,8 @@ const ProviderList: FC = () => {
itemKey={itemKey}
overscan={3}
style={{
height: `calc(100% - 2 * ${BUTTON_WRAPPER_HEIGHT}px)`
flex: 1,
overflow: 'hidden'
}}
scrollerStyle={{
padding: 8,
@@ -372,7 +400,7 @@ const ProviderList: FC = () => {
</Dropdown>
)}
</DraggableVirtualList>
<AddButtonWrapper>
<footer className="h-12">
<Button
size="sm"
style={{ width: '100%', borderRadius: 'var(--list-item-border-radius)' }}
@@ -381,7 +409,7 @@ const ProviderList: FC = () => {
isDisabled={dragging}>
{t('button.add')}
</Button>
</AddButtonWrapper>
</footer>
</ProviderListContainer>
<ProviderSetting providerId={selectedProvider.id} key={selectedProvider.id} />
</Container>
@@ -451,12 +479,4 @@ const ProviderItemName = styled.div`
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

View File

@@ -1 +0,0 @@
export { default as ProviderList } from './ProviderList'

View File

@@ -33,7 +33,7 @@ import GeneralSettings from './GeneralSettings'
import MCPSettings from './MCPSettings'
import MemorySettings from './MemorySettings'
import NotesSettings from './NotesSettings'
import { ProviderList } from './ProviderSettings'
import ProviderList from './ProviderSettings/ProviderList'
import QuickAssistantSettings from './QuickAssistantSettings'
import QuickPhraseSettings from './QuickPhraseSettings'
import SelectionAssistantSettings from './SelectionAssistantSettings/SelectionAssistantSettings'