refactor: mcp setting ui refactor

This commit is contained in:
Teo 2025-03-28 12:14:34 +08:00 committed by 亢奋猫
parent 29f7da1a4c
commit eddbae6f5e
2 changed files with 101 additions and 107 deletions

View File

@ -6,7 +6,7 @@ import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { SettingContainer, SettingDivider, SettingTitle } from '..'
import { SettingContainer, SettingDivider, SettingGroup, SettingTitle } from '..'
interface Props {
server: MCPServer
@ -163,70 +163,81 @@ const McpSettings: React.FC<Props> = ({ server }) => {
}
return (
<SettingContainer style={{ background: 'transparent' }}>
<SettingTitle>
<Flex align="center" gap={8}>
<SettingContainer>
<SettingGroup style={{ marginBottom: 0 }}>
<SettingTitle>
<ServerName>{server?.name}</ServerName>
</Flex>
<Switch
value={server.isActive}
key={server.id}
loading={loadingServer === server.id}
onChange={onToggleActive}
/>
</SettingTitle>
<SettingDivider />
<Form form={form} layout="vertical" onValuesChange={onFormValuesChange}>
<Form.Item name="name" label={t('settings.mcp.name')} rules={[{ required: true, message: '' }]}>
<Input placeholder={t('common.name')} />
</Form.Item>
<Form.Item name="description" label={t('settings.mcp.description')}>
<TextArea rows={2} placeholder={t('common.description')} />
</Form.Item>
<Form.Item name="serverType" label={t('settings.mcp.type')} rules={[{ required: true }]} initialValue="stdio">
<Radio.Group
onChange={(e) => setServerType(e.target.value)}
options={[
{ label: 'SSE', value: 'sse' },
{ label: 'STDIO', value: 'stdio' }
]}
/>
</Form.Item>
{serverType === 'sse' && (
<Form.Item
name="baseUrl"
label={t('settings.mcp.url')}
rules={[{ required: serverType === 'sse', message: '' }]}
tooltip={t('settings.mcp.baseUrlTooltip')}>
<Input placeholder="http://localhost:3000/sse" />
<Flex align="center" gap={16}>
<Switch
value={server.isActive}
key={server.id}
loading={loadingServer === server.id}
onChange={onToggleActive}
/>
<Button type="primary" size="small" onClick={onSave} loading={loading} disabled={!isFormChanged}>
{t('common.save')}
</Button>
</Flex>
</SettingTitle>
<SettingDivider />
<Form
form={form}
layout="vertical"
onValuesChange={onFormValuesChange}
style={{
height: 'calc(100vh - var(--navbar-height) - 115px)',
overflowY: 'auto',
width: 'calc(100% + 10px)',
paddingRight: '10px'
}}>
<Form.Item name="name" label={t('settings.mcp.name')} rules={[{ required: true, message: '' }]}>
<Input placeholder={t('common.name')} />
</Form.Item>
)}
{serverType === 'stdio' && (
<>
<Form.Item name="description" label={t('settings.mcp.description')}>
<TextArea rows={2} placeholder={t('common.description')} />
</Form.Item>
<Form.Item name="serverType" label={t('settings.mcp.type')} rules={[{ required: true }]} initialValue="stdio">
<Radio.Group
onChange={(e) => setServerType(e.target.value)}
options={[
{ label: 'SSE', value: 'sse' },
{ label: 'STDIO', value: 'stdio' }
]}
/>
</Form.Item>
{serverType === 'sse' && (
<Form.Item
name="command"
label={t('settings.mcp.command')}
rules={[{ required: serverType === 'stdio', message: '' }]}>
<Input placeholder="uvx or npx" />
name="baseUrl"
label={t('settings.mcp.url')}
rules={[{ required: serverType === 'sse', message: '' }]}
tooltip={t('settings.mcp.baseUrlTooltip')}>
<Input placeholder="http://localhost:3000/sse" />
</Form.Item>
)}
{serverType === 'stdio' && (
<>
<Form.Item
name="command"
label={t('settings.mcp.command')}
rules={[{ required: serverType === 'stdio', message: '' }]}>
<Input placeholder="uvx or npx" />
</Form.Item>
<Form.Item
name="args"
label={t('settings.mcp.args')}
tooltip={t('settings.mcp.argsTooltip')}
rules={[{ required: serverType === 'stdio', message: '' }]}>
<TextArea rows={3} placeholder={`arg1\narg2`} style={{ fontFamily: 'monospace' }} />
</Form.Item>
<Form.Item
name="args"
label={t('settings.mcp.args')}
tooltip={t('settings.mcp.argsTooltip')}
rules={[{ required: serverType === 'stdio', message: '' }]}>
<TextArea rows={3} placeholder={`arg1\narg2`} style={{ fontFamily: 'monospace' }} />
</Form.Item>
<Form.Item name="env" label={t('settings.mcp.env')} tooltip={t('settings.mcp.envTooltip')}>
<TextArea rows={3} placeholder={`KEY1=value1\nKEY2=value2`} style={{ fontFamily: 'monospace' }} />
</Form.Item>
</>
)}
<Button type="primary" onClick={onSave} loading={loading} disabled={!isFormChanged}>
{t('common.save')}
</Button>
</Form>
<Form.Item name="env" label={t('settings.mcp.env')} tooltip={t('settings.mcp.envTooltip')}>
<TextArea rows={3} placeholder={`KEY1=value1\nKEY2=value2`} style={{ fontFamily: 'monospace' }} />
</Form.Item>
</>
)}
</Form>
</SettingGroup>
</SettingContainer>
)
}

View File

@ -4,7 +4,7 @@ import { HStack } from '@renderer/components/Layout'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useMCPServers } from '@renderer/hooks/useMCPServers'
import type { MCPServer } from '@renderer/types'
import { Button, Input, Space, Spin, Table, Tag, Typography } from 'antd'
import { Button, Card, Flex, Input, Space, Spin, Tag, Typography } from 'antd'
import { npxFinder } from 'npx-scope-finder'
import { type FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -128,48 +128,22 @@ const NpxSearch: FC = () => {
<Spin />
</div>
) : searchResults.length > 0 ? (
<Table
dataSource={searchResults}
columns={[
{
title: t('settings.mcp.npx_list.package_name'),
dataIndex: 'name',
key: 'name',
width: '200px'
},
{
title: t('settings.mcp.npx_list.description'),
key: 'description',
ellipsis: true,
render: (_, record: SearchResult) => (
<Space direction="vertical" size="small" style={{ width: '100%' }}>
<Text ellipsis={{ tooltip: true }}>{record.description}</Text>
<Text ellipsis={{ tooltip: true }} type="secondary">
{t('settings.mcp.npx_list.usage')}: {record.usage}
</Text>
<Paragraph ellipsis={{ tooltip: true }}>
<Link href={record.npmLink} target="_blank" rel="noopener noreferrer">
{record.npmLink}
</Link>
</Paragraph>
</Space>
)
},
{
title: t('settings.mcp.npx_list.version'),
dataIndex: 'version',
key: 'version',
width: '100px',
align: 'center'
},
{
title: t('settings.mcp.npx_list.actions'),
key: 'actions',
width: '80px',
align: 'center',
render: (_, record: SearchResult) => (
searchResults.map((record) => (
<Card
size="small"
key={record.npmLink}
title={
<Typography.Title level={5} style={{ margin: 0 }}>
{record.name}
</Typography.Title>
}
extra={
<Flex>
<Tag bordered={false} color="magenta">
v{record.version}
</Tag>
<Button
type="primary"
type="text"
icon={<PlusOutlined />}
size="small"
onClick={() => {
@ -185,12 +159,21 @@ const NpxSearch: FC = () => {
addMCPServer(tempServer)
}}
/>
)
}
]}
pagination={false}
bordered
/>
</Flex>
}>
<Space direction="vertical" size="small">
<Text ellipsis={{ tooltip: true }}>{record.description}</Text>
<Text ellipsis={{ tooltip: true }} type="secondary">
{t('settings.mcp.npx_list.usage')}: {record.usage}
</Text>
<Text ellipsis={{ tooltip: true }}>
<Link href={record.npmLink} target="_blank" rel="noopener noreferrer">
{record.npmLink}
</Link>
</Text>
</Space>
</Card>
))
) : null}
</Space>
</SettingGroup>