// // SPDX-FileCopyrightText: Copyright (c) 1993-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // "use client" import { useState, useEffect } from "react" import { Network, Database, Zap, AlertCircle, RefreshCw, ChevronDown, ChevronUp, InfoIcon, Trash2, LogOut } from "lucide-react" import { Badge } from '@/components/ui/badge' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' import { Button } from "@/components/ui/button" import { VectorDBStats } from '@/types/graph' import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DialogClose } from "@/components/ui/dialog" interface DatabaseConnectionProps { className?: string } export function DatabaseConnection({ className }: DatabaseConnectionProps) { // Neo4j/Graph DB state const [graphConnectionStatus, setGraphConnectionStatus] = useState<"connected" | "disconnected" | "checking">("disconnected") const [graphError, setGraphError] = useState(null) const [nodeCount, setNodeCount] = useState(null) const [relationshipCount, setRelationshipCount] = useState(null) const [connectionUrl, setConnectionUrl] = useState("") const [dbType, setDbType] = useState("") const [isClearingDB, setIsClearingDB] = useState(false) const [showClearDialog, setShowClearDialog] = useState(false) // Vector DB state const [vectorConnectionStatus, setVectorConnectionStatus] = useState<"connected" | "disconnected" | "checking">("disconnected") const [vectorError, setVectorError] = useState(null) const [vectorStats, setVectorStats] = useState({ nodes: 0, relationships: 0, source: 'none' }) const [isClearingVectorDB, setIsClearingVectorDB] = useState(false) const [showClearVectorDialog, setShowClearVectorDialog] = useState(false) // UI state const [expandedSection, setExpandedSection] = useState<"graph" | "vector" | null>("graph") // Check graph database connection status (Neo4j or ArangoDB) const checkGraphConnection = async () => { setGraphConnectionStatus("checking") setGraphError(null) try { // Get database type from localStorage const graphDbType = localStorage.getItem("graph_db_type") || "arangodb" setDbType(graphDbType === "arangodb" ? "ArangoDB" : "Neo4j") if (graphDbType === "neo4j") { // Neo4j connection logic const dbUrl = localStorage.getItem("NEO4J_URL") const dbUsername = localStorage.getItem("NEO4J_USERNAME") const dbPassword = localStorage.getItem("NEO4J_PASSWORD") // Add query parameters if credentials exist const queryParams = new URLSearchParams() if (dbUrl) queryParams.append("url", dbUrl) if (dbUsername) queryParams.append("username", dbUsername) if (dbPassword) queryParams.append("password", dbPassword) const queryString = queryParams.toString() const endpoint = queryString ? `/api/neo4j?${queryString}` : '/api/neo4j' const response = await fetch(endpoint) if (!response.ok) { const errorData = await response.json() const errorMessage = errorData.error || 'Failed to connect to Neo4j' console.error('Neo4j connection failed:', errorMessage) setGraphConnectionStatus("disconnected") setGraphError(errorMessage) return } const data = await response.json() setNodeCount(data.nodes?.length || 0) setRelationshipCount(data.links?.length || 0) // Use the connection URL from the API response if (data.connectionUrl) { setConnectionUrl(data.connectionUrl) } else if (dbUrl) { setConnectionUrl(dbUrl) } } else { // ArangoDB connection logic const arangoUrl = localStorage.getItem("arango_url") || "http://localhost:8529" const arangoDb = localStorage.getItem("arango_db") || "txt2kg" const arangoUser = localStorage.getItem("arango_user") || "" const arangoPassword = localStorage.getItem("arango_password") || "" // Add query parameters if credentials exist const queryParams = new URLSearchParams() if (arangoUrl) queryParams.append("url", arangoUrl) if (arangoDb) queryParams.append("dbName", arangoDb) if (arangoUser) queryParams.append("username", arangoUser) if (arangoPassword) queryParams.append("password", arangoPassword) const queryString = queryParams.toString() const endpoint = queryString ? `/api/graph-db?${queryString}` : '/api/graph-db' const response = await fetch(endpoint) if (!response.ok) { const errorData = await response.json() const errorMessage = errorData.error || 'Failed to connect to ArangoDB' console.error('ArangoDB connection failed:', errorMessage) setGraphConnectionStatus("disconnected") setGraphError(errorMessage) return } const data = await response.json() setNodeCount(data.nodes?.length || 0) setRelationshipCount(data.links?.length || 0) // Set ArangoDB connection URL setConnectionUrl(`${arangoUrl}/_db/${arangoDb}`) } setGraphConnectionStatus("connected") } catch (err) { console.error('Graph database connection error:', err) setGraphConnectionStatus("disconnected") setGraphError(err instanceof Error ? err.message : 'Unknown error connecting to database') } } // Disconnect from graph database const disconnectGraph = async () => { try { const graphDbType = localStorage.getItem("graph_db_type") || "arangodb" const endpoint = graphDbType === "neo4j" ? '/api/neo4j/disconnect' : '/api/graph-db/disconnect' const response = await fetch(endpoint, { method: 'POST', }) if (!response.ok) { const errorData = await response.json() const errorMessage = errorData.error || `Failed to disconnect from ${graphDbType}` console.error('Graph database disconnect failed:', errorMessage) setGraphError(errorMessage) return } setGraphConnectionStatus("disconnected") setNodeCount(null) setRelationshipCount(null) } catch (err) { console.error('Graph database disconnect error:', err) setGraphError(err instanceof Error ? err.message : 'Unknown error disconnecting from database') } } // Fetch vector DB stats const fetchVectorStats = async () => { try { const response = await fetch('/api/pinecone-diag/stats'); const data = await response.json(); if (response.ok) { setVectorStats({ nodes: typeof data.totalVectorCount === 'number' ? data.totalVectorCount : 0, relationships: 0, // Vector DB doesn't store relationships source: data.source || 'unknown', httpHealthy: data.httpHealthy, // Store additional Qdrant stats ...(data.status && { status: data.status }), ...(data.vectorSize && { vectorSize: data.vectorSize }), ...(data.distance && { distance: data.distance }), ...(data.url && { url: data.url }), } as any); // If we have a healthy HTTP connection, we're connected if (data.httpHealthy) { setVectorConnectionStatus("connected"); setVectorError(null); } else { setVectorConnectionStatus("disconnected"); setVectorError(data.error || 'Connection failed'); } } else { console.error('Failed to fetch vector DB stats:', data); setVectorConnectionStatus("disconnected"); setVectorError(data.error || 'Failed to connect to vector database'); } } catch (error) { console.error('Error fetching vector DB stats:', error); setVectorConnectionStatus("disconnected"); setVectorError(error instanceof Error ? error.message : 'Error connecting to vector database'); } }; // Check vector connection const checkVectorConnection = async () => { setVectorConnectionStatus("checking") setVectorError(null) try { await fetchVectorStats(); } catch (error) { console.error('Error connecting to Vector DB:', error) setVectorConnectionStatus("disconnected") setVectorError(error instanceof Error ? error.message : 'Unknown error connecting to Vector DB') } } // Reset vector connection state const disconnectVector = async () => { setVectorConnectionStatus("disconnected") setVectorStats({ nodes: 0, relationships: 0, source: 'none' }) } // Clear the graph database const clearGraphDatabase = async () => { if (graphConnectionStatus !== "connected") { return } setIsClearingDB(true) setGraphError(null) try { // Call API to clear the database const response = await fetch('/api/graph-db/clear', { method: 'POST', }) if (!response.ok) { const errorData = await response.json() const errorMessage = errorData.error || 'Failed to clear database' console.error('Graph database clear failed:', errorMessage) setGraphError(errorMessage) return } // Refresh graph connection to update stats await checkGraphConnection() setShowClearDialog(false) } catch (err) { console.error('Graph database clear error:', err) setGraphError(err instanceof Error ? err.message : 'Unknown error clearing database') } finally { setIsClearingDB(false) } } // Clear the vector database const clearVectorDatabase = async () => { if (vectorConnectionStatus !== "connected") { return } setIsClearingVectorDB(true) setVectorError(null) try { // Call API to clear the database const response = await fetch('/api/pinecone-diag/clear', { method: 'POST', }) if (!response.ok) { const errorData = await response.json() const errorMessage = errorData.error || 'Failed to clear vector database' console.error('Vector database clear failed:', errorMessage) setVectorError(errorMessage) return } // Refresh vector connection to update stats await checkVectorConnection() setShowClearVectorDialog(false) } catch (err) { console.error('Vector database clear error:', err) setVectorError(err instanceof Error ? err.message : 'Unknown error clearing vector database') } finally { setIsClearingVectorDB(false) } } // Check both connections on mount useEffect(() => { checkGraphConnection() checkVectorConnection() }, []) const toggleSection = (section: "graph" | "vector") => { if (expandedSection === section) { setExpandedSection(null) } else { setExpandedSection(section) } } return (
{/* Graph DB Section */} toggleSection("graph")}>
toggleSection("graph")}>

Graph DB

{graphConnectionStatus === "checking" && ( )} {graphConnectionStatus === "connected" && ( )} {graphConnectionStatus === "disconnected" && ( )}
{graphConnectionStatus === "checking" && (
Checking connection...
)} {graphConnectionStatus === "connected" && ( <>
{dbType} {connectionUrl}
{(nodeCount !== null || relationshipCount !== null) && (
{nodeCount?.toLocaleString()} nodes, {relationshipCount?.toLocaleString()} relationships
)} )} {graphConnectionStatus === "disconnected" && (
Not connected
)} {graphError && (

Error: {graphError}

)}

{graphConnectionStatus === "checking" ? "Checking..." : "Refresh connection"}

{graphConnectionStatus === "connected" ? ( <>

Disconnect

Clear database

Clear Database Are you sure you want to clear all data from the {dbType} database? This action cannot be undone. Warning This will permanently delete all nodes and relationships from the database.
) : ( )}
{/* Vector DB Section */} toggleSection("vector")}>
toggleSection("vector")}>

Vector DB

{vectorConnectionStatus === "checking" && ( )} {vectorConnectionStatus === "connected" && ( )} {vectorConnectionStatus === "disconnected" && ( )}
{vectorConnectionStatus === "checking" && (
Checking connection...
)} {vectorConnectionStatus === "connected" && ( <>
Qdrant {(vectorStats as any).url || 'http://qdrant:6333'}
{vectorStats.nodes.toLocaleString()} vectors indexed
{(vectorStats as any).status && (
Status: {(vectorStats as any).status}
)} {(vectorStats as any).vectorSize && (
{(vectorStats as any).vectorSize}d ({(vectorStats as any).distance})
)}
)} {vectorConnectionStatus === "disconnected" && (
Not connected
)} {vectorError && (

Error: {vectorError}

)}

{vectorConnectionStatus === "checking" ? "Checking..." : "Refresh connection"}

{vectorConnectionStatus === "connected" ? ( <>

Disconnect

Clear database

Clear Qdrant Database Are you sure you want to clear all data from the Qdrant vector database? This action cannot be undone. Warning This will permanently delete all vectors from the Qdrant database.
) : ( )}
); }