diff --git a/web/src/components/settings/MasksAndZones.tsx b/web/src/components/settings/MasksAndZones.tsx index 2ab042bc4..6e744ca38 100644 --- a/web/src/components/settings/MasksAndZones.tsx +++ b/web/src/components/settings/MasksAndZones.tsx @@ -28,110 +28,36 @@ import { Link } from "react-router-dom"; type MasksAndZoneProps = { selectedCamera: string; selectedZoneMask?: PolygonType[]; - isEditing: boolean; - setIsEditing: React.Dispatch>; - unsavedChanges: boolean; setUnsavedChanges: React.Dispatch>; }; export default function MasksAndZones({ selectedCamera, selectedZoneMask, - isEditing, - setIsEditing, - unsavedChanges, setUnsavedChanges, }: MasksAndZoneProps) { const { data: config } = useSWR("config"); const [allPolygons, setAllPolygons] = useState([]); const [editingPolygons, setEditingPolygons] = useState([]); const [isLoading, setIsLoading] = useState(false); - // const [zoneObjects, setZoneObjects] = useState([]); const [activePolygonIndex, setActivePolygonIndex] = useState< number | undefined >(undefined); const [hoveredPolygonIndex, setHoveredPolygonIndex] = useState( null, ); - const containerRef = useRef(null); - // const polygonTypes = [ - // "zone", - // "motion_mask", - // "object_mask", - // undefined, - // ] as const; - - // type EditPaneType = (typeof polygonTypes)[number]; const [editPane, setEditPane] = useState(undefined); - // const cameras = useMemo(() => { - // if (!config) { - // return []; - // } - - // return Object.values(config.cameras) - // .filter((conf) => conf.ui.dashboard && conf.enabled) - // .sort((aConf, bConf) => aConf.ui.order - bConf.ui.order); - // }, [config]); - const cameraConfig = useMemo(() => { if (config && selectedCamera) { return config.cameras[selectedCamera]; } }, [config, selectedCamera]); - // const saveZoneObjects = useCallback( - // (camera: string, zoneName: string, newObjects?: string[]) => { - // setZoneObjects((prevZoneObjects) => - // prevZoneObjects.map((zoneObject) => { - // if ( - // zoneObject.camera === camera && - // zoneObject.zoneName === zoneName - // ) { - // console.log("found", camera, "with", zoneName); - // console.log("new objects", newObjects); - // console.log("new zoneobject", { - // ...zoneObject, - // objects: newObjects ?? [], - // }); - // // Replace objects with newObjects if provided - // return { - // ...zoneObject, - // objects: newObjects ?? [], - // }; - // } - // return zoneObject; // Keep original object - // }), - // ); - // }, - // [setZoneObjects], - // ); - - // const saveZoneObjects = useCallback( - // (camera: string, zoneName: string, objects?: string[]) => { - // setZoneObjects((prevZoneObjects) => { - // const updatedZoneObjects = prevZoneObjects.map((zoneObject) => { - // if ( - // zoneObject.camera === camera && - // zoneObject.zoneName === zoneName - // ) { - // return { ...zoneObject, objects: objects || [] }; - // } - // return zoneObject; - // }); - // return updatedZoneObjects; - // }); - // }, - // [setZoneObjects], - // ); - const [{ width: containerWidth, height: containerHeight }] = useResizeObserver(containerRef); - // const { width: detectWidth, height: detectHeight } = cameraConfig - // ? cameraConfig.detect - // : { width: 1, height: 1 }; const aspectRatio = useMemo(() => { if (!config) { return undefined; @@ -216,7 +142,6 @@ export default function MasksAndZones({ { points: [], isFinished: false, - // isUnsaved: true, type, typeIndex: 9999, name: "", @@ -228,35 +153,27 @@ export default function MasksAndZones({ }; const handleCancel = useCallback(() => { - // console.log("handling cancel"); setEditPane(undefined); - // console.log("all", allPolygons); - // console.log("editing", editingPolygons); - // setAllPolygons(allPolygons.filter((poly) => !poly.isUnsaved)); setEditingPolygons([...allPolygons]); setActivePolygonIndex(undefined); setHoveredPolygonIndex(null); }, [allPolygons]); const handleSave = useCallback(() => { - // console.log("handling save"); setAllPolygons([...(editingPolygons ?? [])]); - - // setEditPane(undefined); setHoveredPolygonIndex(null); }, [editingPolygons]); useEffect(() => { - console.log(isLoading); - console.log("edit pane", editPane); if (isLoading) { return; } if (!isLoading && editPane !== undefined) { - console.log("setting"); setActivePolygonIndex(undefined); setEditPane(undefined); } + // we know that these deps are correct + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoading]); const handleCopyCoordinates = useCallback( @@ -276,8 +193,6 @@ export default function MasksAndZones({ [allPolygons, scaledHeight, scaledWidth], ); - // useEffect(() => {}, [editPane]); - useEffect(() => { if (cameraConfig && containerRef.current && scaledWidth && scaledHeight) { const zones = Object.entries(cameraConfig.zones).map( @@ -295,7 +210,6 @@ export default function MasksAndZones({ scaledHeight, ), isFinished: true, - // isUnsaved: false, color: zoneData.color, }), ); @@ -338,6 +252,7 @@ export default function MasksAndZones({ : cameraConfig.objects.mask ? [cameraConfig.objects.mask] : []; + // TODO: check to see if this is necessary if ( cameraConfig.objects.mask !== null && cameraConfig.objects.mask !== undefined @@ -360,28 +275,15 @@ export default function MasksAndZones({ })); } - // if (globalObjectMasks && !Array.isArray(globalObjectMasks)) { - // globalObjectMasks = [globalObjectMasks]; - // } - - console.log("global", globalObjectMasks); - const globalObjectMasksCount = globalObjectMasks.length; - - console.log("filters", cameraConfig.objects.filters); - let index = 0; + objectMasks = Object.entries(cameraConfig.objects.filters) - .filter(([_, { mask }]) => mask || Array.isArray(mask)) + .filter(([, { mask }]) => mask || Array.isArray(mask)) .flatMap(([objectName, { mask }]): Polygon[] => { - console.log("index", index); - console.log("outer", objectName, mask); - const maskArray = Array.isArray(mask) ? mask : mask ? [mask] : []; - return maskArray.flatMap((maskItem, subIndex) => { const maskItemString = maskItem; - const newMask = { type: "object_mask" as PolygonType, typeIndex: subIndex, @@ -413,11 +315,6 @@ export default function MasksAndZones({ }); }); - console.log(Object.entries(cameraConfig.objects.filters)); - - console.log("final object masks", objectMasks); - - // console.log("setting all and editing"); setAllPolygons([ ...zones, ...motionMasks, @@ -430,46 +327,18 @@ export default function MasksAndZones({ ...globalObjectMasks, ...objectMasks, ]); - - // setZoneObjects( - // Object.entries(cameraConfig.zones).map(([name, zoneData]) => ({ - // camera: cameraConfig.name, - // zoneName: name, - // objects: Object.keys(zoneData.filters), - // })), - // ); } // we know that these deps are correct // eslint-disable-next-line react-hooks/exhaustive-deps }, [cameraConfig, containerRef, scaledHeight, scaledWidth]); - // useEffect(() => { - // console.log("editing polygons changed:", editingPolygons); - // }, [editingPolygons]); - useEffect(() => { if (editPane === undefined) { setEditingPolygons([...allPolygons]); - setIsEditing(false); - // console.log("edit pane undefined, all", allPolygons); - } else { - setIsEditing(true); } // we know that these deps are correct // eslint-disable-next-line react-hooks/exhaustive-deps - }, [setEditingPolygons, setIsEditing, allPolygons]); - - // useEffect(() => { - // console.log( - // "config zone objects", - // Object.entries(cameraConfig.zones).map(([name, zoneData]) => ({ - // camera: cameraConfig.name, - // zoneName: name, - // objects: Object.keys(zoneData.filters), - // })), - // ); - // console.log("component zone objects", zoneObjects); - // }, [zoneObjects]); + }, [setEditingPolygons, allPolygons]); useEffect(() => { if (selectedCamera) { @@ -586,12 +455,10 @@ export default function MasksAndZones({ key={index} polygon={polygon} index={index} - activePolygonIndex={activePolygonIndex} hoveredPolygonIndex={hoveredPolygonIndex} setHoveredPolygonIndex={setHoveredPolygonIndex} setActivePolygonIndex={setActivePolygonIndex} setEditPane={setEditPane} - setAllPolygons={setAllPolygons} handleCopyCoordinates={handleCopyCoordinates} /> ))} @@ -658,12 +525,10 @@ export default function MasksAndZones({ key={index} polygon={polygon} index={index} - activePolygonIndex={activePolygonIndex} hoveredPolygonIndex={hoveredPolygonIndex} setHoveredPolygonIndex={setHoveredPolygonIndex} setActivePolygonIndex={setActivePolygonIndex} setEditPane={setEditPane} - setAllPolygons={setAllPolygons} handleCopyCoordinates={handleCopyCoordinates} /> ))} @@ -729,12 +594,10 @@ export default function MasksAndZones({ key={index} polygon={polygon} index={index} - activePolygonIndex={activePolygonIndex} hoveredPolygonIndex={hoveredPolygonIndex} setHoveredPolygonIndex={setHoveredPolygonIndex} setActivePolygonIndex={setActivePolygonIndex} setEditPane={setEditPane} - setAllPolygons={setAllPolygons} handleCopyCoordinates={handleCopyCoordinates} /> ))} @@ -743,85 +606,6 @@ export default function MasksAndZones({ )} - {/* - - - Name - Coordinates - Edit - - - - {allPolygons.map((polygon, index) => ( - - - {polygon.name} - - - - {JSON.stringify( - interpolatePoints( - polygon.points, - scaledWidth, - scaledHeight, - cameraConfig.detect.width, - cameraConfig.detect.height, - ), - null, - 0, - )} - - - -
setActivePolygonIndex(index)} - > - -
- - saveZoneObjects(polygon.camera, polygon.name, objects) - } - /> -
-
- ))} -
-
-
- scaled width: {scaledWidth}, scaled height: {scaledHeight}, - container width: {containerWidth}, container height: - {containerHeight} -
- -
-
-                {JSON.stringify(
-                  allPolygons &&
-                    allPolygons.map((polygon) =>
-                      interpolatePoints(
-                        polygon.points,
-                        scaledWidth,
-                        scaledHeight,
-                        1,
-                        1,
-                      ),
-                    ),
-                  null,
-                  0,
-                )}
-              
-
*/}
0; // editing existing mask, not creating a new one if (editingMask) { index = polygon.typeIndex; - console.log("editing, index", index); } const filteredMask = ( @@ -125,15 +115,8 @@ export default function MotionMaskEditPane({ ? cameraConfig.motion.mask : [cameraConfig.motion.mask] ).filter((_, currentIndex) => currentIndex !== index); - console.log("filtered", filteredMask); - // if (editingMask) { - // if (index != null) { - - // } - // } filteredMask.splice(index, 0, coordinates); - console.log("filtered after splice", filteredMask); const queryString = filteredMask .map((pointsArray) => { @@ -144,16 +127,6 @@ export default function MotionMaskEditPane({ }) .join(""); - console.log("polygon", polygon); - console.log(queryString); - - // console.log( - // `config/set?cameras.${polygon?.camera}.motion.mask=${coordinates}&${queryString}`, - // ); - console.log("motion masks", cameraConfig.motion.mask); - console.log("new coords", coordinates); - // return; - axios .put(`config/set?${queryString}`, { requires_restart: 0, @@ -163,7 +136,6 @@ export default function MotionMaskEditPane({ toast.success(`${polygon.name || "Motion Mask"} has been saved.`, { position: "top-center", }); - // setChangedValue(false); updateConfig(); } else { toast.error(`Failed to save config changes: ${res.statusText}`, { @@ -180,23 +152,20 @@ export default function MotionMaskEditPane({ .finally(() => { setIsLoading(false); }); - }, [updateConfig, polygon, scaledWidth, scaledHeight, setIsLoading]); + }, [ + updateConfig, + polygon, + scaledWidth, + scaledHeight, + setIsLoading, + cameraConfig, + ]); function onSubmit(values: z.infer) { if (activePolygonIndex === undefined || !values || !polygons) { return; } setIsLoading(true); - // polygons[activePolygonIndex].name = values.name; - // console.log("form values", values); - // console.log( - // "string", - - // flattenPoints( - // interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1), - // ).join(","), - // ); - // console.log("active polygon", polygons[activePolygonIndex]); saveToConfig(); if (onSave) { diff --git a/web/src/components/settings/MotionTuner.tsx b/web/src/components/settings/MotionTuner.tsx index 243a82992..52984a80d 100644 --- a/web/src/components/settings/MotionTuner.tsx +++ b/web/src/components/settings/MotionTuner.tsx @@ -33,6 +33,7 @@ import { LuExternalLink } from "react-icons/lu"; type MotionTunerProps = { selectedCamera: string; + setUnsavedChanges: React.Dispatch>; }; type MotionSettings = { @@ -41,7 +42,10 @@ type MotionSettings = { improve_contrast?: boolean; }; -export default function MotionTuner({ selectedCamera }: MotionTunerProps) { +export default function MotionTuner({ + selectedCamera, + setUnsavedChanges, +}: MotionTunerProps) { const { data: config, mutate: updateConfig } = useSWR("config"); const [changedValue, setChangedValue] = useState(false); diff --git a/web/src/components/settings/ObjectMaskEditPane.tsx b/web/src/components/settings/ObjectMaskEditPane.tsx index 289249d51..ae755c48f 100644 --- a/web/src/components/settings/ObjectMaskEditPane.tsx +++ b/web/src/components/settings/ObjectMaskEditPane.tsx @@ -63,17 +63,6 @@ export default function ObjectMaskEditPane({ }: ObjectMaskEditPaneProps) { const { data: config, mutate: updateConfig } = useSWR("config"); - // const { data: config } = useSWR("config"); - - // const cameras = useMemo(() => { - // if (!config) { - // return []; - // } - - // return Object.values(config.cameras) - // .filter((conf) => conf.ui.dashboard && conf.enabled) - // .sort((aConf, bConf) => aConf.ui.order - bConf.ui.order); - // }, [config]); const polygon = useMemo(() => { if (polygons && activePolygonIndex !== undefined) { @@ -129,22 +118,10 @@ export default function ObjectMaskEditPane({ const saveToConfig = useCallback( async ( { objects: form_objects }: ObjectMaskFormValuesType, // values submitted via the form - objects: string[], ) => { if (!scaledWidth || !scaledHeight || !polygon || !cameraConfig) { return; } - // console.log("loitering time", loitering_time); - // const alertsZones = config?.cameras[camera]?.review.alerts.required_zones; - - // const detectionsZones = - // config?.cameras[camera]?.review.detections.required_zones; - - // console.log("out of try except", mutatedConfig); - - console.log("form objects:", form_objects); - console.log("objects:", objects); - console.log(cameraConfig.objects.filters); const coordinates = flattenPoints( interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1), @@ -183,9 +160,6 @@ export default function ObjectMaskEditPane({ index = polygon.typeIndex; } - console.log("are we an array?", Array.isArray(configObject)); - console.log("index", index); - // editing existing mask, not creating a new one if (editingMask) { index = polygon.typeIndex; @@ -195,10 +169,7 @@ export default function ObjectMaskEditPane({ Array.isArray(configObject) ? configObject : [configObject as string] ).filter((_, currentIndex) => currentIndex !== index); - console.log("filtered", filteredMask); - filteredMask.splice(index, 0, coordinates); - console.log("filtered after splice", filteredMask); } queryString = filteredMask @@ -212,18 +183,7 @@ export default function ObjectMaskEditPane({ }) .join(""); - console.log("polygon", polygon); - console.log(queryString); - - // console.log( - // `config/set?cameras.${polygon?.camera}.objects.mask=${coordinates}&${queryString}`, - // ); - // console.log("object masks", cameraConfig.objects.mask); - // console.log("new coords", coordinates); - // return; - if (!queryString) { - console.log("no query string"); return; } @@ -236,7 +196,6 @@ export default function ObjectMaskEditPane({ toast.success(`${polygon.name || "Object Mask"} has been saved.`, { position: "top-center", }); - // setChangedValue(false); updateConfig(); } else { toast.error(`Failed to save config changes: ${res.statusText}`, { @@ -254,7 +213,14 @@ export default function ObjectMaskEditPane({ setIsLoading(false); }); }, - [updateConfig, polygon, scaledWidth, scaledHeight, setIsLoading], + [ + updateConfig, + polygon, + scaledWidth, + scaledHeight, + setIsLoading, + cameraConfig, + ], ); function onSubmit(values: z.infer) { @@ -262,21 +228,8 @@ export default function ObjectMaskEditPane({ return; } setIsLoading(true); - // polygons[activePolygonIndex].name = values.name; - // console.log("form values", values); - // console.log( - // "string", - // flattenPoints( - // interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1), - // ).join(","), - // ); - // console.log("active polygon", polygons[activePolygonIndex]); - - saveToConfig( - values as ObjectMaskFormValuesType, - polygons[activePolygonIndex].objects, - ); + saveToConfig(values as ObjectMaskFormValuesType); if (onSave) { onSave(); } diff --git a/web/src/components/settings/ObjectSettings.tsx b/web/src/components/settings/ObjectSettings.tsx new file mode 100644 index 000000000..4b45c1fa4 --- /dev/null +++ b/web/src/components/settings/ObjectSettings.tsx @@ -0,0 +1,31 @@ +import { useMemo } from "react"; +import DebugCameraImage from "../camera/DebugCameraImage"; +import { FrigateConfig } from "@/types/frigateConfig"; +import useSWR from "swr"; +import ActivityIndicator from "../indicators/activity-indicator"; + +type ObjectSettingsProps = { + selectedCamera?: string; +}; + +export default function ObjectSettings({ + selectedCamera, +}: ObjectSettingsProps) { + const { data: config } = useSWR("config"); + + const cameraConfig = useMemo(() => { + if (config && selectedCamera) { + return config.cameras[selectedCamera]; + } + }, [config, selectedCamera]); + + if (!cameraConfig) { + return ; + } + + return ( +
+ +
+ ); +} diff --git a/web/src/components/settings/PolygonCanvas.tsx b/web/src/components/settings/PolygonCanvas.tsx index c4c0b52fc..e235ff598 100644 --- a/web/src/components/settings/PolygonCanvas.tsx +++ b/web/src/components/settings/PolygonCanvas.tsx @@ -1,11 +1,11 @@ import React, { useMemo, useRef, useState, useEffect } from "react"; import PolygonDrawer from "./PolygonDrawer"; -import { Stage, Layer, Image, Text, Circle } from "react-konva"; +import { Stage, Layer, Image } from "react-konva"; import Konva from "konva"; import type { KonvaEventObject } from "konva/lib/Node"; import { Polygon, PolygonType } from "@/types/canvas"; import { useApiHost } from "@/api"; -import { getAveragePoint, flattenPoints } from "@/utils/canvasUtil"; +import { flattenPoints } from "@/utils/canvasUtil"; type PolygonCanvasProps = { camera: string; @@ -203,54 +203,19 @@ export function PolygonCanvas({ (polygon, index) => (selectedZoneMask === undefined || selectedZoneMask.includes(polygon.type)) && ( - - - {index === hoveredPolygonIndex && ( - <> - - - - )} - + ), )} diff --git a/web/src/components/settings/PolygonDrawer.tsx b/web/src/components/settings/PolygonDrawer.tsx index c9b824ac7..48a3516bc 100644 --- a/web/src/components/settings/PolygonDrawer.tsx +++ b/web/src/components/settings/PolygonDrawer.tsx @@ -1,11 +1,6 @@ import { useCallback, useRef, useState } from "react"; -import { Line, Circle, Group, Text } from "react-konva"; -import { - minMax, - toRGBColorString, - dragBoundFunc, - getAveragePoint, -} from "@/utils/canvasUtil"; +import { Line, Circle, Group } from "react-konva"; +import { minMax, toRGBColorString, dragBoundFunc } from "@/utils/canvasUtil"; import type { KonvaEventObject } from "konva/lib/Node"; import Konva from "konva"; import { Vector2d } from "konva/lib/types"; @@ -17,7 +12,6 @@ type PolygonDrawerProps = { isHovered: boolean; isFinished: boolean; color: number[]; - name: string; handlePointDragMove: (e: KonvaEventObject) => void; handleGroupDragEnd: (e: KonvaEventObject) => void; handleMouseOverStartPoint: ( @@ -34,7 +28,6 @@ export default function PolygonDrawer({ isActive, isHovered, isFinished, - name, color, handlePointDragMove, handleGroupDragEnd, @@ -93,8 +86,6 @@ export default function PolygonDrawer({ [color], ); - // console.log(groupRef.current?.height()); - return ( ); })} - {groupRef.current && ( - - )} ); } diff --git a/web/src/components/settings/PolygonItem.tsx b/web/src/components/settings/PolygonItem.tsx index 4cc718a69..449572ddd 100644 --- a/web/src/components/settings/PolygonItem.tsx +++ b/web/src/components/settings/PolygonItem.tsx @@ -36,9 +36,7 @@ import { reviewQueries } from "@/utils/zoneEdutUtil"; type PolygonItemProps = { polygon: Polygon; - setAllPolygons: React.Dispatch>; index: number; - activePolygonIndex: number | undefined; hoveredPolygonIndex: number | null; setHoveredPolygonIndex: (index: number | null) => void; setActivePolygonIndex: (index: number | undefined) => void; @@ -48,9 +46,7 @@ type PolygonItemProps = { export default function PolygonItem({ polygon, - setAllPolygons, index, - activePolygonIndex, hoveredPolygonIndex, setHoveredPolygonIndex, setActivePolygonIndex, @@ -60,6 +56,7 @@ export default function PolygonItem({ const { data: config, mutate: updateConfig } = useSWR("config"); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); const cameraConfig = useMemo(() => { if (polygon?.camera && config) { @@ -93,14 +90,11 @@ export default function PolygonItem({ url = `cameras.${polygon.camera}.zones.${polygon.name}${alertQueries}${detectionQueries}`; } if (polygon.type == "motion_mask") { - console.log("deleting", polygon.typeIndex); - const filteredMask = ( Array.isArray(cameraConfig.motion.mask) ? cameraConfig.motion.mask : [cameraConfig.motion.mask] ).filter((_, currentIndex) => currentIndex !== polygon.typeIndex); - console.log(filteredMask); url = filteredMask .map((pointsArray) => { @@ -115,21 +109,14 @@ export default function PolygonItem({ // deleting last mask url = `cameras.${polygon?.camera}.motion.mask&`; } - console.log(url); - - // return; - // url = `config/set?cameras.${polygon.camera}.motion.mask`; } if (polygon.type == "object_mask") { - console.log("deleting", polygon.typeIndex, polygon); let configObject; let globalMask = false; - console.log("polygon objects", polygon.objects, !polygon.objects); // global mask on camera for all objects if (!polygon.objects.length) { - console.log("deleting global"); configObject = cameraConfig.objects.mask; globalMask = true; } else { @@ -152,28 +139,13 @@ export default function PolygonItem({ Array.isArray(configObject) ? configObject : [configObject] ).filter((_, currentIndex) => currentIndex !== polygon.typeIndex); } else { - console.log("not globals config object:", configObject); - filteredMask = ( Array.isArray(configObject) ? configObject : [configObject] ) .filter((mask) => !globalObjectMasksArray.includes(mask)) - .filter((_, currentIndex) => { - console.log( - "current index", - currentIndex, - "global length:", - globalObjectMasksArray.length, - "polygon typeindex", - polygon.typeIndex, - ); - - return currentIndex !== polygon.typeIndex; - }); + .filter((_, currentIndex) => currentIndex !== polygon.typeIndex); } - console.log("filtered:", filteredMask); - url = filteredMask .map((pointsArray) => { const coordinates = flattenPoints( @@ -191,13 +163,10 @@ export default function PolygonItem({ ? `cameras.${polygon?.camera}.objects.mask&` : `cameras.${polygon?.camera}.objects.filters.${polygon.objects[0]}.mask`; } - - console.log("url:", url); - - // return; - // url = `config/set?cameras.${polygon.camera}.motion.mask`; } + setIsLoading(true); + await axios .put(`config/set?${url}`, { requires_restart: 0 }) .then((res) => { @@ -205,7 +174,6 @@ export default function PolygonItem({ toast.success(`${polygon?.name} has been deleted.`, { position: "top-center", }); - // setChangedValue(false); updateConfig(); } else { toast.error(`Failed to save config changes: ${res.statusText}`, { @@ -220,40 +188,13 @@ export default function PolygonItem({ ); }) .finally(() => { - // setIsLoading(false); + setIsLoading(false); }); }, [updateConfig, cameraConfig], ); - const reindexPolygons = (arr: Polygon[]): Polygon[] => { - const typeCounters: { [type: string]: number } = {}; - - return arr.map((obj) => { - if (!typeCounters[obj.type]) { - typeCounters[obj.type] = 0; - } - - const newObj: Polygon = { - ...obj, - typeIndex: typeCounters[obj.type], - }; - typeCounters[obj.type]++; - return newObj; - }); - }; - - const handleDelete = (type: string, typeIndex: number) => { - // setAllPolygons((oldPolygons) => { - // console.log("old polygons", oldPolygons); - // const filteredPolygons = oldPolygons.filter( - // (polygon) => - // !(polygon.type === type && polygon.typeIndex === typeIndex), - // ); - // console.log("filtered", filteredPolygons); - // // console.log("reindexed", reindexPolygons(filteredPolygons)); - // return filteredPolygons; - // }); + const handleDelete = () => { setActivePolygonIndex(undefined); saveToConfig(polygon); }; @@ -307,9 +248,7 @@ export default function PolygonItem({ Cancel - handleDelete(polygon.type, polygon.typeIndex)} - > + Delete @@ -334,7 +273,10 @@ export default function PolygonItem({ handleCopyCoordinates(index)}> Copy - setDeleteDialogOpen(true)}> + setDeleteDialogOpen(true)} + > Delete @@ -378,7 +320,7 @@ export default function PolygonItem({
setDeleteDialogOpen(true)} + onClick={() => !isLoading && setDeleteDialogOpen(true)} > diff --git a/web/src/components/settings/ZoneEditPane.tsx b/web/src/components/settings/ZoneEditPane.tsx index b5a0fe493..f8db2c45d 100644 --- a/web/src/components/settings/ZoneEditPane.tsx +++ b/web/src/components/settings/ZoneEditPane.tsx @@ -156,33 +156,6 @@ export default function ZoneEditPane({ }, }); - // const [changedValue, setChangedValue] = useState(false); - - // const requiredDetectionZones = useMemo( - // () => cameraConfig?.review.detections.required_zones, - // [cameraConfig], - // ); - - // const requiredAlertZones = useMemo( - // () => cameraConfig?.review.alerts.required_zones, - // [cameraConfig], - // ); - - // const [alertQueries, setAlertQueries] = useState(""); - // const [detectionQueries, setDetectionQueries] = useState(""); - - // useEffect(() => { - // console.log("config updated!", config); - // }, [config]); - - // useEffect(() => { - // console.log("camera config updated!", cameraConfig); - // }, [cameraConfig]); - - // useEffect(() => { - // console.log("required zones updated!", requiredZones); - // }, [requiredZones]); - const saveToConfig = useCallback( async ( { @@ -198,11 +171,6 @@ export default function ZoneEditPane({ if (!scaledWidth || !scaledHeight || !polygon) { return; } - // console.log("loitering time", loitering_time); - // const alertsZones = config?.cameras[camera]?.review.alerts.required_zones; - - // const detectionsZones = - // config?.cameras[camera]?.review.detections.required_zones; let mutatedConfig = config; const renamingZone = zoneName != polygon.name && polygon.name != ""; @@ -231,8 +199,6 @@ export default function ZoneEditPane({ // Wait for the config to be updated mutatedConfig = await updateConfig(); - // console.log("this should be updated...", mutatedConfig.cameras); - // console.log("check original config object...", config); } catch (error) { toast.error(`Failed to save config changes.`, { position: "top-center", @@ -241,12 +207,9 @@ export default function ZoneEditPane({ } } - // console.log("out of try except", mutatedConfig); - const coordinates = flattenPoints( interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1), ).join(","); - // const foo = config.cameras["doorbell"].zones["outside"].objects; let objectQueries = objects .map( @@ -263,7 +226,6 @@ export default function ZoneEditPane({ // deleting objects if (!objectQueries && !same_objects && !renamingZone) { - // console.log("deleting objects"); objectQueries = `&cameras.${polygon?.camera}.zones.${zoneName}.objects`; } @@ -278,14 +240,6 @@ export default function ZoneEditPane({ .required_zones || [], ); - // console.log("object queries:", objectQueries); - // console.log("alert queries:", alertQueries); - // console.log("detection queries:", detectionQueries); - - // console.log( - // `config/set?cameras.${polygon?.camera}.zones.${name}.coordinates=${coordinates}&cameras.${polygon?.camera}.zones.${name}.inertia=${inertia}&cameras.${polygon?.camera}.zones.${name}.loitering_time=${loitering_time}${objectQueries}${alertQueries}${detectionQueries}`, - // ); - axios .put( `config/set?cameras.${polygon?.camera}.zones.${zoneName}.coordinates=${coordinates}&cameras.${polygon?.camera}.zones.${zoneName}.inertia=${inertia}&cameras.${polygon?.camera}.zones.${zoneName}.loitering_time=${loitering_time}${objectQueries}${alertQueries}${detectionQueries}`, @@ -296,7 +250,6 @@ export default function ZoneEditPane({ toast.success(`Zone (${zoneName}) has been saved.`, { position: "top-center", }); - // setChangedValue(false); updateConfig(); } else { toast.error(`Failed to save config changes: ${res.statusText}`, { @@ -330,16 +283,6 @@ export default function ZoneEditPane({ return; } setIsLoading(true); - // polygons[activePolygonIndex].name = values.name; - // console.log("form values", values); - // console.log( - // "string", - - // flattenPoints( - // interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1), - // ).join(","), - // ); - // console.log("active polygon", polygons[activePolygonIndex]); saveToConfig( values as ZoneFormValuesType, diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx index f02559064..4abb9db68 100644 --- a/web/src/pages/Settings.tsx +++ b/web/src/pages/Settings.tsx @@ -5,7 +5,6 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -// import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; import MotionTuner from "@/components/settings/MotionTuner"; @@ -13,7 +12,6 @@ import MasksAndZones from "@/components/settings/MasksAndZones"; import { Button } from "@/components/ui/button"; import { useEffect, useMemo, useState } from "react"; import useOptimisticState from "@/hooks/use-optimistic-state"; -import Logo from "@/components/Logo"; import { isMobile } from "react-device-detect"; import { FaVideo } from "react-icons/fa"; import { CameraConfig, FrigateConfig } from "@/types/frigateConfig"; @@ -22,6 +20,7 @@ import General from "@/components/settings/General"; import FilterSwitch from "@/components/filter/FilterSwitch"; import { ZoneMaskFilterButton } from "@/components/filter/ZoneMaskFilter"; import { PolygonType } from "@/types/canvas"; +import ObjectSettings from "@/components/settings/ObjectSettings"; export default function Settings() { const settingsViews = [ @@ -37,7 +36,7 @@ export default function Settings() { const { data: config } = useSWR("config"); - const [isEditing, setIsEditing] = useState(false); + // TODO: confirm leave page const [unsavedChanges, setUnsavedChanges] = useState(false); const cameras = useMemo(() => { @@ -50,7 +49,7 @@ export default function Settings() { .sort((aConf, bConf) => aConf.ui.order - bConf.ui.order); }, [config]); - const [selectedCamera, setSelectedCamera] = useState(); + const [selectedCamera, setSelectedCamera] = useState(""); const [filterZoneMask, setFilterZoneMask] = useState(); @@ -58,6 +57,8 @@ export default function Settings() { if (cameras.length) { setSelectedCamera(cameras[0].name); } + // only run once + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( @@ -77,7 +78,7 @@ export default function Settings() { {Object.values(settingsViews).map((item) => ( @@ -105,19 +106,21 @@ export default function Settings() {
{page == "general" && } - {page == "objects" && <>} + {page == "objects" && ( + + )} {page == "masks / zones" && ( )} {page == "motion tuner" && ( - + )}
diff --git a/web/src/utils/zoneEdutUtil.ts b/web/src/utils/zoneEdutUtil.ts index b108614b9..ce5ed3d96 100644 --- a/web/src/utils/zoneEdutUtil.ts +++ b/web/src/utils/zoneEdutUtil.ts @@ -10,24 +10,9 @@ export const reviewQueries = ( let detectionQueries = ""; let same_alerts = false; let same_detections = false; - // const foo = config; - - // console.log("config in func", config.cameras); - // console.log("config as foo in func", foo.cameras); - // console.log("cameraconfig in func", cameraConfig); - // console.log("required zones in func", requiredZones); - // console.log("name", name); - // console.log("alerts", alertsZones); - // console.log("detections", detectionsZones); - // console.log( - // "orig detections", - // foo?.cameras[camera]?.review.detections.required_zones, - // ); const alerts = new Set(alertsZones || []); - // config?.cameras[camera].review.alerts.required_zones.forEach((zone) => { - // alerts.add(zone); - // }); + if (review_alerts) { alerts.add(name); } else { @@ -40,9 +25,6 @@ export const reviewQueries = ( .join(""); const detections = new Set(detectionsZones || []); - // config?.cameras[camera].review.detections.required_zones.forEach((zone) => { - // detections.add(zone); - // }); if (review_detections) { detections.add(name); @@ -57,36 +39,10 @@ export const reviewQueries = ( ) .join(""); - // console.log("dets set", detections); - - // const updatedConfig = updateConfig({ - // ...config, - // cameras: { - // ...config.cameras, - // [camera]: { - // ...config.cameras[camera], - // review: { - // ...config.cameras[camera].review, - // detection: { - // ...config.cameras[camera].review.detection, - // required_zones: [...detections], - // }, - // }, - // }, - // }, - // }); - - // console.log(updatedConfig); - - // console.log("alert queries", alertQueries); - // console.log("detection queries", detectionQueries); - if (!alertQueries && !same_alerts) { - // console.log("deleting alerts"); alertQueries = `&cameras.${camera}.review.alerts`; } if (!detectionQueries && !same_detections) { - // console.log("deleting detection"); detectionQueries = `&cameras.${camera}.review.detections`; }