Choose how you'd like to authenticate with this toolkit:
+
{/* OAuth2 Composio Managed */}
{toolkit.composio_managed_auth_schemes.includes('OAUTH2') && (
-
-
Connect using OAuth2
+
+
+
Connect using OAuth2
+
Most popular
+
Secure authentication managed by Composio
@@ -446,7 +449,7 @@ export function ToolkitAuthModal({
{(toolkit.composio_managed_auth_schemes.includes('OAUTH2') ||
toolkit.auth_config_details?.some(config => config.mode === 'OAUTH2')) && (
handleCustomAuth('OAUTH2')}
isDisabled={processing}
@@ -456,7 +459,7 @@ export function ToolkitAuthModal({
-
Connect using custom OAuth2 app
+
Connect using custom OAuth2 app
Use your own OAuth2 configuration
@@ -468,7 +471,7 @@ export function ToolkitAuthModal({
{toolkit.auth_config_details?.filter(config => config.mode !== 'OAUTH2').map(config => (
handleCustomAuth(config.mode)}
isDisabled={processing}
@@ -478,7 +481,7 @@ export function ToolkitAuthModal({
{getAuthMethodIcon(config.mode)}
-
Connect using {getAuthMethodName(config.mode)}
+
Connect using {getAuthMethodName(config.mode)}
Enter your credentials
diff --git a/apps/rowboat/app/projects/[projectId]/tools/components/ToolsConfig.tsx b/apps/rowboat/app/projects/[projectId]/tools/components/ToolsConfig.tsx
index 0a063aff..0d4d90b9 100644
--- a/apps/rowboat/app/projects/[projectId]/tools/components/ToolsConfig.tsx
+++ b/apps/rowboat/app/projects/[projectId]/tools/components/ToolsConfig.tsx
@@ -9,17 +9,21 @@ import type { Key } from 'react';
import { Workflow, WorkflowTool } from '@/app/lib/types/workflow_types';
import { z } from 'zod';
+interface ToolsConfigProps {
+ projectId: string;
+ useComposioTools: boolean;
+ tools: z.infer
;
+ onAddTool: (tool: Partial>) => void;
+ initialToolkitSlug?: string | null;
+}
+
export function ToolsConfig({
projectId,
useComposioTools,
tools,
onAddTool,
-}: {
- projectId: string;
- useComposioTools: boolean;
- tools: z.infer;
- onAddTool: (tool: Partial>) => void;
-}) {
+ initialToolkitSlug
+}: ToolsConfigProps) {
let defaultActiveTab = 'mcp';
if (useComposioTools) {
defaultActiveTab = 'composio';
@@ -46,6 +50,7 @@ export function ToolsConfig({
projectId={projectId}
tools={tools}
onAddTool={onAddTool}
+ initialToolkitSlug={initialToolkitSlug}
/>
diff --git a/apps/rowboat/app/projects/[projectId]/workflow/components/ToolsModal.tsx b/apps/rowboat/app/projects/[projectId]/workflow/components/ToolsModal.tsx
index 536d448f..8e67dbb9 100644
--- a/apps/rowboat/app/projects/[projectId]/workflow/components/ToolsModal.tsx
+++ b/apps/rowboat/app/projects/[projectId]/workflow/components/ToolsModal.tsx
@@ -12,6 +12,7 @@ interface ToolsModalProps {
projectId: string;
tools: z.infer
;
onAddTool: (tool: Partial>) => void;
+ initialToolkitSlug?: string | null;
}
export function ToolsModal({
@@ -19,7 +20,8 @@ export function ToolsModal({
onClose,
projectId,
tools,
- onAddTool
+ onAddTool,
+ initialToolkitSlug
}: ToolsModalProps) {
function handleAddTool(tool: Partial>) {
onAddTool(tool);
@@ -45,6 +47,7 @@ export function ToolsModal({
projectId={projectId}
tools={tools}
onAddTool={handleAddTool}
+ initialToolkitSlug={initialToolkitSlug}
/>
diff --git a/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx b/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx
index 5dae831a..76b49c11 100644
--- a/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx
+++ b/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx
@@ -1,9 +1,10 @@
+import React from "react";
import { z } from "zod";
import { WorkflowPrompt, WorkflowAgent, WorkflowTool, Workflow } from "../../../lib/types/workflow_types";
import { Project } from "../../../lib/types/project_types";
import { Dropdown, DropdownItem, DropdownTrigger, DropdownMenu } from "@heroui/react";
import { useRef, useEffect, useState } from "react";
-import { EllipsisVerticalIcon, ImportIcon, PlusIcon, Brain, Boxes, Wrench, PenLine, Library, ChevronDown, ChevronRight, ServerIcon, Component, ScrollText, GripVertical, Users, Cog, CheckCircle2, LinkIcon, UnlinkIcon, MoreVertical, Eye } from "lucide-react";
+import { EllipsisVerticalIcon, ImportIcon, PlusIcon, Brain, Boxes, Wrench, PenLine, Library, ChevronDown, ChevronRight, ServerIcon, Component, ScrollText, GripVertical, Users, Cog, CheckCircle2, LinkIcon, UnlinkIcon, MoreVertical, Eye, Trash2, AlertTriangle, Circle } from "lucide-react";
import { Tooltip } from "@heroui/react";
import { DndContext, DragEndEvent, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import { SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
@@ -105,7 +106,7 @@ const ListItemWithMenu = ({
}) => {
return (
(null);
const handleAddAgentWithType = (agentType: 'internal' | 'user_facing') => {
onAddAgent({
@@ -582,6 +585,8 @@ export function EntityList({
projectId={projectId}
workflow={workflow}
onProjectToolsUpdated={onProjectToolsUpdated}
+ setSelectedToolkitSlug={setSelectedToolkitSlug}
+ setShowToolsModal={setShowToolsModal}
/>
))}
@@ -602,22 +607,28 @@ export function EntityList({
{customTools.length > 0 && (
{customTools.map((tool, index) => (
- handleToolSelection(tool.name)}
- selectedRef={selectedEntity?.type === "tool" && selectedEntity.name === tool.name ? selectedRef : undefined}
- icon={}
- isMocked={tool.mockTool}
- menuContent={
-
- }
- />
+ >
+
+ {tool.name}
+ {tool.mockTool && (
+ Mocked
+ )}
+
+
+
+
))}
)}
@@ -722,10 +733,14 @@ export function EntityList({
/>
setShowToolsModal(false)}
+ onClose={() => {
+ setShowToolsModal(false);
+ setSelectedToolkitSlug(null);
+ }}
projectId={projectId}
tools={tools}
onAddTool={onAddTool}
+ initialToolkitSlug={selectedToolkitSlug}
/>
);
@@ -830,31 +845,48 @@ const ComposioCard = ({
projectId,
workflow,
onProjectToolsUpdated,
-}: ComposioCardProps) => {
+ setSelectedToolkitSlug,
+ setShowToolsModal,
+}: ComposioCardProps & { setSelectedToolkitSlug: (slug: string) => void, setShowToolsModal: (open: boolean) => void }) => {
const [isExpanded, setIsExpanded] = useState(false);
const [showAuthModal, setShowAuthModal] = useState(false);
const [showDisconnectModal, setShowDisconnectModal] = useState(false);
+ const [showRemoveToolkitModal, setShowRemoveToolkitModal] = useState(false);
const [isProcessingAuth, setIsProcessingAuth] = useState(false);
+ const [isProcessingRemove, setIsProcessingRemove] = useState(false);
// Check if the toolkit requires authentication
const hasToolkitWithAuth = card.tools.some(tool => tool.composioData && !tool.composioData.noAuth);
-
// Check if toolkit is connected
const isToolkitConnected = !hasToolkitWithAuth || projectConfig?.composioConnectedAccounts?.[card.slug]?.status === 'ACTIVE';
-
-
- const handleConnect = () => {
- setShowAuthModal(true);
- };
-
- const handleDisconnect = () => {
- setShowDisconnectModal(true);
+ // Remove all tools from this toolkit
+ const handleRemoveToolkit = async () => {
+ setIsProcessingRemove(true);
+ // Disconnect if needed
+ if (hasToolkitWithAuth && isToolkitConnected) {
+ const connectedAccountId = projectConfig?.composioConnectedAccounts?.[card.slug]?.id;
+ try {
+ if (connectedAccountId) {
+ await deleteConnectedAccount(projectId, card.slug, connectedAccountId);
+ }
+ } catch (err) {
+ // ignore error, continue to remove tools
+ }
+ }
+ // Remove all tools from this toolkit
+ card.tools.forEach(tool => {
+ onDeleteTool(tool.name);
+ });
+ setIsProcessingRemove(false);
+ setShowRemoveToolkitModal(false);
+ onProjectToolsUpdated?.();
};
+ const handleConnect = () => setShowAuthModal(true);
+ const handleDisconnect = () => setShowDisconnectModal(true);
const handleConfirmDisconnect = async () => {
const connectedAccountId = projectConfig?.composioConnectedAccounts?.[card.slug]?.id;
-
setIsProcessingAuth(true);
try {
if (connectedAccountId) {
@@ -868,13 +900,105 @@ const ComposioCard = ({
setShowDisconnectModal(false);
}
};
-
const handleAuthComplete = () => {
setShowAuthModal(false);
onProjectToolsUpdated?.();
};
+ // Status dot
+ const statusDot = (
+
+
+
+ );
+ let statusPill = null;
+ if (!isToolkitConnected && hasToolkitWithAuth) {
+ statusPill = (
+
+
+
+ );
+ } else if (isToolkitConnected && hasToolkitWithAuth) {
+ statusPill = (
+
+
+ Connected
+
+ );
+ }
+
+ // Always show the 3-dots menu for all toolkits
+ let toolkitMenu = null;
+ toolkitMenu = (
+
+
+
+
+
+ {
+ switch (key) {
+ case 'disconnect':
+ handleDisconnect && handleDisconnect();
+ break;
+ case 'remove-toolkit':
+ setShowRemoveToolkitModal(true);
+ break;
+ case 'more-tools':
+ setSelectedToolkitSlug(card.slug);
+ setShowToolsModal(true);
+ break;
+ }
+ }}
+ disabledKeys={[
+ ...(isProcessingAuth ? ['disconnect'] : []),
+ ...(isProcessingRemove ? ['remove-toolkit'] : []),
+ ]}
+ >
+ }
+ >
+ More tools
+
+ {hasToolkitWithAuth && isToolkitConnected ? (
+
+ ) : (
+
+ )}
+ >
+ {isProcessingAuth ? 'Disconnecting...' : 'Disconnect'}
+
+ ) : null}
+
+ )}
+ >
+ {isProcessingRemove ? 'Removing...' : 'Remove Toolkit'}
+
+
+
+