diff --git a/lightrag_webui/src/App.tsx b/lightrag_webui/src/App.tsx
index 1cf8c5e3..bb4a84cb 100644
--- a/lightrag_webui/src/App.tsx
+++ b/lightrag_webui/src/App.tsx
@@ -1,5 +1,6 @@
import { useState, useCallback } from 'react'
import ThemeProvider from '@/components/ThemeProvider'
+import TabVisibilityProvider from '@/contexts/TabVisibilityProvider'
import MessageAlert from '@/components/MessageAlert'
import ApiKeyAlert from '@/components/ApiKeyAlert'
import StatusIndicator from '@/components/graph/StatusIndicator'
@@ -54,33 +55,35 @@ function App() {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {enableHealthCheck && }
- {message !== null && !apiKeyInvalid && }
- {apiKeyInvalid && }
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {enableHealthCheck && }
+ {message !== null && !apiKeyInvalid && }
+ {apiKeyInvalid && }
+
+
+
)
}
diff --git a/lightrag_webui/src/components/ui/TabContent.tsx b/lightrag_webui/src/components/ui/TabContent.tsx
new file mode 100644
index 00000000..f3c0b80f
--- /dev/null
+++ b/lightrag_webui/src/components/ui/TabContent.tsx
@@ -0,0 +1,39 @@
+import React, { useEffect } from 'react';
+import { useTabVisibility } from '@/contexts/useTabVisibility';
+
+interface TabContentProps {
+ tabId: string;
+ children: React.ReactNode;
+ className?: string;
+}
+
+/**
+ * TabContent component that manages visibility based on tab selection
+ * Works with the TabVisibilityContext to show/hide content based on active tab
+ */
+const TabContent: React.FC = ({ tabId, children, className = '' }) => {
+ const { isTabVisible, setTabVisibility } = useTabVisibility();
+ const isVisible = isTabVisible(tabId);
+
+ // Register this tab with the context when mounted
+ useEffect(() => {
+ setTabVisibility(tabId, true);
+
+ // Cleanup when unmounted
+ return () => {
+ setTabVisibility(tabId, false);
+ };
+ }, [tabId, setTabVisibility]);
+
+ if (!isVisible) {
+ return null;
+ }
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default TabContent;
diff --git a/lightrag_webui/src/contexts/TabVisibilityProvider.tsx b/lightrag_webui/src/contexts/TabVisibilityProvider.tsx
new file mode 100644
index 00000000..73be2f64
--- /dev/null
+++ b/lightrag_webui/src/contexts/TabVisibilityProvider.tsx
@@ -0,0 +1,38 @@
+import React, { useState, useMemo } from 'react';
+import { TabVisibilityContext } from './context';
+import { TabVisibilityContextType } from './types';
+
+interface TabVisibilityProviderProps {
+ children: React.ReactNode;
+}
+
+/**
+ * Provider component for the TabVisibility context
+ * Manages the visibility state of tabs throughout the application
+ */
+export const TabVisibilityProvider: React.FC = ({ children }) => {
+ const [visibleTabs, setVisibleTabs] = useState>({});
+
+ // Create the context value with memoization to prevent unnecessary re-renders
+ const contextValue = useMemo(
+ () => ({
+ visibleTabs,
+ setTabVisibility: (tabId: string, isVisible: boolean) => {
+ setVisibleTabs((prev) => ({
+ ...prev,
+ [tabId]: isVisible,
+ }));
+ },
+ isTabVisible: (tabId: string) => !!visibleTabs[tabId],
+ }),
+ [visibleTabs]
+ );
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default TabVisibilityProvider;
diff --git a/lightrag_webui/src/contexts/context.ts b/lightrag_webui/src/contexts/context.ts
new file mode 100644
index 00000000..e6b569a2
--- /dev/null
+++ b/lightrag_webui/src/contexts/context.ts
@@ -0,0 +1,12 @@
+import { createContext } from 'react';
+import { TabVisibilityContextType } from './types';
+
+// Default context value
+const defaultContext: TabVisibilityContextType = {
+ visibleTabs: {},
+ setTabVisibility: () => {},
+ isTabVisible: () => false,
+};
+
+// Create the context
+export const TabVisibilityContext = createContext(defaultContext);
diff --git a/lightrag_webui/src/contexts/types.ts b/lightrag_webui/src/contexts/types.ts
new file mode 100644
index 00000000..051c398c
--- /dev/null
+++ b/lightrag_webui/src/contexts/types.ts
@@ -0,0 +1,5 @@
+export interface TabVisibilityContextType {
+ visibleTabs: Record;
+ setTabVisibility: (tabId: string, isVisible: boolean) => void;
+ isTabVisible: (tabId: string) => boolean;
+}
diff --git a/lightrag_webui/src/contexts/useTabVisibility.ts b/lightrag_webui/src/contexts/useTabVisibility.ts
new file mode 100644
index 00000000..436ce50f
--- /dev/null
+++ b/lightrag_webui/src/contexts/useTabVisibility.ts
@@ -0,0 +1,17 @@
+import { useContext } from 'react';
+import { TabVisibilityContext } from './context';
+import { TabVisibilityContextType } from './types';
+
+/**
+ * Custom hook to access the tab visibility context
+ * @returns The tab visibility context
+ */
+export const useTabVisibility = (): TabVisibilityContextType => {
+ const context = useContext(TabVisibilityContext);
+
+ if (!context) {
+ throw new Error('useTabVisibility must be used within a TabVisibilityProvider');
+ }
+
+ return context;
+};
diff --git a/lightrag_webui/src/features/DocumentManager.tsx b/lightrag_webui/src/features/DocumentManager.tsx
index b8841fe4..3d4a6717 100644
--- a/lightrag_webui/src/features/DocumentManager.tsx
+++ b/lightrag_webui/src/features/DocumentManager.tsx
@@ -48,11 +48,11 @@ export default function DocumentManager() {
} catch (err) {
toast.error(t('documentPanel.documentManager.errors.loadFailed', { error: errorMessage(err) }))
}
- }, [setDocs])
+ }, [setDocs, t])
useEffect(() => {
fetchDocuments()
- }, []) // eslint-disable-line react-hooks/exhaustive-deps
+ }, [fetchDocuments, t])
const scanDocuments = useCallback(async () => {
try {
@@ -61,7 +61,7 @@ export default function DocumentManager() {
} catch (err) {
toast.error(t('documentPanel.documentManager.errors.scanFailed', { error: errorMessage(err) }))
}
- }, [])
+ }, [t])
useEffect(() => {
const interval = setInterval(async () => {
@@ -75,7 +75,7 @@ export default function DocumentManager() {
}
}, 5000)
return () => clearInterval(interval)
- }, [health, fetchDocuments])
+ }, [health, fetchDocuments, t])
return (