diff --git a/surfsense_web/components/assistant-ui/connector-popup/constants/connector-constants.ts b/surfsense_web/components/assistant-ui/connector-popup/constants/connector-constants.ts index 5de623c22..315574aa9 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/constants/connector-constants.ts +++ b/surfsense_web/components/assistant-ui/connector-popup/constants/connector-constants.ts @@ -243,6 +243,38 @@ export function getConnectorTitle(connectorType: string): string { ); } +/** + * Primary way a user interacts with a connector. + * Drives the two top-level groupings in the connector catalog UI. + */ +export type ConnectorCategory = "knowledge_base" | "tools_live"; + +export const CONNECTOR_CATEGORY_LABELS: Record = { + knowledge_base: "Knowledge Base", + tools_live: "Tools & Live Sources", +}; + +const KNOWLEDGE_BASE_CONNECTOR_TYPES = new Set([ + EnumConnectorName.GOOGLE_DRIVE_CONNECTOR, + EnumConnectorName.COMPOSIO_GOOGLE_DRIVE_CONNECTOR, + EnumConnectorName.ONEDRIVE_CONNECTOR, + EnumConnectorName.DROPBOX_CONNECTOR, + EnumConnectorName.NOTION_CONNECTOR, + EnumConnectorName.CONFLUENCE_CONNECTOR, + EnumConnectorName.YOUTUBE_CONNECTOR, + EnumConnectorName.WEBCRAWLER_CONNECTOR, + EnumConnectorName.BOOKSTACK_CONNECTOR, + EnumConnectorName.GITHUB_CONNECTOR, + EnumConnectorName.ELASTICSEARCH_CONNECTOR, + EnumConnectorName.CIRCLEBACK_CONNECTOR, + EnumConnectorName.OBSIDIAN_CONNECTOR, +]); + +/** Unmapped connectors surface under Tools & Live Sources. */ +export function getConnectorCategory(connectorType: string): ConnectorCategory { + return KNOWLEDGE_BASE_CONNECTOR_TYPES.has(connectorType) ? "knowledge_base" : "tools_live"; +} + // Composio Toolkits (available integrations via Composio) export const COMPOSIO_TOOLKITS = [ { diff --git a/surfsense_web/components/assistant-ui/connector-popup/tabs/all-connectors-tab.tsx b/surfsense_web/components/assistant-ui/connector-popup/tabs/all-connectors-tab.tsx index 814959ec4..4977219f7 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/tabs/all-connectors-tab.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/tabs/all-connectors-tab.tsx @@ -9,7 +9,10 @@ import { isSelfHosted } from "@/lib/env-config"; import { ConnectorCard } from "../components/connector-card"; import { COMPOSIO_CONNECTORS, + CONNECTOR_CATEGORY_LABELS, + type ConnectorCategory, CRAWLERS, + getConnectorCategory, OAUTH_CONNECTORS, OTHER_CONNECTORS, } from "../constants/connector-constants"; @@ -20,19 +23,6 @@ type ComposioConnector = (typeof COMPOSIO_CONNECTORS)[number]; type OtherConnector = (typeof OTHER_CONNECTORS)[number]; type CrawlerConnector = (typeof CRAWLERS)[number]; -const DOCUMENT_FILE_CONNECTOR_TYPES = new Set([ - EnumConnectorName.GOOGLE_DRIVE_CONNECTOR, - EnumConnectorName.COMPOSIO_GOOGLE_DRIVE_CONNECTOR, - EnumConnectorName.ONEDRIVE_CONNECTOR, - EnumConnectorName.DROPBOX_CONNECTOR, -]); - -const OTHER_DOCUMENT_CONNECTOR_TYPES = new Set([ - EnumConnectorName.YOUTUBE_CONNECTOR, - EnumConnectorName.NOTION_CONNECTOR, - EnumConnectorName.AIRTABLE_CONNECTOR, -]); - /** * Extract the display name from a full connector name. * Full names are in format "Base Name - identifier" (e.g., "Gmail - john@example.com"). @@ -106,45 +96,23 @@ export const AllConnectorsTab: FC = ({ c.description.toLowerCase().includes(searchQuery.toLowerCase()) ); - const nativeGoogleDriveConnectors = filteredOAuth.filter( - (c) => c.connectorType === EnumConnectorName.GOOGLE_DRIVE_CONNECTOR - ); - const composioGoogleDriveConnectors = filteredComposio.filter( - (c) => c.connectorType === EnumConnectorName.COMPOSIO_GOOGLE_DRIVE_CONNECTOR - ); - const fileStorageConnectors = filteredOAuth.filter( - (c) => - c.connectorType === EnumConnectorName.ONEDRIVE_CONNECTOR || - c.connectorType === EnumConnectorName.DROPBOX_CONNECTOR - ); + const inCategory = + (category: ConnectorCategory) => + (connector: T): boolean => + !!connector.connectorType && getConnectorCategory(connector.connectorType) === category; - const otherDocumentYouTubeConnectors = filteredCrawlers.filter( - (c) => c.connectorType === EnumConnectorName.YOUTUBE_CONNECTOR - ); - const otherDocumentNotionConnectors = filteredOAuth.filter( - (c) => c.connectorType === EnumConnectorName.NOTION_CONNECTOR - ); - const otherDocumentAirtableConnectors = filteredOAuth.filter( - (c) => c.connectorType === EnumConnectorName.AIRTABLE_CONNECTOR - ); - - const moreIntegrationsComposio = filteredComposio.filter( - (c) => - !DOCUMENT_FILE_CONNECTOR_TYPES.has(c.connectorType) && - !OTHER_DOCUMENT_CONNECTOR_TYPES.has(c.connectorType) - ); - const moreIntegrationsOAuth = filteredOAuth.filter( - (c) => - !DOCUMENT_FILE_CONNECTOR_TYPES.has(c.connectorType) && - !OTHER_DOCUMENT_CONNECTOR_TYPES.has(c.connectorType) - ); - const moreIntegrationsOther = filteredOther; - const moreIntegrationsCrawlers = filteredCrawlers.filter( - (c) => - !c.connectorType || - (!DOCUMENT_FILE_CONNECTOR_TYPES.has(c.connectorType) && - !OTHER_DOCUMENT_CONNECTOR_TYPES.has(c.connectorType)) - ); + const knowledgeBase = { + oauth: filteredOAuth.filter(inCategory("knowledge_base")), + composio: filteredComposio.filter(inCategory("knowledge_base")), + other: filteredOther.filter(inCategory("knowledge_base")), + crawlers: filteredCrawlers.filter(inCategory("knowledge_base")), + }; + const toolsLive = { + oauth: filteredOAuth.filter(inCategory("tools_live")), + composio: filteredComposio.filter(inCategory("tools_live")), + other: filteredOther.filter(inCategory("tools_live")), + crawlers: filteredCrawlers.filter(inCategory("tools_live")), + }; const renderOAuthCard = (connector: OAuthConnector | ComposioConnector) => { const isConnected = connectedTypes.has(connector.connectorType); @@ -275,20 +243,18 @@ export const AllConnectorsTab: FC = ({ ); }; - const hasDocumentFileConnectors = - nativeGoogleDriveConnectors.length > 0 || - composioGoogleDriveConnectors.length > 0 || - fileStorageConnectors.length > 0; - const hasMoreIntegrations = - otherDocumentYouTubeConnectors.length > 0 || - otherDocumentNotionConnectors.length > 0 || - otherDocumentAirtableConnectors.length > 0 || - moreIntegrationsComposio.length > 0 || - moreIntegrationsOAuth.length > 0 || - moreIntegrationsOther.length > 0 || - moreIntegrationsCrawlers.length > 0; + const hasKnowledgeBase = + knowledgeBase.oauth.length > 0 || + knowledgeBase.composio.length > 0 || + knowledgeBase.other.length > 0 || + knowledgeBase.crawlers.length > 0; + const hasToolsLive = + toolsLive.oauth.length > 0 || + toolsLive.composio.length > 0 || + toolsLive.other.length > 0 || + toolsLive.crawlers.length > 0; - const hasAnyResults = hasDocumentFileConnectors || hasMoreIntegrations; + const hasAnyResults = hasKnowledgeBase || hasToolsLive; if (!hasAnyResults && searchQuery) { return ( @@ -302,36 +268,34 @@ export const AllConnectorsTab: FC = ({ return (
- {/* File Storage Integrations */} - {hasDocumentFileConnectors && ( + {hasKnowledgeBase && (

- File Storage Integrations + {CONNECTOR_CATEGORY_LABELS.knowledge_base}

- {nativeGoogleDriveConnectors.map(renderOAuthCard)} - {composioGoogleDriveConnectors.map(renderOAuthCard)} - {fileStorageConnectors.map(renderOAuthCard)} + {knowledgeBase.oauth.map(renderOAuthCard)} + {knowledgeBase.composio.map(renderOAuthCard)} + {knowledgeBase.crawlers.map(renderCrawlerCard)} + {knowledgeBase.other.map(renderOtherCard)}
)} - {/* More Integrations */} - {hasMoreIntegrations && ( + {hasToolsLive && (
-

More Integrations

+

+ {CONNECTOR_CATEGORY_LABELS.tools_live} +

- {otherDocumentYouTubeConnectors.map(renderCrawlerCard)} - {otherDocumentNotionConnectors.map(renderOAuthCard)} - {otherDocumentAirtableConnectors.map(renderOAuthCard)} - {moreIntegrationsComposio.map(renderOAuthCard)} - {moreIntegrationsOAuth.map(renderOAuthCard)} - {moreIntegrationsOther.map(renderOtherCard)} - {moreIntegrationsCrawlers.map(renderCrawlerCard)} + {toolsLive.oauth.map(renderOAuthCard)} + {toolsLive.composio.map(renderOAuthCard)} + {toolsLive.crawlers.map(renderCrawlerCard)} + {toolsLive.other.map(renderOtherCard)}
)}