yangdx commited on
Commit
a44a6ec
·
1 Parent(s): 920a7ad

Added tab visibility context and provider for dynamic tab management

Browse files

- Introduced TabVisibilityProvider component
- Created TabContent for conditional rendering
- Added context and hooks for tab visibility
- Updated DocumentManager dependencies
- Integrated provider in App component

lightrag_webui/src/App.tsx CHANGED
@@ -1,5 +1,6 @@
1
  import { useState, useCallback } from 'react'
2
  import ThemeProvider from '@/components/ThemeProvider'
 
3
  import MessageAlert from '@/components/MessageAlert'
4
  import ApiKeyAlert from '@/components/ApiKeyAlert'
5
  import StatusIndicator from '@/components/graph/StatusIndicator'
@@ -54,33 +55,35 @@ function App() {
54
 
55
  return (
56
  <ThemeProvider>
57
- <main className="flex h-screen w-screen overflow-x-hidden">
58
- <Tabs
59
- defaultValue={currentTab}
60
- className="!m-0 flex grow flex-col !p-0"
61
- onValueChange={handleTabChange}
62
- >
63
- <SiteHeader />
64
- <div className="relative grow">
65
- <TabsContent value="documents" className="absolute top-0 right-0 bottom-0 left-0">
66
- <DocumentManager />
67
- </TabsContent>
68
- <TabsContent value="knowledge-graph" className="absolute top-0 right-0 bottom-0 left-0">
69
- <GraphViewer />
70
- </TabsContent>
71
- <TabsContent value="retrieval" className="absolute top-0 right-0 bottom-0 left-0">
72
- <RetrievalTesting />
73
- </TabsContent>
74
- <TabsContent value="api" className="absolute top-0 right-0 bottom-0 left-0">
75
- <ApiSite />
76
- </TabsContent>
77
- </div>
78
- </Tabs>
79
- {enableHealthCheck && <StatusIndicator />}
80
- {message !== null && !apiKeyInvalid && <MessageAlert />}
81
- {apiKeyInvalid && <ApiKeyAlert />}
82
- <Toaster />
83
- </main>
 
 
84
  </ThemeProvider>
85
  )
86
  }
 
1
  import { useState, useCallback } from 'react'
2
  import ThemeProvider from '@/components/ThemeProvider'
3
+ import TabVisibilityProvider from '@/contexts/TabVisibilityProvider'
4
  import MessageAlert from '@/components/MessageAlert'
5
  import ApiKeyAlert from '@/components/ApiKeyAlert'
6
  import StatusIndicator from '@/components/graph/StatusIndicator'
 
55
 
56
  return (
57
  <ThemeProvider>
58
+ <TabVisibilityProvider>
59
+ <main className="flex h-screen w-screen overflow-x-hidden">
60
+ <Tabs
61
+ defaultValue={currentTab}
62
+ className="!m-0 flex grow flex-col !p-0"
63
+ onValueChange={handleTabChange}
64
+ >
65
+ <SiteHeader />
66
+ <div className="relative grow">
67
+ <TabsContent value="documents" className="absolute top-0 right-0 bottom-0 left-0">
68
+ <DocumentManager />
69
+ </TabsContent>
70
+ <TabsContent value="knowledge-graph" className="absolute top-0 right-0 bottom-0 left-0">
71
+ <GraphViewer />
72
+ </TabsContent>
73
+ <TabsContent value="retrieval" className="absolute top-0 right-0 bottom-0 left-0">
74
+ <RetrievalTesting />
75
+ </TabsContent>
76
+ <TabsContent value="api" className="absolute top-0 right-0 bottom-0 left-0">
77
+ <ApiSite />
78
+ </TabsContent>
79
+ </div>
80
+ </Tabs>
81
+ {enableHealthCheck && <StatusIndicator />}
82
+ {message !== null && !apiKeyInvalid && <MessageAlert />}
83
+ {apiKeyInvalid && <ApiKeyAlert />}
84
+ <Toaster />
85
+ </main>
86
+ </TabVisibilityProvider>
87
  </ThemeProvider>
88
  )
89
  }
lightrag_webui/src/components/ui/TabContent.tsx ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useEffect } from 'react';
2
+ import { useTabVisibility } from '@/contexts/useTabVisibility';
3
+
4
+ interface TabContentProps {
5
+ tabId: string;
6
+ children: React.ReactNode;
7
+ className?: string;
8
+ }
9
+
10
+ /**
11
+ * TabContent component that manages visibility based on tab selection
12
+ * Works with the TabVisibilityContext to show/hide content based on active tab
13
+ */
14
+ const TabContent: React.FC<TabContentProps> = ({ tabId, children, className = '' }) => {
15
+ const { isTabVisible, setTabVisibility } = useTabVisibility();
16
+ const isVisible = isTabVisible(tabId);
17
+
18
+ // Register this tab with the context when mounted
19
+ useEffect(() => {
20
+ setTabVisibility(tabId, true);
21
+
22
+ // Cleanup when unmounted
23
+ return () => {
24
+ setTabVisibility(tabId, false);
25
+ };
26
+ }, [tabId, setTabVisibility]);
27
+
28
+ if (!isVisible) {
29
+ return null;
30
+ }
31
+
32
+ return (
33
+ <div className={className}>
34
+ {children}
35
+ </div>
36
+ );
37
+ };
38
+
39
+ export default TabContent;
lightrag_webui/src/contexts/TabVisibilityProvider.tsx ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useMemo } from 'react';
2
+ import { TabVisibilityContext } from './context';
3
+ import { TabVisibilityContextType } from './types';
4
+
5
+ interface TabVisibilityProviderProps {
6
+ children: React.ReactNode;
7
+ }
8
+
9
+ /**
10
+ * Provider component for the TabVisibility context
11
+ * Manages the visibility state of tabs throughout the application
12
+ */
13
+ export const TabVisibilityProvider: React.FC<TabVisibilityProviderProps> = ({ children }) => {
14
+ const [visibleTabs, setVisibleTabs] = useState<Record<string, boolean>>({});
15
+
16
+ // Create the context value with memoization to prevent unnecessary re-renders
17
+ const contextValue = useMemo<TabVisibilityContextType>(
18
+ () => ({
19
+ visibleTabs,
20
+ setTabVisibility: (tabId: string, isVisible: boolean) => {
21
+ setVisibleTabs((prev) => ({
22
+ ...prev,
23
+ [tabId]: isVisible,
24
+ }));
25
+ },
26
+ isTabVisible: (tabId: string) => !!visibleTabs[tabId],
27
+ }),
28
+ [visibleTabs]
29
+ );
30
+
31
+ return (
32
+ <TabVisibilityContext.Provider value={contextValue}>
33
+ {children}
34
+ </TabVisibilityContext.Provider>
35
+ );
36
+ };
37
+
38
+ export default TabVisibilityProvider;
lightrag_webui/src/contexts/context.ts ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { createContext } from 'react';
2
+ import { TabVisibilityContextType } from './types';
3
+
4
+ // Default context value
5
+ const defaultContext: TabVisibilityContextType = {
6
+ visibleTabs: {},
7
+ setTabVisibility: () => {},
8
+ isTabVisible: () => false,
9
+ };
10
+
11
+ // Create the context
12
+ export const TabVisibilityContext = createContext<TabVisibilityContextType>(defaultContext);
lightrag_webui/src/contexts/types.ts ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ export interface TabVisibilityContextType {
2
+ visibleTabs: Record<string, boolean>;
3
+ setTabVisibility: (tabId: string, isVisible: boolean) => void;
4
+ isTabVisible: (tabId: string) => boolean;
5
+ }
lightrag_webui/src/contexts/useTabVisibility.ts ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useContext } from 'react';
2
+ import { TabVisibilityContext } from './context';
3
+ import { TabVisibilityContextType } from './types';
4
+
5
+ /**
6
+ * Custom hook to access the tab visibility context
7
+ * @returns The tab visibility context
8
+ */
9
+ export const useTabVisibility = (): TabVisibilityContextType => {
10
+ const context = useContext(TabVisibilityContext);
11
+
12
+ if (!context) {
13
+ throw new Error('useTabVisibility must be used within a TabVisibilityProvider');
14
+ }
15
+
16
+ return context;
17
+ };
lightrag_webui/src/features/DocumentManager.tsx CHANGED
@@ -48,11 +48,11 @@ export default function DocumentManager() {
48
  } catch (err) {
49
  toast.error(t('documentPanel.documentManager.errors.loadFailed', { error: errorMessage(err) }))
50
  }
51
- }, [setDocs])
52
 
53
  useEffect(() => {
54
  fetchDocuments()
55
- }, []) // eslint-disable-line react-hooks/exhaustive-deps
56
 
57
  const scanDocuments = useCallback(async () => {
58
  try {
@@ -61,7 +61,7 @@ export default function DocumentManager() {
61
  } catch (err) {
62
  toast.error(t('documentPanel.documentManager.errors.scanFailed', { error: errorMessage(err) }))
63
  }
64
- }, [])
65
 
66
  useEffect(() => {
67
  const interval = setInterval(async () => {
@@ -75,7 +75,7 @@ export default function DocumentManager() {
75
  }
76
  }, 5000)
77
  return () => clearInterval(interval)
78
- }, [health, fetchDocuments])
79
 
80
  return (
81
  <Card className="!size-full !rounded-none !border-none">
 
48
  } catch (err) {
49
  toast.error(t('documentPanel.documentManager.errors.loadFailed', { error: errorMessage(err) }))
50
  }
51
+ }, [setDocs, t])
52
 
53
  useEffect(() => {
54
  fetchDocuments()
55
+ }, [fetchDocuments, t])
56
 
57
  const scanDocuments = useCallback(async () => {
58
  try {
 
61
  } catch (err) {
62
  toast.error(t('documentPanel.documentManager.errors.scanFailed', { error: errorMessage(err) }))
63
  }
64
+ }, [t])
65
 
66
  useEffect(() => {
67
  const interval = setInterval(async () => {
 
75
  }
76
  }, 5000)
77
  return () => clearInterval(interval)
78
+ }, [health, fetchDocuments, t])
79
 
80
  return (
81
  <Card className="!size-full !rounded-none !border-none">