import { Component, type ErrorInfo, type ReactNode, lazy, Suspense, useEffect, useRef, } from "react"; import { Navigate, NavLink, Route, Routes, useLocation, } from "react-router-dom"; import type { BackupToolClient, Components } from "../api/generated/client"; import type { OperatorPageProps } from "./OperatorPages"; type SessionUser = Components["schemas"]["SessionUser"]; type RouteDefinition = { path: string; label: string; title: string; component: React.LazyExoticComponent>; }; const DashboardPage = lazy(() => import("./OperatorPages").then(({ DashboardPage: Page }) => ({ default: Page, })), ); const SourcesPage = lazy(() => import("./OperatorPages").then(({ SourcesPage: Page }) => ({ default: Page, })), ); const RepositoriesPage = lazy(() => import("./OperatorPages").then(({ RepositoriesPage: Page }) => ({ default: Page, })), ); const JobsPage = lazy(() => import("./OperatorPages").then(({ JobsPage: Page }) => ({ default: Page })), ); const ExecutionsPage = lazy(() => import("./OperatorPages").then(({ ExecutionsPage: Page }) => ({ default: Page, })), ); const BackupsPage = lazy(() => import("./M13Workflows").then(({ BackupsPage: Page }) => ({ default: Page })), ); const SecurityPage = lazy(() => import("./M13Workflows").then(({ SecurityPage: Page }) => ({ default: Page, })), ); const NotificationsPage = lazy(() => import("./M13Workflows").then(({ NotificationsPage: Page }) => ({ default: Page, })), ); const AuditPage = lazy(() => import("./M13Workflows").then(({ AuditPage: Page }) => ({ default: Page })), ); const AdministrationPage = lazy(() => import("./AdministrationPage").then(({ AdministrationPage: Page }) => ({ default: Page, })), ); const routes: RouteDefinition[] = [ { path: "/dashboard", label: "Dashboard", title: "Dashboard", component: DashboardPage, }, { path: "/sources", label: "Sources", title: "Sources", component: SourcesPage, }, { path: "/repositories", label: "Repositories", title: "Repositories", component: RepositoriesPage, }, { path: "/jobs", label: "Jobs & schedules", title: "Jobs & schedules", component: JobsPage, }, { path: "/executions", label: "Executions", title: "Executions", component: ExecutionsPage, }, { path: "/backups", label: "Backups", title: "Backups", component: BackupsPage, }, { path: "/security", label: "Security & recovery", title: "Security & recovery", component: SecurityPage, }, { path: "/notifications", label: "Notifications", title: "Notifications", component: NotificationsPage, }, { path: "/audit", label: "Audit", title: "Audit", component: AuditPage }, { path: "/administration", label: "Administration", title: "Administration", component: AdministrationPage, }, ]; class RouteErrorBoundary extends Component< { children: ReactNode }, { error?: Error } > { state: { error?: Error } = {}; static getDerivedStateFromError(error: Error) { return { error }; } componentDidCatch(_error: Error, _info: ErrorInfo) {} componentDidUpdate(previousProps: Readonly<{ children: ReactNode }>) { if (this.state.error && previousProps.children !== this.props.children) this.setState({ error: undefined }); } render() { if (this.state.error) return (

Page unavailable

This page could not be loaded. Try another page or refresh your browser.

); return this.props.children; } } function RouteLoading() { return (

Loading page…

); } function SkipLink() { return ( { event.preventDefault(); document.getElementById("main-content")?.focus(); }} > Skip to main content ); } function PageRoute({ component: Page, ...props }: RouteDefinition & OperatorPageProps) { return ( }> ); } function RouteEffects() { const { pathname } = useLocation(); const hasMounted = useRef(false); useEffect(() => { const route = routes.find((item) => item.path === pathname); document.title = `${route?.title ?? "Dashboard"} | Backup Tool`; if (hasMounted.current) document.getElementById("main-content")?.focus(); hasMounted.current = true; }, [pathname]); return null; } export function OperatorViews({ client, onSessionExpired, user, }: { client: BackupToolClient; onSessionExpired: () => void; user: SessionUser; }) { const pageProps = { client, onSessionExpired }; return (

Backup Tool

Operator console

Signed in as {user.username}

} path="/" /> {routes.map((route) => ( } key={route.path} path={route.path} /> ))} } path="*" />
); }