diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentTypeIcon.tsx b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentTypeIcon.tsx index 99d7a7b8d..e483dea12 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentTypeIcon.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentTypeIcon.tsx @@ -3,8 +3,6 @@ import type React from "react"; import { getConnectorIcon } from "@/contracts/enums/connectorIcons"; -type IconComponent = React.ComponentType<{ size?: number; className?: string }>; - export function getDocumentTypeIcon(type: string): React.ReactNode { return getConnectorIcon(type); } diff --git a/surfsense_web/components/assistant-ui/attachment.tsx b/surfsense_web/components/assistant-ui/attachment.tsx index c08736d7c..74d0c0d63 100644 --- a/surfsense_web/components/assistant-ui/attachment.tsx +++ b/surfsense_web/components/assistant-ui/attachment.tsx @@ -337,12 +337,12 @@ export const ComposerAddAttachment: FC = () => { @@ -350,7 +350,7 @@ export const ComposerAddAttachment: FC = () => { - Add attachment(s) + Add attachment diff --git a/surfsense_web/components/assistant-ui/composer-action.tsx b/surfsense_web/components/assistant-ui/composer-action.tsx index ba27f40c2..4692ddd82 100644 --- a/surfsense_web/components/assistant-ui/composer-action.tsx +++ b/surfsense_web/components/assistant-ui/composer-action.tsx @@ -38,11 +38,10 @@ const ConnectorIndicator: FC = () => { ? Object.entries(documentTypeCounts).filter(([_, count]) => count > 0) : []; - const nonIndexableConnectors = connectors.filter((connector) => !connector.is_indexable); - - const hasConnectors = nonIndexableConnectors.length > 0; + // Count only active connectors (matching what's shown in the Active tab) + const activeConnectorsCount = connectors.length; + const hasConnectors = activeConnectorsCount > 0; const hasSources = hasConnectors || activeDocumentTypes.length > 0; - const totalSourceCount = nonIndexableConnectors.length + activeDocumentTypes.length; const handleMouseEnter = useCallback(() => { // Clear any pending close timeout @@ -76,7 +75,7 @@ const ConnectorIndicator: FC = () => { "text-muted-foreground" )} aria-label={ - hasSources ? `View ${totalSourceCount} connected sources` : "Add your first connector" + hasConnectors ? `View ${activeConnectorsCount} active connectors` : "Add your first connector" } onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} @@ -86,9 +85,9 @@ const ConnectorIndicator: FC = () => { ) : ( <> - {totalSourceCount > 0 && ( + {activeConnectorsCount > 0 && ( - {totalSourceCount > 99 ? "99+" : totalSourceCount} + {activeConnectorsCount > 99 ? "99+" : activeConnectorsCount} )} @@ -104,35 +103,50 @@ const ConnectorIndicator: FC = () => { > {hasSources ? (
-
-

Connected Sources

- - {totalSourceCount} - -
-
- {activeDocumentTypes.map(([docType, count]) => ( -
- {getConnectorIcon(docType, "size-3.5")} - {getDocumentTypeLabel(docType)} - - {count > 999 ? "999+" : count} - + {activeConnectorsCount > 0 && ( +
+

Active Connectors

+ + {activeConnectorsCount} + +
+ )} + {activeConnectorsCount > 0 && ( +
+ {connectors.map((connector) => ( +
+ {getConnectorIcon(connector.connector_type, "size-3.5")} + {connector.name} +
+ ))} +
+ )} + {activeDocumentTypes.length > 0 && ( + <> + {activeConnectorsCount > 0 && ( +
+

Documents

+
+ )} +
+ {activeDocumentTypes.map(([docType, count]) => ( +
+ {getConnectorIcon(docType, "size-3.5")} + {getDocumentTypeLabel(docType)} + + {count > 999 ? "999+" : count} + +
+ ))}
- ))} - {nonIndexableConnectors.map((connector) => ( -
- {getConnectorIcon(connector.connector_type, "size-3.5")} - {connector.name} -
- ))} -
+ + )}
{ const hasConnectors = connectors.length > 0; const hasSources = hasConnectors || activeDocumentTypes.length > 0; const totalSourceCount = connectors.length + activeDocumentTypes.length; + const activeConnectorsCount = connectors.length; // Only actual connectors, not document types // Check which connectors are already connected const connectedTypes = new Set( @@ -170,7 +171,7 @@ export const ConnectorIndicator: FC = () => { return ( { "border-0 ring-0 focus:ring-0 shadow-none focus:shadow-none" )} aria-label={ - hasSources ? `View ${totalSourceCount} connected sources` : "Add your first connector" + hasConnectors ? `View ${activeConnectorsCount} connectors` : "Add your first connector" } onClick={() => handleOpenChange(true)} > @@ -188,9 +189,9 @@ export const ConnectorIndicator: FC = () => { ) : ( <> - {totalSourceCount > 0 && ( + {activeConnectorsCount > 0 && ( - {totalSourceCount > 99 ? "99+" : totalSourceCount} + {activeConnectorsCount > 99 ? "99+" : activeConnectorsCount} )} @@ -259,7 +260,7 @@ export const ConnectorIndicator: FC = () => { {/* Header */} void; @@ -33,6 +35,20 @@ function extractIndexedCount(message: string | undefined): number | null { return match ? parseInt(match[1], 10) : null; } +/** + * Format document count (e.g., "1.2k docs", "500 docs", "1.5M docs") + */ +function formatDocumentCount(count: number | undefined): string { + if (count === undefined || count === 0) return "0 docs"; + if (count < 1000) return `${count} docs`; + if (count < 1000000) { + const k = (count / 1000).toFixed(1); + return `${k.replace(/\.0$/, "")}k docs`; + } + const m = (count / 1000000).toFixed(1); + return `${m.replace(/\.0$/, "")}M docs`; +} + export const ConnectorCard: FC = ({ id, title, @@ -41,6 +57,7 @@ export const ConnectorCard: FC = ({ isConnected = false, isConnecting = false, documentCount, + lastIndexedAt, isIndexing = false, activeTask, onConnect, @@ -70,18 +87,16 @@ export const ConnectorCard: FC = ({ } if (isConnected) { - if (documentCount !== undefined && documentCount > 0) { + // Show last indexed date for connected connectors + if (lastIndexedAt) { return ( - - - - {documentCount.toLocaleString()} document{documentCount !== 1 ? "s" : ""} - + + Last indexed: {format(new Date(lastIndexedAt), "MMM d, yyyy")} ); } - // Fallback for connected but no documents yet - return No documents indexed; + // Fallback for connected but never indexed + return Never indexed; } return description; @@ -105,6 +120,11 @@ export const ConnectorCard: FC = ({
{getStatusContent()}
+ {isConnected && documentCount !== undefined && ( +

+ {formatDocumentCount(documentCount)} +

+ )}
{/* Fixed Footer - Action buttons */} -
+
{showDisconnectConfirm ? ( -
- Are you sure? - - +
+ Are you sure? +
+ + +
) : ( )} -
); })} -
+
+
+ )} + + {/* Standalone Documents Section */} + {standaloneDocuments.length > 0 && ( +
+
+

+ Documents +

+ +
+
+ {standaloneDocuments.map((doc) => ( +
+
+ {getConnectorIcon(doc.type, "size-3.5")} +
+ + {doc.label} + + + {formatDocumentCount(doc.count)} + +
+ ))} +
+
+ )} ) : (
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 7ea9035c4..193e3adee 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 @@ -101,6 +101,7 @@ export const AllConnectorsTab: FC = ({ isConnected={isConnected} isConnecting={isConnecting} documentCount={documentCount} + lastIndexedAt={actualConnector?.last_indexed_at} isIndexing={isIndexing} activeTask={activeTask} onConnect={() => onConnectOAuth(connector)} @@ -162,6 +163,7 @@ export const AllConnectorsTab: FC = ({ isConnected={isConnected} isConnecting={isConnecting} documentCount={documentCount} + lastIndexedAt={actualConnector?.last_indexed_at} isIndexing={isIndexing} activeTask={activeTask} onConnect={handleConnect} @@ -230,6 +232,7 @@ export const AllConnectorsTab: FC = ({ isConnected={isConnected} isConnecting={isConnecting} documentCount={documentCount} + lastIndexedAt={actualConnector?.last_indexed_at} isIndexing={isIndexing} activeTask={activeTask} onConnect={handleConnect} diff --git a/surfsense_web/contracts/enums/connectorIcons.tsx b/surfsense_web/contracts/enums/connectorIcons.tsx index e37bea55e..fc509795b 100644 --- a/surfsense_web/contracts/enums/connectorIcons.tsx +++ b/surfsense_web/contracts/enums/connectorIcons.tsx @@ -29,7 +29,7 @@ export const getConnectorIcon = (connectorType: EnumConnectorName | string, clas case EnumConnectorName.TAVILY_API: return Tavily; case EnumConnectorName.SEARXNG_API: - return ; + return SearXNG; case EnumConnectorName.BAIDU_SEARCH_API: return Baidu; case EnumConnectorName.SLACK_CONNECTOR: @@ -81,6 +81,8 @@ export const getConnectorIcon = (connectorType: EnumConnectorName | string, clas return Zoom; case "FILE": return ; + case "GOOGLE_DRIVE_FILE": + return ; case "NOTE": return ; case "EXTENSION": diff --git a/surfsense_web/public/connectors/bookstack.svg b/surfsense_web/public/connectors/bookstack.svg index 8b7829055..c97639b74 100644 --- a/surfsense_web/public/connectors/bookstack.svg +++ b/surfsense_web/public/connectors/bookstack.svg @@ -1 +1 @@ -BookStack \ No newline at end of file + \ No newline at end of file diff --git a/surfsense_web/public/connectors/searxng.svg b/surfsense_web/public/connectors/searxng.svg new file mode 100644 index 000000000..a5e210e20 --- /dev/null +++ b/surfsense_web/public/connectors/searxng.svg @@ -0,0 +1 @@ + \ No newline at end of file