From 890ae6ae50017dabe43a5f818fbec1dd74b4f2dd Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 26 Nov 2025 10:42:22 -0600 Subject: [PATCH] fix camera group access for non admin users changes from previous PR wrongly included users from the standard viewer role (but excluded custom viewer roles) --- .../components/filter/CameraGroupSelector.tsx | 24 +++++++++---------- web/src/pages/Live.tsx | 8 +++---- web/src/views/live/LiveDashboardView.tsx | 6 ++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/web/src/components/filter/CameraGroupSelector.tsx b/web/src/components/filter/CameraGroupSelector.tsx index c772bc2ba..295477b2a 100644 --- a/web/src/components/filter/CameraGroupSelector.tsx +++ b/web/src/components/filter/CameraGroupSelector.tsx @@ -78,7 +78,7 @@ import { useStreamingSettings } from "@/context/streaming-settings-provider"; import { Trans, useTranslation } from "react-i18next"; import { CameraNameLabel } from "../camera/FriendlyNameLabel"; import { useAllowedCameras } from "@/hooks/use-allowed-cameras"; -import { useIsCustomRole } from "@/hooks/use-is-custom-role"; +import { useIsAdmin } from "@/hooks/use-is-admin"; type CameraGroupSelectorProps = { className?: string; @@ -88,7 +88,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { const { t } = useTranslation(["components/camera"]); const { data: config } = useSWR("config"); const allowedCameras = useAllowedCameras(); - const isCustomRole = useIsCustomRole(); + const isAdmin = useIsAdmin(); // tooltip @@ -124,7 +124,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { const allGroups = Object.entries(config.camera_groups); // If custom role, filter out groups where user has no accessible cameras - if (isCustomRole) { + if (!isAdmin) { return allGroups .filter(([, groupConfig]) => { // Check if user has access to at least one camera in this group @@ -136,7 +136,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { } return allGroups.sort((a, b) => a[1].order - b[1].order); - }, [config, allowedCameras, isCustomRole]); + }, [config, allowedCameras, isAdmin]); // add group @@ -153,7 +153,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { activeGroup={group} setGroup={setGroup} deleteGroup={deleteGroup} - isCustomRole={isCustomRole} + isAdmin={isAdmin} />
void; deleteGroup: () => void; - isCustomRole?: boolean; + isAdmin?: boolean; }; function NewGroupDialog({ open, @@ -254,7 +254,7 @@ function NewGroupDialog({ activeGroup, setGroup, deleteGroup, - isCustomRole, + isAdmin, }: NewGroupDialogProps) { const { t } = useTranslation(["components/camera"]); const { mutate: updateConfig } = useSWR("config"); @@ -390,7 +390,7 @@ function NewGroupDialog({ > {t("group.label")} {t("group.edit")} - {!isCustomRole && ( + {isAdmin && (
onDeleteGroup(group[0])} onEditGroup={() => onEditGroup(group)} - isReadOnly={isCustomRole} + isReadOnly={!isAdmin} /> ))}
@@ -677,7 +677,7 @@ export function CameraGroupEdit({ ); const allowedCameras = useAllowedCameras(); - const isCustomRole = useIsCustomRole(); + const isAdmin = useIsAdmin(); const [openCamera, setOpenCamera] = useState(); @@ -867,7 +867,7 @@ export function CameraGroupEdit({ {[ ...(birdseyeConfig?.enabled && - (!isCustomRole || "birdseye" in allowedCameras) + (isAdmin || "birdseye" in allowedCameras) ? ["birdseye"] : []), ...Object.keys(config?.cameras ?? {}) diff --git a/web/src/pages/Live.tsx b/web/src/pages/Live.tsx index a17494a39..18ec7f469 100644 --- a/web/src/pages/Live.tsx +++ b/web/src/pages/Live.tsx @@ -14,12 +14,12 @@ import { useTranslation } from "react-i18next"; import { useEffect, useMemo, useRef } from "react"; import useSWR from "swr"; import { useAllowedCameras } from "@/hooks/use-allowed-cameras"; -import { useIsCustomRole } from "@/hooks/use-is-custom-role"; +import { useIsAdmin } from "@/hooks/use-is-admin"; function Live() { const { t } = useTranslation(["views/live"]); const { data: config } = useSWR("config"); - const isCustomRole = useIsCustomRole(); + const isAdmin = useIsAdmin(); // selection @@ -94,7 +94,7 @@ function Live() { const includesBirdseye = useMemo(() => { // Restricted users should never have access to birdseye - if (isCustomRole) { + if (!isAdmin) { return false; } @@ -109,7 +109,7 @@ function Live() { } else { return false; } - }, [config, cameraGroup, isCustomRole]); + }, [config, cameraGroup, isAdmin]); const cameras = useMemo(() => { if (!config) { diff --git a/web/src/views/live/LiveDashboardView.tsx b/web/src/views/live/LiveDashboardView.tsx index c096e05ef..e4e935ac6 100644 --- a/web/src/views/live/LiveDashboardView.tsx +++ b/web/src/views/live/LiveDashboardView.tsx @@ -54,7 +54,7 @@ import { useTranslation } from "react-i18next"; import { EmptyCard } from "@/components/card/EmptyCard"; import { BsFillCameraVideoOffFill } from "react-icons/bs"; import { AuthContext } from "@/context/auth-context"; -import { useIsCustomRole } from "@/hooks/use-is-custom-role"; +import { useIsAdmin } from "@/hooks/use-is-admin"; type LiveDashboardViewProps = { cameras: CameraConfig[]; @@ -661,10 +661,10 @@ export default function LiveDashboardView({ function NoCameraView() { const { t } = useTranslation(["views/live"]); const { auth } = useContext(AuthContext); - const isCustomRole = useIsCustomRole(); + const isAdmin = useIsAdmin(); // Check if this is a restricted user with no cameras in this group - const isRestricted = isCustomRole && auth.isAuthenticated; + const isRestricted = !isAdmin && auth.isAuthenticated; return (