From 889dfca36cd739c2a02241386ef46402b3e5ed4c Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sat, 7 Mar 2026 07:43:00 -0600 Subject: [PATCH] Frontend fixes (#22309) * prevent unnecessary reloads in useUserPersistence hook * always render ProtectedRoute (handling undefined roles internally) and add Suspense fallback * add missing i18n namespaces react 19 enforces Suspense more strictly, so components using useTranslation() with unloaded namespaces would suspend, blanking the content behind the empty Suspense fallback * add missing namespace * remove unneeded * remove modal from actions dropdown --- web/src/App.tsx | 29 +++++++------------ web/src/components/auth/ProtectedRoute.tsx | 9 +++++- .../components/overlay/ActionsDropdown.tsx | 2 +- web/src/hooks/use-user-persistence.ts | 5 ++++ web/src/utils/i18n.ts | 18 ++++++++---- 5 files changed, 38 insertions(+), 25 deletions(-) diff --git a/web/src/App.tsx b/web/src/App.tsx index 21babc2b9..01c415de4 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -11,7 +11,6 @@ import { Redirect } from "./components/navigation/Redirect"; import { cn } from "./lib/utils"; import { isPWA } from "./utils/isPWA"; import ProtectedRoute from "@/components/auth/ProtectedRoute"; -import { AuthProvider } from "@/context/auth-context"; import useSWR from "swr"; import { FrigateConfig } from "./types/frigateConfig"; import ActivityIndicator from "@/components/indicators/activity-indicator"; @@ -39,13 +38,11 @@ function App() { return ( - - - - {config?.safe_mode ? : } - - - + + + {config?.safe_mode ? : } + + ); } @@ -85,17 +82,13 @@ function DefaultAppView() { : "bottom-8 left-[52px]", )} > - + + } + > - - ) : ( - - ) - } - > + }> } /> } /> } /> diff --git a/web/src/components/auth/ProtectedRoute.tsx b/web/src/components/auth/ProtectedRoute.tsx index a7d1b3596..bcfa8fdf3 100644 --- a/web/src/components/auth/ProtectedRoute.tsx +++ b/web/src/components/auth/ProtectedRoute.tsx @@ -10,7 +10,7 @@ import { export default function ProtectedRoute({ requiredRoles, }: { - requiredRoles: string[]; + requiredRoles?: string[]; }) { const { auth } = useContext(AuthContext); @@ -36,6 +36,13 @@ export default function ProtectedRoute({ ); } + // Wait for config to provide required roles + if (!requiredRoles) { + return ( + + ); + } + if (auth.isLoading) { return ( diff --git a/web/src/components/overlay/ActionsDropdown.tsx b/web/src/components/overlay/ActionsDropdown.tsx index d73ae71e3..9ddb0bd35 100644 --- a/web/src/components/overlay/ActionsDropdown.tsx +++ b/web/src/components/overlay/ActionsDropdown.tsx @@ -20,7 +20,7 @@ export default function ActionsDropdown({ const { t } = useTranslation(["components/dialog", "views/replay", "common"]); return ( - +