mirror of https://github.com/kortix-ai/suna.git
wip
This commit is contained in:
parent
9b73d72352
commit
c20b5e70e8
|
@ -2,7 +2,7 @@
|
|||
|
||||
import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { ArrowLeft, Loader2, Settings2, Sparkles, Check, Clock, Eye, Menu, Zap, Brain, Workflow } from 'lucide-react';
|
||||
import { Loader2, Settings2, Sparkles, Check, Clock, Eye, Menu, Zap, Brain, Workflow } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
@ -375,7 +375,7 @@ export default function AgentConfigurationPage() {
|
|||
<AccordionTrigger className="hover:no-underline text-sm md:text-base">
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles className="h-4 w-4" />
|
||||
Integrations (via MCP)
|
||||
Integrations & MCPs
|
||||
<Badge variant='new'>New</Badge>
|
||||
</div>
|
||||
</AccordionTrigger>
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
AlertTriangle,
|
||||
Zap
|
||||
} from 'lucide-react';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { PipedreamConnectionsSection } from '../../../../components/agents/pipedream/pipedream-connections-section';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useFeatureFlag } from '@/lib/feature-flags';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
export default function AppProfilesPage() {
|
||||
const { enabled: customAgentsEnabled, loading: flagLoading } = useFeatureFlag("custom_agents");
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { Card } from '@/components/ui/card';
|
||||
|
||||
export const McpSearchLoader: React.FC = () => {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Skeleton className="h-5 w-32" />
|
||||
<Skeleton className="h-4 w-16" />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{Array.from({ length: 8 }).map((_, index) => (
|
||||
<Card key={index} className="p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<Skeleton className="h-6 w-6 rounded" />
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-4 w-28" />
|
||||
<Skeleton className="h-3 w-3 rounded-full" />
|
||||
<Skeleton className="h-4 w-16 rounded-full" />
|
||||
</div>
|
||||
<Skeleton className="h-3 w-full" />
|
||||
<Skeleton className="h-3 w-4/5" />
|
||||
<div className="flex items-center gap-4">
|
||||
<Skeleton className="h-3 w-16" />
|
||||
<Skeleton className="h-3 w-3" />
|
||||
</div>
|
||||
</div>
|
||||
<Skeleton className="h-4 w-4" />
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -1,17 +1,15 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Loader2, AlertCircle, CheckCircle2, Zap, Globe, Code, ChevronRight, Sparkles, Database, Wifi, Server } from 'lucide-react';
|
||||
import { Loader2, AlertCircle, CheckCircle2, Zap, ChevronRight, Sparkles, Wifi, Server } from 'lucide-react';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { createClient } from '@/lib/supabase/client';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { CredentialProfile } from '@/hooks/react-query/mcp/use-credential-profiles';
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_BACKEND_URL || '';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Plus, Settings, Zap, Code2, Server, Store } from 'lucide-react';
|
||||
import { Zap, Server, Store } from 'lucide-react';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { MCPConfigurationProps, MCPConfiguration as MCPConfigurationType } from './types';
|
||||
import { ConfiguredMcpList } from './configured-mcp-list';
|
||||
|
@ -68,51 +68,6 @@ export const MCPConfigurationNew: React.FC<MCPConfigurationProps> = ({
|
|||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="rounded-xl p-6 border">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className="p-2 bg-primary/10 rounded-lg">
|
||||
<Settings className="h-5 w-5 text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed max-w-md">
|
||||
Give your agent access to external tools and services.
|
||||
</p>
|
||||
{configuredMCPs.length > 0 && (
|
||||
<div className="flex items-center mt-3 space-x-2">
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="w-2 h-2 bg-emerald-500 rounded-full animate-pulse"></div>
|
||||
<span className="text-xs font-medium text-emerald-600 dark:text-emerald-400">
|
||||
{configuredMCPs.length} integration{configuredMCPs.length !== 1 ? 's' : ''} configured
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => setShowRegistryDialog(true)}
|
||||
className="transition-all duration-200"
|
||||
>
|
||||
<Store className="h-4 w-4" />
|
||||
Browse Apps
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => setShowCustomDialog(true)}
|
||||
className="transition-all duration-200"
|
||||
>
|
||||
<Server className="h-4 w-4" />
|
||||
Custom MCP
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{configuredMCPs.length === 0 && (
|
||||
<div className="text-center py-12 px-6 bg-muted/30 rounded-xl border-2 border-dashed border-border">
|
||||
<div className="mx-auto w-12 h-12 bg-muted rounded-full flex items-center justify-center mb-4">
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
import React from 'react';
|
||||
import { McpSearchLoader } from './_loaders/mcp-search-loader';
|
||||
import { McpServerCard } from './mcp-server-card';
|
||||
|
||||
interface SearchResultsProps {
|
||||
searchResults: any;
|
||||
isSearching: boolean;
|
||||
onServerSelect: (server: any) => void;
|
||||
}
|
||||
|
||||
export const SearchResults: React.FC<SearchResultsProps> = ({
|
||||
searchResults,
|
||||
isSearching,
|
||||
onServerSelect,
|
||||
}) => {
|
||||
if (isSearching) {
|
||||
return <McpSearchLoader />;
|
||||
}
|
||||
|
||||
if (!searchResults?.servers || searchResults.servers.length === 0) {
|
||||
return (
|
||||
<div className="text-center py-8">
|
||||
<p className="text-sm text-muted-foreground">No servers found</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-sm font-semibold text-muted-foreground">
|
||||
Search Results ({searchResults.pagination.totalCount})
|
||||
</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{searchResults.servers.map((server) => (
|
||||
<McpServerCard
|
||||
key={server.qualifiedName}
|
||||
server={server}
|
||||
onClick={onServerSelect}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Input } from '@/components/ui/input';
|
||||
|
@ -45,7 +45,6 @@ import {
|
|||
Loader2,
|
||||
User,
|
||||
Link2,
|
||||
AlertCircle,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
usePipedreamProfiles,
|
||||
|
@ -54,8 +53,7 @@ import {
|
|||
useDeletePipedreamProfile,
|
||||
useConnectPipedreamProfile,
|
||||
} from '@/hooks/react-query/pipedream/use-pipedream-profiles';
|
||||
import type { PipedreamProfile, CreateProfileRequest } from '@/components/agents/pipedream/pipedream-profiles';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import type { PipedreamProfile, CreateProfileRequest } from '@/components/agents/pipedream/pipedream-types';
|
||||
|
||||
interface CredentialProfileManagerProps {
|
||||
appSlug?: string;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Select,
|
||||
|
@ -9,7 +9,6 @@ import {
|
|||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import {
|
||||
Dialog,
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import type { PipedreamProfile } from '@/components/agents/pipedream/pipedream-profiles';
|
||||
import type { PipedreamProfile } from '@/components/agents/pipedream/pipedream-types';
|
||||
|
||||
interface AppTableProps {
|
||||
appSlug: string;
|
||||
|
|
|
@ -3,9 +3,8 @@ import { Button } from '@/components/ui/button';
|
|||
import { Input } from '@/components/ui/input';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Search, Loader2, ExternalLink, Zap, Filter, Grid, List, User, CheckCircle2, Plus, X, Settings, Star, Globe, Database, MessageSquare, Mail, Bot, FileText, Calculator, Calendar, Building, Workflow, Sparkles } from 'lucide-react';
|
||||
import { Search, Loader2, Grid, User, CheckCircle2, Plus, X, Settings, Star } from 'lucide-react';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { usePipedreamApps } from '@/hooks/react-query/pipedream/use-pipedream';
|
||||
import { usePipedreamProfiles } from '@/hooks/react-query/pipedream/use-pipedream-profiles';
|
||||
import { CredentialProfileSelector } from './credential-profile-selector';
|
||||
|
@ -13,21 +12,10 @@ import { PipedreamToolSelector } from './pipedream-tool-selector';
|
|||
import { CredentialProfileManager } from './credential-profile-manager';
|
||||
import { toast } from 'sonner';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { PipedreamProfile } from '@/components/agents/pipedream/pipedream-profiles';
|
||||
import type { PipedreamProfile } from '@/components/agents/pipedream/pipedream-types';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { pipedreamKeys } from '@/hooks/react-query/pipedream/keys';
|
||||
|
||||
interface PipedreamApp {
|
||||
id: string;
|
||||
name: string;
|
||||
name_slug: string;
|
||||
app_hid: string;
|
||||
description: string;
|
||||
categories: string[];
|
||||
featured_weight: number;
|
||||
api_docs_url: string | null;
|
||||
status: number;
|
||||
}
|
||||
import type { PipedreamApp } from '@/hooks/react-query/pipedream/utils';
|
||||
|
||||
interface PipedreamRegistryProps {
|
||||
onProfileSelected?: (profile: PipedreamProfile) => void;
|
||||
|
@ -37,25 +25,6 @@ interface PipedreamRegistryProps {
|
|||
onClose?: () => void;
|
||||
}
|
||||
|
||||
const getCategoryIcon = (category: string) => {
|
||||
const icons: Record<string, React.ReactNode> = {
|
||||
'All': <Globe className="h-4 w-4" />,
|
||||
'Storage & Drive': <Database className="h-4 w-4" />,
|
||||
'Tasks': <CheckCircle2 className="h-4 w-4" />,
|
||||
'Management': <Settings className="h-4 w-4" />,
|
||||
'Communication': <MessageSquare className="h-4 w-4" />,
|
||||
'Mail': <Mail className="h-4 w-4" />,
|
||||
'Automation': <Bot className="h-4 w-4" />,
|
||||
'Knowledge': <FileText className="h-4 w-4" />,
|
||||
'Finance': <Calculator className="h-4 w-4" />,
|
||||
'Calendar': <Calendar className="h-4 w-4" />,
|
||||
'Business': <Building className="h-4 w-4" />,
|
||||
'Workflow': <Workflow className="h-4 w-4" />,
|
||||
'AI': <Sparkles className="h-4 w-4" />,
|
||||
};
|
||||
return icons[category] || <Grid className="h-4 w-4" />;
|
||||
};
|
||||
|
||||
export const PipedreamRegistry: React.FC<PipedreamRegistryProps> = ({
|
||||
onProfileSelected,
|
||||
onToolsSelected,
|
||||
|
@ -169,7 +138,7 @@ export const PipedreamRegistry: React.FC<PipedreamRegistryProps> = ({
|
|||
const AppCard: React.FC<{ app: PipedreamApp; compact?: boolean }> = ({ app, compact = false }) => {
|
||||
const appProfiles = getAppProfiles(app.name_slug);
|
||||
const connectedProfiles = appProfiles.filter(p => p.is_connected);
|
||||
const [selectedProfileId, setSelectedProfileId] = useState<string | null>(null);
|
||||
const [selectedProfileId, setSelectedProfileId] = useState<string | undefined>(undefined);
|
||||
|
||||
return (
|
||||
<Card className="group transition-all duration-200 hover:shadow-md border-border/50 hover:border-border/80 bg-card/50 hover:bg-card/80 w-full">
|
||||
|
@ -252,7 +221,7 @@ export const PipedreamRegistry: React.FC<PipedreamRegistryProps> = ({
|
|||
appName={app.name}
|
||||
selectedProfileId={selectedProfileId}
|
||||
onProfileSelect={(profileId) => {
|
||||
setSelectedProfileId(profileId);
|
||||
setSelectedProfileId(profileId || undefined);
|
||||
if (profileId) {
|
||||
handleProfileSelect(profileId, app);
|
||||
}
|
||||
|
@ -303,7 +272,7 @@ export const PipedreamRegistry: React.FC<PipedreamRegistryProps> = ({
|
|||
: "hover:bg-muted/50"
|
||||
)}
|
||||
>
|
||||
{getCategoryIcon(category)}
|
||||
<Grid className="h-4 w-4" />
|
||||
<span>{category}</span>
|
||||
{categoryCount > 0 && (
|
||||
<Badge variant="secondary" className="ml-1 h-4 px-1.5 text-xs bg-muted/50">
|
||||
|
@ -414,24 +383,11 @@ export const PipedreamRegistry: React.FC<PipedreamRegistryProps> = ({
|
|||
{selectedCategory !== 'All' && (
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
{getCategoryIcon(selectedCategory)}
|
||||
<Grid className="h-4 w-4 text-muted-foreground" />
|
||||
<h3 className="font-semibold text-foreground">{selectedCategory}</h3>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
{selectedCategory === 'Storage & Drive' && 'Access and manage your files across cloud storage platforms'}
|
||||
{selectedCategory === 'Communication' && 'Connect your messaging and communication tools'}
|
||||
{selectedCategory === 'Mail' && 'Integrate with your email services and providers'}
|
||||
{selectedCategory === 'Tasks' && 'Manage and track your tasks and project workflows'}
|
||||
{selectedCategory === 'Management' && 'Connect your business and project management tools'}
|
||||
{selectedCategory === 'Automation' && 'Automate workflows with powerful automation tools'}
|
||||
{selectedCategory === 'Knowledge' && 'Access your knowledge bases and documentation'}
|
||||
{selectedCategory === 'Calendar' && 'Sync and manage your calendar events and schedules'}
|
||||
{selectedCategory === 'Finance' && 'Connect your financial and accounting tools'}
|
||||
{selectedCategory === 'Business' && 'Integrate with your business and enterprise tools'}
|
||||
{selectedCategory === 'Workflow' && 'Streamline your workflows and processes'}
|
||||
{selectedCategory === 'AI' && 'Enhance your workflows with AI-powered tools'}
|
||||
{!['Storage & Drive', 'Communication', 'Mail', 'Tasks', 'Management', 'Automation', 'Knowledge', 'Calendar', 'Finance', 'Business', 'Workflow', 'AI'].includes(selectedCategory) &&
|
||||
`Explore ${selectedCategory} integrations and tools`}
|
||||
Explore {selectedCategory} integrations and tools
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
@ -507,7 +463,7 @@ export const PipedreamRegistry: React.FC<PipedreamRegistryProps> = ({
|
|||
</DialogHeader>
|
||||
<PipedreamToolSelector
|
||||
appSlug={selectedProfile?.app_slug || ''}
|
||||
profile={selectedProfile}
|
||||
profile={selectedProfile || undefined}
|
||||
onToolsSelected={handleToolsSelected}
|
||||
/>
|
||||
</DialogContent>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Badge } from '@/components/ui/badge';
|
|||
import { Loader2, Zap, CheckCircle2, RefreshCw, AlertCircle } from 'lucide-react';
|
||||
import { type PipedreamTool, type PipedreamAppWithTools, pipedreamApi } from '@/hooks/react-query/pipedream/utils';
|
||||
import { toast } from 'sonner';
|
||||
import type { PipedreamProfile } from '@/components/agents/pipedream/pipedream-profiles';
|
||||
import type { PipedreamProfile } from '@/components/agents/pipedream/pipedream-types';
|
||||
|
||||
interface PipedreamToolSelectorProps {
|
||||
appSlug: string;
|
||||
|
|
|
@ -2,6 +2,5 @@ import { isLocalMode } from './lib/config';
|
|||
|
||||
export const agentPlaygroundFlagFrontend = isLocalMode();
|
||||
export const marketplaceFlagFrontend = isLocalMode();
|
||||
|
||||
export const agentPlaygroundEnabled = isLocalMode();
|
||||
export const marketplaceEnabled = isLocalMode();
|
||||
|
|
|
@ -5,7 +5,7 @@ import type {
|
|||
PipedreamProfile,
|
||||
CreateProfileRequest,
|
||||
UpdateProfileRequest,
|
||||
} from '@/components/agents/pipedream/pipedream-profiles';
|
||||
} from '@/components/agents/pipedream/pipedream-types';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
export const usePipedreamProfiles = (params?: { app_slug?: string; is_active?: boolean }) => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import type {
|
|||
UpdateProfileRequest,
|
||||
ProfileConnectionResponse,
|
||||
ProfileConnectionsResponse
|
||||
} from '@/components/agents/pipedream/pipedream-profiles';
|
||||
} from '@/components/agents/pipedream/pipedream-types';
|
||||
|
||||
export interface CreateConnectionTokenRequest {
|
||||
app?: string;
|
||||
|
|
Loading…
Reference in New Issue