fix: flatten React Router structure — no nested Routes, each page is a top-level route
This commit is contained in:
+30
-48
@@ -27,8 +27,8 @@ function Loading() {
|
||||
)
|
||||
}
|
||||
|
||||
/** Redirect to /login if not authenticated. */
|
||||
function RequireAuth({ children }: { children: ReactNode }) {
|
||||
/** Protected route wrapper — redirects to /login if not authenticated */
|
||||
function ProtectedRoute({ children }: { children: ReactNode }) {
|
||||
const { isAuthenticated } = useAuth()
|
||||
const location = useLocation()
|
||||
|
||||
@@ -38,14 +38,13 @@ function RequireAuth({ children }: { children: ReactNode }) {
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
/** Redirect to /dashboard if already authenticated. */
|
||||
function RedirectIfAuth({ children }: { children: ReactNode }) {
|
||||
/** Login page wrapper — redirects to / if already authenticated */
|
||||
function LoginRoute() {
|
||||
const { isAuthenticated } = useAuth()
|
||||
|
||||
if (isAuthenticated) {
|
||||
return <Navigate to="/" replace />
|
||||
}
|
||||
return <>{children}</>
|
||||
return <LoginPage />
|
||||
}
|
||||
|
||||
function AppRoutes() {
|
||||
@@ -60,14 +59,12 @@ function AppRoutes() {
|
||||
if (res.data.profiles.length > 0) {
|
||||
groups.push({
|
||||
label: 'Profiles',
|
||||
items: res.data.profiles.map((p) => ({
|
||||
items: res.data.profiles.map((p: any) => ({
|
||||
value: '/gateway',
|
||||
label: (
|
||||
<span className="flex items-center gap-2">
|
||||
{p.name}
|
||||
<Badge variant={p.status === 'online' ? 'success' : 'danger'}>
|
||||
{p.status}
|
||||
</Badge>
|
||||
<Badge variant={p.status === 'online' ? 'success' : 'danger'}>{p.status}</Badge>
|
||||
</span>
|
||||
),
|
||||
})),
|
||||
@@ -76,7 +73,7 @@ function AppRoutes() {
|
||||
if (res.data.kanban_tasks.length > 0) {
|
||||
groups.push({
|
||||
label: 'Kanban 任务',
|
||||
items: res.data.kanban_tasks.map((t) => ({
|
||||
items: res.data.kanban_tasks.map((t: any) => ({
|
||||
value: '/kanban',
|
||||
label: (
|
||||
<span className="flex items-center gap-2">
|
||||
@@ -90,7 +87,7 @@ function AppRoutes() {
|
||||
if (res.data.cron_jobs.length > 0) {
|
||||
groups.push({
|
||||
label: 'Cron 任务',
|
||||
items: res.data.cron_jobs.map((j) => ({
|
||||
items: res.data.cron_jobs.map((j: any) => ({
|
||||
value: '/cron',
|
||||
label: (
|
||||
<span className="flex items-center gap-2">
|
||||
@@ -104,7 +101,7 @@ function AppRoutes() {
|
||||
if (res.data.events.length > 0) {
|
||||
groups.push({
|
||||
label: '事件',
|
||||
items: res.data.events.map((e) => ({
|
||||
items: res.data.events.map((e: any) => ({
|
||||
value: '/events',
|
||||
label: (
|
||||
<span className="flex items-center gap-2">
|
||||
@@ -127,42 +124,27 @@ function AppRoutes() {
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<RedirectIfAuth>
|
||||
<LoginPage />
|
||||
</RedirectIfAuth>
|
||||
}
|
||||
/>
|
||||
{/* Public */}
|
||||
<Route path="/login" element={<LoginRoute />} />
|
||||
<Route path="/404" element={<NotFoundPage />} />
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}>
|
||||
<Suspense fallback={<Loading />}>
|
||||
<Routes>
|
||||
<Route index element={<Navigate to="dashboard" replace />} />
|
||||
<Route path="dashboard" element={<DashboardPage />} />
|
||||
<Route path="gateway" element={<GatewayPage />} />
|
||||
<Route path="health" element={<HealthPage />} />
|
||||
<Route path="kanban" element={<KanbanPage />} />
|
||||
<Route path="cron" element={<CronPage />} />
|
||||
<Route path="keys" element={<KeysPage />} />
|
||||
<Route path="events" element={<EventArchivePage />} />
|
||||
{user?.role === 'owner' && (
|
||||
<>
|
||||
<Route path="users" element={<UserManagementPage />} />
|
||||
<Route path="audit" element={<AuditLogPage />} />
|
||||
</>
|
||||
)}
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</AppLayout>
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Protected — each page is its own route (no nested Routes) */}
|
||||
<Route path="/" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><DashboardPage /></AppLayout></ProtectedRoute>} />
|
||||
<Route path="/dashboard" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><DashboardPage /></AppLayout></ProtectedRoute>} />
|
||||
<Route path="/gateway" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><GatewayPage /></AppLayout></ProtectedRoute>} />
|
||||
<Route path="/health" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><HealthPage /></AppLayout></ProtectedRoute>} />
|
||||
<Route path="/kanban" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><KanbanPage /></AppLayout></ProtectedRoute>} />
|
||||
<Route path="/cron" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><CronPage /></AppLayout></ProtectedRoute>} />
|
||||
<Route path="/keys" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><KeysPage /></AppLayout></ProtectedRoute>} />
|
||||
<Route path="/events" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><EventArchivePage /></AppLayout></ProtectedRoute>} />
|
||||
{user?.role === 'owner' && (
|
||||
<>
|
||||
<Route path="/users" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><UserManagementPage /></AppLayout></ProtectedRoute>} />
|
||||
<Route path="/audit" element={<ProtectedRoute><AppLayout onSearch={handleSearch} onSearchNavigate={handleSearchNavigate}><AuditLogPage /></AppLayout></ProtectedRoute>} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Catch-all */}
|
||||
<Route path="*" element={<Navigate to="/404" replace />} />
|
||||
</Routes>
|
||||
)
|
||||
|
||||
@@ -269,7 +269,7 @@ export default function HealthPage() {
|
||||
{/* table */}
|
||||
<Table columns={columns} data={tableData as any} rowKey="key"
|
||||
onRowClick={(record) => setExpandedRow(expandedRow === record.key ? null : String(record.key))}
|
||||
rowClassName={(record) => String(record.grade?.props?.grade || '') === 'D' ? 'row-danger' : ''} />
|
||||
rowClassName={(record: any) => String(record._grade || '') === 'D' ? 'row-danger' : ''} />
|
||||
|
||||
{/* expanded detail */}
|
||||
{expandedRow && (
|
||||
|
||||
Reference in New Issue
Block a user