refactor(MCPSettings): update navigation and enhance scroll position handling

- Updated navigation logic in `useMCPServers` and `McpServersList` to use server IDs in the URL for better routing.
- Implemented scroll position memory in `McpServersList` to enhance user experience when navigating back to the server list.
- Adjusted route parameters in `MCPSettings` to retrieve server IDs from the URL, improving data handling and clarity.
This commit is contained in:
kangfenmao 2025-07-25 10:15:13 +08:00
parent e3f061a54d
commit baad783d64
5 changed files with 37 additions and 14 deletions

View File

@ -83,7 +83,7 @@ export function useAssistant(id: string) {
), ),
updateAssistant: (assistant: Assistant) => dispatch(updateAssistant(assistant)), updateAssistant: (assistant: Assistant) => dispatch(updateAssistant(assistant)),
updateAssistantSettings: (settings: Partial<AssistantSettings>) => { updateAssistantSettings: (settings: Partial<AssistantSettings>) => {
dispatch(updateAssistantSettings({ assistantId: assistant.id, settings })) assistant?.id && dispatch(updateAssistantSettings({ assistantId: assistant.id, settings }))
} }
} }
} }

View File

@ -13,7 +13,7 @@ window.electron.ipcRenderer.on(IpcChannel.Mcp_ServersChanged, (_event, servers)
window.electron.ipcRenderer.on(IpcChannel.Mcp_AddServer, (_event, server: MCPServer) => { window.electron.ipcRenderer.on(IpcChannel.Mcp_AddServer, (_event, server: MCPServer) => {
store.dispatch(addMCPServer(server)) store.dispatch(addMCPServer(server))
NavigationService.navigate?.('/settings/mcp') NavigationService.navigate?.('/settings/mcp')
NavigationService.navigate?.('/settings/mcp/settings', { state: { server } }) NavigationService.navigate?.(`/settings/mcp/settings/${encodeURIComponent(server.id)}`)
}) })
const selectMcpServers = (state) => state.mcp.servers const selectMcpServers = (state) => state.mcp.servers

View File

@ -7,7 +7,7 @@ import { MCPServer } from '@renderer/types'
import { formatMcpError } from '@renderer/utils/error' import { formatMcpError } from '@renderer/utils/error'
import { Badge, Button, Dropdown, Empty, Switch, Tag } from 'antd' import { Badge, Button, Dropdown, Empty, Switch, Tag } from 'antd'
import { MonitorCheck, Plus, RefreshCw, Settings2, SquareArrowOutUpRight } from 'lucide-react' import { MonitorCheck, Plus, RefreshCw, Settings2, SquareArrowOutUpRight } from 'lucide-react'
import { FC, useCallback, useEffect, useState } from 'react' import { FC, useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router' import { useNavigate } from 'react-router'
import styled from 'styled-components' import styled from 'styled-components'
@ -29,6 +29,28 @@ const McpServersList: FC = () => {
const [loadingServerIds, setLoadingServerIds] = useState<Set<string>>(new Set()) const [loadingServerIds, setLoadingServerIds] = useState<Set<string>>(new Set())
const [serverVersions, setServerVersions] = useState<Record<string, string | null>>({}) const [serverVersions, setServerVersions] = useState<Record<string, string | null>>({})
const scrollRef = useRef<HTMLDivElement>(null)
// 简单的滚动位置记忆
useEffect(() => {
// 恢复滚动位置
const savedScroll = sessionStorage.getItem('mcp-list-scroll')
if (savedScroll && scrollRef.current) {
scrollRef.current.scrollTop = Number(savedScroll)
}
// 保存滚动位置
const handleScroll = () => {
if (scrollRef.current) {
sessionStorage.setItem('mcp-list-scroll', String(scrollRef.current.scrollTop))
}
}
const container = scrollRef.current
container?.addEventListener('scroll', handleScroll)
return () => container?.removeEventListener('scroll', handleScroll)
}, [])
const fetchServerVersion = useCallback(async (server: MCPServer) => { const fetchServerVersion = useCallback(async (server: MCPServer) => {
if (!server.isActive) return if (!server.isActive) return
@ -61,7 +83,7 @@ const McpServersList: FC = () => {
isActive: false isActive: false
} }
addMCPServer(newServer) addMCPServer(newServer)
navigate(`/settings/mcp/settings`, { state: { server: newServer } }) navigate(`/settings/mcp/settings/${encodeURIComponent(newServer.id)}`)
window.message.success({ content: t('settings.mcp.addSuccess'), key: 'mcp-list' }) window.message.success({ content: t('settings.mcp.addSuccess'), key: 'mcp-list' })
}, [addMCPServer, navigate, t]) }, [addMCPServer, navigate, t])
@ -75,7 +97,7 @@ const McpServersList: FC = () => {
setIsAddModalVisible(false) setIsAddModalVisible(false)
window.message.success({ content: t('settings.mcp.addSuccess'), key: 'mcp-quick-add' }) window.message.success({ content: t('settings.mcp.addSuccess'), key: 'mcp-quick-add' })
// Optionally navigate to the new server's settings page // Optionally navigate to the new server's settings page
// navigate(`/settings/mcp/settings`, { state: { server } }) // navigate(`/settings/mcp/settings/${encodeURIComponent(server.id)}`)
}, },
[addMCPServer, t] [addMCPServer, t]
) )
@ -112,7 +134,7 @@ const McpServersList: FC = () => {
} }
return ( return (
<Container> <Container ref={scrollRef}>
<ListHeader> <ListHeader>
<SettingTitle style={{ gap: 3 }}> <SettingTitle style={{ gap: 3 }}>
<span>{t('settings.mcp.newServer')}</span> <span>{t('settings.mcp.newServer')}</span>
@ -160,7 +182,9 @@ const McpServersList: FC = () => {
</ListHeader> </ListHeader>
<DraggableList style={{ width: '100%' }} list={mcpServers} onUpdate={updateMcpServers}> <DraggableList style={{ width: '100%' }} list={mcpServers} onUpdate={updateMcpServers}>
{(server: MCPServer) => ( {(server: MCPServer) => (
<ServerCard key={server.id} onClick={() => navigate(`/settings/mcp/settings`, { state: { server } })}> <ServerCard
key={server.id}
onClick={() => navigate(`/settings/mcp/settings/${encodeURIComponent(server.id)}`)}>
<ServerHeader> <ServerHeader>
<ServerName> <ServerName>
{server.logoUrl && <ServerLogo src={server.logoUrl} alt={`${server.name} logo`} />} {server.logoUrl && <ServerLogo src={server.logoUrl} alt={`${server.name} logo`} />}
@ -190,7 +214,7 @@ const McpServersList: FC = () => {
<Button <Button
icon={<Settings2 size={16} />} icon={<Settings2 size={16} />}
type="text" type="text"
onClick={() => navigate(`/settings/mcp/settings`, { state: { server } })} onClick={() => navigate(`/settings/mcp/settings/${encodeURIComponent(server.id)}`)}
/> />
</StatusIndicator> </StatusIndicator>
</ServerHeader> </ServerHeader>

View File

@ -10,7 +10,7 @@ import TextArea from 'antd/es/input/TextArea'
import { ChevronDown } from 'lucide-react' import { ChevronDown } from 'lucide-react'
import React, { useCallback, useEffect, useState } from 'react' import React, { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useLocation, useNavigate } from 'react-router' import { useNavigate, useParams } from 'react-router'
import styled from 'styled-components' import styled from 'styled-components'
import { SettingContainer, SettingDivider, SettingGroup, SettingTitle } from '..' import { SettingContainer, SettingDivider, SettingGroup, SettingTitle } from '..'
@ -75,10 +75,9 @@ const parseKeyValueString = (str: string): Record<string, string> => {
const McpSettings: React.FC = () => { const McpSettings: React.FC = () => {
const { t } = useTranslation() const { t } = useTranslation()
const { const { serverId } = useParams<{ serverId: string }>()
server: { id: serverId } const decodedServerId = serverId ? decodeURIComponent(serverId) : ''
} = useLocation().state as { server: MCPServer } const server = useMCPServer(decodedServerId).server as MCPServer
const server = useMCPServer(serverId).server as MCPServer
const { deleteMCPServer, updateMCPServer } = useMCPServers() const { deleteMCPServer, updateMCPServer } = useMCPServers()
const [serverType, setServerType] = useState<MCPServer['type']>('stdio') const [serverType, setServerType] = useState<MCPServer['type']>('stdio')
const [form] = Form.useForm<MCPFormValues>() const [form] = Form.useForm<MCPFormValues>()

View File

@ -32,7 +32,7 @@ const MCPSettings: FC = () => {
<MainContainer> <MainContainer>
<Routes> <Routes>
<Route path="/" element={<McpServersList />} /> <Route path="/" element={<McpServersList />} />
<Route path="settings" element={<McpSettings />} /> <Route path="settings/:serverId" element={<McpSettings />} />
<Route <Route
path="npx-search" path="npx-search"
element={ element={