feat: 技能市场Hub导入MCP/Skills添加名称说明输入;MCP传输代码验证后独立导入按钮
This commit is contained in:
1 parent
c0ec9e0e88
commit
62631a3b95
1 file changed
+57
-5
@@ -870,7 +870,7 @@ interface HubImportModalProps {
|
||||
appType: 'skill' | 'mcp';
|
||||
platforms: typeof skillsHubPlatforms;
|
||||
onClose: () => void;
|
||||
onImport: (platformName: string, url: string, skillName: string, price?: number) => void;
|
||||
onImport: (platformName: string, url: string, skillName: string, price?: number, description?: string) => void;
|
||||
}
|
||||
|
||||
const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onClose, onImport }) => {
|
||||
@@ -884,6 +884,8 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
|
||||
const [hubCode, setHubCode] = useState('');
|
||||
const [hubCodeVerifyResult, setHubCodeVerifyResult] = useState<'idle' | 'checking' | 'pass' | 'fail'>('idle');
|
||||
const [hubCodeVerifyMsg, setHubCodeVerifyMsg] = useState('');
|
||||
const [hubName, setHubName] = useState('');
|
||||
const [hubDescription, setHubDescription] = useState('');
|
||||
|
||||
const handleVisit = (url: string) => {
|
||||
window.open(url, '_blank');
|
||||
@@ -908,9 +910,10 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
|
||||
|
||||
const handleImport = (platformId: string) => {
|
||||
const url = importUrl[platformId];
|
||||
// For Skills: require URL; for MCP: require code verification pass
|
||||
// For Skills: require URL; for MCP: require code verification pass + name
|
||||
if (appType === 'skill' && !url?.trim()) return;
|
||||
if (appType === 'mcp' && hubCodeVerifyResult !== 'pass') return;
|
||||
if (appType === 'mcp' && !hubName.trim()) return;
|
||||
setImportingId(platformId);
|
||||
setImportStatus('verifying');
|
||||
setStatusMsg(appType === 'mcp' ? '正在验证代码...' : '正在验证URL链接...');
|
||||
@@ -930,13 +933,16 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
|
||||
setStatusMsg(step.msg);
|
||||
if (step.status === 'published') {
|
||||
setTimeout(() => {
|
||||
onImport(platformId, appType === 'mcp' ? hubCode : url, extractSkillName(url, platformId), importPrice);
|
||||
const name = appType === 'skill' ? (hubName || extractSkillName(url || '', platformId)) : hubName;
|
||||
onImport(platformId, appType === 'mcp' ? hubCode : (url || ''), name, importPrice, hubDescription);
|
||||
setImportingId(null);
|
||||
setImportStatus('idle');
|
||||
setImportUrl(prev => ({ ...prev, [platformId]: '' }));
|
||||
setHubCode('');
|
||||
setHubCodeVerifyResult('idle');
|
||||
setHubCodeVerifyMsg('');
|
||||
setHubName('');
|
||||
setHubDescription('');
|
||||
}, 1000);
|
||||
}
|
||||
}, delay);
|
||||
@@ -974,6 +980,28 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Name & Description */}
|
||||
<div className="form-section">
|
||||
<label className="form-label">名称 <span className="required">*</span></label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-input"
|
||||
placeholder={appType === 'skill' ? '请输入Skills工具名称' : '请输入MCP应用名称'}
|
||||
value={hubName}
|
||||
onChange={e => setHubName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">说明</label>
|
||||
<textarea
|
||||
className="form-textarea"
|
||||
placeholder="请描述功能、使用场景等..."
|
||||
value={hubDescription}
|
||||
onChange={e => setHubDescription(e.target.value)}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* MCP Hub Import: Code Editor + AI验证 */}
|
||||
{appType === 'mcp' && (
|
||||
<div className="hub-code-section">
|
||||
@@ -1013,6 +1041,29 @@ const mcpClient = new MCPClient({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* MCP 独立导入按钮:直接导入(不依赖选择平台卡片) */}
|
||||
{appType === 'mcp' && hubCodeVerifyResult === 'pass' && (
|
||||
<div className="hub-standalone-import" style={{ textAlign: 'center', marginBottom: 20, padding: '16px', background: 'var(--color-bg-secondary)', borderRadius: 8 }}>
|
||||
<button
|
||||
className="hub-import-btn"
|
||||
style={{ padding: '10px 40px', fontSize: 15, fontWeight: 600 }}
|
||||
onClick={() => handleImport('custom-import')}
|
||||
disabled={!hubName.trim()}
|
||||
>
|
||||
{importingId === 'custom-import' ? (
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<div className="audit-spinner tiny" />
|
||||
导入中...
|
||||
</span>
|
||||
) : '导入'}
|
||||
</button>
|
||||
{!hubName.trim() && <div style={{ color: '#f85149', fontSize: 12, marginTop: 6 }}>请先输入名称</div>}
|
||||
<div style={{ fontSize: 12, color: 'var(--color-text-tertiary)', marginTop: 6 }}>
|
||||
直接从传输代码导入,无需选择平台
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="hub-platforms">
|
||||
{platforms.map(p => (
|
||||
<div key={p.id} className="hub-platform-card">
|
||||
@@ -1317,12 +1368,13 @@ const MarketPage: React.FC = () => {
|
||||
};
|
||||
|
||||
// Handle hub import - 调用后端 API 创建应用
|
||||
const handleHubImport = async (platformName: string, url: string, skillName: string, price?: number) => {
|
||||
const handleHubImport = async (platformName: string, url: string, skillName: string, price?: number, description?: string) => {
|
||||
try {
|
||||
const desc = description || `从 ${platformName} 导入的${showHubImport === 'skill' ? 'Skills工具' : 'MCP应用'} (来源: ${url})`;
|
||||
await marketAPI.createApp({
|
||||
name: skillName,
|
||||
type: showHubImport || 'skill',
|
||||
description: `从 ${platformName} 导入的${showHubImport === 'skill' ? 'Skills工具' : 'MCP应用'} (来源: ${url})`,
|
||||
description: desc,
|
||||
price: price || 0,
|
||||
is_member_free: (price || 0) === 0,
|
||||
join_promotion: false,
|
||||
|
||||
Reference in new issue
Block a user