- AdminTestsPage with filters (q, tactic, opsec, tag), modal-based CRUD, markdown textareas for procedure/result/detection, embedded MitreTagPicker for tagging. - AdminScenariosPage with @dnd-kit/sortable drag-and-drop on the ordered test list, two-step save (PATCH metadata + PUT tests), catalogue picker excluding soft-deleted items. - lib/templates.ts typed client + queryKey factory. - MarkdownField helper (textarea with markdown hint label). - Layout adds Tests + Scenarios admin nav links; App.tsx routes both behind RequireAdmin. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
113 lines
3.5 KiB
TypeScript
113 lines
3.5 KiB
TypeScript
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
|
|
|
|
import { Layout } from '@/components/Layout';
|
|
import { RequireAdmin } from '@/components/RequireAdmin';
|
|
import { RequireAuth } from '@/components/RequireAuth';
|
|
import { AdminGroupsPage } from '@/pages/AdminGroupsPage';
|
|
import { AdminInvitationsPage } from '@/pages/AdminInvitationsPage';
|
|
import { AdminScenariosPage } from '@/pages/AdminScenariosPage';
|
|
import { AdminTestsPage } from '@/pages/AdminTestsPage';
|
|
import { AdminUsersPage } from '@/pages/AdminUsersPage';
|
|
import { HomePage } from '@/pages/HomePage';
|
|
import { MitrePage } from '@/pages/MitrePage';
|
|
import { LoginPage } from '@/pages/LoginPage';
|
|
import { ProfilePage } from '@/pages/ProfilePage';
|
|
import { RegisterPage } from '@/pages/RegisterPage';
|
|
import { SetupPage } from '@/pages/SetupPage';
|
|
import { AuthContext, useProvideAuth } from '@/lib/auth';
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
refetchOnWindowFocus: false,
|
|
staleTime: 30_000,
|
|
},
|
|
},
|
|
});
|
|
|
|
function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
const auth = useProvideAuth();
|
|
return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<BrowserRouter>
|
|
<AuthProvider>
|
|
<Routes>
|
|
<Route element={<Layout />}>
|
|
<Route path="/login" element={<LoginPage />} />
|
|
<Route path="/setup" element={<SetupPage />} />
|
|
<Route path="/register" element={<RegisterPage />} />
|
|
{/* Home page stays public — it's an ops dashboard, not sensitive. */}
|
|
<Route path="/" element={<HomePage />} />
|
|
<Route
|
|
path="/profile"
|
|
element={
|
|
<RequireAuth>
|
|
<ProfilePage />
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/mitre"
|
|
element={
|
|
<RequireAuth>
|
|
<MitrePage />
|
|
</RequireAuth>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/admin/users"
|
|
element={
|
|
<RequireAdmin>
|
|
<AdminUsersPage />
|
|
</RequireAdmin>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/admin/groups"
|
|
element={
|
|
<RequireAdmin>
|
|
<AdminGroupsPage />
|
|
</RequireAdmin>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/admin/invitations"
|
|
element={
|
|
<RequireAdmin>
|
|
<AdminInvitationsPage />
|
|
</RequireAdmin>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/admin/tests"
|
|
element={
|
|
<RequireAdmin>
|
|
<AdminTestsPage />
|
|
</RequireAdmin>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/admin/scenarios"
|
|
element={
|
|
<RequireAdmin>
|
|
<AdminScenariosPage />
|
|
</RequireAdmin>
|
|
}
|
|
/>
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Route>
|
|
</Routes>
|
|
</AuthProvider>
|
|
</BrowserRouter>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|
|
|
|
export default App;
|