@@ -276,6 +278,8 @@ export function Composio() {
onClose={handleCloseToolsPanel}
projectConfig={projectConfig}
onUpdateToolsSelection={handleUpdateToolsSelection}
+ onProjectConfigUpdate={handleProjectConfigUpdate}
+ onRemoveToolkitTools={handleRemoveToolkitTools}
isSaving={savingTools}
/>
diff --git a/apps/rowboat/app/projects/[projectId]/tools/components/ComposioToolsPanel.tsx b/apps/rowboat/app/projects/[projectId]/tools/components/ComposioToolsPanel.tsx
index 4dd25e87..7cfb5348 100644
--- a/apps/rowboat/app/projects/[projectId]/tools/components/ComposioToolsPanel.tsx
+++ b/apps/rowboat/app/projects/[projectId]/tools/components/ComposioToolsPanel.tsx
@@ -2,15 +2,15 @@
import { useState, useEffect, useCallback } from 'react';
import { useParams } from 'next/navigation';
-import { Button } from '@/components/ui/button';
import { PictureImg } from '@/components/ui/picture-img';
-import { Checkbox } from '@heroui/react';
-import { ChevronLeft, ChevronRight } from 'lucide-react';
-import { listTools } from '@/app/actions/composio_actions';
+import { Button, Checkbox } from '@heroui/react';
+import { ChevronLeft, ChevronRight, LinkIcon, Loader2, UnlinkIcon } from 'lucide-react';
+import { listTools, deleteConnectedAccount } from '@/app/actions/composio_actions';
import { z } from 'zod';
import { ZTool, ZListResponse } from '@/app/lib/composio/composio';
import { SlidePanel } from '@/components/ui/slide-panel';
import { Project } from '@/app/lib/types/project_types';
+import { ToolkitAuthModal } from './ToolkitAuthModal';
type ToolType = z.infer
;
type ToolListResponse = z.infer>>;
@@ -29,6 +29,8 @@ interface ComposioToolsPanelProps {
onClose: () => void;
projectConfig: ProjectType | null;
onUpdateToolsSelection: (selectedToolObjects: ToolType[]) => void;
+ onProjectConfigUpdate: () => void;
+ onRemoveToolkitTools: (toolkitSlug: string) => void;
isSaving: boolean;
}
@@ -38,6 +40,8 @@ export function ComposioToolsPanel({
onClose,
projectConfig,
onUpdateToolsSelection,
+ onProjectConfigUpdate,
+ onRemoveToolkitTools,
isSaving
}: ComposioToolsPanelProps) {
const params = useParams();
@@ -51,6 +55,8 @@ export function ComposioToolsPanel({
const [cursorHistory, setCursorHistory] = useState([]);
const [selectedTools, setSelectedTools] = useState>(new Set());
const [hasChanges, setHasChanges] = useState(false);
+ const [showAuthModal, setShowAuthModal] = useState(false);
+ const [isProcessingAuth, setIsProcessingAuth] = useState(false);
const loadToolsForToolkit = useCallback(async (toolkitSlug: string, cursor: string | null = null) => {
try {
@@ -117,6 +123,34 @@ export function ComposioToolsPanel({
setHasChanges(false);
}, [onUpdateToolsSelection, selectedTools, tools]);
+ const handleConnect = useCallback(() => {
+ setShowAuthModal(true);
+ }, []);
+
+ const handleDisconnect = useCallback(async () => {
+ if (!toolkit) return;
+
+ const connectedAccountId = projectConfig?.composioConnectedAccounts?.[toolkit.slug]?.id;
+
+ setIsProcessingAuth(true);
+ try {
+ if (connectedAccountId) {
+ await deleteConnectedAccount(projectId, toolkit.slug, connectedAccountId);
+ onProjectConfigUpdate();
+ onRemoveToolkitTools(toolkit.slug);
+ }
+ } catch (err: any) {
+ console.error('Disconnect failed:', err);
+ } finally {
+ setIsProcessingAuth(false);
+ }
+ }, [projectId, toolkit, projectConfig, onProjectConfigUpdate, onRemoveToolkitTools]);
+
+ const handleAuthComplete = useCallback(() => {
+ setShowAuthModal(false);
+ onProjectConfigUpdate();
+ }, [onProjectConfigUpdate]);
+
const handleClose = useCallback(() => {
setTools([]);
setSelectedTools(new Set());
@@ -151,119 +185,170 @@ export function ComposioToolsPanel({
const isToolkitConnected = toolkit.no_auth || projectConfig?.composioConnectedAccounts?.[toolkit.slug]?.status === 'ACTIVE';
return (
-
- {toolkit.meta.logo && (
-
- )}
- {toolkit.name}
-