diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/(manage)/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/(manage)/page.tsx index af92a6ae5..95c769c00 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/(manage)/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/connectors/(manage)/page.tsx @@ -4,256 +4,308 @@ import { useState, useEffect } from "react"; import { useRouter, useParams } from "next/navigation"; import { motion } from "framer-motion"; import { toast } from "sonner"; -import { Edit, Plus, Search, Trash2, ExternalLink, RefreshCw } from "lucide-react"; +import { + Edit, + Plus, + Search, + Trash2, + ExternalLink, + RefreshCw, +} from "lucide-react"; import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { Button } from "@/components/ui/button"; import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, } from "@/components/ui/card"; import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, } from "@/components/ui/table"; import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, } from "@/components/ui/alert-dialog"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { getConnectorIcon } from "@/components/chat"; // Helper function to get connector type display name const getConnectorTypeDisplay = (type: string): string => { - const typeMap: Record = { - "SERPER_API": "Serper API", - "TAVILY_API": "Tavily API", - "SLACK_CONNECTOR": "Slack", - "NOTION_CONNECTOR": "Notion", - "GITHUB_CONNECTOR": "GitHub", - "LINEAR_CONNECTOR": "Linear", - "LINKUP_API": "Linkup", - // Add other connector types here as needed - }; - return typeMap[type] || type; + const typeMap: Record = { + SERPER_API: "Serper API", + TAVILY_API: "Tavily API", + SLACK_CONNECTOR: "Slack", + NOTION_CONNECTOR: "Notion", + GITHUB_CONNECTOR: "GitHub", + LINEAR_CONNECTOR: "Linear", + LINKUP_API: "Linkup", + // Add other connector types here as needed + }; + return typeMap[type] || type; }; // Helper function to format date with time const formatDateTime = (dateString: string | null): string => { - if (!dateString) return "Never"; - - const date = new Date(dateString); - return new Intl.DateTimeFormat('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric', - hour: '2-digit', - minute: '2-digit' - }).format(date); + if (!dateString) return "Never"; + + const date = new Date(dateString); + return new Intl.DateTimeFormat("en-US", { + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }).format(date); }; export default function ConnectorsPage() { - const router = useRouter(); - const params = useParams(); - const searchSpaceId = params.search_space_id as string; - - const { connectors, isLoading, error, deleteConnector, indexConnector } = useSearchSourceConnectors(); - const [connectorToDelete, setConnectorToDelete] = useState(null); - const [indexingConnectorId, setIndexingConnectorId] = useState(null); + const router = useRouter(); + const params = useParams(); + const searchSpaceId = params.search_space_id as string; - useEffect(() => { - if (error) { - toast.error("Failed to load connectors"); - console.error("Error fetching connectors:", error); - } - }, [error]); + const { connectors, isLoading, error, deleteConnector, indexConnector } = + useSearchSourceConnectors(); + const [connectorToDelete, setConnectorToDelete] = useState( + null, + ); + const [indexingConnectorId, setIndexingConnectorId] = useState( + null, + ); - // Handle connector deletion - const handleDeleteConnector = async () => { - if (connectorToDelete === null) return; - - try { - await deleteConnector(connectorToDelete); - toast.success("Connector deleted successfully"); - } catch (error) { - console.error("Error deleting connector:", error); - toast.error("Failed to delete connector"); - } finally { - setConnectorToDelete(null); - } - }; + useEffect(() => { + if (error) { + toast.error("Failed to load connectors"); + console.error("Error fetching connectors:", error); + } + }, [error]); - // Handle connector indexing - const handleIndexConnector = async (connectorId: number) => { - setIndexingConnectorId(connectorId); - try { - await indexConnector(connectorId, searchSpaceId); - toast.success("Connector content indexed successfully"); - } catch (error) { - console.error("Error indexing connector content:", error); - toast.error(error instanceof Error ? error.message : "Failed to index connector content"); - } finally { - setIndexingConnectorId(null); - } - }; + // Handle connector deletion + const handleDeleteConnector = async () => { + if (connectorToDelete === null) return; - return ( -
- -
-

Connectors

-

- Manage your connected services and data sources. -

-
- -
+ try { + await deleteConnector(connectorToDelete); + toast.success("Connector deleted successfully"); + } catch (error) { + console.error("Error deleting connector:", error); + toast.error("Failed to delete connector"); + } finally { + setConnectorToDelete(null); + } + }; - - - Your Connectors - - View and manage all your connected services. - - - - {isLoading ? ( -
-
-
-
-
-
- ) : connectors.length === 0 ? ( -
-

No connectors found

-

- You haven't added any connectors yet. Add one to enhance your search capabilities. -

- -
- ) : ( -
- - - - Name - Type - Last Indexed - Actions - - - - {connectors.map((connector) => ( - - {connector.name} - {getConnectorTypeDisplay(connector.connector_type)} - - {connector.is_indexable - ? formatDateTime(connector.last_indexed_at) - : "Not indexable"} - - -
- {connector.is_indexable && ( - - - - - - -

Index Content

-
-
-
- )} - - - - - - - - Delete Connector - - Are you sure you want to delete this connector? This action cannot be undone. - - - - setConnectorToDelete(null)}> - Cancel - - - Delete - - - - -
-
-
- ))} -
-
-
- )} -
-
-
- ); -} + // Handle connector indexing + const handleIndexConnector = async (connectorId: number) => { + setIndexingConnectorId(connectorId); + try { + await indexConnector(connectorId, searchSpaceId); + toast.success("Connector content indexed successfully"); + } catch (error) { + console.error("Error indexing connector content:", error); + toast.error( + error instanceof Error + ? error.message + : "Failed to index connector content", + ); + } finally { + setIndexingConnectorId(null); + } + }; + + return ( +
+ +
+

Connectors

+

+ Manage your connected services and data sources. +

+
+ +
+ + + + Your Connectors + + View and manage all your connected services. + + + + {isLoading ? ( +
+
+
+
+
+
+ ) : connectors.length === 0 ? ( +
+

No connectors found

+

+ You haven't added any connectors yet. Add one to enhance your + search capabilities. +

+ +
+ ) : ( +
+ + + + Name + Type + Last Indexed + Actions + + + + {connectors.map((connector) => ( + + + {connector.name} + + + {getConnectorIcon(connector.connector_type)} + + + {connector.is_indexable + ? formatDateTime(connector.last_indexed_at) + : "Not indexable"} + + +
+ {connector.is_indexable && ( + + + + + + +

Index Content

+
+
+
+ )} + + + + + + + + + Delete Connector + + + Are you sure you want to delete this + connector? This action cannot be undone. + + + + setConnectorToDelete(null)} + > + Cancel + + + Delete + + + + +
+
+
+ ))} +
+
+
+ )} +
+
+
+ ); +}