rowboat/apps/rowboat/app/projects/[projectId]/tools/components/ToolkitCard.tsx

121 lines
3.8 KiB
TypeScript
Raw Normal View History

2025-07-03 15:19:48 +05:30
'use client';
2025-07-10 16:26:37 +05:30
import { useCallback } from 'react';
2025-07-03 15:19:48 +05:30
import { PictureImg } from '@/components/ui/picture-img';
import clsx from 'clsx';
import { z } from 'zod';
import { ZToolkit } from '@/app/lib/composio/composio';
2025-07-10 16:26:37 +05:30
import { Chip } from '@heroui/react';
import { LinkIcon } from 'lucide-react';
2025-07-23 15:37:49 +05:30
import { Workflow } from '@/app/lib/types/workflow_types';
2025-07-03 15:19:48 +05:30
type ToolkitType = z.infer<typeof ZToolkit>;
const toolkitCardStyles = {
base: clsx(
2025-07-10 16:26:37 +05:30
"group p-6 rounded-xl transition-all duration-200 cursor-pointer",
"bg-white dark:bg-gray-900",
"border border-gray-200 dark:border-gray-700",
"shadow-md dark:shadow-gray-900/20",
"hover:shadow-lg dark:hover:shadow-gray-900/30",
"hover:border-blue-300 dark:hover:border-blue-600",
"hover:bg-gray-50/50 dark:hover:bg-gray-800/50",
"hover:-translate-y-1",
"min-h-[200px] flex flex-col"
2025-07-03 15:19:48 +05:30
),
};
interface ToolkitCardProps {
toolkit: ToolkitType;
isConnected: boolean;
2025-07-23 15:37:49 +05:30
onSelectToolkit: () => void;
workflowTools: z.infer<typeof Workflow.shape.tools>;
showTriggerCounts?: boolean; // New prop to show trigger counts instead of tool counts
2025-07-03 15:19:48 +05:30
}
export function ToolkitCard({
toolkit,
isConnected,
2025-07-23 15:37:49 +05:30
onSelectToolkit,
workflowTools,
showTriggerCounts = false,
2025-07-03 15:19:48 +05:30
}: ToolkitCardProps) {
2025-07-10 16:26:37 +05:30
const handleCardClick = useCallback(() => {
2025-07-23 15:37:49 +05:30
onSelectToolkit();
}, [onSelectToolkit]);
2025-07-03 15:19:48 +05:30
// Calculate selected tools count for this toolkit
2025-07-23 15:37:49 +05:30
const selectedToolsCount = workflowTools
.filter(tool => tool.isComposio && tool.composioData?.toolkitSlug === toolkit.slug)
.length;
2025-07-03 15:19:48 +05:30
return (
2025-07-10 16:26:37 +05:30
<div className={toolkitCardStyles.base} onClick={handleCardClick}>
2025-07-03 15:19:48 +05:30
<div className="flex flex-col h-full">
2025-07-10 16:26:37 +05:30
{/* Header */}
<div className="flex items-start gap-3 mb-4">
{toolkit.meta.logo && (
<PictureImg
src={toolkit.meta.logo}
alt={`${toolkit.name} logo`}
className="w-8 h-8 rounded-md object-cover flex-shrink-0"
/>
)}
<div className="flex-1 min-w-0">
<h3 className="font-semibold text-lg text-gray-900 dark:text-gray-100 truncate">
{toolkit.name}
</h3>
<div className="flex items-center gap-2 mt-1 flex-wrap">
<Chip
color="secondary"
variant="faded"
size="sm"
>
{showTriggerCounts
? `${toolkit.meta.triggers_count} triggers`
: selectedToolsCount > 0
? `${toolkit.meta.tools_count} tools, ${selectedToolsCount} selected`
: `${toolkit.meta.tools_count} tools`
2025-07-10 16:26:37 +05:30
}
</Chip>
2025-07-03 15:19:48 +05:30
</div>
</div>
</div>
2025-07-10 16:26:37 +05:30
{/* Description */}
2025-07-03 15:19:48 +05:30
<div className="flex-1">
2025-07-10 16:26:37 +05:30
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-3">
2025-07-03 15:19:48 +05:30
{toolkit.meta.description}
</p>
</div>
2025-07-10 16:26:37 +05:30
{/* Footer */}
<div className="mt-4 pt-4 border-t border-gray-100 dark:border-gray-700">
2025-07-03 15:19:48 +05:30
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
2025-07-10 16:26:37 +05:30
{isConnected && !toolkit.no_auth && (
<Chip
color='success'
variant='flat'
size="sm"
startContent={<LinkIcon className="w-3 h-3 mr-1" />}
>
Connected
</Chip>
2025-07-03 15:19:48 +05:30
)}
2025-07-10 16:26:37 +05:30
{toolkit.no_auth && (
<Chip
color='success'
variant='flat'
size="sm"
>
Ready
</Chip>
2025-07-03 15:19:48 +05:30
)}
</div>
</div>
</div>
</div>
</div>
);
2025-07-10 16:26:37 +05:30
}