mirror of https://github.com/kortix-ai/suna.git
fix: frontend mcp type fix
This commit is contained in:
parent
f723977916
commit
7bc95af934
|
@ -289,7 +289,10 @@ export const CreateAgentDialog = ({ isOpen, onOpenChange, onAgentCreated }: Crea
|
||||||
|
|
||||||
<TabsContent value="mcp" className="flex-1 m-0 p-6 overflow-y-auto">
|
<TabsContent value="mcp" className="flex-1 m-0 p-6 overflow-y-auto">
|
||||||
<MCPConfigurationNew
|
<MCPConfigurationNew
|
||||||
configuredMCPs={formData.configured_mcps}
|
configuredMCPs={formData.configured_mcps.map(mcp => ({
|
||||||
|
...mcp,
|
||||||
|
enabledTools: mcp.enabledTools || []
|
||||||
|
}))}
|
||||||
onConfigurationChange={handleMCPConfigurationChange}
|
onConfigurationChange={handleMCPConfigurationChange}
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
|
@ -393,14 +393,20 @@ export const UpdateAgentDialog = ({ agentId, isOpen, onOpenChange, onAgentUpdate
|
||||||
|
|
||||||
<TabsContent value="mcp" className="flex-1 m-0 p-6 overflow-y-auto">
|
<TabsContent value="mcp" className="flex-1 m-0 p-6 overflow-y-auto">
|
||||||
<MCPConfigurationNew
|
<MCPConfigurationNew
|
||||||
configuredMCPs={[...(formData.configured_mcps || []), ...(formData.custom_mcps || []).map(customMcp => ({
|
configuredMCPs={[
|
||||||
name: customMcp.name,
|
...(formData.configured_mcps || []).map(mcp => ({
|
||||||
qualifiedName: `custom_${customMcp.type}_${customMcp.name.replace(' ', '_').toLowerCase()}`,
|
...mcp,
|
||||||
config: customMcp.config,
|
enabledTools: mcp.enabledTools || []
|
||||||
enabledTools: customMcp.enabledTools,
|
})),
|
||||||
isCustom: true,
|
...(formData.custom_mcps || []).map(customMcp => ({
|
||||||
customType: customMcp.type
|
name: customMcp.name,
|
||||||
}))]}
|
qualifiedName: `custom_${customMcp.type}_${customMcp.name.replace(' ', '_').toLowerCase()}`,
|
||||||
|
config: customMcp.config,
|
||||||
|
enabledTools: customMcp.enabledTools,
|
||||||
|
isCustom: true,
|
||||||
|
customType: customMcp.type
|
||||||
|
}))
|
||||||
|
]}
|
||||||
onConfigurationChange={handleMCPConfigurationChange}
|
onConfigurationChange={handleMCPConfigurationChange}
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
|
@ -86,15 +86,25 @@ export const PipedreamAppBrowser: React.FC<PipedreamAppBrowserProps> = ({
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<div className="relative flex-1">
|
<form onSubmit={(e) => {e.preventDefault()}} className="relative flex-1">
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="Search apps..."
|
placeholder="Search apps... (e.g., Gmail, Slack, Notion)"
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
className="pl-10"
|
className="pl-10"
|
||||||
/>
|
/>
|
||||||
</div>
|
{searchQuery && (
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="absolute right-1 top-1/2 transform -translate-y-1/2 h-8 px-2"
|
||||||
|
>
|
||||||
|
Search
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
{selectedCategory && (
|
{selectedCategory && (
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
|
|
|
@ -66,6 +66,11 @@ export const PipedreamRegistry: React.FC<PipedreamRegistryProps> = ({
|
||||||
setPage(1);
|
setPage(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSearchSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
refetch();
|
||||||
|
};
|
||||||
|
|
||||||
const handleCategorySelect = (category: string) => {
|
const handleCategorySelect = (category: string) => {
|
||||||
setSelectedCategory(category === selectedCategory ? '' : category);
|
setSelectedCategory(category === selectedCategory ? '' : category);
|
||||||
setPage(1);
|
setPage(1);
|
||||||
|
@ -281,15 +286,25 @@ export const PipedreamRegistry: React.FC<PipedreamRegistryProps> = ({
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<form onSubmit={handleSearchSubmit} className="relative">
|
||||||
<Search className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-3 w-3 text-muted-foreground" />
|
<Search className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-3 w-3 text-muted-foreground" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="Search apps..."
|
placeholder="Search apps... (e.g., Gmail, Slack, Notion)"
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => handleSearch(e.target.value)}
|
onChange={(e) => handleSearch(e.target.value)}
|
||||||
className="pl-8 h-8 text-sm"
|
className="pl-8 h-8 text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
{search && (
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="absolute right-1 top-1/2 transform -translate-y-1/2 h-6 px-2"
|
||||||
|
>
|
||||||
|
Search
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-auto p-4">
|
<div className="flex-1 overflow-auto p-4">
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
|
|
|
@ -7,6 +7,7 @@ export const pipedreamKeys = {
|
||||||
workflows: () => [...pipedreamKeys.all, 'workflows'] as const,
|
workflows: () => [...pipedreamKeys.all, 'workflows'] as const,
|
||||||
workflowRuns: (workflowId: string) => [...pipedreamKeys.all, 'workflow-runs', workflowId] as const,
|
workflowRuns: (workflowId: string) => [...pipedreamKeys.all, 'workflow-runs', workflowId] as const,
|
||||||
apps: (page: number, search?: string, category?: string) => [...pipedreamKeys.all, 'apps', page, search || '', category || ''] as const,
|
apps: (page: number, search?: string, category?: string) => [...pipedreamKeys.all, 'apps', page, search || '', category || ''] as const,
|
||||||
|
appsSearch: (query: string, page: number, category?: string) => [...pipedreamKeys.all, 'apps', 'search', query, page, category || ''] as const,
|
||||||
availableTools: () => [...pipedreamKeys.all, 'available-tools'] as const,
|
availableTools: () => [...pipedreamKeys.all, 'available-tools'] as const,
|
||||||
mcpDiscovery: (options?: { app_slug?: string; oauth_app_id?: string; custom?: boolean }) =>
|
mcpDiscovery: (options?: { app_slug?: string; oauth_app_id?: string; custom?: boolean }) =>
|
||||||
[...pipedreamKeys.all, 'mcp-discovery', options?.app_slug, options?.oauth_app_id, options?.custom] as const,
|
[...pipedreamKeys.all, 'mcp-discovery', options?.app_slug, options?.oauth_app_id, options?.custom] as const,
|
||||||
|
|
|
@ -62,6 +62,18 @@ export const usePipedreamApps = (page: number = 1, search?: string, category?: s
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const usePipedreamAppsSearch = (query: string, page: number = 1, category?: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['pipedream', 'apps', 'search', query, page, category],
|
||||||
|
queryFn: async (): Promise<PipedreamAppResponse> => {
|
||||||
|
return await pipedreamApi.searchApps(query, page, category);
|
||||||
|
},
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
retry: 2,
|
||||||
|
enabled: !!query && query.length > 0,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const usePipedreamAvailableTools = createQueryHook(
|
export const usePipedreamAvailableTools = createQueryHook(
|
||||||
pipedreamKeys.availableTools(),
|
pipedreamKeys.availableTools(),
|
||||||
async (forceRefresh: boolean = false): Promise<PipedreamToolsResponse> => {
|
async (forceRefresh: boolean = false): Promise<PipedreamToolsResponse> => {
|
||||||
|
|
|
@ -100,8 +100,13 @@ export interface PipedreamAppResponse {
|
||||||
current_page: number;
|
current_page: number;
|
||||||
page_size: number;
|
page_size: number;
|
||||||
has_more: boolean;
|
has_more: boolean;
|
||||||
|
count?: number;
|
||||||
|
start_cursor?: string;
|
||||||
|
end_cursor?: string;
|
||||||
};
|
};
|
||||||
total_count: number;
|
total_count: number;
|
||||||
|
error?: string;
|
||||||
|
search_query?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PipedreamTool {
|
export interface PipedreamTool {
|
||||||
|
@ -174,13 +179,14 @@ export const pipedreamApi = {
|
||||||
},
|
},
|
||||||
|
|
||||||
async getApps(page: number = 1, search?: string, category?: string): Promise<PipedreamAppResponse> {
|
async getApps(page: number = 1, search?: string, category?: string): Promise<PipedreamAppResponse> {
|
||||||
|
if (search) {
|
||||||
|
return await this.searchApps(search, page, category);
|
||||||
|
}
|
||||||
|
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
page: page.toString(),
|
page: page.toString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (search) {
|
|
||||||
params.append('search', search);
|
|
||||||
}
|
|
||||||
if (category) {
|
if (category) {
|
||||||
params.append('category', category);
|
params.append('category', category);
|
||||||
}
|
}
|
||||||
|
@ -195,8 +201,41 @@ export const pipedreamApi = {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.error?.message || 'Failed to get apps');
|
throw new Error(result.error?.message || 'Failed to get apps');
|
||||||
}
|
}
|
||||||
|
const data = result.data!;
|
||||||
|
if (!data.success && data.error) {
|
||||||
|
throw new Error(data.error);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
return result.data!;
|
async searchApps(query: string, page: number = 1, category?: string): Promise<PipedreamAppResponse> {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
q: query,
|
||||||
|
page: page.toString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
params.append('category', category);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await backendApi.get<PipedreamAppResponse>(
|
||||||
|
`/pipedream/apps/search?${params.toString()}`,
|
||||||
|
{
|
||||||
|
errorContext: { operation: 'search apps', resource: 'Pipedream apps' },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.error?.message || 'Failed to search apps');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle both success response and potential error in the data
|
||||||
|
const data = result.data!;
|
||||||
|
if (!data.success && data.error) {
|
||||||
|
throw new Error(data.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
async getAvailableTools(): Promise<PipedreamToolsResponse> {
|
async getAvailableTools(): Promise<PipedreamToolsResponse> {
|
||||||
|
|
Loading…
Reference in New Issue