import { useState, useCallback, useEffect, useRef } from 'react' import ThemeProvider from '@/components/ThemeProvider' import TabVisibilityProvider from '@/contexts/TabVisibilityProvider' import ApiKeyAlert from '@/components/ApiKeyAlert' import StatusIndicator from '@/components/status/StatusIndicator' import { healthCheckInterval, SiteInfo, webuiPrefix } from '@/lib/constants' import { useBackendState, useAuthStore } from '@/stores/state' import { useSettingsStore } from '@/stores/settings' import { getAuthStatus } from '@/api/lightrag' import SiteHeader from '@/features/SiteHeader' import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag' import { ZapIcon } from 'lucide-react' import GraphViewer from '@/features/GraphViewer' import DocumentManager from '@/features/DocumentManager' import RetrievalTesting from '@/features/RetrievalTesting' import ApiSite from '@/features/ApiSite' import { Tabs, TabsContent } from '@/components/ui/Tabs' function App() { const message = useBackendState.use.message() const enableHealthCheck = useSettingsStore.use.enableHealthCheck() const currentTab = useSettingsStore.use.currentTab() const [apiKeyAlertOpen, setApiKeyAlertOpen] = useState(false) const [initializing, setInitializing] = useState(true) // Add initializing state const versionCheckRef = useRef(false); // Prevent duplicate calls in Vite dev mode const handleApiKeyAlertOpenChange = useCallback((open: boolean) => { setApiKeyAlertOpen(open) if (!open) { useBackendState.getState().clear() } }, []) // Health check - can be disabled useEffect(() => { // Only execute if health check is enabled and ApiKeyAlert is closed if (!enableHealthCheck || apiKeyAlertOpen) return; // Health check function const performHealthCheck = async () => { await useBackendState.getState().check(); }; // Set interval for periodic execution const interval = setInterval(performHealthCheck, healthCheckInterval * 1000); return () => clearInterval(interval); }, [enableHealthCheck, apiKeyAlertOpen]); // Version check - independent and executed only once useEffect(() => { const checkVersion = async () => { // Prevent duplicate calls in Vite dev mode if (versionCheckRef.current) return; versionCheckRef.current = true; // Check if version info was already obtained in login page const versionCheckedFromLogin = sessionStorage.getItem('VERSION_CHECKED_FROM_LOGIN') === 'true'; if (versionCheckedFromLogin) { setInitializing(false); // Skip initialization if already checked return; } try { setInitializing(true); // Start initialization // Get version info const token = localStorage.getItem('LIGHTRAG-API-TOKEN'); const status = await getAuthStatus(); // If auth is not configured and a new token is returned, use the new token if (!status.auth_configured && status.access_token) { useAuthStore.getState().login( status.access_token, // Use the new token true, // Guest mode status.core_version, status.api_version, status.webui_title || null, status.webui_description || null ); } else if (token && (status.core_version || status.api_version || status.webui_title || status.webui_description)) { // Otherwise use the old token (if it exists) const isGuestMode = status.auth_mode === 'disabled' || useAuthStore.getState().isGuestMode; useAuthStore.getState().login( token, isGuestMode, status.core_version, status.api_version, status.webui_title || null, status.webui_description || null ); } // Set flag to indicate version info has been checked sessionStorage.setItem('VERSION_CHECKED_FROM_LOGIN', 'true'); } catch (error) { console.error('Failed to get version info:', error); } finally { // Ensure initializing is set to false even if there's an error setInitializing(false); } }; // Execute version check checkVersion(); }, []); // Empty dependency array ensures it only runs once on mount const handleTabChange = useCallback( (tab: string) => useSettingsStore.getState().setCurrentTab(tab as any), [] ) useEffect(() => { if (message) { if (message.includes(InvalidApiKeyError) || message.includes(RequireApiKeError)) { setApiKeyAlertOpen(true) } } }, [message]) return ( {initializing ? ( // Loading state while initializing with simplified header
{/* Simplified header during initialization - matches SiteHeader structure */}
{/* Empty middle section to maintain layout */}
{/* Empty right section to maintain layout */}
{/* Loading indicator in content area */}

Initializing...

) : ( // Main content after initialization
{enableHealthCheck && }
)}
) } export default App