mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-06-03 00:39:48 +08:00
first commit
This commit is contained in:
61
web/src/router/ProtectedRoute.test.tsx
Normal file
61
web/src/router/ProtectedRoute.test.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { MemoryRouter, Routes, Route } from 'react-router-dom'
|
||||
import { ProtectedRoute } from './ProtectedRoute'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
|
||||
describe('ProtectedRoute', () => {
|
||||
beforeEach(() => {
|
||||
useAuthStore.setState({
|
||||
token: '',
|
||||
user: null,
|
||||
status: 'anonymous',
|
||||
bootstrapped: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('redirects anonymous users to login', () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/dashboard']}>
|
||||
<Routes>
|
||||
<Route path="/login" element={<div>login page</div>} />
|
||||
<Route
|
||||
path="/dashboard"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<div>dashboard page</div>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</MemoryRouter>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('login page')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders protected content for authenticated users', () => {
|
||||
useAuthStore.setState({
|
||||
token: 'token',
|
||||
user: { id: 1, username: 'admin', displayName: 'Admin', role: 'admin' },
|
||||
status: 'authenticated',
|
||||
bootstrapped: true,
|
||||
})
|
||||
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/dashboard']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/dashboard"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<div>dashboard page</div>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</MemoryRouter>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('dashboard page')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
24
web/src/router/ProtectedRoute.tsx
Normal file
24
web/src/router/ProtectedRoute.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ReactNode } from 'react'
|
||||
import { Navigate, useLocation } from 'react-router-dom'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
import { FullPageLoading } from '../components/FullPageLoading'
|
||||
|
||||
interface ProtectedRouteProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export function ProtectedRoute({ children }: ProtectedRouteProps) {
|
||||
const status = useAuthStore((state) => state.status)
|
||||
const bootstrapped = useAuthStore((state) => state.bootstrapped)
|
||||
const location = useLocation()
|
||||
|
||||
if (!bootstrapped || status === 'loading') {
|
||||
return <FullPageLoading tip="正在验证登录状态..." />
|
||||
}
|
||||
|
||||
if (status !== 'authenticated') {
|
||||
return <Navigate to="/login" replace state={{ from: location.pathname }} />
|
||||
}
|
||||
|
||||
return <>{children}</>
|
||||
}
|
||||
40
web/src/router/index.tsx
Normal file
40
web/src/router/index.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Navigate, Route, Routes } from 'react-router-dom'
|
||||
import { AppLayout } from '../layouts/AppLayout'
|
||||
import { DashboardPage } from '../pages/dashboard/DashboardPage'
|
||||
import { LoginPage } from '../pages/login/LoginPage'
|
||||
import { NotificationsPage } from '../pages/notifications/NotificationsPage'
|
||||
import { BackupRecordsPage } from '../pages/backup-records/BackupRecordsPage'
|
||||
import { BackupTasksPage } from '../pages/backup-tasks/BackupTasksPage'
|
||||
import { GoogleDriveCallbackPage } from '../pages/storage-targets/GoogleDriveCallbackPage'
|
||||
import { StorageTargetsPage } from '../pages/storage-targets/StorageTargetsPage'
|
||||
import { SettingsPage } from '../pages/settings/SettingsPage'
|
||||
import NodesPage from '../pages/nodes/NodesPage'
|
||||
import { ProtectedRoute } from './ProtectedRoute'
|
||||
|
||||
export function RouterView() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<AppLayout />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
>
|
||||
<Route index element={<Navigate to="/dashboard" replace />} />
|
||||
<Route path="dashboard" element={<DashboardPage />} />
|
||||
<Route path="backup/tasks" element={<BackupTasksPage />} />
|
||||
<Route path="backup/records" element={<BackupRecordsPage />} />
|
||||
<Route path="storage-targets" element={<StorageTargetsPage />} />
|
||||
<Route path="storage-targets/google-drive/callback" element={<GoogleDriveCallbackPage />} />
|
||||
<Route path="settings" element={<SettingsPage />} />
|
||||
<Route path="settings/notifications" element={<NotificationsPage />} />
|
||||
<Route path="nodes" element={<NodesPage />} />
|
||||
<Route path="system-info" element={<Navigate to="/settings" replace />} />
|
||||
</Route>
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user