"use client"; import { ChatInput } from "@llamaindex/chat-ui"; import { Brain, Check, FolderOpen, Zap } from "lucide-react"; import { useParams } from "next/navigation"; import React, { Suspense, useCallback, useState } from "react"; import { DocumentsDataTable } from "@/components/chat/DocumentsDataTable"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { getConnectorIcon } from "@/contracts/enums/connectorIcons"; import { useDocumentTypes } from "@/hooks/use-document-types"; import type { Document } from "@/hooks/use-documents"; import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs"; const DocumentSelector = React.memo( ({ onSelectionChange, selectedDocuments = [], }: { onSelectionChange?: (documents: Document[]) => void; selectedDocuments?: Document[]; }) => { const { search_space_id } = useParams(); const [isOpen, setIsOpen] = useState(false); const handleOpenChange = useCallback((open: boolean) => { setIsOpen(open); }, []); const handleSelectionChange = useCallback( (documents: Document[]) => { onSelectionChange?.(documents); }, [onSelectionChange] ); const handleDone = useCallback(() => { setIsOpen(false); }, []); const selectedCount = React.useMemo(() => selectedDocuments.length, [selectedDocuments.length]); return (
Select Documents Choose specific documents to include in your research context
); } ); DocumentSelector.displayName = "DocumentSelector"; const ConnectorSelector = React.memo( ({ onSelectionChange, selectedConnectors = [], }: { onSelectionChange?: (connectorTypes: string[]) => void; selectedConnectors?: string[]; }) => { const { search_space_id } = useParams(); const [isOpen, setIsOpen] = useState(false); const { documentTypes, isLoading, isLoaded, fetchDocumentTypes } = useDocumentTypes( Number(search_space_id), true ); const handleOpenChange = useCallback( (open: boolean) => { setIsOpen(open); if (open && !isLoaded) { fetchDocumentTypes(Number(search_space_id)); } }, [fetchDocumentTypes, isLoaded, search_space_id] ); const handleConnectorToggle = useCallback( (connectorType: string) => { const isSelected = selectedConnectors.includes(connectorType); const newSelection = isSelected ? selectedConnectors.filter((type) => type !== connectorType) : [...selectedConnectors, connectorType]; onSelectionChange?.(newSelection); }, [selectedConnectors, onSelectionChange] ); const handleSelectAll = useCallback(() => { onSelectionChange?.(documentTypes.map((dt) => dt.type)); }, [documentTypes, onSelectionChange]); const handleClearAll = useCallback(() => { onSelectionChange?.([]); }, [onSelectionChange]); // Get display name for document type const getDisplayName = (type: string) => { return type .split("_") .map((word) => word.charAt(0) + word.slice(1).toLowerCase()) .join(" "); }; // Get selected document types with their counts const selectedDocTypes = documentTypes.filter((dt) => selectedConnectors.includes(dt.type)); return (
Select Document Types Choose which document types to include in your search
{/* Document type selection grid */}
{isLoading ? (
) : documentTypes.length === 0 ? (

No documents found

Add documents to this search space to enable filtering by type

) : ( documentTypes.map((docType) => { const isSelected = selectedConnectors.includes(docType.type); return ( ); }) )}
{documentTypes.length > 0 && ( )}
); } ); ConnectorSelector.displayName = "ConnectorSelector"; const SearchModeSelector = React.memo( ({ searchMode, onSearchModeChange, }: { searchMode?: "DOCUMENTS" | "CHUNKS"; onSearchModeChange?: (mode: "DOCUMENTS" | "CHUNKS") => void; }) => { const handleDocumentsClick = React.useCallback(() => { onSearchModeChange?.("DOCUMENTS"); }, [onSearchModeChange]); const handleChunksClick = React.useCallback(() => { onSearchModeChange?.("CHUNKS"); }, [onSearchModeChange]); return (
); } ); SearchModeSelector.displayName = "SearchModeSelector"; const LLMSelector = React.memo(() => { const { search_space_id } = useParams(); const searchSpaceId = Number(search_space_id); const { llmConfigs, loading: llmLoading, error } = useLLMConfigs(searchSpaceId); const { preferences, updatePreferences, loading: preferencesLoading, } = useLLMPreferences(searchSpaceId); const isLoading = llmLoading || preferencesLoading; // Memoize the selected config to avoid repeated lookups const selectedConfig = React.useMemo(() => { if (!preferences.fast_llm_id || !llmConfigs.length) return null; return llmConfigs.find((config) => config.id === preferences.fast_llm_id) || null; }, [preferences.fast_llm_id, llmConfigs]); // Memoize the display value for the trigger const displayValue = React.useMemo(() => { if (!selectedConfig) return null; return (
{selectedConfig.provider} {selectedConfig.name}
); }, [selectedConfig]); const handleValueChange = React.useCallback( (value: string) => { const llmId = value ? parseInt(value, 10) : undefined; updatePreferences({ fast_llm_id: llmId }); }, [updatePreferences] ); // Loading skeleton if (isLoading) { return (
); } // Error state if (error) { return (
); } return (
); }); LLMSelector.displayName = "LLMSelector"; const CustomChatInputOptions = React.memo( ({ onDocumentSelectionChange, selectedDocuments, onConnectorSelectionChange, selectedConnectors, searchMode, onSearchModeChange, }: { onDocumentSelectionChange?: (documents: Document[]) => void; selectedDocuments?: Document[]; onConnectorSelectionChange?: (connectorTypes: string[]) => void; selectedConnectors?: string[]; searchMode?: "DOCUMENTS" | "CHUNKS"; onSearchModeChange?: (mode: "DOCUMENTS" | "CHUNKS") => void; }) => { // Memoize the loading fallback to prevent recreation const loadingFallback = React.useMemo( () =>
, [] ); return (
); } ); CustomChatInputOptions.displayName = "CustomChatInputOptions"; export const ChatInputUI = React.memo( ({ onDocumentSelectionChange, selectedDocuments, onConnectorSelectionChange, selectedConnectors, searchMode, onSearchModeChange, }: { onDocumentSelectionChange?: (documents: Document[]) => void; selectedDocuments?: Document[]; onConnectorSelectionChange?: (connectorTypes: string[]) => void; selectedConnectors?: string[]; searchMode?: "DOCUMENTS" | "CHUNKS"; onSearchModeChange?: (mode: "DOCUMENTS" | "CHUNKS") => void; }) => { return ( ); } ); ChatInputUI.displayName = "ChatInputUI";