yangdx commited on
Commit
f9b14ab
·
1 Parent(s): e901bfa

Refactor navigation and authentication flow

Browse files

- Move navigation setup to AppRouter
- Prevent protected route logic to handle login 401

lightrag_webui/src/App.tsx CHANGED
@@ -5,11 +5,9 @@ import MessageAlert from '@/components/MessageAlert'
5
  import ApiKeyAlert from '@/components/ApiKeyAlert'
6
  import StatusIndicator from '@/components/graph/StatusIndicator'
7
  import { healthCheckInterval } from '@/lib/constants'
8
- import { useBackendState, useAuthStore } from '@/stores/state'
9
  import { useSettingsStore } from '@/stores/settings'
10
  import { useEffect } from 'react'
11
- import { useNavigate } from 'react-router-dom'
12
- import { navigationService } from '@/services/navigation'
13
  import SiteHeader from '@/features/SiteHeader'
14
  import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag'
15
 
@@ -21,22 +19,13 @@ import ApiSite from '@/features/ApiSite'
21
  import { Tabs, TabsContent } from '@/components/ui/Tabs'
22
 
23
  function App() {
24
- const navigate = useNavigate();
25
  const message = useBackendState.use.message()
26
-
27
- // Initialize navigation service
28
- useEffect(() => {
29
- navigationService.setNavigate(navigate);
30
- }, [navigate]);
31
  const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
32
  const currentTab = useSettingsStore.use.currentTab()
33
  const [apiKeyInvalid, setApiKeyInvalid] = useState(false)
34
 
35
  // Health check
36
  useEffect(() => {
37
- const { isAuthenticated } = useAuthStore.getState();
38
- if (!enableHealthCheck || !isAuthenticated) return
39
-
40
  // Check immediately
41
  useBackendState.getState().check()
42
 
 
5
  import ApiKeyAlert from '@/components/ApiKeyAlert'
6
  import StatusIndicator from '@/components/graph/StatusIndicator'
7
  import { healthCheckInterval } from '@/lib/constants'
8
+ import { useBackendState } from '@/stores/state'
9
  import { useSettingsStore } from '@/stores/settings'
10
  import { useEffect } from 'react'
 
 
11
  import SiteHeader from '@/features/SiteHeader'
12
  import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag'
13
 
 
19
  import { Tabs, TabsContent } from '@/components/ui/Tabs'
20
 
21
  function App() {
 
22
  const message = useBackendState.use.message()
 
 
 
 
 
23
  const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
24
  const currentTab = useSettingsStore.use.currentTab()
25
  const [apiKeyInvalid, setApiKeyInvalid] = useState(false)
26
 
27
  // Health check
28
  useEffect(() => {
 
 
 
29
  // Check immediately
30
  useBackendState.getState().check()
31
 
lightrag_webui/src/AppRouter.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { HashRouter as Router, Routes, Route, Navigate } from 'react-router-dom'
2
  import { useEffect, useState } from 'react'
3
  import { useAuthStore } from '@/stores/state'
4
  import { navigationService } from '@/services/navigation'
@@ -16,6 +16,12 @@ interface ProtectedRouteProps {
16
  const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
17
  const { isAuthenticated } = useAuthStore()
18
  const [isChecking, setIsChecking] = useState(true)
 
 
 
 
 
 
19
 
20
  useEffect(() => {
21
  let isMounted = true; // Flag to prevent state updates after unmount
@@ -71,29 +77,33 @@ const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
71
  // Get current path and check if it's a direct access
72
  const currentPath = window.location.hash.slice(1); // Remove the '#' from hash
73
  const isLoginPage = currentPath === '/login';
74
- const isDirectAccess = !document.referrer;
75
-
76
- // Handle direct access to root path
77
- if (isDirectAccess && currentPath === '/') {
78
- navigationService.resetAllApplicationState();
79
- }
80
-
81
  // Skip redirect if already on login page
82
  if (isLoginPage) {
83
  return null;
84
  }
85
 
86
- // Use React Router's Navigate for redirection
87
- console.log('Not authenticated, redirecting to login');
88
- return <Navigate to="/login" replace />;
 
 
 
 
89
  }
90
 
91
  return <>{children}</>
92
  }
93
 
94
- const AppRouter = () => {
95
  const [initializing, setInitializing] = useState(true)
96
  const { isAuthenticated } = useAuthStore()
 
 
 
 
 
 
97
 
98
  // Check token validity and auth configuration on app initialization
99
  useEffect(() => {
@@ -152,21 +162,27 @@ const AppRouter = () => {
152
  return null
153
  }
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  return (
156
  <ThemeProvider>
157
  <Router>
158
- <Routes>
159
- <Route path="/login" element={<LoginPage />} />
160
- <Route
161
- path="/*"
162
- element={
163
- <ProtectedRoute>
164
- <App />
165
- </ProtectedRoute>
166
- }
167
- />
168
- </Routes>
169
- <Toaster position="top-center" />
170
  </Router>
171
  </ThemeProvider>
172
  )
 
1
+ import { HashRouter as Router, Routes, Route, useNavigate } from 'react-router-dom'
2
  import { useEffect, useState } from 'react'
3
  import { useAuthStore } from '@/stores/state'
4
  import { navigationService } from '@/services/navigation'
 
16
  const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
17
  const { isAuthenticated } = useAuthStore()
18
  const [isChecking, setIsChecking] = useState(true)
19
+ const navigate = useNavigate()
20
+
21
+ // Set navigate function for navigation service
22
+ useEffect(() => {
23
+ navigationService.setNavigate(navigate)
24
+ }, [navigate])
25
 
26
  useEffect(() => {
27
  let isMounted = true; // Flag to prevent state updates after unmount
 
77
  // Get current path and check if it's a direct access
78
  const currentPath = window.location.hash.slice(1); // Remove the '#' from hash
79
  const isLoginPage = currentPath === '/login';
80
+
 
 
 
 
 
 
81
  // Skip redirect if already on login page
82
  if (isLoginPage) {
83
  return null;
84
  }
85
 
86
+ // For non-login pages, handle state reset and navigation
87
+ if (!isLoginPage) {
88
+ // Use navigation service for redirection
89
+ console.log('Not authenticated, redirecting to login');
90
+ navigationService.navigateToLogin();
91
+ return null;
92
+ }
93
  }
94
 
95
  return <>{children}</>
96
  }
97
 
98
+ const AppContent = () => {
99
  const [initializing, setInitializing] = useState(true)
100
  const { isAuthenticated } = useAuthStore()
101
+ const navigate = useNavigate()
102
+
103
+ // Set navigate function for navigation service
104
+ useEffect(() => {
105
+ navigationService.setNavigate(navigate)
106
+ }, [navigate])
107
 
108
  // Check token validity and auth configuration on app initialization
109
  useEffect(() => {
 
162
  return null
163
  }
164
 
165
+ return (
166
+ <Routes>
167
+ <Route path="/login" element={<LoginPage />} />
168
+ <Route
169
+ path="/*"
170
+ element={
171
+ <ProtectedRoute>
172
+ <App />
173
+ </ProtectedRoute>
174
+ }
175
+ />
176
+ </Routes>
177
+ )
178
+ }
179
+
180
+ const AppRouter = () => {
181
  return (
182
  <ThemeProvider>
183
  <Router>
184
+ <AppContent />
185
+ <Toaster position="bottom-center" />
 
 
 
 
 
 
 
 
 
 
186
  </Router>
187
  </ThemeProvider>
188
  )
lightrag_webui/src/api/lightrag.ts CHANGED
@@ -173,9 +173,12 @@ axiosInstance.interceptors.response.use(
173
  (error: AxiosError) => {
174
  if (error.response) {
175
  if (error.response?.status === 401) {
176
- // Use navigation service to handle redirection
 
 
 
 
177
  navigationService.navigateToLogin();
178
-
179
  // Return a never-resolving promise to prevent further execution
180
  return new Promise(() => {});
181
  }
 
173
  (error: AxiosError) => {
174
  if (error.response) {
175
  if (error.response?.status === 401) {
176
+ // For login API, throw error directly
177
+ if (error.config?.url?.includes('/login')) {
178
+ throw error;
179
+ }
180
+ // For other APIs, navigate to login page
181
  navigationService.navigateToLogin();
 
182
  // Return a never-resolving promise to prevent further execution
183
  return new Promise(() => {});
184
  }
lightrag_webui/src/features/LoginPage.tsx CHANGED
@@ -48,7 +48,7 @@ const LoginPage = () => {
48
  toast.info(status.message)
49
  }
50
  navigate('/')
51
- return; // Exit early, no need to set checkingAuth to false
52
  }
53
  } catch (error) {
54
  console.error('Failed to check auth configuration:', error)
@@ -95,11 +95,17 @@ const LoginPage = () => {
95
  } else {
96
  toast.success(t('login.successMessage'))
97
  }
98
-
 
99
  navigate('/')
100
  } catch (error) {
101
  console.error('Login failed...', error)
102
  toast.error(t('login.errorInvalidCredentials'))
 
 
 
 
 
103
  } finally {
104
  setLoading(false)
105
  }
 
48
  toast.info(status.message)
49
  }
50
  navigate('/')
51
+ return // Exit early, no need to set checkingAuth to false
52
  }
53
  } catch (error) {
54
  console.error('Failed to check auth configuration:', error)
 
95
  } else {
96
  toast.success(t('login.successMessage'))
97
  }
98
+
99
+ // Navigate to home page after successful login
100
  navigate('/')
101
  } catch (error) {
102
  console.error('Login failed...', error)
103
  toast.error(t('login.errorInvalidCredentials'))
104
+
105
+ // Clear any existing auth state
106
+ useAuthStore.getState().logout()
107
+ // Clear local storage
108
+ localStorage.removeItem('LIGHTRAG-API-TOKEN')
109
  } finally {
110
  setLoading(false)
111
  }
lightrag_webui/src/services/navigation.ts CHANGED
@@ -61,13 +61,28 @@ class NavigationService {
61
  * @param skipReset whether to skip state reset (used for direct access scenario where reset is already handled)
62
  */
63
  navigateToLogin() {
 
 
 
 
64
 
65
- this.resetAllApplicationState();
66
- useAuthStore.getState().logout();
67
 
68
- if (this.navigate) {
69
- this.navigate('/login');
 
 
 
 
 
 
 
 
 
70
  }
 
 
71
  }
72
  }
73
 
 
61
  * @param skipReset whether to skip state reset (used for direct access scenario where reset is already handled)
62
  */
63
  navigateToLogin() {
64
+ if (!this.navigate) {
65
+ console.error('Navigation function not set');
66
+ return;
67
+ }
68
 
69
+ // First navigate to login page
70
+ this.navigate('/login');
71
 
72
+ // Then reset state after navigation
73
+ setTimeout(() => {
74
+ this.resetAllApplicationState();
75
+ useAuthStore.getState().logout();
76
+ }, 0);
77
+ }
78
+
79
+ navigateToHome() {
80
+ if (!this.navigate) {
81
+ console.error('Navigation function not set');
82
+ return;
83
  }
84
+
85
+ this.navigate('/');
86
  }
87
  }
88