This commit is contained in:
marko-kraemer 2025-07-10 02:51:55 +02:00
parent 9b73d72352
commit c20b5e70e8
15 changed files with 21 additions and 201 deletions

View File

@ -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>

View File

@ -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");

View File

@ -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>
);
};

View File

@ -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 || '';

View File

@ -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">

View File

@ -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>
);
};

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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>

View File

@ -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;

View File

@ -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();

View File

@ -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 }) => {

View File

@ -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;