feat: initial public release
ConsentOS — a privacy-first cookie consent management platform. Self-hosted, source-available alternative to OneTrust, Cookiebot, and CookieYes. Full standards coverage (IAB TCF v2.2, GPP v1, Google Consent Mode v2, GPC, Shopify Customer Privacy API), multi-tenant architecture with role-based access, configuration cascade (system → org → group → site → region), dark-pattern detection in the scanner, and a tamper-evident consent record audit trail. This is the initial public release. Prior development history is retained internally. See README.md for the feature list, architecture overview, and quick-start instructions. Licensed under the Elastic Licence 2.0 — self-host freely; do not resell as a managed service.
This commit is contained in:
90
apps/admin-ui/src/App.tsx
Normal file
90
apps/admin-ui/src/App.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
BrowserRouter,
|
||||
Navigate,
|
||||
Route,
|
||||
Routes,
|
||||
useLocation,
|
||||
} from 'react-router-dom';
|
||||
|
||||
import Layout from './components/Layout';
|
||||
import { trackPageView } from './services/analytics';
|
||||
import ProtectedRoute from './components/ProtectedRoute';
|
||||
import ComplianceDashboardPage from './pages/ComplianceDashboardPage';
|
||||
import LoginPage from './pages/LoginPage';
|
||||
import SettingsPage from './pages/SettingsPage';
|
||||
import SiteDetailPage from './pages/SiteDetailPage';
|
||||
import SiteGroupDetailPage from './pages/SiteGroupDetailPage';
|
||||
import SitesPage from './pages/SitesPage';
|
||||
import { useAuthStore } from './stores/auth';
|
||||
import { discoverExtensions, getPages } from './extensions/registry';
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: 1,
|
||||
staleTime: 30_000,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function AppRoutes() {
|
||||
const { loadUser, isAuthenticated } = useAuthStore();
|
||||
const location = useLocation();
|
||||
const [extensionsReady, setExtensionsReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
loadUser();
|
||||
discoverExtensions().then(() => setExtensionsReady(true));
|
||||
}, [loadUser]);
|
||||
|
||||
useEffect(() => {
|
||||
trackPageView(location.pathname);
|
||||
}, [location.pathname]);
|
||||
|
||||
const extensionPages = extensionsReady ? getPages() : [];
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Layout />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
>
|
||||
<Route path="/sites" element={<SitesPage />} />
|
||||
<Route path="/sites/:siteId" element={<SiteDetailPage />} />
|
||||
<Route path="/groups/:groupId" element={<SiteGroupDetailPage />} />
|
||||
<Route path="/compliance" element={<ComplianceDashboardPage />} />
|
||||
<Route path="/settings" element={<SettingsPage />} />
|
||||
{extensionPages
|
||||
.filter((p) => p.protected !== false)
|
||||
.map((p) => (
|
||||
<Route key={p.path} path={p.path} element={<p.component />} />
|
||||
))}
|
||||
</Route>
|
||||
{extensionPages
|
||||
.filter((p) => p.protected === false)
|
||||
.map((p) => (
|
||||
<Route key={p.path} path={p.path} element={<p.component />} />
|
||||
))}
|
||||
<Route
|
||||
path="*"
|
||||
element={<Navigate to={isAuthenticated ? '/sites' : '/login'} replace />}
|
||||
/>
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<BrowserRouter>
|
||||
<AppRoutes />
|
||||
</BrowserRouter>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user