import { useEffect, useState, type ReactElement } from "react"; import { useFileStore } from "@/stores/fileStore"; import { api } from "@/services/api"; import { Button } from "@/components/ui/button"; import { FolderIcon, FileText, Trash2, Database, ChevronLeft, ChevronRight, RefreshCcw, Plus, } from "lucide-react"; import { cn } from "@/lib/utils"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; interface SidebarProps { onNavigateToSchemas?: () => void; disabled?: boolean; collapsed?: boolean; onToggleCollapse?: () => void; } export function Sidebar({ onNavigateToSchemas, disabled = false, collapsed = false, onToggleCollapse, }: SidebarProps = {}) { const { temas, selectedTema, setTemas, setSelectedTema, loading, setLoading, } = useFileStore(); const [deletingTema, setDeletingTema] = useState(null); const [createDialogOpen, setCreateDialogOpen] = useState(false); const [newDataroomName, setNewDataroomName] = useState(""); const [creatingDataroom, setCreatingDataroom] = useState(false); const [createError, setCreateError] = useState(null); const renderWithTooltip = (label: string, element: ReactElement) => { if (!collapsed) { return element; } return ( {element} {label} ); }; const handleCreateDialogOpenChange = (open: boolean) => { setCreateDialogOpen(open); if (!open) { setNewDataroomName(""); setCreateError(null); } }; const handleCreateDataroom = async () => { const trimmed = newDataroomName.trim(); if (!trimmed) { setCreateError("Name is required"); return; } setCreatingDataroom(true); setCreateError(null); try { const result = await api.createDataroom({ name: trimmed }); // Refresh the datarooms list (this will load all datarooms including the new one) await loadTemas(); // Select the newly created dataroom setSelectedTema(trimmed); // Close dialog and show success handleCreateDialogOpenChange(false); } catch (error) { console.error("Error creating dataroom:", error); setCreateError( error instanceof Error ? error.message : "Could not create the dataroom. Please try again.", ); } finally { setCreatingDataroom(false); } }; useEffect(() => { loadTemas(); }, []); const loadTemas = async () => { try { setLoading(true); const response = await api.getDatarooms(); // Extract dataroom names from the response with better error handling let dataroomNames: string[] = []; if (response && response.datarooms && Array.isArray(response.datarooms)) { dataroomNames = response.datarooms .filter((dataroom) => dataroom && dataroom.name) .map((dataroom) => dataroom.name); } setTemas(dataroomNames); // Auto-select first dataroom if none is selected and datarooms are available if (!selectedTema && dataroomNames.length > 0) { setSelectedTema(dataroomNames[0]); } } catch (error) { console.error("Error loading datarooms:", error); // Fallback to legacy getTemas if dataroom endpoint fails try { const legacyResponse = await api.getTemas(); const legacyTemas = Array.isArray(legacyResponse?.temas) ? legacyResponse.temas.filter(Boolean) : []; setTemas(legacyTemas); // Auto-select first legacy tema if none is selected if (!selectedTema && legacyTemas.length > 0) { setSelectedTema(legacyTemas[0]); } } catch (legacyError) { console.error("Error loading legacy temas:", legacyError); // Ensure we always set an array, never undefined or null setTemas([]); } } finally { setLoading(false); } }; const handleTemaSelect = (tema: string | null) => { setSelectedTema(tema); }; const handleDeleteTema = async ( tema: string, e: React.MouseEvent, ) => { e.stopPropagation(); // Prevent selecting the dataroom when clicking delete const confirmed = window.confirm( `Are you sure you want to delete the dataroom "${tema}"?\n\n` + `This will remove:\n` + `• The dataroom from the database\n` + `• All files stored for this topic in Azure Blob Storage\n` + `• The "${tema}" collection in Qdrant (if it exists)\n\n` + `This action cannot be undone.`, ); if (!confirmed) return; try { setDeletingTema(tema); // 1. Delete the dataroom (this will also delete the vector collection) try { await api.deleteDataroom(tema); } catch (error) { console.error(`Error deleting dataroom "${tema}":`, error); // If dataroom deletion fails, fall back to legacy deletion // Delete all topic files in Azure Blob Storage await api.deleteTema(tema); // Attempt to delete the Qdrant collection (if it exists) try { const collectionExists = await api.checkCollectionExists(tema); if (collectionExists.exists) { await api.deleteCollection(tema); } } catch (collectionError) { console.warn( `Could not delete the "${tema}" collection from Qdrant:`, collectionError, ); } } // 2. Actualizar la lista de temas await loadTemas(); // 3. Si el tema eliminado estaba seleccionado, deseleccionar if (selectedTema === tema) { setSelectedTema(null); } } catch (error) { console.error(`Error deleting dataroom "${tema}":`, error); alert( `Unable to delete dataroom: ${error instanceof Error ? error.message : "Unknown error"}`, ); } finally { setDeletingTema(null); } }; return (
{/* Header */}
{!collapsed &&

Luma

}
{onToggleCollapse && ( )}
{/* Temas List */}
{!collapsed && (

Datarooms

)} {renderWithTooltip( "Create", , )}
{/* Dataroom list */} {loading ? (
{collapsed ? "..." : "Loading..."}
) : Array.isArray(temas) && temas.length > 0 ? ( temas.map((tema) => (
{renderWithTooltip( tema, , )} {!collapsed && ( )}
)) ) : (
{Array.isArray(temas) && temas.length === 0 ? "No datarooms found" : "Loading datarooms..."}
)}
{/* Footer */}
{onNavigateToSchemas && renderWithTooltip( "Manage schemas", , )} {renderWithTooltip( "Refresh datarooms", , )}
Create dataroom Choose a unique name to organize your files.
{ setNewDataroomName(e.target.value); if (createError) { setCreateError(null); } }} placeholder="e.g., policies, contracts, finance..." autoFocus /> {createError && (

{createError}

)}
); }