import { BrowserRouter, Routes, Route, NavLink, useLocation, Outlet, Navigate, } from "react-router-dom"; import { QueryClient, QueryClientProvider, useQuery, } from "@tanstack/react-query"; import { useEffect, useMemo, useState } from "react"; import { AuthProvider, useAuth } from "react-oidc-context"; import { Dashboard } from "./pages/Dashboard"; import { Applications } from "./pages/Applications"; import { Settings } from "./pages/Settings"; import { UsersPage } from "./pages/Users"; import { FileBrowser } from "./pages/FileBrowser"; import { Actions } from "./pages/Actions"; import BackupsPage from "./components/BackupsPage"; import { ObservabilityPage } from "./components/ObservabilityPage"; import { ServicePage } from "./pages/ServicePage"; import { ServicesPage } from "./pages/ServicesPage"; import { getOidcConfig, isOidcConfigured, setAccessToken } from "./auth"; import { fetchAppVersion } from "./api/client"; import { FRONTEND_VERSION_LABEL } from "./version"; import { usePersistentState } from "./hooks/usePersistentState"; import { useIsMobile } from "./hooks/useIsMobile"; import { Button } from "@/components/ui/button"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, } from "@/components/ui/sheet"; import { LayoutDashboard, Activity, DatabaseBackup, Monitor, Users, Zap, FolderOpen, Settings as SettingsIcon, Menu, Sun, Moon, LogOut, ChevronLeft, ChevronRight, Boxes, } from "lucide-react"; const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false, // Pause interval-based refetches (widgets ~30s, queue status 5s, // media build progress 1s) when the tab is hidden. Saves battery on // mobile (D8 follow-up). Build progress polls resume on return. refetchIntervalInBackground: false, }, }, }); function useDarkMode() { const [darkMode, setDarkMode] = usePersistentState( "dark-mode", () => window.matchMedia("(prefers-color-scheme: dark)").matches, ); useEffect(() => { const root = document.documentElement; if (darkMode) { root.classList.add("dark"); } else { root.classList.remove("dark"); } }, [darkMode]); return [darkMode, () => setDarkMode((prev) => !prev)] as const; } // Navigation items for sidebar const navItems = [ { path: "/", label: "Dashboard", icon: LayoutDashboard }, { path: "/observability", label: "Observability", icon: Activity }, { path: "/media", label: "Media", icon: Monitor }, { path: "/files", label: "Files", icon: FolderOpen }, { path: "/backups", label: "Backups", icon: DatabaseBackup }, { path: "/users", label: "Users", icon: Users }, { path: "/actions", label: "Actions", icon: Zap }, { path: "/services", label: "Services", icon: Boxes }, { path: "/settings", label: "Settings", icon: SettingsIcon }, ]; function Sidebar({ collapsed, onToggle, isMobile, }: { collapsed: boolean; onToggle: () => void; isMobile: boolean; }) { const location = useLocation(); if (isMobile) return null; return ( ); } function MobileDrawer() { const [open, setOpen] = useState(false); const location = useLocation(); return (
M
Manage
); } function TopBar({ darkMode, authLabel, onSignOut, onToggleDarkMode, }: { darkMode: boolean; authLabel?: string; onSignOut?: () => void; onToggleDarkMode: () => void; }) { const location = useLocation(); const { data: appVersion } = useQuery({ queryKey: ["app-version"], queryFn: fetchAppVersion, staleTime: 60 * 60 * 1000, }); const backendLabel = appVersion?.backend_label || "…"; const pageTitle = navItems.find((item) => item.path === location.pathname)?.label || "Dashboard"; return (

{pageTitle}

FE {FRONTEND_VERSION_LABEL} BE {backendLabel} {authLabel && ( {authLabel} )} {onSignOut && ( )}
); } function ShellLayout({ darkMode, authLabel, onSignOut, onToggleDarkMode, }: { darkMode: boolean; authLabel?: string; onSignOut?: () => void; onToggleDarkMode: () => void; }) { const [sidebarCollapsed, setSidebarCollapsed] = useState(false); const isMobile = useIsMobile(); return (
setSidebarCollapsed(!sidebarCollapsed)} isMobile={isMobile} />
); } function LoadingScreen({ label }: { label: string }) { return (

{label}

); } function SignInScreen({ onSignIn }: { onSignIn: () => void }) { return (

Sign in required

Use your Authentik account to access Manage.

); } function AuthenticatedApp() { const auth = useAuth(); const [darkMode, toggleDarkMode] = useDarkMode(); useEffect(() => { setAccessToken(auth.user?.access_token ?? null); }, [auth.user?.access_token]); const authLabel = useMemo(() => { const profile = auth.user?.profile as Record | undefined; return String( profile?.name ?? profile?.preferred_username ?? profile?.email ?? auth.user?.profile?.sub ?? "Authenticated", ); }, [auth.user]); if (auth.isLoading || auth.activeNavigator) { return ; } if (auth.error) { return ( ); } if (!auth.isAuthenticated) { return void auth.signinRedirect()} />; } return ( void auth.signoutRedirect()} onToggleDarkMode={toggleDarkMode} /> ); } function AppInner() { const [darkMode, toggleDarkMode] = useDarkMode(); return ( {isOidcConfigured() ? ( }> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> ) : ( } > } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> )} ); } export default function App() { return ; }