Files
MyGoNavi/frontend/src/components/ai/AIMCPClientInstallPanel.tsx
Syngnat c1d27448bc ♻️ refactor(ai): 拆分 MCP 客户端接入面板
- 将客户端选择和状态详情拆为独立组件

- 保留本机安装、远程桥接和快速配置展示行为

- 补充选择区和状态区渲染测试
2026-06-11 19:47:11 +08:00

134 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React from 'react';
import { Button } from 'antd';
import type { AIMCPClientInstallStatus } from '../../types';
import {
isRemoteMCPClientStatus,
type MCPClientKey,
} from '../../utils/mcpClientInstallStatus';
import type { OverlayWorkbenchTheme } from '../../utils/overlayWorkbenchTheme';
import AIMCPClientSelectorPanel from './AIMCPClientSelectorPanel';
import AIMCPClientStatusPanel from './AIMCPClientStatusPanel';
import {
getMCPClientDetectionSummary,
resolveMCPClientInstallActionLabel,
} from './mcpClientInstallPanelState';
interface AIMCPClientInstallPanelProps {
statuses: AIMCPClientInstallStatus[];
selectedClient: MCPClientKey;
selectedStatus?: AIMCPClientInstallStatus;
selectedCommandText: string;
darkMode: boolean;
overlayTheme: OverlayWorkbenchTheme;
cardBg: string;
cardBorder: string;
loading: boolean;
statusLoading: boolean;
onSelectClient: (client: MCPClientKey) => void;
onRefreshStatus: () => void;
onCopyConfigPath: () => void;
onCopyLaunchCommand: () => void;
onInstall: () => void;
}
const AIMCPClientInstallPanel: React.FC<AIMCPClientInstallPanelProps> = ({
statuses,
selectedClient,
selectedStatus,
selectedCommandText,
darkMode,
overlayTheme,
cardBg,
cardBorder,
loading,
statusLoading,
onSelectClient,
onRefreshStatus,
onCopyConfigPath,
onCopyLaunchCommand,
onInstall,
}) => {
const selectedIsRemoteClient = isRemoteMCPClientStatus(selectedStatus);
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
<div
style={{
padding: '16px',
borderRadius: 14,
border: `1px solid ${cardBorder}`,
background: cardBg,
display: 'flex',
flexDirection: 'column',
gap: 14,
}}
>
<div
style={{
padding: '12px 14px',
borderRadius: 12,
border: `1px solid ${darkMode ? 'rgba(96,165,250,0.16)' : 'rgba(96,165,250,0.18)'}`,
background: darkMode ? 'rgba(59,130,246,0.08)' : 'rgba(59,130,246,0.05)',
display: 'flex',
flexDirection: 'column',
gap: 6,
}}
>
<div style={{ fontWeight: 700, fontSize: 13, color: overlayTheme.titleText }}>
GoNavi MCP Claude Code / Codex / OpenClaw / Hermans GoNavi
</div>
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.7 }}>
Claude Code Codex MCP OpenClawHermans Agent
</div>
</div>
<AIMCPClientSelectorPanel
statuses={statuses}
selectedClient={selectedClient}
darkMode={darkMode}
overlayTheme={overlayTheme}
cardBorder={cardBorder}
statusLoading={statusLoading}
onSelectClient={onSelectClient}
/>
<AIMCPClientStatusPanel
selectedStatus={selectedStatus}
selectedCommandText={selectedCommandText}
darkMode={darkMode}
overlayTheme={overlayTheme}
cardBorder={cardBorder}
statusLoading={statusLoading}
onRefreshStatus={onRefreshStatus}
onCopyConfigPath={onCopyConfigPath}
onCopyLaunchCommand={onCopyLaunchCommand}
/>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{getMCPClientDetectionSummary(selectedStatus)}
{!selectedIsRemoteClient && (
<>
{' '}
GoNavi
</>
)}
</div>
<Button
type={selectedStatus?.matchesCurrent ? 'default' : 'primary'}
onClick={onInstall}
loading={loading}
disabled={Boolean(selectedStatus?.matchesCurrent)}
style={{ borderRadius: 10, fontWeight: 600, width: 208, maxWidth: '100%', height: 40 }}
>
{resolveMCPClientInstallActionLabel(selectedStatus)}
</Button>
</div>
</div>
</div>
);
};
export default AIMCPClientInstallPanel;