diff --git a/lightrag/utils.py b/lightrag/utils.py index 9f751ec7..362e5531 100644 --- a/lightrag/utils.py +++ b/lightrag/utils.py @@ -75,8 +75,8 @@ class LightragPathFilter(logging.Filter): def __init__(self): super().__init__() # Define paths to be filtered - # self.filtered_paths = ["/documents", "/health", "/webui/"] - self.filtered_paths = ["/health", "/webui/"] + self.filtered_paths = ["/documents", "/health", "/webui/"] + # self.filtered_paths = ["/health", "/webui/"] def filter(self, record): try: diff --git a/lightrag_webui/src/App.tsx b/lightrag_webui/src/App.tsx index bb4a84cb..b7d66b7e 100644 --- a/lightrag_webui/src/App.tsx +++ b/lightrag_webui/src/App.tsx @@ -22,7 +22,7 @@ import { Tabs, TabsContent } from '@/components/ui/Tabs' function App() { const message = useBackendState.use.message() const enableHealthCheck = useSettingsStore.use.enableHealthCheck() - const [currentTab] = useState(() => useSettingsStore.getState().currentTab) + const currentTab = useSettingsStore.use.currentTab() const [apiKeyInvalid, setApiKeyInvalid] = useState(false) // Health check diff --git a/lightrag_webui/src/components/graph/GraphLabels.tsx b/lightrag_webui/src/components/graph/GraphLabels.tsx index 1a1e428b..243c26cc 100644 --- a/lightrag_webui/src/components/graph/GraphLabels.tsx +++ b/lightrag_webui/src/components/graph/GraphLabels.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react' +import { useCallback, useEffect, useRef } from 'react' import { AsyncSelect } from '@/components/ui/AsyncSelect' import { useSettingsStore } from '@/stores/settings' import { useGraphStore } from '@/stores/graph' @@ -10,6 +10,37 @@ const GraphLabels = () => { const { t } = useTranslation() const label = useSettingsStore.use.queryLabel() const allDatabaseLabels = useGraphStore.use.allDatabaseLabels() + const labelsLoadedRef = useRef(false) + + // Track if a fetch is in progress to prevent multiple simultaneous fetches + const fetchInProgressRef = useRef(false) + + // Fetch labels once on component mount, using global flag to prevent duplicates + useEffect(() => { + // Check if we've already attempted to fetch labels in this session + const labelsFetchAttempted = useGraphStore.getState().labelsFetchAttempted + + // Only fetch if we haven't attempted in this session and no fetch is in progress + if (!labelsFetchAttempted && !fetchInProgressRef.current) { + fetchInProgressRef.current = true + // Set global flag to indicate we've attempted to fetch in this session + useGraphStore.getState().setLabelsFetchAttempted(true) + + console.log('Fetching graph labels (once per session)...') + + useGraphStore.getState().fetchAllDatabaseLabels() + .then(() => { + labelsLoadedRef.current = true + fetchInProgressRef.current = false + }) + .catch((error) => { + console.error('Failed to fetch labels:', error) + fetchInProgressRef.current = false + // Reset global flag to allow retry + useGraphStore.getState().setLabelsFetchAttempted(false) + }) + } + }, []) // Empty dependency array ensures this only runs once on mount const getSearchEngine = useCallback(() => { // Create search engine diff --git a/lightrag_webui/src/components/ui/TabContent.tsx b/lightrag_webui/src/components/ui/TabContent.tsx index f3c0b80f..2d14d849 100644 --- a/lightrag_webui/src/components/ui/TabContent.tsx +++ b/lightrag_webui/src/components/ui/TabContent.tsx @@ -25,12 +25,10 @@ const TabContent: React.FC = ({ tabId, children, className = '' }; }, [tabId, setTabVisibility]); - if (!isVisible) { - return null; - } - + // Use CSS to hide content instead of not rendering it + // This prevents components from unmounting when tabs are switched return ( -
+
{children}
); diff --git a/lightrag_webui/src/contexts/TabVisibilityProvider.tsx b/lightrag_webui/src/contexts/TabVisibilityProvider.tsx index 73be2f64..c4659906 100644 --- a/lightrag_webui/src/contexts/TabVisibilityProvider.tsx +++ b/lightrag_webui/src/contexts/TabVisibilityProvider.tsx @@ -1,6 +1,7 @@ -import React, { useState, useMemo } from 'react'; +import React, { useState, useEffect, useMemo } from 'react'; import { TabVisibilityContext } from './context'; import { TabVisibilityContextType } from './types'; +import { useSettingsStore } from '@/stores/settings'; interface TabVisibilityProviderProps { children: React.ReactNode; @@ -11,7 +12,21 @@ interface TabVisibilityProviderProps { * Manages the visibility state of tabs throughout the application */ export const TabVisibilityProvider: React.FC = ({ children }) => { - const [visibleTabs, setVisibleTabs] = useState>({}); + // Get current tab from settings store + const currentTab = useSettingsStore.use.currentTab(); + + // Initialize visibility state with current tab as visible + const [visibleTabs, setVisibleTabs] = useState>(() => ({ + [currentTab]: true + })); + + // Update visibility when current tab changes + useEffect(() => { + setVisibleTabs((prev) => ({ + ...prev, + [currentTab]: true + })); + }, [currentTab]); // Create the context value with memoization to prevent unnecessary re-renders const contextValue = useMemo( diff --git a/lightrag_webui/src/features/ApiSite.tsx b/lightrag_webui/src/features/ApiSite.tsx index fa9e263f..7adf9240 100644 --- a/lightrag_webui/src/features/ApiSite.tsx +++ b/lightrag_webui/src/features/ApiSite.tsx @@ -1,5 +1,38 @@ +import { useState, useEffect } from 'react' +import { useTabVisibility } from '@/contexts/useTabVisibility' import { backendBaseUrl } from '@/lib/constants' export default function ApiSite() { - return