Add RuntimeSettingsRead/RuntimeSettingsUpdate schemas with flow_retention_hours field (1-8760 hours), implement runtime_setting helper to initialize/fetch runtime system setting with 24h default, add require_super_admin guard to validate * permission, update agent_heartbeat to use configurable retention_cutoff from runtime settings instead of hardcoded 24h, replace /settings GET endpoint to return RuntimeSettingsRead with flow_retention_hours,
87 lines
3.7 KiB
TypeScript
87 lines
3.7 KiB
TypeScript
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
|
|
import { useEffect } from "react";
|
|
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
|
|
|
|
import { publicApi, SetupStatus } from "./api/client";
|
|
import { Layout } from "./components/Layout";
|
|
import { Dashboard } from "./pages/Dashboard";
|
|
import { FirewallPreview } from "./pages/FirewallPreview";
|
|
import { Clusters } from "./pages/Clusters";
|
|
import { Ipam } from "./pages/Ipam";
|
|
import { ListPage } from "./pages/ListPage";
|
|
import { Login } from "./pages/Login";
|
|
import { Networks } from "./pages/Networks";
|
|
import { Nodes } from "./pages/Nodes";
|
|
import { Policies } from "./pages/Policies";
|
|
import { PolicyDesigner } from "./pages/PolicyDesigner";
|
|
import { SecurityGroups } from "./pages/SecurityGroups";
|
|
import { ServiceCatalog } from "./pages/ServiceCatalog";
|
|
import { Settings } from "./pages/Settings";
|
|
import { SetupWizard } from "./pages/SetupWizard";
|
|
import { TenantsProjects } from "./pages/TenantsProjects";
|
|
import { UsersRoles } from "./pages/UsersRoles";
|
|
import { WorkloadDetail, WorkloadFlows, Workloads } from "./pages/Workloads";
|
|
import { useTheme } from "./stores/theme";
|
|
|
|
const queryClient = new QueryClient();
|
|
|
|
function AppRoutes() {
|
|
const setup = useQuery({ queryKey: ["setup-status"], queryFn: () => publicApi<SetupStatus>("/setup/status") });
|
|
|
|
if (setup.isLoading) {
|
|
return <div className="grid min-h-screen place-items-center bg-canvas text-sm">Loading NexaFabric...</div>;
|
|
}
|
|
|
|
if (!setup.data?.complete) {
|
|
return (
|
|
<Routes>
|
|
<Route path="/setup" element={<SetupWizard />} />
|
|
<Route path="*" element={<Navigate to="/setup" replace />} />
|
|
</Routes>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Routes>
|
|
<Route path="/setup" element={<Navigate to="/login" replace />} />
|
|
<Route path="/login" element={<Login />} />
|
|
<Route element={<Layout />}>
|
|
<Route index element={<Dashboard />} />
|
|
<Route path="clusters" element={<Clusters />} />
|
|
<Route path="nodes" element={<Nodes />} />
|
|
<Route path="workloads" element={<Workloads />} />
|
|
<Route path="workloads/:workloadId" element={<WorkloadDetail />} />
|
|
<Route path="workloads/:workloadId/flows" element={<WorkloadFlows />} />
|
|
<Route path="networks" element={<Networks />} />
|
|
<Route path="ipam" element={<Ipam />} />
|
|
<Route path="tenants" element={<TenantsProjects />} />
|
|
<Route path="security-groups" element={<SecurityGroups />} />
|
|
<Route path="policies" element={<Policies />} />
|
|
<Route path="services" element={<ServiceCatalog />} />
|
|
<Route path="designer" element={<PolicyDesigner />} />
|
|
<Route path="firewall" element={<FirewallPreview />} />
|
|
<Route path="jobs" element={<ListPage title="Jobs" subtitle="Background task state and execution logs." path="/jobs" columns={[{ key: "kind", label: "Kind" }, { key: "status", label: "Status" }, { key: "progress", label: "Progress" }]} />} />
|
|
<Route path="audit" element={<ListPage title="Audit Logs" subtitle="Security-relevant activity and change history." path="/audit" columns={[{ key: "created_at", label: "Time" }, { key: "action", label: "Action" }, { key: "object_type", label: "Object" }, { key: "result", label: "Result" }]} />} />
|
|
<Route path="users" element={<UsersRoles />} />
|
|
<Route path="settings" element={<Settings />} />
|
|
</Route>
|
|
</Routes>
|
|
);
|
|
}
|
|
|
|
export function App() {
|
|
const dark = useTheme((state) => state.dark);
|
|
|
|
useEffect(() => {
|
|
document.documentElement.classList.toggle("dark", dark);
|
|
}, [dark]);
|
|
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<BrowserRouter>
|
|
<AppRoutes />
|
|
</BrowserRouter>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|