diff --git a/frontend/src/Pages/RouteOverviewPage/RouteOverviewPage.tsx b/frontend/src/Pages/RouteOverviewPage/RouteOverviewPage.tsx index 27125d587..0a07406e1 100644 --- a/frontend/src/Pages/RouteOverviewPage/RouteOverviewPage.tsx +++ b/frontend/src/Pages/RouteOverviewPage/RouteOverviewPage.tsx @@ -1,6 +1,33 @@ import { useState } from 'react'; import { Button, Link, Page } from '~/Components'; import { ROUTES } from '~/routes'; +import { downloadFrontendRoutesJson } from '~/routes/export'; + +type RouteEntry = { + name: string; + path: string; +}; + +function collectRouteEntries(routes: unknown, parentName = ''): RouteEntry[] { + if (typeof routes !== 'object' || routes === null) { + return []; + } + + const entries: RouteEntry[] = []; + + for (const [name, value] of Object.entries(routes)) { + const fullName = parentName ? `${parentName}.${name}` : name; + + if (typeof value === 'string') { + entries.push({ name: fullName, path: value }); + continue; + } + + entries.push(...collectRouteEntries(value, fullName)); + } + + return entries; +} export function RouteOverviewPage() { const [showName, setShowName] = useState(false); @@ -8,6 +35,7 @@ export function RouteOverviewPage() { return ( +

Routes


@@ -15,18 +43,17 @@ export function RouteOverviewPage() { {Object.entries(ROUTES).map((domainRouteObj) => { const domain = domainRouteObj[0]; const domainRoutes = domainRouteObj[1]; + const routeEntries = collectRouteEntries(domainRoutes); return (

{domain}:


- {Object.entries(domainRoutes).map((routes) => { - const routeName = routes[0]; - const route = routes[1]; - const displayName = showName ? routeName : route; + {routeEntries.map((routeEntry) => { + const displayName = showName ? routeEntry.name : routeEntry.path; return ( - - {displayName} + + {displayName}
); diff --git a/frontend/src/routes/export.ts b/frontend/src/routes/export.ts new file mode 100644 index 000000000..8ac103755 --- /dev/null +++ b/frontend/src/routes/export.ts @@ -0,0 +1,34 @@ +import { ROUTES } from './index'; + +export type FrontendRouteExport = { + name: keyof typeof ROUTES.frontend; + path: (typeof ROUTES.frontend)[keyof typeof ROUTES.frontend]; +}; + +export function getFrontendRoutesForExport(): FrontendRouteExport[] { + return Object.entries(ROUTES.frontend).map(([name, path]) => ({ + name: name as keyof typeof ROUTES.frontend, + path: path as (typeof ROUTES.frontend)[keyof typeof ROUTES.frontend], + })); +} + +export function getFrontendRoutesExportJson(pretty = true): string { + return JSON.stringify(getFrontendRoutesForExport(), null, pretty ? 2 : 0); +} + +export function downloadFrontendRoutesJson(fileName = 'frontend-routes.json'): void { + const json = getFrontendRoutesExportJson(); + const blob = new Blob([json], { type: 'application/json' }); + const objectUrl = URL.createObjectURL(blob); + + try { + const anchor = document.createElement('a'); + anchor.href = objectUrl; + anchor.download = fileName; + document.body.append(anchor); + anchor.click(); + anchor.remove(); + } finally { + URL.revokeObjectURL(objectUrl); + } +}