limit cameras in camera groups

This commit is contained in:
Josh Hawkins 2025-09-10 10:46:01 -05:00
parent fa863bad63
commit a0928cf325
3 changed files with 32 additions and 14 deletions

View File

@ -77,6 +77,8 @@ import { DialogTrigger } from "@radix-ui/react-dialog";
import { useStreamingSettings } from "@/context/streaming-settings-provider"; import { useStreamingSettings } from "@/context/streaming-settings-provider";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { CameraNameLabel } from "../camera/CameraNameLabel"; import { CameraNameLabel } from "../camera/CameraNameLabel";
import { useAllowedCameras } from "@/hooks/use-allowed-cameras";
import { useIsCustomRole } from "@/hooks/use-is-custom-role";
type CameraGroupSelectorProps = { type CameraGroupSelectorProps = {
className?: string; className?: string;
@ -650,6 +652,9 @@ export function CameraGroupEdit({
allGroupsStreamingSettings[editingGroup?.[0] ?? ""], allGroupsStreamingSettings[editingGroup?.[0] ?? ""],
); );
const allowedCameras = useAllowedCameras();
const isCustomRole = useIsCustomRole();
const [openCamera, setOpenCamera] = useState<string | null>(); const [openCamera, setOpenCamera] = useState<string | null>();
const birdseyeConfig = useMemo(() => config?.birdseye, [config]); const birdseyeConfig = useMemo(() => config?.birdseye, [config]);
@ -837,12 +842,17 @@ export function CameraGroupEdit({
<FormDescription>{t("group.cameras.desc")}</FormDescription> <FormDescription>{t("group.cameras.desc")}</FormDescription>
<FormMessage /> <FormMessage />
{[ {[
...(birdseyeConfig?.enabled ? ["birdseye"] : []), ...(birdseyeConfig?.enabled &&
...Object.keys(config?.cameras ?? {}).sort( (!isCustomRole || "birdseye" in allowedCameras)
(a, b) => ? ["birdseye"]
(config?.cameras[a]?.ui?.order ?? 0) - : []),
(config?.cameras[b]?.ui?.order ?? 0), ...Object.keys(config?.cameras ?? {})
), .filter((camera) => allowedCameras.includes(camera))
.sort(
(a, b) =>
(config?.cameras[a]?.ui?.order ?? 0) -
(config?.cameras[b]?.ui?.order ?? 0),
),
].map((camera) => ( ].map((camera) => (
<FormControl key={camera}> <FormControl key={camera}>
<div className="flex items-center justify-between gap-1"> <div className="flex items-center justify-between gap-1">

View File

@ -0,0 +1,11 @@
import { useContext } from "react";
import { AuthContext } from "@/context/auth-context";
export function useIsCustomRole() {
const { auth } = useContext(AuthContext);
return !(
auth.user?.role === "admin" ||
auth.user?.role == "viewer" ||
!auth.isAuthenticated
);
}

View File

@ -11,15 +11,15 @@ import LiveCameraView from "@/views/live/LiveCameraView";
import LiveDashboardView from "@/views/live/LiveDashboardView"; import LiveDashboardView from "@/views/live/LiveDashboardView";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useContext, useEffect, useMemo, useRef } from "react"; import { useEffect, useMemo, useRef } from "react";
import useSWR from "swr"; import useSWR from "swr";
import { useAllowedCameras } from "@/hooks/use-allowed-cameras"; import { useAllowedCameras } from "@/hooks/use-allowed-cameras";
import { AuthContext } from "@/context/auth-context"; import { useIsCustomRole } from "@/hooks/use-is-custom-role";
function Live() { function Live() {
const { t } = useTranslation(["views/live"]); const { t } = useTranslation(["views/live"]);
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
const { auth } = useContext(AuthContext); const isCustomRole = useIsCustomRole();
// selection // selection
@ -93,16 +93,13 @@ function Live() {
cameraGroup && cameraGroup &&
config.camera_groups[cameraGroup] && config.camera_groups[cameraGroup] &&
cameraGroup != "default" && cameraGroup != "default" &&
(auth.user?.role === "admin" || (!isCustomRole || "birdseye" in allowedCameras)
auth.user?.role == "viewer" ||
!auth.isAuthenticated ||
"birdseye" in allowedCameras)
) { ) {
return config.camera_groups[cameraGroup].cameras.includes("birdseye"); return config.camera_groups[cameraGroup].cameras.includes("birdseye");
} else { } else {
return false; return false;
} }
}, [config, cameraGroup, allowedCameras, auth]); }, [config, cameraGroup, allowedCameras, isCustomRole]);
const cameras = useMemo(() => { const cameras = useMemo(() => {
if (!config) { if (!config) {