diff --git a/surfsense_web/components/assistant-ui/connector-popup.tsx b/surfsense_web/components/assistant-ui/connector-popup.tsx index f234f46eb..e0b2e475f 100644 --- a/surfsense_web/components/assistant-ui/connector-popup.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup.tsx @@ -4,7 +4,7 @@ import { useAtomValue } from "jotai"; import { AlertTriangle, Cable, Settings } from "lucide-react"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; -import { type FC, useMemo } from "react"; +import { type FC, forwardRef, useImperativeHandle, useMemo } from "react"; import { documentTypeCountsAtom } from "@/atoms/documents/document-query.atoms"; import { globalNewLLMConfigsAtom, @@ -37,7 +37,16 @@ import { AllConnectorsTab } from "./connector-popup/tabs/all-connectors-tab"; import { ConnectorAccountsListView } from "./connector-popup/views/connector-accounts-list-view"; import { YouTubeCrawlerView } from "./connector-popup/views/youtube-crawler-view"; -export const ConnectorIndicator: FC = () => { +export interface ConnectorIndicatorHandle { + open: () => void; +} + +interface ConnectorIndicatorProps { + showTrigger?: boolean; +} + +export const ConnectorIndicator = forwardRef( + ({ showTrigger = true }, ref) => { const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom); const searchParams = useSearchParams(); const { data: currentUser } = useAtomValue(currentUserAtom); @@ -189,38 +198,44 @@ export const ConnectorIndicator: FC = () => { (connectors || []).map((c: SearchSourceConnector) => c.connector_type) ); + useImperativeHandle(ref, () => ({ + open: () => handleOpenChange(true), + })); + if (!searchSpaceId) return null; return ( - handleOpenChange(true)} - > - {isLoading ? ( - - ) : ( - <> - - {activeConnectorsCount > 0 && ( - - {activeConnectorsCount > 99 ? "99+" : activeConnectorsCount} - - )} - - )} - + {showTrigger && ( + handleOpenChange(true)} + > + {isLoading ? ( + + ) : ( + <> + + {activeConnectorsCount > 0 && ( + + {activeConnectorsCount > 99 ? "99+" : activeConnectorsCount} + + )} + + )} + + )} Manage Connectors @@ -429,4 +444,6 @@ export const ConnectorIndicator: FC = () => { ); -}; +}); + +ConnectorIndicator.displayName = "ConnectorIndicator"; diff --git a/surfsense_web/components/assistant-ui/thread.tsx b/surfsense_web/components/assistant-ui/thread.tsx index 9646ec036..4281ca2a7 100644 --- a/surfsense_web/components/assistant-ui/thread.tsx +++ b/surfsense_web/components/assistant-ui/thread.tsx @@ -14,6 +14,7 @@ import { AlertCircle, ArrowDownIcon, ArrowUpIcon, + Cable, CheckIcon, ChevronLeftIcon, ChevronRightIcon, @@ -22,6 +23,7 @@ import { PlusIcon, RefreshCwIcon, SquareIcon, + SquareLibrary, } from "lucide-react"; import { useParams } from "next/navigation"; import { type FC, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; @@ -42,8 +44,10 @@ import { import { currentUserAtom } from "@/atoms/user/user-query.atoms"; import { AssistantMessage } from "@/components/assistant-ui/assistant-message"; import { ChatSessionStatus } from "@/components/assistant-ui/chat-session-status"; -import { ConnectorIndicator } from "@/components/assistant-ui/connector-popup"; -import { useDocumentUploadDialog } from "@/components/assistant-ui/document-upload-popup"; +import { + ConnectorIndicator, + type ConnectorIndicatorHandle, +} from "@/components/assistant-ui/connector-popup"; import { InlineMentionEditor, type InlineMentionEditorRef, @@ -62,6 +66,7 @@ import { } from "@/components/new-chat/document-mention-picker"; import type { ThinkingStep } from "@/components/tool-ui/deepagent-thinking"; import { Button } from "@/components/ui/button"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import type { Document } from "@/contracts/types/document.types"; import { useBatchCommentsPreload } from "@/hooks/use-comments"; import { useCommentsElectric } from "@/hooks/use-comments-electric"; @@ -474,7 +479,8 @@ const ComposerAction: FC = ({ isBlockedByOtherUser = false const mentionedDocuments = useAtomValue(mentionedDocumentsAtom); const sidebarDocs = useAtomValue(sidebarSelectedDocumentsAtom); const setDocumentsSidebarOpen = useSetAtom(documentsSidebarOpenAtom); - const { openDialog: openUploadDialog } = useDocumentUploadDialog(); + const connectorRef = useRef(null); + const [addMenuOpen, setAddMenuOpen] = useState(false); const isComposerTextEmpty = useAssistantState(({ composer }) => { const text = composer.text?.trim() || ""; @@ -502,18 +508,53 @@ const ComposerAction: FC = ({ isBlockedByOtherUser = false return (
- - - - + + + + + + + +
+ + +
+
+
+
{!hasModelConfigured && (