From 2241c85a85b982a9f1035cc534b69769a7844b8f Mon Sep 17 00:00:00 2001 From: Nick Mowen Date: Fri, 15 Dec 2023 13:05:14 -0700 Subject: [PATCH] Show camera dashboard --- web-new/src/App.tsx | 2 +- web-new/src/components/camera/CameraImage.tsx | 14 +- web-new/src/components/card/HistoryCard.tsx | 2 +- web-new/src/pages/Dashboard.tsx | 158 +++++++++++------- web-new/src/pages/Live.tsx | 6 +- web-new/themes/theme-blue.css | 2 +- 6 files changed, 119 insertions(+), 65 deletions(-) diff --git a/web-new/src/App.tsx b/web-new/src/App.tsx index babafbd60..294b4cd75 100644 --- a/web-new/src/App.tsx +++ b/web-new/src/App.tsx @@ -32,7 +32,7 @@ function App() {
} /> - } /> + } /> } /> } /> } /> diff --git a/web-new/src/components/camera/CameraImage.tsx b/web-new/src/components/camera/CameraImage.tsx index 61a405352..6d38c488a 100644 --- a/web-new/src/components/camera/CameraImage.tsx +++ b/web-new/src/components/camera/CameraImage.tsx @@ -7,8 +7,9 @@ import { useResizeObserver } from "@/hooks/resize-observer"; type CameraImageProps = { camera: string; onload?: (event: Event) => void; - searchParams: {}; - stretch?: boolean; + searchParams?: {}; + stretch?: boolean; // stretch to fit width + fitAspect?: number; // shrink to fit height }; export default function CameraImage({ @@ -16,13 +17,15 @@ export default function CameraImage({ onload, searchParams = "", stretch = false, + fitAspect, }: CameraImageProps) { const { data: config } = useSWR("config"); const apiHost = useApiHost(); const [hasLoaded, setHasLoaded] = useState(false); const containerRef = useRef(null); const canvasRef = useRef(null); - const [{ width: containerWidth }] = useResizeObserver(containerRef); + const [{ width: containerWidth, height: containerHeight }] = + useResizeObserver(containerRef); // Add scrollbar width (when visible) to the available observer width to eliminate screen juddering. // https://github.com/blakeblackshear/frigate/issues/1657 @@ -42,8 +45,9 @@ export default function CameraImage({ const aspectRatio = width / height; const scaledHeight = useMemo(() => { - const scaledHeight = Math.floor(availableWidth / aspectRatio); + const scaledHeight = (aspectRatio < (fitAspect ?? 0)) ? Math.floor(containerHeight) : Math.floor(availableWidth / aspectRatio); const finalHeight = stretch ? scaledHeight : Math.min(scaledHeight, height); + console.log("returning " + containerHeight + " for " + camera) if (finalHeight > 0) { return finalHeight; @@ -79,7 +83,7 @@ export default function CameraImage({ }, [apiHost, canvasRef, name, img, searchParams, scaledHeight, config]); return ( -
+
{enabled ? ( ("config"); - const [selectedCamera, setSelectedCamera] = useState( - undefined - ); - let cameras; - if (config?.cameras) { - cameras = Object.keys(config.cameras).map((name) => ( -
- setSelectedCamera(name)}> - {name} - -
- )); - } + const sortedCameras = useMemo(() => { + if (!config) { + return []; + } + + return Object.values(config.cameras) + .filter((conf) => conf.ui.dashboard) + .sort((aConf, bConf) => aConf.ui.order - bConf.ui.order); + }, [config]); return ( <> + Dashboard + {!config && } - Components testing - -
- -
- {selectedCamera && } + {config && ( +
+
+ {sortedCameras.map((camera) => { + return ; + })} +
+
+ )} ); } -function Camera({ cameraName }: { cameraName: string }) { - const { payload: detectValue, send: sendDetect } = useDetectState(cameraName); +function Camera({ camera }: { camera: CameraConfig }) { + const { payload: detectValue, send: sendDetect } = useDetectState( + camera.name + ); + const { payload: recordValue, send: sendRecord } = useRecordingsState( + camera.name + ); + const { payload: snapshotValue, send: sendSnapshot } = useSnapshotsState( + camera.name + ); + const { payload: audioValue, send: sendAudio } = useAudioState(camera.name); return ( <> - - {cameraName} - -
- - sendDetect(detectValue === "ON" ? "OFF" : "ON", true) - } - /> - -
+ + + + + +
+ + {camera.name.replaceAll("_", " ")} + +
+ + + + {camera.audio.enabled_in_config && ( + + )} +
+
+
+
); } diff --git a/web-new/src/pages/Live.tsx b/web-new/src/pages/Live.tsx index 66061a0db..86aeddb95 100644 --- a/web-new/src/pages/Live.tsx +++ b/web-new/src/pages/Live.tsx @@ -13,12 +13,16 @@ import Heading from "@/components/ui/heading"; import { usePersistence } from "@/hooks/use-persistence"; import { FrigateConfig } from "@/types/frigateConfig"; import { useMemo, useState } from "react"; +import { useParams } from "react-router-dom"; import useSWR from "swr"; function Live() { const { data: config } = useSWR("config"); + const { camera: openedCamera } = useParams(); - const [camera, setCamera] = useState("Select A Camera"); + const [camera, setCamera] = useState( + openedCamera ?? "Select A Camera" + ); const cameraConfig = useMemo(() => { return config?.cameras[camera]; }, [camera, config]); diff --git a/web-new/themes/theme-blue.css b/web-new/themes/theme-blue.css index be2609668..205662cd7 100644 --- a/web-new/themes/theme-blue.css +++ b/web-new/themes/theme-blue.css @@ -25,7 +25,7 @@ .theme-blue.dark { --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; - --card: 222.2 84% 4.9%; + --card: 217.2 32.6% 17.5%; --card-foreground: 210 40% 98%; --popover: 222.2 84% 4.9%; --popover-foreground: 210 40% 98%;