Unify dark UI surfaces and add adjustable topology canvas background.

Lazy-load module routes, restyle remaining light cards/modals/sidebars, and let canvas background be tuned from the display menu.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-08-04 23:56:18 +08:00
parent 254c50a2c0
commit 3e7bfdb8e9
6 changed files with 722 additions and 344 deletions

View file

@ -1,33 +1,63 @@
import { lazy, Suspense } from "react";
import { Navigate, Route, Routes, useLocation } from "react-router-dom";
import { useQuery } from "@tanstack/react-query";
import { AppLayout } from "./layout/AppLayout";
import { queryKeys } from "./constants/queryKeys";
import { WorkbenchPage } from "./pages/WorkbenchPage";
import { CollectPage } from "./pages/CollectPage";
import { ConfigSyncPage } from "./pages/ConfigSyncPage";
import { NePage } from "./pages/NePage";
import { UmePage } from "./pages/UmePage";
import { WebcrtPage } from "./pages/WebcrtPage";
import { TopologyPage } from "./pages/TopologyPage";
import { NetworkLayout } from "./pages/network/NetworkLayout";
import { NetworkDevicesPage } from "./pages/network/NetworkDevicesPage";
import { NetworkAlarmsPage } from "./pages/network/NetworkAlarmsPage";
import { NetworkConfigsPage } from "./pages/network/NetworkConfigsPage";
import { LldpLinksPage } from "./pages/network/LldpLinksPage";
import { TopologyClassifyPage } from "./pages/network/TopologyClassifyPage";
import { PortTrafficPage } from "./pages/network/PortTrafficPage";
import { PortTrafficBoardListPage } from "./pages/network/PortTrafficBoardListPage";
import { PortTrafficWallPage } from "./pages/network/PortTrafficWallPage";
import { LoginPage } from "./pages/LoginPage";
import { UsersPage } from "./pages/UsersPage";
import { AuditLayout } from "./pages/audit/AuditLayout";
import { TaskOverviewPage } from "./pages/audit/TaskOverviewPage";
import { AuditPage } from "./pages/AuditPage";
import { ApiTokensPage } from "./pages/ApiTokensPage";
import { ForceChangePasswordPage } from "./pages/ForceChangePasswordPage";
import { fetchIntegrationStatus } from "./services/api";
import { useAuth } from "./auth/AuthContext";
const CollectPage = lazy(() => import("./pages/CollectPage").then((m) => ({ default: m.CollectPage })));
const ConfigSyncPage = lazy(() =>
import("./pages/ConfigSyncPage").then((m) => ({ default: m.ConfigSyncPage })),
);
const NePage = lazy(() => import("./pages/NePage").then((m) => ({ default: m.NePage })));
const UmePage = lazy(() => import("./pages/UmePage").then((m) => ({ default: m.UmePage })));
const WebcrtPage = lazy(() => import("./pages/WebcrtPage").then((m) => ({ default: m.WebcrtPage })));
const TopologyPage = lazy(() => import("./pages/TopologyPage").then((m) => ({ default: m.TopologyPage })));
const NetworkLayout = lazy(() =>
import("./pages/network/NetworkLayout").then((m) => ({ default: m.NetworkLayout })),
);
const NetworkDevicesPage = lazy(() =>
import("./pages/network/NetworkDevicesPage").then((m) => ({ default: m.NetworkDevicesPage })),
);
const NetworkAlarmsPage = lazy(() =>
import("./pages/network/NetworkAlarmsPage").then((m) => ({ default: m.NetworkAlarmsPage })),
);
const NetworkConfigsPage = lazy(() =>
import("./pages/network/NetworkConfigsPage").then((m) => ({ default: m.NetworkConfigsPage })),
);
const LldpLinksPage = lazy(() =>
import("./pages/network/LldpLinksPage").then((m) => ({ default: m.LldpLinksPage })),
);
const TopologyClassifyPage = lazy(() =>
import("./pages/network/TopologyClassifyPage").then((m) => ({ default: m.TopologyClassifyPage })),
);
const PortTrafficPage = lazy(() =>
import("./pages/network/PortTrafficPage").then((m) => ({ default: m.PortTrafficPage })),
);
const PortTrafficBoardListPage = lazy(() =>
import("./pages/network/PortTrafficBoardListPage").then((m) => ({
default: m.PortTrafficBoardListPage,
})),
);
const PortTrafficWallPage = lazy(() =>
import("./pages/network/PortTrafficWallPage").then((m) => ({ default: m.PortTrafficWallPage })),
);
const UsersPage = lazy(() => import("./pages/UsersPage").then((m) => ({ default: m.UsersPage })));
const AuditLayout = lazy(() =>
import("./pages/audit/AuditLayout").then((m) => ({ default: m.AuditLayout })),
);
const TaskOverviewPage = lazy(() =>
import("./pages/audit/TaskOverviewPage").then((m) => ({ default: m.TaskOverviewPage })),
);
const AuditPage = lazy(() => import("./pages/AuditPage").then((m) => ({ default: m.AuditPage })));
const ApiTokensPage = lazy(() =>
import("./pages/ApiTokensPage").then((m) => ({ default: m.ApiTokensPage })),
);
/** Preserve query when redirecting legacy /network/webcrt → /webcrt. */
function NetworkWebcrtRedirect() {
const { search } = useLocation();
@ -44,13 +74,21 @@ function LegacyPortTrafficWallRedirect() {
return <PortTrafficBoardListPage />;
}
function PageFallback() {
return (
<div className="page-loading" role="status" aria-live="polite">
Loading…
</div>
);
}
function ProtectedApp() {
const { ready, user } = useAuth();
const integrationsQuery = useQuery({
queryKey: queryKeys.integrationsStatus,
queryFn: fetchIntegrationStatus,
refetchInterval: 5000,
staleTime: 2000,
refetchInterval: 10_000,
staleTime: 5_000,
enabled: ready && Boolean(user) && !user?.must_change_password,
});
@ -95,38 +133,40 @@ function ProtectedApp() {
: undefined,
}}
>
<Routes>
<Route path="/" element={<WorkbenchPage />} />
<Route path="/workbench" element={<Navigate to="/" replace />} />
<Route path="/ume" element={<UmePage />} />
<Route path="/ne" element={<NePage />} />
<Route path="/topology" element={<TopologyPage />} />
<Route path="/webcrt" element={<WebcrtPage />} />
<Route path="/port-traffic/wall/:boardId" element={<PortTrafficWallPage />} />
<Route path="/network" element={<NetworkLayout />}>
<Route index element={<Navigate to="devices" replace />} />
<Route path="devices" element={<NetworkDevicesPage />} />
<Route path="alarms" element={<NetworkAlarmsPage />} />
<Route path="configs" element={<NetworkConfigsPage />} />
<Route path="topology/lldp" element={<LldpLinksPage />} />
<Route path="topology/classify" element={<TopologyClassifyPage />} />
<Route path="topology" element={<Navigate to="/network/topology/lldp" replace />} />
<Route path="webcrt" element={<NetworkWebcrtRedirect />} />
<Route path="tasks/collect" element={<CollectPage />} />
<Route path="tasks/config-sync" element={<ConfigSyncPage />} />
<Route path="tasks/port-traffic/wall" element={<LegacyPortTrafficWallRedirect />} />
<Route path="tasks/port-traffic" element={<PortTrafficPage />} />
</Route>
<Route path="/collect" element={<Navigate to="/network/tasks/collect" replace />} />
<Route path="/users" element={<UsersPage />} />
<Route path="/audit" element={<AuditLayout />}>
<Route index element={<Navigate to="tasks" replace />} />
<Route path="tasks" element={<TaskOverviewPage />} />
<Route path="logs" element={<AuditPage />} />
</Route>
<Route path="/api-keys" element={<ApiTokensPage />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
<Suspense fallback={<PageFallback />}>
<Routes>
<Route path="/" element={<WorkbenchPage />} />
<Route path="/workbench" element={<Navigate to="/" replace />} />
<Route path="/ume" element={<UmePage />} />
<Route path="/ne" element={<NePage />} />
<Route path="/topology" element={<TopologyPage />} />
<Route path="/webcrt" element={<WebcrtPage />} />
<Route path="/port-traffic/wall/:boardId" element={<PortTrafficWallPage />} />
<Route path="/network" element={<NetworkLayout />}>
<Route index element={<Navigate to="devices" replace />} />
<Route path="devices" element={<NetworkDevicesPage />} />
<Route path="alarms" element={<NetworkAlarmsPage />} />
<Route path="configs" element={<NetworkConfigsPage />} />
<Route path="topology/lldp" element={<LldpLinksPage />} />
<Route path="topology/classify" element={<TopologyClassifyPage />} />
<Route path="topology" element={<Navigate to="/network/topology/lldp" replace />} />
<Route path="webcrt" element={<NetworkWebcrtRedirect />} />
<Route path="tasks/collect" element={<CollectPage />} />
<Route path="tasks/config-sync" element={<ConfigSyncPage />} />
<Route path="tasks/port-traffic/wall" element={<LegacyPortTrafficWallRedirect />} />
<Route path="tasks/port-traffic" element={<PortTrafficPage />} />
</Route>
<Route path="/collect" element={<Navigate to="/network/tasks/collect" replace />} />
<Route path="/users" element={<UsersPage />} />
<Route path="/audit" element={<AuditLayout />}>
<Route index element={<Navigate to="tasks" replace />} />
<Route path="tasks" element={<TaskOverviewPage />} />
<Route path="logs" element={<AuditPage />} />
</Route>
<Route path="/api-keys" element={<ApiTokensPage />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</Suspense>
</AppLayout>
);
}