yangdx commited on
Commit
c114561
·
1 Parent(s): a8128c3

Refactor navigation and authentication flow, prevent mounting login page multiple times

Browse files

- Improved protected route handling
- Enhanced direct login access detection
- Centralized navigation logic
- Optimized state reset process
- Fixed logout navigation behavior

lightrag/api/webui/assets/{index-BiPN9eZH.js → index-CMFGmyjk.js} RENAMED
Binary files a/lightrag/api/webui/assets/index-BiPN9eZH.js and b/lightrag/api/webui/assets/index-CMFGmyjk.js differ
 
lightrag/api/webui/index.html CHANGED
Binary files a/lightrag/api/webui/index.html and b/lightrag/api/webui/index.html differ
 
lightrag_webui/src/AppRouter.tsx CHANGED
@@ -1,6 +1,7 @@
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 { getAuthStatus } from '@/api/lightrag'
5
  import { toast } from 'sonner'
6
  import { Toaster } from 'sonner'
@@ -65,9 +66,26 @@ const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
65
  return null
66
  }
67
 
68
- // After checking, if still not authenticated, redirect to login
69
  if (!isAuthenticated) {
70
- return <Navigate to="/login" replace />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  }
72
 
73
  return <>{children}</>
 
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'
5
  import { getAuthStatus } from '@/api/lightrag'
6
  import { toast } from 'sonner'
7
  import { Toaster } from 'sonner'
 
66
  return null
67
  }
68
 
69
+ // After checking, if still not authenticated
70
  if (!isAuthenticated) {
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}</>
lightrag_webui/src/api/lightrag.ts CHANGED
@@ -2,7 +2,6 @@ import axios, { AxiosError } from 'axios'
2
  import { backendBaseUrl } from '@/lib/constants'
3
  import { errorMessage } from '@/lib/utils'
4
  import { useSettingsStore } from '@/stores/settings'
5
- import { useAuthStore } from '@/stores/state'
6
  import { navigationService } from '@/services/navigation'
7
 
8
  // Types
@@ -174,10 +173,6 @@ axiosInstance.interceptors.response.use(
174
  (error: AxiosError) => {
175
  if (error.response) {
176
  if (error.response?.status === 401) {
177
- localStorage.removeItem('LIGHTRAG-API-TOKEN');
178
- sessionStorage.clear();
179
- useAuthStore.getState().logout();
180
-
181
  // Use navigation service to handle redirection
182
  navigationService.navigateToLogin();
183
 
 
2
  import { backendBaseUrl } from '@/lib/constants'
3
  import { errorMessage } from '@/lib/utils'
4
  import { useSettingsStore } from '@/stores/settings'
 
5
  import { navigationService } from '@/services/navigation'
6
 
7
  // Types
 
173
  (error: AxiosError) => {
174
  if (error.response) {
175
  if (error.response?.status === 401) {
 
 
 
 
176
  // Use navigation service to handle redirection
177
  navigationService.navigateToLogin();
178
 
lightrag_webui/src/components/AppSettings.tsx CHANGED
@@ -32,7 +32,7 @@ export default function AppSettings({ className }: AppSettingsProps) {
32
  return (
33
  <Popover open={opened} onOpenChange={setOpened}>
34
  <PopoverTrigger asChild>
35
- <Button variant="ghost" size="icon" className={cn("h-9 w-9", className)}>
36
  <PaletteIcon className="h-5 w-5" />
37
  </Button>
38
  </PopoverTrigger>
 
32
  return (
33
  <Popover open={opened} onOpenChange={setOpened}>
34
  <PopoverTrigger asChild>
35
+ <Button variant="ghost" size="icon" className={cn('h-9 w-9', className)}>
36
  <PaletteIcon className="h-5 w-5" />
37
  </Button>
38
  </PopoverTrigger>
lightrag_webui/src/features/LoginPage.tsx CHANGED
@@ -4,8 +4,6 @@ import { useAuthStore } from '@/stores/state'
4
  import { loginToServer, getAuthStatus } from '@/api/lightrag'
5
  import { toast } from 'sonner'
6
  import { useTranslation } from 'react-i18next'
7
- import { navigationService } from '@/services/navigation'
8
-
9
  import { Card, CardContent, CardHeader } from '@/components/ui/Card'
10
  import Input from '@/components/ui/Input'
11
  import Button from '@/components/ui/Button'
@@ -21,12 +19,11 @@ const LoginPage = () => {
21
  const [password, setPassword] = useState('')
22
  const [checkingAuth, setCheckingAuth] = useState(true)
23
 
24
- // Reset application state on first mount
25
  useEffect(() => {
26
- navigationService.resetAllApplicationState();
27
- }, []); // Empty dependency array means this runs only once on mount
28
 
29
- // Check if authentication is configured
30
  useEffect(() => {
31
  let isMounted = true; // Flag to prevent state updates after unmount
32
 
 
4
  import { loginToServer, getAuthStatus } from '@/api/lightrag'
5
  import { toast } from 'sonner'
6
  import { useTranslation } from 'react-i18next'
 
 
7
  import { Card, CardContent, CardHeader } from '@/components/ui/Card'
8
  import Input from '@/components/ui/Input'
9
  import Button from '@/components/ui/Button'
 
19
  const [password, setPassword] = useState('')
20
  const [checkingAuth, setCheckingAuth] = useState(true)
21
 
 
22
  useEffect(() => {
23
+ console.log('LoginPage mounted')
24
+ }, []);
25
 
26
+ // Check if authentication is configured, skip login if not
27
  useEffect(() => {
28
  let isMounted = true; // Flag to prevent state updates after unmount
29
 
lightrag_webui/src/features/SiteHeader.tsx CHANGED
@@ -6,8 +6,7 @@ import { useSettingsStore } from '@/stores/settings'
6
  import { useAuthStore } from '@/stores/state'
7
  import { cn } from '@/lib/utils'
8
  import { useTranslation } from 'react-i18next'
9
- import { useNavigate } from 'react-router-dom'
10
-
11
  import { ZapIcon, GithubIcon, LogOutIcon } from 'lucide-react'
12
 
13
  interface NavigationTabProps {
@@ -56,12 +55,10 @@ function TabsNavigation() {
56
 
57
  export default function SiteHeader() {
58
  const { t } = useTranslation()
59
- const navigate = useNavigate()
60
- const { logout, isGuestMode } = useAuthStore()
61
 
62
  const handleLogout = () => {
63
- logout()
64
- navigate('/login')
65
  }
66
 
67
  return (
 
6
  import { useAuthStore } from '@/stores/state'
7
  import { cn } from '@/lib/utils'
8
  import { useTranslation } from 'react-i18next'
9
+ import { navigationService } from '@/services/navigation'
 
10
  import { ZapIcon, GithubIcon, LogOutIcon } from 'lucide-react'
11
 
12
  interface NavigationTabProps {
 
55
 
56
  export default function SiteHeader() {
57
  const { t } = useTranslation()
58
+ const { isGuestMode } = useAuthStore()
 
59
 
60
  const handleLogout = () => {
61
+ navigationService.navigateToLogin();
 
62
  }
63
 
64
  return (
lightrag_webui/src/services/navigation.ts CHANGED
@@ -20,32 +20,51 @@ class NavigationService {
20
  resetAllApplicationState() {
21
  console.log('Resetting all application state...');
22
 
23
- // Clear authentication state
24
- localStorage.removeItem('LIGHTRAG-API-TOKEN');
25
- sessionStorage.clear();
26
- useAuthStore.getState().logout();
27
-
28
  // Reset graph state
29
  const graphStore = useGraphStore.getState();
 
30
  graphStore.reset();
31
  graphStore.setGraphDataFetchAttempted(false);
32
  graphStore.setLabelsFetchAttempted(false);
 
33
 
34
  // Reset backend state
35
  useBackendState.getState().clear();
36
 
37
  // Reset retrieval history while preserving other user preferences
38
  useSettingsStore.getState().setRetrievalHistory([]);
 
 
 
 
 
 
 
 
 
39
  }
40
 
41
  /**
42
- * Navigate to login page after resetting application state
43
- * to ensure a clean environment for the next session
 
 
 
 
 
 
 
 
 
 
 
 
44
  */
45
  navigateToLogin() {
46
- // Reset state before navigation
47
- this.resetAllApplicationState();
48
 
 
 
 
49
  if (this.navigate) {
50
  this.navigate('/login');
51
  }
 
20
  resetAllApplicationState() {
21
  console.log('Resetting all application state...');
22
 
 
 
 
 
 
23
  // Reset graph state
24
  const graphStore = useGraphStore.getState();
25
+ const sigma = graphStore.sigmaInstance;
26
  graphStore.reset();
27
  graphStore.setGraphDataFetchAttempted(false);
28
  graphStore.setLabelsFetchAttempted(false);
29
+ graphStore.setSigmaInstance(null);
30
 
31
  // Reset backend state
32
  useBackendState.getState().clear();
33
 
34
  // Reset retrieval history while preserving other user preferences
35
  useSettingsStore.getState().setRetrievalHistory([]);
36
+
37
+ // Clear authentication state
38
+ sessionStorage.clear();
39
+
40
+ if (sigma) {
41
+ sigma.getGraph().clear();
42
+ sigma.kill();
43
+ useGraphStore.getState().setSigmaInstance(null);
44
+ }
45
  }
46
 
47
  /**
48
+ * Handle direct access to login page
49
+ * @returns true if it's a direct access, false if navigated from another page
50
+ */
51
+ handleDirectLoginAccess() {
52
+ const isDirectAccess = !document.referrer;
53
+ if (isDirectAccess) {
54
+ this.resetAllApplicationState();
55
+ }
56
+ return isDirectAccess;
57
+ }
58
+
59
+ /**
60
+ * Navigate to login page and reset application state
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
  }