feat: successfully install

This commit is contained in:
WangCham
2026-05-07 13:19:02 +08:00
parent 80911a3d91
commit 58f9ff94d3
9 changed files with 194 additions and 19 deletions

View File

@@ -233,8 +233,8 @@ export function SidebarDataProvider({
const resp = await httpClient.getMCPServers();
setMCPServers(
resp.servers.map((server) => ({
id: server.name,
name: server.name,
id: server.name, // Keep __ for API calls
name: server.name.replace(/__/g, '/'), // Display with / for readability
enabled: server.enable,
runtimeStatus: server.runtime_info?.status,
})),

View File

@@ -39,7 +39,9 @@ export default function MCPDetailContent({ id }: { id: string }) {
setDetailEntityName(t('mcp.createServer'));
} else {
const server = mcpServers.find((s) => s.id === id);
setDetailEntityName(server?.name ?? id);
// Convert __ back to / for display (since / is used as separator in stored names)
const displayName = (server?.name ?? id).replace(/__/g, '/');
setDetailEntityName(displayName);
}
return () => setDetailEntityName(null);
}, [id, isCreateMode, mcpServers, setDetailEntityName, t]);

View File

@@ -309,7 +309,7 @@ const MCPForm = forwardRef<MCPFormHandle, MCPFormProps>(function MCPForm(
const server = resp.server ?? resp;
const formValues: FormValues = {
name: server.name,
name: server.name.replace(/__/g, '/'), // Convert __ back to / for display
mode: server.mode,
url: '',
command: '',

View File

@@ -33,7 +33,7 @@ import PluginMarketCardComponent from './plugin-market-card/PluginMarketCardComp
import { PluginMarketCardVO } from './plugin-market-card/PluginMarketCardVO';
import { getCloudServiceClientSync } from '@/app/infra/http';
import { useTranslation } from 'react-i18next';
import { PluginV4 } from '@/app/infra/entities/plugin';
import { PluginV4, PluginV4Status } from '@/app/infra/entities/plugin';
import { extractI18nObject } from '@/i18n/I18nProvider';
import { toast } from 'sonner';
import { ApiRespMarketplacePlugins } from '@/app/infra/entities/api';
@@ -489,13 +489,44 @@ function MarketPageContent({
// 处理安装插件
const handleInstallPlugin = useCallback(
async (author: string, pluginName: string) => {
async (cardVO: PluginMarketCardVO) => {
try {
// Fetch full plugin details to get PluginV4 object
if (cardVO.type === 'mcp' || cardVO.type === 'skill') {
// For MCP and Skill, directly pass the data - backend will fetch from Space
const pluginV4: PluginV4 = {
id: 0,
plugin_id: `${cardVO.author}/${cardVO.pluginName}`,
mcp_id: cardVO.type === 'mcp' ? `${cardVO.author}/${cardVO.pluginName}` : undefined,
skill_id: cardVO.type === 'skill' ? `${cardVO.author}/${cardVO.pluginName}` : undefined,
author: cardVO.author,
name: cardVO.pluginName,
label: { en_US: cardVO.label, zh_Hans: cardVO.label },
description: { en_US: cardVO.description, zh_Hans: cardVO.description },
icon: cardVO.iconURL,
repository: cardVO.githubURL,
tags: cardVO.tags || [],
install_count: cardVO.installCount,
latest_version: cardVO.version,
components: cardVO.components || {},
status: PluginV4Status.Live,
type: cardVO.type,
created_at: '',
updated_at: '',
};
installPlugin(pluginV4);
return;
}
// For plugin type, fetch full details via API
const response = await getCloudServiceClientSync().getPluginDetail(
author,
pluginName,
cardVO.author,
cardVO.pluginName,
);
if (!response?.plugin) {
console.error('Failed to install plugin: plugin not found', { author: cardVO.author, pluginName: cardVO.pluginName });
toast.error(t('market.installFailed'));
return;
}
const pluginV4: PluginV4 = response.plugin;
// Call the install function passed from parent
@@ -505,7 +536,7 @@ function MarketPageContent({
toast.error(t('market.installFailed'));
}
},
[plugins, installPlugin, t],
[installPlugin, t],
);
// 清理定时器

View File

@@ -50,7 +50,7 @@ function RecommendationListRow({
}: {
list: RecommendationList;
tagNames: Record<string, string>;
onInstall: (author: string, pluginName: string) => void;
onInstall: (cardVO: PluginMarketCardVO) => void;
isLast: boolean;
}) {
const { t } = useTranslation();
@@ -162,7 +162,7 @@ export function RecommendationLists({
}: {
lists: RecommendationList[];
tagNames: Record<string, string>;
onInstall: (author: string, pluginName: string) => void;
onInstall: (cardVO: PluginMarketCardVO) => void;
}) {
if (!lists || lists.length === 0) return null;

View File

@@ -18,7 +18,7 @@ export default function PluginMarketCardComponent({
tagNames = {},
}: {
cardVO: PluginMarketCardVO;
onInstall?: (author: string, pluginName: string) => void;
onInstall?: (cardVO: PluginMarketCardVO) => void;
tagNames?: Record<string, string>;
}) {
const { t } = useTranslation();
@@ -244,7 +244,7 @@ export default function PluginMarketCardComponent({
onClick={(e) => {
e.stopPropagation();
if (onInstall) {
onInstall(cardVO.author, cardVO.pluginName);
onInstall(cardVO);
}
}}
className={`bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg shadow-sm flex items-center gap-2 transition-all duration-200 ${

View File

@@ -804,7 +804,7 @@ export class BackendClient extends BaseHttpClient {
}
public getMCPServer(serverName: string): Promise<ApiRespMCPServer> {
return this.get(`/api/v1/mcp/servers/${serverName}`);
return this.get(`/api/v1/mcp/servers/${encodeURIComponent(serverName)}`);
}
public createMCPServer(server: MCPServer): Promise<AsyncTaskCreatedResp> {
@@ -815,18 +815,18 @@ export class BackendClient extends BaseHttpClient {
serverName: string,
server: Partial<MCPServer>,
): Promise<AsyncTaskCreatedResp> {
return this.put(`/api/v1/mcp/servers/${serverName}`, server);
return this.put(`/api/v1/mcp/servers/${encodeURIComponent(serverName)}`, server);
}
public deleteMCPServer(serverName: string): Promise<AsyncTaskCreatedResp> {
return this.delete(`/api/v1/mcp/servers/${serverName}`);
return this.delete(`/api/v1/mcp/servers/${encodeURIComponent(serverName)}`);
}
public toggleMCPServer(
serverName: string,
target_enabled: boolean,
): Promise<AsyncTaskCreatedResp> {
return this.put(`/api/v1/mcp/servers/${serverName}`, {
return this.put(`/api/v1/mcp/servers/${encodeURIComponent(serverName)}`, {
enable: target_enabled,
});
}
@@ -835,7 +835,7 @@ export class BackendClient extends BaseHttpClient {
serverName: string,
serverData: object,
): Promise<AsyncTaskCreatedResp> {
return this.post(`/api/v1/mcp/servers/${serverName}/test`, serverData);
return this.post(`/api/v1/mcp/servers/${encodeURIComponent(serverName)}/test`, serverData);
}
public installMCPServerFromGithub(