mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-25 16:00:28 +08:00
162 lines
7.6 KiB
TypeScript
162 lines
7.6 KiB
TypeScript
import React from 'react';
|
||
import { Button, Input } from 'antd';
|
||
|
||
import type { OverlayWorkbenchTheme } from '../../utils/overlayWorkbenchTheme';
|
||
import type { ParseMCPCommandDraftResult } from '../../utils/mcpCommandDraft';
|
||
import {
|
||
MCP_COMMAND_EXAMPLES,
|
||
MCP_COMMAND_PARSE_EXAMPLE,
|
||
MCP_FIELD_GUIDES,
|
||
MCP_SERVER_FILL_STEPS,
|
||
MCP_TROUBLESHOOTING_GUIDES,
|
||
} from '../../utils/mcpServerGuidance';
|
||
import AIMCPCommandDraftPreview from './AIMCPCommandDraftPreview';
|
||
import AIMCPFieldGuideCard from './AIMCPFieldGuideCard';
|
||
import { buildMCPHintStyle, mcpLabelStyle } from './AIMCPHelpBlock';
|
||
|
||
interface AIMCPServerGuidePanelProps {
|
||
cardBorder: string;
|
||
inputBg: string;
|
||
darkMode: boolean;
|
||
overlayTheme: OverlayWorkbenchTheme;
|
||
rawCommandDraft: string;
|
||
parsedCommandDraft: ParseMCPCommandDraftResult;
|
||
onApplyCommandDraft: () => void;
|
||
onRawCommandDraftChange: (value: string) => void;
|
||
}
|
||
|
||
const AIMCPServerGuidePanel: React.FC<AIMCPServerGuidePanelProps> = ({
|
||
cardBorder,
|
||
inputBg,
|
||
darkMode,
|
||
overlayTheme,
|
||
rawCommandDraft,
|
||
parsedCommandDraft,
|
||
onApplyCommandDraft,
|
||
onRawCommandDraftChange,
|
||
}) => (
|
||
<>
|
||
<div style={{ padding: '10px 12px', borderRadius: 10, border: `1px dashed ${cardBorder}`, background: darkMode ? 'rgba(255,255,255,0.03)' : 'rgba(255,255,255,0.7)' }}>
|
||
<div style={{ ...mcpLabelStyle, color: overlayTheme.titleText }}>填写示例</div>
|
||
<div style={{ ...buildMCPHintStyle(overlayTheme.mutedText), marginTop: 4 }}>
|
||
启动命令只填可执行程序本身,不要把参数混在一起。常见形式:
|
||
{' '}
|
||
<code style={{ fontFamily: 'var(--gn-font-mono)' }}>{MCP_COMMAND_EXAMPLES.join(' / ')}</code>
|
||
</div>
|
||
</div>
|
||
|
||
<div style={{ padding: '12px 14px', borderRadius: 12, border: `1px solid ${cardBorder}`, background: darkMode ? 'rgba(255,255,255,0.03)' : 'rgba(255,255,255,0.76)', display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||
<div style={{ ...mcpLabelStyle, color: overlayTheme.titleText }}>推荐填写顺序</div>
|
||
<div style={buildMCPHintStyle(overlayTheme.mutedText)}>
|
||
小白用户可以按这个顺序填:先选上面的模板或粘整行命令,再确认下面的必填项,最后只在需要时补参数、环境变量和超时。
|
||
</div>
|
||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
|
||
{MCP_SERVER_FILL_STEPS.map((item) => (
|
||
<span
|
||
key={item.step}
|
||
style={{
|
||
padding: '4px 10px',
|
||
borderRadius: 999,
|
||
fontSize: 12,
|
||
color: overlayTheme.titleText,
|
||
background: darkMode ? 'rgba(255,255,255,0.06)' : 'rgba(15,23,42,0.05)',
|
||
}}
|
||
>
|
||
{item.step}. {item.title}
|
||
</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div style={{ padding: '12px 14px', borderRadius: 12, border: `1px solid ${cardBorder}`, background: darkMode ? 'rgba(255,255,255,0.03)' : 'rgba(255,255,255,0.76)', display: 'flex', flexDirection: 'column', gap: 10 }}>
|
||
<div style={{ ...mcpLabelStyle, color: overlayTheme.titleText }}>字段速查</div>
|
||
<div style={buildMCPHintStyle(overlayTheme.mutedText)}>
|
||
如果看到某个参数名不知道该填什么,先看这一块;下面每个字段也都有更具体的示例和注意事项。
|
||
</div>
|
||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(210px, 1fr))', gap: 10 }}>
|
||
{MCP_FIELD_GUIDES.map((item) => (
|
||
<AIMCPFieldGuideCard
|
||
key={item.key}
|
||
item={item}
|
||
cardBorder={cardBorder}
|
||
darkMode={darkMode}
|
||
overlayTheme={overlayTheme}
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div style={{ padding: '12px 14px', borderRadius: 12, border: `1px solid ${cardBorder}`, background: darkMode ? 'rgba(255,255,255,0.03)' : 'rgba(255,255,255,0.76)', display: 'flex', flexDirection: 'column', gap: 10 }}>
|
||
<div style={{ ...mcpLabelStyle, color: overlayTheme.titleText }}>常见填错现象</div>
|
||
<div style={buildMCPHintStyle(overlayTheme.mutedText)}>
|
||
如果测试失败,先按这里反查要改哪个字段;大多数问题都不是 MCP 坏了,而是命令、参数或环境变量拆错了。
|
||
</div>
|
||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(230px, 1fr))', gap: 10 }}>
|
||
{MCP_TROUBLESHOOTING_GUIDES.map((item) => (
|
||
<div
|
||
key={item.key}
|
||
style={{
|
||
padding: '10px 12px',
|
||
borderRadius: 10,
|
||
border: `1px solid ${cardBorder}`,
|
||
background: darkMode ? 'rgba(255,255,255,0.025)' : 'rgba(255,255,255,0.78)',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 6,
|
||
}}
|
||
>
|
||
<div style={{ fontSize: 12, fontWeight: 700, color: overlayTheme.titleText }}>{item.symptom}</div>
|
||
<div style={{ fontSize: 12, lineHeight: 1.6, color: overlayTheme.titleText }}>
|
||
常见原因:{item.likelyCause}
|
||
</div>
|
||
<div style={buildMCPHintStyle(overlayTheme.mutedText)}>处理方式:{item.fix}</div>
|
||
{item.example ? (
|
||
<div style={buildMCPHintStyle(overlayTheme.mutedText)}>
|
||
示例:
|
||
{' '}
|
||
<code style={{ fontFamily: 'var(--gn-font-mono)' }}>{item.example}</code>
|
||
</div>
|
||
) : null}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div style={{ padding: '12px', borderRadius: 12, border: `1px solid ${cardBorder}`, background: darkMode ? 'rgba(255,255,255,0.03)' : 'rgba(255,255,255,0.76)', display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||
<div style={{ ...mcpLabelStyle, color: overlayTheme.titleText }}>只有一条完整命令?</div>
|
||
<div style={buildMCPHintStyle(overlayTheme.mutedText)}>
|
||
直接粘贴完整命令,GoNavi 会自动拆成“启动命令 / 命令参数 / 环境变量”三块;支持 Unix 的 KEY=VALUE,也支持 Windows PowerShell 的 $env:KEY=VALUE; 和 cmd 的 set KEY=VALUE && 写法。
|
||
</div>
|
||
<Input.TextArea
|
||
rows={2}
|
||
value={rawCommandDraft}
|
||
onChange={(event) => onRawCommandDraftChange(event.target.value)}
|
||
placeholder={`直接粘贴完整命令,例如:\n${MCP_COMMAND_PARSE_EXAMPLE}`}
|
||
style={{ borderRadius: 10, background: inputBg, border: `1px solid ${cardBorder}`, fontFamily: 'var(--gn-font-mono)' }}
|
||
/>
|
||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||
<div style={{ ...buildMCPHintStyle(parsedCommandDraft.ok ? overlayTheme.mutedText : '#dc2626') }}>
|
||
{rawCommandDraft.trim()
|
||
? parsedCommandDraft.ok && parsedCommandDraft.draft
|
||
? `将解析为:命令 ${parsedCommandDraft.draft.command},参数 ${parsedCommandDraft.draft.args.length} 个,环境变量 ${Object.keys(parsedCommandDraft.draft.env).length} 个。`
|
||
: parsedCommandDraft.error
|
||
: '支持带引号路径、带空格参数,以及 KEY=VALUE / $env:KEY=VALUE; / set KEY=VALUE && 环境变量前缀。'}
|
||
</div>
|
||
<Button onClick={onApplyCommandDraft} disabled={!parsedCommandDraft.ok} style={{ borderRadius: 10 }}>
|
||
自动拆分到下方字段
|
||
</Button>
|
||
</div>
|
||
{parsedCommandDraft.ok && parsedCommandDraft.draft && rawCommandDraft.trim() && (
|
||
<AIMCPCommandDraftPreview
|
||
draft={parsedCommandDraft.draft}
|
||
darkMode={darkMode}
|
||
overlayTheme={overlayTheme}
|
||
cardBorder={cardBorder}
|
||
/>
|
||
)}
|
||
</div>
|
||
</>
|
||
);
|
||
|
||
export default AIMCPServerGuidePanel;
|