diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index db3626f..c5db70d 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,12 +1,13 @@ // Orchestration Engine - App Router // -// Depends on: hooks/useAuth.tsx, components/AuthGuard.tsx, components/Layout.tsx, -// components/ErrorBoundary.tsx +// Depends on: hooks/useAuth.tsx, components/AuthGuard.tsx, components/RequireRole.tsx, +// components/Layout.tsx, components/ErrorBoundary.tsx // Used by: main.tsx import { BrowserRouter, Routes, Route } from 'react-router-dom' import { AuthProvider } from './hooks/useAuth' import AuthGuard from './components/AuthGuard' +import RequireRole from './components/RequireRole' import ErrorBoundary from './components/ErrorBoundary' import Layout from './components/Layout' import Login from './pages/Login' @@ -41,9 +42,12 @@ export default function App() { } /> } /> } /> - } /> - } /> } /> + {/* Admin-only routes */} + }> + } /> + } /> + diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index d1d11c8..6fb4831 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -10,7 +10,7 @@ import { getAccessToken, apiRefresh } from './auth' const BASE = '/api' -async function authFetch(path: string, init?: RequestInit): Promise { +export async function authFetch(path: string, init?: RequestInit): Promise { const token = getAccessToken() const headers = new Headers(init?.headers) if (token) { diff --git a/frontend/src/api/projects.ts b/frontend/src/api/projects.ts index 924fd1e..4366b51 100644 --- a/frontend/src/api/projects.ts +++ b/frontend/src/api/projects.ts @@ -1,6 +1,6 @@ // Orchestration Engine - Projects API -import { apiFetch, apiPost, apiPatch, apiDelete } from './client' +import { apiFetch, apiPost, apiPatch, apiDelete, authFetch } from './client' import type { Project, Plan, Task, Checkpoint, CoverageReport, PlanningRigor } from '../types' export const listProjects = (status?: string) => @@ -83,11 +83,7 @@ export const cloneProject = (projectId: string) => apiPost(`/projects/${projectId}/clone`) export const exportProject = async (projectId: string) => { - const { getAccessToken } = await import('./auth') - const token = getAccessToken() - const resp = await fetch(`/api/projects/${projectId}/export`, { - headers: token ? { Authorization: `Bearer ${token}` } : {}, - }) + const resp = await authFetch(`/projects/${projectId}/export`) if (!resp.ok) throw new Error('Export failed') const blob = await resp.blob() const url = URL.createObjectURL(blob) diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index e16ad38..30755b1 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -13,7 +13,7 @@ export default function Layout() { return (
-