refactor(Inputbar): remove MentionModelsInput and KnowledgeBaseInput components; update InputbarTools and Inputbar to handle model mentions and knowledge base selections directly. Update icons to use Hammer instead of SquareTerminal in various components. Enhance i18n translations for clear actions across multiple languages.

This commit is contained in:
kangfenmao 2025-08-19 10:40:45 +08:00
parent 263166c9d1
commit c8c0d22787
17 changed files with 128 additions and 99 deletions

View File

@ -14,6 +14,7 @@ import { Tooltip } from 'antd'
import {
FileSearch,
Folder,
Hammer,
Home,
Languages,
LayoutGrid,
@ -22,7 +23,6 @@ import {
Palette,
Settings,
Sparkle,
SquareTerminal,
Sun,
Terminal,
X
@ -53,7 +53,7 @@ const getTabIcon = (tabId: string): React.ReactNode | undefined => {
case 'knowledge':
return <FileSearch size={14} />
case 'mcp':
return <SquareTerminal size={14} />
return <Hammer size={14} />
case 'files':
return <Folder size={14} />
case 'settings':

View File

@ -2703,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "Quickly translate with 3 spaces",
"clear": {
"all": "[to be translated]:清除",
"knowledge_base": "Clear selected knowledge bases",
"models": "Clear all models"
},
"show_translate_confirm": "Show translation confirmation dialog",
"target_language": {
"chinese": "Simplified Chinese",

View File

@ -2703,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "スペースを3回押して翻訳",
"clear": {
"all": "[to be translated]:清除",
"knowledge_base": "選択された知識ベースをクリア",
"models": "すべてのモデルをクリア"
},
"show_translate_confirm": "翻訳確認ダイアログを表示",
"target_language": {
"chinese": "簡体字中国語",

View File

@ -2703,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "Быстрый перевод с помощью 3-х пробелов",
"clear": {
"all": "[to be translated]:清除",
"knowledge_base": "Очистить выбранные базы знаний",
"models": "Очистить все модели"
},
"show_translate_confirm": "Показать диалоговое окно подтверждения перевода",
"target_language": {
"chinese": "Китайский упрощенный",

View File

@ -2703,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "3 个空格快速翻译",
"clear": {
"all": "清除",
"knowledge_base": "清除选中的知识库",
"models": "清除@的所有模型"
},
"show_translate_confirm": "显示翻译确认对话框",
"target_language": {
"chinese": "简体中文",

View File

@ -2703,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "快速敲擊 3 次空格翻譯",
"clear": {
"all": "[to be translated]:清除",
"knowledge_base": "清除選中的知識庫",
"models": "清除@的所有模型"
},
"show_translate_confirm": "顯示翻譯確認對話框",
"target_language": {
"chinese": "簡體中文",

View File

@ -1578,6 +1578,7 @@
"style_type_tip": "Ο τύπος στυλ για την επεξεργασμένη εικόνα, ισχύει μόνο για την έκδοση V_2 και νεότερες"
},
"generate": {
"height": "Ύψος",
"magic_prompt_option_tip": "Έξυπνη βελτιστοποίηση της προτροπής για βελτίωση των αποτελεσμάτων",
"model_tip": "Έκδοση μοντέλου: Το V2 είναι το τελευταίο μοντέλο διεπαφής, το V2A είναι γρήγορο μοντέλο, το V_1 είναι το αρχικό μοντέλο και το _TURBO είναι η επιταχυνόμενη έκδοση",
"negative_prompt_tip": "Περιγράψτε στοιχεία που δεν θέλετε να εμφανίζονται στην εικόνα, υποστηρίζεται μόνο στις εκδόσεις V_1, V_1_TURBO, V_2 και V_2_TURBO",
@ -1585,8 +1586,11 @@
"person_generation": "Δημιουργία προσώπου",
"person_generation_tip": "Επιτρέπει στο μοντέλο να δημιουργεί εικόνες προσώπων",
"rendering_speed_tip": "Ελέγχει την ισορροπία μεταξύ ταχύτητας και ποιότητας απόδοσης, ισχύει μόνο για την έκδοση V_3",
"safety_tolerance": "Ασφάλεια",
"safety_tolerance_tip": "Έλεγχος της ασφάλειας της δημιουργίας εικόνας, ισχύει μόνο για την έκδοση FLUX.1-Kontext-pro",
"seed_tip": "Ελέγχει την τυχαιότητα της δημιουργίας εικόνας, χρησιμοποιείται για να επαναληφθεί το ίδιο αποτέλεσμα",
"style_type_tip": "Στυλ δημιουργίας εικόνας, ισχύει μόνο για την έκδοση V_2 και μεταγενέστερες"
"style_type_tip": "Στυλ δημιουργίας εικόνας, ισχύει μόνο για την έκδοση V_2 και μεταγενέστερες",
"width": "Πλάτος"
},
"generated_image": "Δημιουργία εικόνας",
"go_to_settings": "Πηγαίνετε στις ρυθμίσεις",
@ -2699,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "Μετάφραση με τρεις γρήγορες πιστώσεις",
"clear": {
"all": "Εκκαθάριση",
"knowledge_base": "Εκκαθάριση επιλεγμένων βάσεων γνώσης",
"models": "Εκκαθάριση όλων των μοντέλων"
},
"show_translate_confirm": "Εμφάνιση παραθύρου επιβεβαίωσης μετάφρασης",
"target_language": {
"chinese": "Σινογραμματικό",

View File

@ -1578,6 +1578,7 @@
"style_type_tip": "Estilo de la imagen editada, solo aplicable para la versión V_2 y posteriores"
},
"generate": {
"height": "Altura",
"magic_prompt_option_tip": "Optimización inteligente de indicaciones para mejorar los resultados de generación",
"model_tip": "Versión del modelo: V2 es el modelo más reciente de la interfaz, V2A es un modelo rápido, V_1 es el modelo inicial y _TURBO es la versión acelerada",
"negative_prompt_tip": "Describe elementos que no deseas en la imagen. Solo compatible con las versiones V_1, V_1_TURBO, V_2 y V_2_TURBO",
@ -1585,8 +1586,11 @@
"person_generation": "Generar Persona",
"person_generation_tip": "Permite que el modelo genere imágenes de personas",
"rendering_speed_tip": "Controla el equilibrio entre velocidad y calidad de renderizado, solo aplicable a la versión V_3",
"safety_tolerance": "Tolerancia de seguridad",
"safety_tolerance_tip": "Controla la tolerancia de seguridad en la generación de imágenes, solo aplicable a la versión FLUX.1-Kontext-pro",
"seed_tip": "Controla la aleatoriedad en la generación de imágenes, útil para reproducir resultados idénticos",
"style_type_tip": "Estilo de generación de imágenes, solo aplicable para la versión V_2 y posteriores"
"style_type_tip": "Estilo de generación de imágenes, solo aplicable para la versión V_2 y posteriores",
"width": "Ancho"
},
"generated_image": "Generar imagen",
"go_to_settings": "Ir a configuración",
@ -2699,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "Traducir con tres espacios rápidos",
"clear": {
"all": "Limpiar",
"knowledge_base": "Limpiar bases de conocimiento seleccionadas",
"models": "Limpiar todos los modelos"
},
"show_translate_confirm": "Mostrar diálogo de confirmación de traducción",
"target_language": {
"chinese": "Chino simplificado",

View File

@ -1578,6 +1578,7 @@
"style_type_tip": "Style de l'image après édition, uniquement applicable aux versions V_2 et ultérieures"
},
"generate": {
"height": "Hauteur",
"magic_prompt_option_tip": "Интеллектуальная оптимизация подсказок для улучшения результатов генерации",
"model_tip": "Версия модели: V2 — это последняя модель API, V2A — быстрая модель, V_1 — первое поколение модели, _TURBO — ускоренная версия",
"negative_prompt_tip": "Описывает элементы, которые вы не хотите видеть на изображении. Поддерживается только версиями V_1, V_1_TURBO, V_2 и V_2_TURBO",
@ -1585,8 +1586,11 @@
"person_generation": "Générer un personnage",
"person_generation_tip": "Autoriser le modèle à générer des images de personnages",
"rendering_speed_tip": "Contrôler l'équilibre entre la vitesse et la qualité du rendu, uniquement applicable à la version V_3",
"safety_tolerance": "Tolérance de sécurité",
"safety_tolerance_tip": "Contrôle la tolérance de sécurité dans la génération d'images, uniquement applicable à la version FLUX.1-Kontext-pro",
"seed_tip": "Контролирует случайность генерации изображения, используется для воспроизведения одинаковых результатов",
"style_type_tip": "Стиль генерации изображения, применим к версии V_2 и выше"
"style_type_tip": "Стиль генерации изображения, применим к версии V_2 и выше",
"width": "Largeur"
},
"generated_image": "Image générée",
"go_to_settings": "Aller aux paramètres",
@ -2699,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "Traduire en frappant rapidement 3 fois l'espace",
"clear": {
"all": "Effacer",
"knowledge_base": "Effacer les bases de connaissances sélectionnées",
"models": "Effacer tous les modèles"
},
"show_translate_confirm": "Afficher la boîte de dialogue de confirmation de traduction",
"target_language": {
"chinese": "Chinois simplifié",

View File

@ -1578,6 +1578,7 @@
"style_type_tip": "Estilo da imagem editada, disponível apenas para a versão V_2 ou superior"
},
"generate": {
"height": "[to be translated]:高度",
"magic_prompt_option_tip": "Otimização inteligente do prompt para melhorar os resultados da geração",
"model_tip": "Versão do modelo: V2 é o modelo mais recente da interface, V2A é o modelo rápido, V_1 é o modelo de primeira geração e _TURBO é a versão acelerada",
"negative_prompt_tip": "Descreve elementos que você não deseja ver nas imagens; suportado apenas nas versões V_1, V_1_TURBO, V_2 e V_2_TURBO",
@ -1585,8 +1586,11 @@
"person_generation": "Gerar Personagem",
"person_generation_tip": "Permite que o modelo gere imagens de personagens",
"rendering_speed_tip": "Controla o equilíbrio entre velocidade e qualidade de renderização, aplicável apenas à versão V_3",
"safety_tolerance": "[to be translated]:安全容忍度",
"safety_tolerance_tip": "[to be translated]:控制图像生成的安全容忍度,仅适用于 FLUX.1-Kontext-pro 版本",
"seed_tip": "Controla a aleatoriedade na geração das imagens, usado para reproduzir resultados idênticos",
"style_type_tip": "Estilo de geração da imagem, aplicável apenas às versões V_2 e superiores"
"style_type_tip": "Estilo de geração da imagem, aplicável apenas às versões V_2 e superiores",
"width": "[to be translated]:宽度"
},
"generated_image": "Imagem gerada",
"go_to_settings": "Ir para configurações",
@ -2699,6 +2703,11 @@
},
"input": {
"auto_translate_with_space": "Traduzir com três espaços rápidos",
"clear": {
"all": "[to be translated]:清除",
"knowledge_base": "[to be translated]:清除选中的知识库",
"models": "[to be translated]:清除@的所有模型"
},
"show_translate_confirm": "Mostrar diálogo de confirmação de tradução",
"target_language": {
"chinese": "Chinês simplificado",

View File

@ -58,8 +58,6 @@ import styled from 'styled-components'
import NarrowLayout from '../Messages/NarrowLayout'
import AttachmentPreview from './AttachmentPreview'
import InputbarTools, { InputbarToolsRef } from './InputbarTools'
import KnowledgeBaseInput from './KnowledgeBaseInput'
import MentionModelsInput from './MentionModelsInput'
import SendMessageButton from './SendMessageButton'
import TokenCount from './TokenCount'
@ -439,11 +437,6 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
}
}
if (enableBackspaceDeleteModel && event.key === 'Backspace' && text.trim() === '' && mentionedModels.length > 0) {
setMentionedModels((prev) => prev.slice(0, -1))
return event.preventDefault()
}
if (enableBackspaceDeleteModel && event.key === 'Backspace' && text.trim() === '' && files.length > 0) {
setFiles((prev) => prev.slice(0, -1))
return event.preventDefault()
@ -766,19 +759,6 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
setSelectedKnowledgeBases(bases ?? [])
}
const handleRemoveModel = (model: Model) => {
setMentionedModels(mentionedModels.filter((m) => m.id !== model.id))
}
const handleRemoveKnowledgeBase = (knowledgeBase: KnowledgeBase) => {
const newKnowledgeBases = assistant.knowledge_bases?.filter((kb) => kb.id !== knowledgeBase.id)
updateAssistant({
...assistant,
knowledge_bases: newKnowledgeBases
})
setSelectedKnowledgeBases(newKnowledgeBases ?? [])
}
const onEnableGenerateImage = () => {
updateAssistant({ ...assistant, enableGenerateImage: !assistant.enableGenerateImage })
}
@ -858,15 +838,6 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
className={classNames('inputbar-container', inputFocus && 'focus', isFileDragging && 'file-dragging')}
ref={containerRef}>
{files.length > 0 && <AttachmentPreview files={files} setFiles={setFiles} />}
{selectedKnowledgeBases.length > 0 && (
<KnowledgeBaseInput
selectedKnowledgeBases={selectedKnowledgeBases}
onRemoveKnowledgeBase={handleRemoveKnowledgeBase}
/>
)}
{mentionedModels.length > 0 && (
<MentionModelsInput selectedModels={mentionedModels} onRemoveModel={handleRemoveModel} />
)}
<Textarea
value={text}
onChange={onChange}
@ -923,6 +894,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
resizeTextArea={resizeTextArea}
mentionModels={mentionedModels}
onMentionModel={onMentionModel}
onClearMentionModels={() => setMentionedModels([])}
couldMentionNotVisionModel={couldMentionNotVisionModel}
couldAddImageFile={couldAddImageFile}
onEnableGenerateImage={onEnableGenerateImage}

View File

@ -13,9 +13,9 @@ import {
CircleChevronRight,
FileSearch,
Globe,
Hammer,
Languages,
Link,
LucideSquareTerminal,
Maximize,
MessageSquareDiff,
Minimize,
@ -67,6 +67,7 @@ export interface InputbarToolsProps {
resizeTextArea: () => void
mentionModels: Model[]
onMentionModel: (model: Model) => void
onClearMentionModels: () => void
couldMentionNotVisionModel: boolean
couldAddImageFile: boolean
onEnableGenerateImage: () => void
@ -108,6 +109,7 @@ const InputbarTools = ({
resizeTextArea,
mentionModels,
onMentionModel,
onClearMentionModels,
couldMentionNotVisionModel,
couldAddImageFile,
onEnableGenerateImage,
@ -200,7 +202,7 @@ const InputbarTools = ({
{
label: t('settings.mcp.title'),
description: t('settings.mcp.not_support'),
icon: <LucideSquareTerminal />,
icon: <Hammer />,
isMenu: true,
action: () => {
mcpToolsButtonRef.current?.openQuickPanel()
@ -209,7 +211,7 @@ const InputbarTools = ({
{
label: `MCP ${t('settings.mcp.tabs.prompts')}`,
description: '',
icon: <LucideSquareTerminal />,
icon: <Hammer />,
isMenu: true,
action: () => {
mcpToolsButtonRef.current?.openPromptList()
@ -218,7 +220,7 @@ const InputbarTools = ({
{
label: `MCP ${t('settings.mcp.tabs.resources')}`,
description: '',
icon: <LucideSquareTerminal />,
icon: <Hammer />,
isMenu: true,
action: () => {
mcpToolsButtonRef.current?.openResourcesList()
@ -394,6 +396,7 @@ const InputbarTools = ({
ref={mentionModelsButtonRef}
mentionedModels={mentionModels}
onMentionModel={onMentionModel}
onClearMentionModels={onClearMentionModels}
ToolbarButton={ToolbarButton}
couldMentionNotVisionModel={couldMentionNotVisionModel}
files={files}
@ -464,6 +467,7 @@ const InputbarTools = ({
mentionModels,
model,
newTopicShortcut,
onClearMentionModels,
onEnableGenerateImage,
onMentionModel,
onNewContext,

View File

@ -2,7 +2,7 @@ import { QuickPanelListItem, useQuickPanel } from '@renderer/components/QuickPan
import { useAppSelector } from '@renderer/store'
import { KnowledgeBase } from '@renderer/types'
import { Tooltip } from 'antd'
import { FileSearch, Plus } from 'lucide-react'
import { CircleX, FileSearch, Plus } from 'lucide-react'
import { FC, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router'
@ -44,28 +44,41 @@ const KnowledgeBaseButton: FC<Props> = ({ ref, selectedBases, onSelect, disabled
)
const baseItems = useMemo<QuickPanelListItem[]>(() => {
const newList: QuickPanelListItem[] = knowledgeState.bases.map((base) => ({
const items: QuickPanelListItem[] = knowledgeState.bases.map((base) => ({
label: base.name,
description: `${base.items.length} ${t('files.count')}`,
icon: <FileSearch />,
action: () => handleBaseSelect(base),
isSelected: selectedBases?.some((selected) => selected.id === base.id)
}))
newList.push({
items.push({
label: t('knowledge.add.title') + '...',
icon: <Plus />,
action: () => navigate('/knowledge'),
isSelected: false
})
return newList
}, [knowledgeState.bases, handleBaseSelect, selectedBases, t, navigate])
items.unshift({
label: t('settings.input.clear.all'),
description: t('settings.input.clear.knowledge_base'),
icon: <CircleX />,
isSelected: false,
action: () => {
onSelect([])
quickPanel.close()
}
})
return items
}, [knowledgeState.bases, t, selectedBases, handleBaseSelect, navigate, onSelect, quickPanel])
const openQuickPanel = useCallback(() => {
quickPanel.open({
title: t('chat.input.knowledge_base'),
list: baseItems,
symbol: '#',
multiple: false,
multiple: true,
afterAction({ item }) {
item.isSelected = !item.isSelected
}

View File

@ -4,7 +4,7 @@ import { useMCPServers } from '@renderer/hooks/useMCPServers'
import { EventEmitter } from '@renderer/services/EventService'
import { Assistant, MCPPrompt, MCPResource, MCPServer } from '@renderer/types'
import { Form, Input, Tooltip } from 'antd'
import { CircleX, Plus, SquareTerminal } from 'lucide-react'
import { CircleX, Hammer, Plus } from 'lucide-react'
import React, { FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router'
@ -168,7 +168,7 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
const newList: QuickPanelListItem[] = activedMcpServers.map((server) => ({
label: server.name,
description: server.description || server.baseUrl,
icon: <SquareTerminal />,
icon: <Hammer />,
action: () => EventEmitter.emit('mcp-server-select', server),
isSelected: assistantMcpServers.some((s) => s.id === server.id)
}))
@ -180,7 +180,7 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
})
newList.unshift({
label: t('common.close'),
label: t('settings.input.clear.all'),
description: t('settings.mcp.disable.description'),
icon: <CircleX />,
isSelected: false,
@ -335,7 +335,7 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
return prompts.map((prompt) => ({
label: prompt.name,
description: prompt.description,
icon: <SquareTerminal />,
icon: <Hammer />,
action: () => handlePromptSelect(prompt as MCPPromptWithArgs)
}))
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -415,7 +415,7 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
resources.map((resource) => ({
label: resource.name,
description: resource.description,
icon: <SquareTerminal />,
icon: <Hammer />,
action: () => handleResourceSelect(resource)
}))
)
@ -456,7 +456,7 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
return (
<Tooltip placement="top" title={t('settings.mcp.title')} mouseLeaveDelay={0} arrow>
<ToolbarButton type="text" onClick={handleOpenQuickPanel}>
<SquareTerminal
<Hammer
size={18}
color={assistant.mcpServers && assistant.mcpServers.length > 0 ? 'var(--color-primary)' : 'var(--color-icon)'}
/>

View File

@ -10,7 +10,7 @@ import { getFancyProviderName } from '@renderer/utils'
import { Avatar, Tooltip } from 'antd'
import { useLiveQuery } from 'dexie-react-hooks'
import { first, sortBy } from 'lodash'
import { AtSign, Plus } from 'lucide-react'
import { AtSign, CircleX, Plus } from 'lucide-react'
import { FC, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router'
@ -24,6 +24,7 @@ interface Props {
ref?: React.RefObject<MentionModelsButtonRef | null>
mentionedModels: Model[]
onMentionModel: (model: Model) => void
onClearMentionModels: () => void
couldMentionNotVisionModel: boolean
files: FileType[]
ToolbarButton: any
@ -34,6 +35,7 @@ const MentionModelsButton: FC<Props> = ({
ref,
mentionedModels,
onMentionModel,
onClearMentionModels,
couldMentionNotVisionModel,
files,
ToolbarButton,
@ -134,8 +136,29 @@ const MentionModelsButton: FC<Props> = ({
isSelected: false
})
items.unshift({
label: t('settings.input.clear.all'),
description: t('settings.input.clear.models'),
icon: <CircleX />,
isSelected: false,
action: () => {
onClearMentionModels()
quickPanel.close()
}
})
return items
}, [pinnedModels, providers, t, couldMentionNotVisionModel, mentionedModels, onMentionModel, navigate])
}, [
pinnedModels,
providers,
t,
couldMentionNotVisionModel,
mentionedModels,
onMentionModel,
navigate,
quickPanel,
onClearMentionModels
])
const openQuickPanel = useCallback(
(triggerInfo?: { type: 'input' | 'button'; position?: number; originalText?: string }) => {

View File

@ -1,44 +0,0 @@
import CustomTag from '@renderer/components/Tags/CustomTag'
import { useProviders } from '@renderer/hooks/useProvider'
import { getModelUniqId } from '@renderer/services/ModelService'
import { Model } from '@renderer/types'
import { getFancyProviderName } from '@renderer/utils'
import { FC } from 'react'
import styled from 'styled-components'
const MentionModelsInput: FC<{
selectedModels: Model[]
onRemoveModel: (model: Model) => void
}> = ({ selectedModels, onRemoveModel }) => {
const { providers } = useProviders()
const getProviderName = (model: Model) => {
const provider = providers.find((p) => p.id === model?.provider)
return provider ? getFancyProviderName(provider) : ''
}
return (
<Container>
{selectedModels.map((model) => (
<CustomTag
icon={<i className="iconfont icon-at" />}
color="#1677ff"
key={getModelUniqId(model)}
closable
onClose={() => onRemoveModel(model)}>
{model.name} ({getProviderName(model)})
</CustomTag>
))}
</Container>
)
}
const Container = styled.div`
width: 100%;
padding: 5px 15px 5px 15px;
display: flex;
flex-wrap: wrap;
gap: 4px 4px;
`
export default MentionModelsInput

View File

@ -8,13 +8,13 @@ import {
Cloud,
Command,
FileCode,
Hammer,
HardDrive,
Info,
MonitorCog,
Package,
PictureInPicture2,
Settings2,
SquareTerminal,
TextCursorInput,
Zap
} from 'lucide-react'
@ -84,7 +84,7 @@ const SettingsPage: FC = () => {
<Divider />
<MenuItemLink to="/settings/mcp">
<MenuItem className={isRoute('/settings/mcp')}>
<SquareTerminal size={18} />
<Hammer size={18} />
{t('settings.mcp.title')}
</MenuItem>
</MenuItemLink>