diff --git a/surfsense_backend/app/routes/composio_routes.py b/surfsense_backend/app/routes/composio_routes.py index 5ad2266b7..9e9b59f82 100644 --- a/surfsense_backend/app/routes/composio_routes.py +++ b/surfsense_backend/app/routes/composio_routes.py @@ -344,13 +344,16 @@ async def composio_callback( try: # Generate a unique, user-friendly connector name - connector_name = await generate_unique_connector_name( + # Pass just toolkit_name (without "(Composio)") to avoid redundancy + base_name = await generate_unique_connector_name( session, connector_type, space_id, user_id, - f"{toolkit_name} (Composio)", + toolkit_name, ) + # Append "(Composio)" suffix for identification + connector_name = f"{base_name} (Composio)" db_connector = SearchSourceConnector( name=connector_name, diff --git a/surfsense_web/components/assistant-ui/connector-popup.tsx b/surfsense_web/components/assistant-ui/connector-popup.tsx index a04e2a9fd..1ec8fad73 100644 --- a/surfsense_web/components/assistant-ui/connector-popup.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup.tsx @@ -7,7 +7,7 @@ import type { FC } from "react"; import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms"; import { currentUserAtom } from "@/atoms/user/user-query.atoms"; import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button"; -import { Dialog, DialogContent } from "@/components/ui/dialog"; +import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"; import { Tabs, TabsContent } from "@/components/ui/tabs"; import type { SearchSourceConnector } from "@/contracts/types/connector.types"; import { useConnectorsElectric } from "@/hooks/use-connectors-electric"; @@ -185,6 +185,7 @@ export const ConnectorIndicator: FC = () => { + Manage Connectors {/* YouTube Crawler View - shown when adding YouTube videos */} {isYouTubeView && searchSpaceId ? ( diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-calendar-config.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-calendar-config.tsx index 6e7a06073..ce5133a9d 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-calendar-config.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-calendar-config.tsx @@ -1,17 +1,6 @@ "use client"; -import { Calendar, Clock } from "lucide-react"; import type { FC } from "react"; -import { useEffect, useState } from "react"; -import { Label } from "@/components/ui/label"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Switch } from "@/components/ui/switch"; import type { SearchSourceConnector } from "@/contracts/types/connector.types"; interface ComposioCalendarConfigProps { @@ -20,201 +9,7 @@ interface ComposioCalendarConfigProps { onNameChange?: (name: string) => void; } -interface CalendarIndexingOptions { - max_events: number; - include_recurring: boolean; - include_past_events: boolean; - days_ahead: number; -} - -const DEFAULT_CALENDAR_OPTIONS: CalendarIndexingOptions = { - max_events: 500, - include_recurring: true, - include_past_events: true, - days_ahead: 365, -}; - -export const ComposioCalendarConfig: FC = ({ connector, onConfigChange }) => { - const isIndexable = connector.config?.is_indexable as boolean; - - // Initialize with existing options from connector config - const existingOptions = - (connector.config?.calendar_options as CalendarIndexingOptions | undefined) || DEFAULT_CALENDAR_OPTIONS; - - const [calendarOptions, setCalendarOptions] = useState(existingOptions); - - // Update options when connector config changes - useEffect(() => { - const options = - (connector.config?.calendar_options as CalendarIndexingOptions | undefined) || - DEFAULT_CALENDAR_OPTIONS; - setCalendarOptions(options); - }, [connector.config]); - - const updateConfig = (options: CalendarIndexingOptions) => { - if (onConfigChange) { - onConfigChange({ - ...connector.config, - calendar_options: options, - }); - } - }; - - const handleOptionChange = (key: keyof CalendarIndexingOptions, value: number | boolean) => { - const newOptions = { ...calendarOptions, [key]: value }; - setCalendarOptions(newOptions); - updateConfig(newOptions); - }; - - // Only show configuration if the connector is indexable - if (!isIndexable) { - return
; - } - - return ( -
- {/* Calendar Indexing Options */} -
-
-
- -

Calendar Indexing Options

-
-

- Configure how events are indexed from your Google Calendar. -

-
- - {/* Max events to index */} -
-
-
- -

- Maximum number of events to index per sync -

-
- -
-
- - {/* Days ahead */} -
-
-
-
- - -
-

- How far ahead to index future events -

-
- -
-
- - {/* Include recurring events toggle */} -
-
- -

- Index individual instances of recurring events -

-
- - handleOptionChange("include_recurring", checked) - } - /> -
- - {/* Include past events toggle */} -
-
- -

- Index events from before the selected date range -

-
- - handleOptionChange("include_past_events", checked) - } - /> -
-
-
- ); +export const ComposioCalendarConfig: FC = () => { + return
; }; diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-drive-config.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-drive-config.tsx index 755b91a5a..0ab0869ff 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-drive-config.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-drive-config.tsx @@ -1,6 +1,6 @@ "use client"; -import { File, FileSpreadsheet, FileText, FolderClosed, Image, Presentation } from "lucide-react"; +import { File, FileSpreadsheet, FileText, FolderClosed, Image, Presentation, X } from "lucide-react"; import type { FC } from "react"; import { useEffect, useState } from "react"; import { ComposioDriveFolderTree } from "@/components/connectors/composio-drive-folder-tree"; @@ -143,6 +143,18 @@ export const ComposioDriveConfig: FC = ({ connector, o updateConfig(selectedFolders, selectedFiles, newOptions); }; + const handleRemoveFolder = (folderId: string) => { + const newFolders = selectedFolders.filter((folder) => folder.id !== folderId); + setSelectedFolders(newFolders); + updateConfig(newFolders, selectedFiles, indexingOptions); + }; + + const handleRemoveFile = (fileId: string) => { + const newFiles = selectedFiles.filter((file) => file.id !== fileId); + setSelectedFiles(newFiles); + updateConfig(selectedFolders, newFiles, indexingOptions); + }; + const totalSelected = selectedFolders.length + selectedFiles.length; // Only show configuration if the connector is indexable @@ -176,29 +188,45 @@ export const ComposioDriveConfig: FC = ({ connector, o `${selectedFiles.length} file${selectedFiles.length > 1 ? "s" : ""}` ); } - return parts.length > 0 ? `(${parts.join(" ")})` : ""; + return parts.length > 0 ? `(${parts.join(", ")})` : ""; })()}

{selectedFolders.map((folder) => ( -

- {folder.name} -

+ {folder.name} + +
))} {selectedFiles.map((file) => ( -

{getFileIconFromName(file.name)} - {file.name} -

+ {file.name} + +
))}
diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-gmail-config.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-gmail-config.tsx index 963753ab3..4664e3e64 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-gmail-config.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/composio-gmail-config.tsx @@ -1,17 +1,6 @@ "use client"; -import { Mail, Tag } from "lucide-react"; import type { FC } from "react"; -import { useEffect, useState } from "react"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; import type { SearchSourceConnector } from "@/contracts/types/connector.types"; interface ComposioGmailConfigProps { @@ -20,155 +9,7 @@ interface ComposioGmailConfigProps { onNameChange?: (name: string) => void; } -interface GmailIndexingOptions { - max_emails: number; - label_filter: string; - search_query: string; -} - -const DEFAULT_GMAIL_OPTIONS: GmailIndexingOptions = { - max_emails: 500, - label_filter: "", - search_query: "", -}; - -export const ComposioGmailConfig: FC = ({ connector, onConfigChange }) => { - const isIndexable = connector.config?.is_indexable as boolean; - - // Initialize with existing options from connector config - const existingOptions = - (connector.config?.gmail_options as GmailIndexingOptions | undefined) || DEFAULT_GMAIL_OPTIONS; - - const [gmailOptions, setGmailOptions] = useState(existingOptions); - - // Update options when connector config changes - useEffect(() => { - const options = - (connector.config?.gmail_options as GmailIndexingOptions | undefined) || - DEFAULT_GMAIL_OPTIONS; - setGmailOptions(options); - }, [connector.config]); - - const updateConfig = (options: GmailIndexingOptions) => { - if (onConfigChange) { - onConfigChange({ - ...connector.config, - gmail_options: options, - }); - } - }; - - const handleOptionChange = (key: keyof GmailIndexingOptions, value: number | string) => { - const newOptions = { ...gmailOptions, [key]: value }; - setGmailOptions(newOptions); - updateConfig(newOptions); - }; - - // Only show configuration if the connector is indexable - if (!isIndexable) { - return
; - } - - return ( -
- {/* Gmail Indexing Options */} -
-
-
- -

Gmail Indexing Options

-
-

- Configure how emails are indexed from your Gmail account. -

-
- - {/* Max emails to index */} -
-
-
- -

- Maximum number of emails to index per sync -

-
- -
-
- - {/* Label filter */} -
-
-
- - -
-

- Only index emails with this label (e.g., "INBOX", "IMPORTANT", "work") -

-
- handleOptionChange("label_filter", e.target.value)} - placeholder="Enter label name..." - className="bg-slate-400/5 dark:bg-slate-400/5 border-slate-400/20 text-xs sm:text-sm" - /> -
- - {/* Search query */} -
-
- -

- Gmail search query to filter emails (e.g., "from:boss@company.com", "has:attachment") -

-
- handleOptionChange("search_query", e.target.value)} - placeholder="Enter Gmail search query..." - className="bg-slate-400/5 dark:bg-slate-400/5 border-slate-400/20 text-xs sm:text-sm" - /> -
-
-
- ); +export const ComposioGmailConfig: FC = () => { + return
; }; diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/google-drive-config.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/google-drive-config.tsx index 17f4a49a5..b6cfb39ae 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/google-drive-config.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/google-drive-config.tsx @@ -1,6 +1,6 @@ "use client"; -import { File, FileSpreadsheet, FileText, FolderClosed, Image, Presentation } from "lucide-react"; +import { File, FileSpreadsheet, FileText, FolderClosed, Image, Presentation, X } from "lucide-react"; import type { FC } from "react"; import { useEffect, useState } from "react"; import { GoogleDriveFolderTree } from "@/components/connectors/google-drive-folder-tree"; @@ -135,6 +135,18 @@ export const GoogleDriveConfig: FC = ({ connector, onConfi updateConfig(selectedFolders, selectedFiles, newOptions); }; + const handleRemoveFolder = (folderId: string) => { + const newFolders = selectedFolders.filter((folder) => folder.id !== folderId); + setSelectedFolders(newFolders); + updateConfig(newFolders, selectedFiles, indexingOptions); + }; + + const handleRemoveFile = (fileId: string) => { + const newFiles = selectedFiles.filter((file) => file.id !== fileId); + setSelectedFiles(newFiles); + updateConfig(selectedFolders, newFiles, indexingOptions); + }; + const totalSelected = selectedFolders.length + selectedFiles.length; return ( @@ -161,29 +173,45 @@ export const GoogleDriveConfig: FC = ({ connector, onConfi if (selectedFiles.length > 0) { parts.push(`${selectedFiles.length} file${selectedFiles.length > 1 ? "s" : ""}`); } - return parts.length > 0 ? `(${parts.join(" ")})` : ""; + return parts.length > 0 ? `(${parts.join(", ")})` : ""; })()}

{selectedFolders.map((folder) => ( -

- {folder.name} -

+ {folder.name} + +
))} {selectedFiles.map((file) => ( -

{getFileIconFromName(file.name)} - {file.name} -

+ {file.name} + +
))}
diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx index 6b1a8c92b..8951336c5 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx @@ -9,6 +9,7 @@ import { cn } from "@/lib/utils"; import { DateRangeSelector } from "../../components/date-range-selector"; import { PeriodicSyncConfig } from "../../components/periodic-sync-config"; import { getConnectorConfigComponent } from "../index"; +import { getConnectorDisplayName } from "../../tabs/all-connectors-tab"; interface ConnectorEditViewProps { connector: SearchSourceConnector; @@ -151,7 +152,7 @@ export const ConnectorEditView: FC = ({

- {connector.name} + {getConnectorDisplayName(connector.name)}

Manage your connector settings and sync configuration diff --git a/surfsense_web/components/assistant-ui/connector-popup/tabs/active-connectors-tab.tsx b/surfsense_web/components/assistant-ui/connector-popup/tabs/active-connectors-tab.tsx index e45888bb1..2067ca9ad 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/tabs/active-connectors-tab.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/tabs/active-connectors-tab.tsx @@ -15,6 +15,7 @@ import { connectorsApiService } from "@/lib/apis/connectors-api.service"; import { cn } from "@/lib/utils"; import { COMPOSIO_CONNECTORS, OAUTH_CONNECTORS } from "../constants/connector-constants"; import { getDocumentCountForConnector } from "../utils/connector-document-mapping"; +import { getConnectorDisplayName } from "./all-connectors-tab"; interface ActiveConnectorsTabProps { searchQuery: string; @@ -263,8 +264,8 @@ export const ActiveConnectorsTab: FC = ({

-

- {connector.name} +

+ {getConnectorDisplayName(connector.name)}

{isIndexing ? (