This commit is contained in:
Josh Hawkins 2024-04-17 23:15:44 -05:00
parent 1ba4502b07
commit f92de9af2e
11 changed files with 102 additions and 581 deletions

View File

@ -28,110 +28,36 @@ import { Link } from "react-router-dom";
type MasksAndZoneProps = { type MasksAndZoneProps = {
selectedCamera: string; selectedCamera: string;
selectedZoneMask?: PolygonType[]; selectedZoneMask?: PolygonType[];
isEditing: boolean;
setIsEditing: React.Dispatch<React.SetStateAction<boolean>>;
unsavedChanges: boolean;
setUnsavedChanges: React.Dispatch<React.SetStateAction<boolean>>; setUnsavedChanges: React.Dispatch<React.SetStateAction<boolean>>;
}; };
export default function MasksAndZones({ export default function MasksAndZones({
selectedCamera, selectedCamera,
selectedZoneMask, selectedZoneMask,
isEditing,
setIsEditing,
unsavedChanges,
setUnsavedChanges, setUnsavedChanges,
}: MasksAndZoneProps) { }: MasksAndZoneProps) {
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
const [allPolygons, setAllPolygons] = useState<Polygon[]>([]); const [allPolygons, setAllPolygons] = useState<Polygon[]>([]);
const [editingPolygons, setEditingPolygons] = useState<Polygon[]>([]); const [editingPolygons, setEditingPolygons] = useState<Polygon[]>([]);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
// const [zoneObjects, setZoneObjects] = useState<ZoneObjects[]>([]);
const [activePolygonIndex, setActivePolygonIndex] = useState< const [activePolygonIndex, setActivePolygonIndex] = useState<
number | undefined number | undefined
>(undefined); >(undefined);
const [hoveredPolygonIndex, setHoveredPolygonIndex] = useState<number | null>( const [hoveredPolygonIndex, setHoveredPolygonIndex] = useState<number | null>(
null, null,
); );
const containerRef = useRef<HTMLDivElement | null>(null); const containerRef = useRef<HTMLDivElement | null>(null);
// const polygonTypes = [
// "zone",
// "motion_mask",
// "object_mask",
// undefined,
// ] as const;
// type EditPaneType = (typeof polygonTypes)[number];
const [editPane, setEditPane] = useState<PolygonType | undefined>(undefined); const [editPane, setEditPane] = useState<PolygonType | undefined>(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(() => { const cameraConfig = useMemo(() => {
if (config && selectedCamera) { if (config && selectedCamera) {
return config.cameras[selectedCamera]; return config.cameras[selectedCamera];
} }
}, [config, 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 }] = const [{ width: containerWidth, height: containerHeight }] =
useResizeObserver(containerRef); useResizeObserver(containerRef);
// const { width: detectWidth, height: detectHeight } = cameraConfig
// ? cameraConfig.detect
// : { width: 1, height: 1 };
const aspectRatio = useMemo(() => { const aspectRatio = useMemo(() => {
if (!config) { if (!config) {
return undefined; return undefined;
@ -216,7 +142,6 @@ export default function MasksAndZones({
{ {
points: [], points: [],
isFinished: false, isFinished: false,
// isUnsaved: true,
type, type,
typeIndex: 9999, typeIndex: 9999,
name: "", name: "",
@ -228,35 +153,27 @@ export default function MasksAndZones({
}; };
const handleCancel = useCallback(() => { const handleCancel = useCallback(() => {
// console.log("handling cancel");
setEditPane(undefined); setEditPane(undefined);
// console.log("all", allPolygons);
// console.log("editing", editingPolygons);
// setAllPolygons(allPolygons.filter((poly) => !poly.isUnsaved));
setEditingPolygons([...allPolygons]); setEditingPolygons([...allPolygons]);
setActivePolygonIndex(undefined); setActivePolygonIndex(undefined);
setHoveredPolygonIndex(null); setHoveredPolygonIndex(null);
}, [allPolygons]); }, [allPolygons]);
const handleSave = useCallback(() => { const handleSave = useCallback(() => {
// console.log("handling save");
setAllPolygons([...(editingPolygons ?? [])]); setAllPolygons([...(editingPolygons ?? [])]);
// setEditPane(undefined);
setHoveredPolygonIndex(null); setHoveredPolygonIndex(null);
}, [editingPolygons]); }, [editingPolygons]);
useEffect(() => { useEffect(() => {
console.log(isLoading);
console.log("edit pane", editPane);
if (isLoading) { if (isLoading) {
return; return;
} }
if (!isLoading && editPane !== undefined) { if (!isLoading && editPane !== undefined) {
console.log("setting");
setActivePolygonIndex(undefined); setActivePolygonIndex(undefined);
setEditPane(undefined); setEditPane(undefined);
} }
// we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoading]); }, [isLoading]);
const handleCopyCoordinates = useCallback( const handleCopyCoordinates = useCallback(
@ -276,8 +193,6 @@ export default function MasksAndZones({
[allPolygons, scaledHeight, scaledWidth], [allPolygons, scaledHeight, scaledWidth],
); );
// useEffect(() => {}, [editPane]);
useEffect(() => { useEffect(() => {
if (cameraConfig && containerRef.current && scaledWidth && scaledHeight) { if (cameraConfig && containerRef.current && scaledWidth && scaledHeight) {
const zones = Object.entries(cameraConfig.zones).map( const zones = Object.entries(cameraConfig.zones).map(
@ -295,7 +210,6 @@ export default function MasksAndZones({
scaledHeight, scaledHeight,
), ),
isFinished: true, isFinished: true,
// isUnsaved: false,
color: zoneData.color, color: zoneData.color,
}), }),
); );
@ -338,6 +252,7 @@ export default function MasksAndZones({
: cameraConfig.objects.mask : cameraConfig.objects.mask
? [cameraConfig.objects.mask] ? [cameraConfig.objects.mask]
: []; : [];
// TODO: check to see if this is necessary
if ( if (
cameraConfig.objects.mask !== null && cameraConfig.objects.mask !== null &&
cameraConfig.objects.mask !== undefined 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; const globalObjectMasksCount = globalObjectMasks.length;
console.log("filters", cameraConfig.objects.filters);
let index = 0; let index = 0;
objectMasks = Object.entries(cameraConfig.objects.filters) objectMasks = Object.entries(cameraConfig.objects.filters)
.filter(([_, { mask }]) => mask || Array.isArray(mask)) .filter(([, { mask }]) => mask || Array.isArray(mask))
.flatMap(([objectName, { mask }]): Polygon[] => { .flatMap(([objectName, { mask }]): Polygon[] => {
console.log("index", index);
console.log("outer", objectName, mask);
const maskArray = Array.isArray(mask) ? mask : mask ? [mask] : []; const maskArray = Array.isArray(mask) ? mask : mask ? [mask] : [];
return maskArray.flatMap((maskItem, subIndex) => { return maskArray.flatMap((maskItem, subIndex) => {
const maskItemString = maskItem; const maskItemString = maskItem;
const newMask = { const newMask = {
type: "object_mask" as PolygonType, type: "object_mask" as PolygonType,
typeIndex: subIndex, 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([ setAllPolygons([
...zones, ...zones,
...motionMasks, ...motionMasks,
@ -430,46 +327,18 @@ export default function MasksAndZones({
...globalObjectMasks, ...globalObjectMasks,
...objectMasks, ...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 // we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [cameraConfig, containerRef, scaledHeight, scaledWidth]); }, [cameraConfig, containerRef, scaledHeight, scaledWidth]);
// useEffect(() => {
// console.log("editing polygons changed:", editingPolygons);
// }, [editingPolygons]);
useEffect(() => { useEffect(() => {
if (editPane === undefined) { if (editPane === undefined) {
setEditingPolygons([...allPolygons]); setEditingPolygons([...allPolygons]);
setIsEditing(false);
// console.log("edit pane undefined, all", allPolygons);
} else {
setIsEditing(true);
} }
// we know that these deps are correct // we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [setEditingPolygons, setIsEditing, allPolygons]); }, [setEditingPolygons, 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]);
useEffect(() => { useEffect(() => {
if (selectedCamera) { if (selectedCamera) {
@ -586,12 +455,10 @@ export default function MasksAndZones({
key={index} key={index}
polygon={polygon} polygon={polygon}
index={index} index={index}
activePolygonIndex={activePolygonIndex}
hoveredPolygonIndex={hoveredPolygonIndex} hoveredPolygonIndex={hoveredPolygonIndex}
setHoveredPolygonIndex={setHoveredPolygonIndex} setHoveredPolygonIndex={setHoveredPolygonIndex}
setActivePolygonIndex={setActivePolygonIndex} setActivePolygonIndex={setActivePolygonIndex}
setEditPane={setEditPane} setEditPane={setEditPane}
setAllPolygons={setAllPolygons}
handleCopyCoordinates={handleCopyCoordinates} handleCopyCoordinates={handleCopyCoordinates}
/> />
))} ))}
@ -658,12 +525,10 @@ export default function MasksAndZones({
key={index} key={index}
polygon={polygon} polygon={polygon}
index={index} index={index}
activePolygonIndex={activePolygonIndex}
hoveredPolygonIndex={hoveredPolygonIndex} hoveredPolygonIndex={hoveredPolygonIndex}
setHoveredPolygonIndex={setHoveredPolygonIndex} setHoveredPolygonIndex={setHoveredPolygonIndex}
setActivePolygonIndex={setActivePolygonIndex} setActivePolygonIndex={setActivePolygonIndex}
setEditPane={setEditPane} setEditPane={setEditPane}
setAllPolygons={setAllPolygons}
handleCopyCoordinates={handleCopyCoordinates} handleCopyCoordinates={handleCopyCoordinates}
/> />
))} ))}
@ -729,12 +594,10 @@ export default function MasksAndZones({
key={index} key={index}
polygon={polygon} polygon={polygon}
index={index} index={index}
activePolygonIndex={activePolygonIndex}
hoveredPolygonIndex={hoveredPolygonIndex} hoveredPolygonIndex={hoveredPolygonIndex}
setHoveredPolygonIndex={setHoveredPolygonIndex} setHoveredPolygonIndex={setHoveredPolygonIndex}
setActivePolygonIndex={setActivePolygonIndex} setActivePolygonIndex={setActivePolygonIndex}
setEditPane={setEditPane} setEditPane={setEditPane}
setAllPolygons={setAllPolygons}
handleCopyCoordinates={handleCopyCoordinates} handleCopyCoordinates={handleCopyCoordinates}
/> />
))} ))}
@ -743,85 +606,6 @@ export default function MasksAndZones({
</div> </div>
</> </>
)} )}
{/* <Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Name</TableHead>
<TableHead className="max-w-[200px]">Coordinates</TableHead>
<TableHead>Edit</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{allPolygons.map((polygon, index) => (
<TableRow key={index}>
<TableCell className="font-medium">
{polygon.name}
</TableCell>
<TableCell className="max-w-[200px] text-wrap">
<code>
{JSON.stringify(
interpolatePoints(
polygon.points,
scaledWidth,
scaledHeight,
cameraConfig.detect.width,
cameraConfig.detect.height,
),
null,
0,
)}
</code>
</TableCell>
<TableCell>
<div
className="cursor-pointer"
onClick={() => setActivePolygonIndex(index)}
>
<LuPencil className="size-4 text-white" />
</div>
<ZoneObjectSelector
camera={polygon.camera}
zoneName={polygon.name}
allLabels={allLabels}
updateLabelFilter={(objects) =>
saveZoneObjects(polygon.camera, polygon.name, objects)
}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<div>
scaled width: {scaledWidth}, scaled height: {scaledHeight},
container width: {containerWidth}, container height:
{containerHeight}
</div>
<ZoneControls
camera={cameraConfig.name}
polygons={allPolygons}
setPolygons={setAllPolygons}
activePolygonIndex={activePolygonIndex}
setActivePolygonIndex={setActivePolygonIndex}
/>
<div className="flex flex-col justify-center items-center m-auto w-[30%] bg-secondary">
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(
allPolygons &&
allPolygons.map((polygon) =>
interpolatePoints(
polygon.points,
scaledWidth,
scaledHeight,
1,
1,
),
),
null,
0,
)}
</pre>
</div> */}
</div> </div>
<div <div
ref={containerRef} ref={containerRef}

View File

@ -92,13 +92,6 @@ export default function MotionMaskEditPane({
if (!scaledWidth || !scaledHeight || !polygon || !cameraConfig) { if (!scaledWidth || !scaledHeight || !polygon || !cameraConfig) {
return; 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);
const coordinates = flattenPoints( const coordinates = flattenPoints(
interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1), interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1),
@ -110,14 +103,11 @@ export default function MotionMaskEditPane({
? 1 ? 1
: 0; : 0;
console.log("are we an array?", Array.isArray(cameraConfig.motion.mask));
console.log("index", index);
const editingMask = polygon.name.length > 0; const editingMask = polygon.name.length > 0;
// editing existing mask, not creating a new one // editing existing mask, not creating a new one
if (editingMask) { if (editingMask) {
index = polygon.typeIndex; index = polygon.typeIndex;
console.log("editing, index", index);
} }
const filteredMask = ( const filteredMask = (
@ -125,15 +115,8 @@ export default function MotionMaskEditPane({
? cameraConfig.motion.mask ? cameraConfig.motion.mask
: [cameraConfig.motion.mask] : [cameraConfig.motion.mask]
).filter((_, currentIndex) => currentIndex !== index); ).filter((_, currentIndex) => currentIndex !== index);
console.log("filtered", filteredMask);
// if (editingMask) {
// if (index != null) {
// }
// }
filteredMask.splice(index, 0, coordinates); filteredMask.splice(index, 0, coordinates);
console.log("filtered after splice", filteredMask);
const queryString = filteredMask const queryString = filteredMask
.map((pointsArray) => { .map((pointsArray) => {
@ -144,16 +127,6 @@ export default function MotionMaskEditPane({
}) })
.join(""); .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 axios
.put(`config/set?${queryString}`, { .put(`config/set?${queryString}`, {
requires_restart: 0, requires_restart: 0,
@ -163,7 +136,6 @@ export default function MotionMaskEditPane({
toast.success(`${polygon.name || "Motion Mask"} has been saved.`, { toast.success(`${polygon.name || "Motion Mask"} has been saved.`, {
position: "top-center", position: "top-center",
}); });
// setChangedValue(false);
updateConfig(); updateConfig();
} else { } else {
toast.error(`Failed to save config changes: ${res.statusText}`, { toast.error(`Failed to save config changes: ${res.statusText}`, {
@ -180,23 +152,20 @@ export default function MotionMaskEditPane({
.finally(() => { .finally(() => {
setIsLoading(false); setIsLoading(false);
}); });
}, [updateConfig, polygon, scaledWidth, scaledHeight, setIsLoading]); }, [
updateConfig,
polygon,
scaledWidth,
scaledHeight,
setIsLoading,
cameraConfig,
]);
function onSubmit(values: z.infer<typeof formSchema>) { function onSubmit(values: z.infer<typeof formSchema>) {
if (activePolygonIndex === undefined || !values || !polygons) { if (activePolygonIndex === undefined || !values || !polygons) {
return; return;
} }
setIsLoading(true); 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(); saveToConfig();
if (onSave) { if (onSave) {

View File

@ -33,6 +33,7 @@ import { LuExternalLink } from "react-icons/lu";
type MotionTunerProps = { type MotionTunerProps = {
selectedCamera: string; selectedCamera: string;
setUnsavedChanges: React.Dispatch<React.SetStateAction<boolean>>;
}; };
type MotionSettings = { type MotionSettings = {
@ -41,7 +42,10 @@ type MotionSettings = {
improve_contrast?: boolean; improve_contrast?: boolean;
}; };
export default function MotionTuner({ selectedCamera }: MotionTunerProps) { export default function MotionTuner({
selectedCamera,
setUnsavedChanges,
}: MotionTunerProps) {
const { data: config, mutate: updateConfig } = const { data: config, mutate: updateConfig } =
useSWR<FrigateConfig>("config"); useSWR<FrigateConfig>("config");
const [changedValue, setChangedValue] = useState(false); const [changedValue, setChangedValue] = useState(false);

View File

@ -63,17 +63,6 @@ export default function ObjectMaskEditPane({
}: ObjectMaskEditPaneProps) { }: ObjectMaskEditPaneProps) {
const { data: config, mutate: updateConfig } = const { data: config, mutate: updateConfig } =
useSWR<FrigateConfig>("config"); useSWR<FrigateConfig>("config");
// const { data: config } = useSWR<FrigateConfig>("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(() => { const polygon = useMemo(() => {
if (polygons && activePolygonIndex !== undefined) { if (polygons && activePolygonIndex !== undefined) {
@ -129,22 +118,10 @@ export default function ObjectMaskEditPane({
const saveToConfig = useCallback( const saveToConfig = useCallback(
async ( async (
{ objects: form_objects }: ObjectMaskFormValuesType, // values submitted via the form { objects: form_objects }: ObjectMaskFormValuesType, // values submitted via the form
objects: string[],
) => { ) => {
if (!scaledWidth || !scaledHeight || !polygon || !cameraConfig) { if (!scaledWidth || !scaledHeight || !polygon || !cameraConfig) {
return; 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( const coordinates = flattenPoints(
interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1), interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1),
@ -183,9 +160,6 @@ export default function ObjectMaskEditPane({
index = polygon.typeIndex; index = polygon.typeIndex;
} }
console.log("are we an array?", Array.isArray(configObject));
console.log("index", index);
// editing existing mask, not creating a new one // editing existing mask, not creating a new one
if (editingMask) { if (editingMask) {
index = polygon.typeIndex; index = polygon.typeIndex;
@ -195,10 +169,7 @@ export default function ObjectMaskEditPane({
Array.isArray(configObject) ? configObject : [configObject as string] Array.isArray(configObject) ? configObject : [configObject as string]
).filter((_, currentIndex) => currentIndex !== index); ).filter((_, currentIndex) => currentIndex !== index);
console.log("filtered", filteredMask);
filteredMask.splice(index, 0, coordinates); filteredMask.splice(index, 0, coordinates);
console.log("filtered after splice", filteredMask);
} }
queryString = filteredMask queryString = filteredMask
@ -212,18 +183,7 @@ export default function ObjectMaskEditPane({
}) })
.join(""); .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) { if (!queryString) {
console.log("no query string");
return; return;
} }
@ -236,7 +196,6 @@ export default function ObjectMaskEditPane({
toast.success(`${polygon.name || "Object Mask"} has been saved.`, { toast.success(`${polygon.name || "Object Mask"} has been saved.`, {
position: "top-center", position: "top-center",
}); });
// setChangedValue(false);
updateConfig(); updateConfig();
} else { } else {
toast.error(`Failed to save config changes: ${res.statusText}`, { toast.error(`Failed to save config changes: ${res.statusText}`, {
@ -254,7 +213,14 @@ export default function ObjectMaskEditPane({
setIsLoading(false); setIsLoading(false);
}); });
}, },
[updateConfig, polygon, scaledWidth, scaledHeight, setIsLoading], [
updateConfig,
polygon,
scaledWidth,
scaledHeight,
setIsLoading,
cameraConfig,
],
); );
function onSubmit(values: z.infer<typeof formSchema>) { function onSubmit(values: z.infer<typeof formSchema>) {
@ -262,21 +228,8 @@ export default function ObjectMaskEditPane({
return; return;
} }
setIsLoading(true); setIsLoading(true);
// polygons[activePolygonIndex].name = values.name;
// console.log("form values", values);
// console.log(
// "string",
// flattenPoints( saveToConfig(values as ObjectMaskFormValuesType);
// interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1),
// ).join(","),
// );
// console.log("active polygon", polygons[activePolygonIndex]);
saveToConfig(
values as ObjectMaskFormValuesType,
polygons[activePolygonIndex].objects,
);
if (onSave) { if (onSave) {
onSave(); onSave();
} }

View File

@ -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<FrigateConfig>("config");
const cameraConfig = useMemo(() => {
if (config && selectedCamera) {
return config.cameras[selectedCamera];
}
}, [config, selectedCamera]);
if (!cameraConfig) {
return <ActivityIndicator />;
}
return (
<div className="flex flex-col h-50">
<DebugCameraImage cameraConfig={cameraConfig} className="size-full" />
</div>
);
}

View File

@ -1,11 +1,11 @@
import React, { useMemo, useRef, useState, useEffect } from "react"; import React, { useMemo, useRef, useState, useEffect } from "react";
import PolygonDrawer from "./PolygonDrawer"; 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 Konva from "konva";
import type { KonvaEventObject } from "konva/lib/Node"; import type { KonvaEventObject } from "konva/lib/Node";
import { Polygon, PolygonType } from "@/types/canvas"; import { Polygon, PolygonType } from "@/types/canvas";
import { useApiHost } from "@/api"; import { useApiHost } from "@/api";
import { getAveragePoint, flattenPoints } from "@/utils/canvasUtil"; import { flattenPoints } from "@/utils/canvasUtil";
type PolygonCanvasProps = { type PolygonCanvasProps = {
camera: string; camera: string;
@ -203,54 +203,19 @@ export function PolygonCanvas({
(polygon, index) => (polygon, index) =>
(selectedZoneMask === undefined || (selectedZoneMask === undefined ||
selectedZoneMask.includes(polygon.type)) && ( selectedZoneMask.includes(polygon.type)) && (
<React.Fragment key={index}> <PolygonDrawer
<PolygonDrawer key={index}
key={index} points={polygon.points}
points={polygon.points} flattenedPoints={flattenPoints(polygon.points)}
flattenedPoints={flattenPoints(polygon.points)} isActive={index === activePolygonIndex}
isActive={index === activePolygonIndex} isHovered={index === hoveredPolygonIndex}
isHovered={index === hoveredPolygonIndex} isFinished={polygon.isFinished}
isFinished={polygon.isFinished} color={polygon.color}
color={polygon.color} handlePointDragMove={handlePointDragMove}
name={polygon.name} handleGroupDragEnd={handleGroupDragEnd}
handlePointDragMove={handlePointDragMove} handleMouseOverStartPoint={handleMouseOverStartPoint}
handleGroupDragEnd={handleGroupDragEnd} handleMouseOutStartPoint={handleMouseOutStartPoint}
handleMouseOverStartPoint={handleMouseOverStartPoint} />
handleMouseOutStartPoint={handleMouseOutStartPoint}
/>
{index === hoveredPolygonIndex && (
<>
<Circle
x={
getAveragePoint(flattenPoints(polygon.points)).x //-
//(polygon.name.length * 16 * 0.6) / 2
}
y={
getAveragePoint(flattenPoints(polygon.points)).y //-
//16 / 2
}
radius={2}
fill="red"
/>
<Text
text={polygon.name}
// align="left"
// verticalAlign="top"
align="center"
verticalAlign="middle"
x={
getAveragePoint(flattenPoints(polygon.points)).x //-
//(polygon.name.length * 16 * 0.6) / 2
}
y={
getAveragePoint(flattenPoints(polygon.points)).y //-
//16 / 2
}
fontSize={16}
/>
</>
)}
</React.Fragment>
), ),
)} )}
</Layer> </Layer>

View File

@ -1,11 +1,6 @@
import { useCallback, useRef, useState } from "react"; import { useCallback, useRef, useState } from "react";
import { Line, Circle, Group, Text } from "react-konva"; import { Line, Circle, Group } from "react-konva";
import { import { minMax, toRGBColorString, dragBoundFunc } from "@/utils/canvasUtil";
minMax,
toRGBColorString,
dragBoundFunc,
getAveragePoint,
} from "@/utils/canvasUtil";
import type { KonvaEventObject } from "konva/lib/Node"; import type { KonvaEventObject } from "konva/lib/Node";
import Konva from "konva"; import Konva from "konva";
import { Vector2d } from "konva/lib/types"; import { Vector2d } from "konva/lib/types";
@ -17,7 +12,6 @@ type PolygonDrawerProps = {
isHovered: boolean; isHovered: boolean;
isFinished: boolean; isFinished: boolean;
color: number[]; color: number[];
name: string;
handlePointDragMove: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void; handlePointDragMove: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void;
handleGroupDragEnd: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void; handleGroupDragEnd: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void;
handleMouseOverStartPoint: ( handleMouseOverStartPoint: (
@ -34,7 +28,6 @@ export default function PolygonDrawer({
isActive, isActive,
isHovered, isHovered,
isFinished, isFinished,
name,
color, color,
handlePointDragMove, handlePointDragMove,
handleGroupDragEnd, handleGroupDragEnd,
@ -93,8 +86,6 @@ export default function PolygonDrawer({
[color], [color],
); );
// console.log(groupRef.current?.height());
return ( return (
<Group <Group
name="polygon" name="polygon"
@ -157,26 +148,6 @@ export default function PolygonDrawer({
/> />
); );
})} })}
{groupRef.current && (
<Text
text={name}
// align="left"
// verticalAlign="top"
width={groupRef.current.width()}
height={groupRef.current.height()}
align="center"
verticalAlign="middle"
x={
getAveragePoint(flattenedPoints).x //-
//(polygon.name.length * 16 * 0.6) / 2
}
y={
getAveragePoint(flattenedPoints).y //-
//16 / 2
}
fontSize={16}
/>
)}
</Group> </Group>
); );
} }

View File

@ -36,9 +36,7 @@ import { reviewQueries } from "@/utils/zoneEdutUtil";
type PolygonItemProps = { type PolygonItemProps = {
polygon: Polygon; polygon: Polygon;
setAllPolygons: React.Dispatch<React.SetStateAction<Polygon[]>>;
index: number; index: number;
activePolygonIndex: number | undefined;
hoveredPolygonIndex: number | null; hoveredPolygonIndex: number | null;
setHoveredPolygonIndex: (index: number | null) => void; setHoveredPolygonIndex: (index: number | null) => void;
setActivePolygonIndex: (index: number | undefined) => void; setActivePolygonIndex: (index: number | undefined) => void;
@ -48,9 +46,7 @@ type PolygonItemProps = {
export default function PolygonItem({ export default function PolygonItem({
polygon, polygon,
setAllPolygons,
index, index,
activePolygonIndex,
hoveredPolygonIndex, hoveredPolygonIndex,
setHoveredPolygonIndex, setHoveredPolygonIndex,
setActivePolygonIndex, setActivePolygonIndex,
@ -60,6 +56,7 @@ export default function PolygonItem({
const { data: config, mutate: updateConfig } = const { data: config, mutate: updateConfig } =
useSWR<FrigateConfig>("config"); useSWR<FrigateConfig>("config");
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const cameraConfig = useMemo(() => { const cameraConfig = useMemo(() => {
if (polygon?.camera && config) { if (polygon?.camera && config) {
@ -93,14 +90,11 @@ export default function PolygonItem({
url = `cameras.${polygon.camera}.zones.${polygon.name}${alertQueries}${detectionQueries}`; url = `cameras.${polygon.camera}.zones.${polygon.name}${alertQueries}${detectionQueries}`;
} }
if (polygon.type == "motion_mask") { if (polygon.type == "motion_mask") {
console.log("deleting", polygon.typeIndex);
const filteredMask = ( const filteredMask = (
Array.isArray(cameraConfig.motion.mask) Array.isArray(cameraConfig.motion.mask)
? cameraConfig.motion.mask ? cameraConfig.motion.mask
: [cameraConfig.motion.mask] : [cameraConfig.motion.mask]
).filter((_, currentIndex) => currentIndex !== polygon.typeIndex); ).filter((_, currentIndex) => currentIndex !== polygon.typeIndex);
console.log(filteredMask);
url = filteredMask url = filteredMask
.map((pointsArray) => { .map((pointsArray) => {
@ -115,21 +109,14 @@ export default function PolygonItem({
// deleting last mask // deleting last mask
url = `cameras.${polygon?.camera}.motion.mask&`; url = `cameras.${polygon?.camera}.motion.mask&`;
} }
console.log(url);
// return;
// url = `config/set?cameras.${polygon.camera}.motion.mask`;
} }
if (polygon.type == "object_mask") { if (polygon.type == "object_mask") {
console.log("deleting", polygon.typeIndex, polygon);
let configObject; let configObject;
let globalMask = false; let globalMask = false;
console.log("polygon objects", polygon.objects, !polygon.objects);
// global mask on camera for all objects // global mask on camera for all objects
if (!polygon.objects.length) { if (!polygon.objects.length) {
console.log("deleting global");
configObject = cameraConfig.objects.mask; configObject = cameraConfig.objects.mask;
globalMask = true; globalMask = true;
} else { } else {
@ -152,28 +139,13 @@ export default function PolygonItem({
Array.isArray(configObject) ? configObject : [configObject] Array.isArray(configObject) ? configObject : [configObject]
).filter((_, currentIndex) => currentIndex !== polygon.typeIndex); ).filter((_, currentIndex) => currentIndex !== polygon.typeIndex);
} else { } else {
console.log("not globals config object:", configObject);
filteredMask = ( filteredMask = (
Array.isArray(configObject) ? configObject : [configObject] Array.isArray(configObject) ? configObject : [configObject]
) )
.filter((mask) => !globalObjectMasksArray.includes(mask)) .filter((mask) => !globalObjectMasksArray.includes(mask))
.filter((_, currentIndex) => { .filter((_, currentIndex) => currentIndex !== polygon.typeIndex);
console.log(
"current index",
currentIndex,
"global length:",
globalObjectMasksArray.length,
"polygon typeindex",
polygon.typeIndex,
);
return currentIndex !== polygon.typeIndex;
});
} }
console.log("filtered:", filteredMask);
url = filteredMask url = filteredMask
.map((pointsArray) => { .map((pointsArray) => {
const coordinates = flattenPoints( const coordinates = flattenPoints(
@ -191,13 +163,10 @@ export default function PolygonItem({
? `cameras.${polygon?.camera}.objects.mask&` ? `cameras.${polygon?.camera}.objects.mask&`
: `cameras.${polygon?.camera}.objects.filters.${polygon.objects[0]}.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 await axios
.put(`config/set?${url}`, { requires_restart: 0 }) .put(`config/set?${url}`, { requires_restart: 0 })
.then((res) => { .then((res) => {
@ -205,7 +174,6 @@ export default function PolygonItem({
toast.success(`${polygon?.name} has been deleted.`, { toast.success(`${polygon?.name} has been deleted.`, {
position: "top-center", position: "top-center",
}); });
// setChangedValue(false);
updateConfig(); updateConfig();
} else { } else {
toast.error(`Failed to save config changes: ${res.statusText}`, { toast.error(`Failed to save config changes: ${res.statusText}`, {
@ -220,40 +188,13 @@ export default function PolygonItem({
); );
}) })
.finally(() => { .finally(() => {
// setIsLoading(false); setIsLoading(false);
}); });
}, },
[updateConfig, cameraConfig], [updateConfig, cameraConfig],
); );
const reindexPolygons = (arr: Polygon[]): Polygon[] => { const handleDelete = () => {
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;
// });
setActivePolygonIndex(undefined); setActivePolygonIndex(undefined);
saveToConfig(polygon); saveToConfig(polygon);
}; };
@ -307,9 +248,7 @@ export default function PolygonItem({
</AlertDialogDescription> </AlertDialogDescription>
<AlertDialogFooter> <AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction <AlertDialogAction onClick={handleDelete}>
onClick={() => handleDelete(polygon.type, polygon.typeIndex)}
>
Delete Delete
</AlertDialogAction> </AlertDialogAction>
</AlertDialogFooter> </AlertDialogFooter>
@ -334,7 +273,10 @@ export default function PolygonItem({
<DropdownMenuItem onClick={() => handleCopyCoordinates(index)}> <DropdownMenuItem onClick={() => handleCopyCoordinates(index)}>
Copy Copy
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem onClick={() => setDeleteDialogOpen(true)}> <DropdownMenuItem
disabled={isLoading}
onClick={() => setDeleteDialogOpen(true)}
>
Delete Delete
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
@ -378,7 +320,7 @@ export default function PolygonItem({
</div> </div>
<div <div
className="cursor-pointer size-[15px]" className="cursor-pointer size-[15px]"
onClick={() => setDeleteDialogOpen(true)} onClick={() => !isLoading && setDeleteDialogOpen(true)}
> >
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>

View File

@ -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( const saveToConfig = useCallback(
async ( async (
{ {
@ -198,11 +171,6 @@ export default function ZoneEditPane({
if (!scaledWidth || !scaledHeight || !polygon) { if (!scaledWidth || !scaledHeight || !polygon) {
return; 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; let mutatedConfig = config;
const renamingZone = zoneName != polygon.name && polygon.name != ""; const renamingZone = zoneName != polygon.name && polygon.name != "";
@ -231,8 +199,6 @@ export default function ZoneEditPane({
// Wait for the config to be updated // Wait for the config to be updated
mutatedConfig = await updateConfig(); mutatedConfig = await updateConfig();
// console.log("this should be updated...", mutatedConfig.cameras);
// console.log("check original config object...", config);
} catch (error) { } catch (error) {
toast.error(`Failed to save config changes.`, { toast.error(`Failed to save config changes.`, {
position: "top-center", position: "top-center",
@ -241,12 +207,9 @@ export default function ZoneEditPane({
} }
} }
// console.log("out of try except", mutatedConfig);
const coordinates = flattenPoints( const coordinates = flattenPoints(
interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1), interpolatePoints(polygon.points, scaledWidth, scaledHeight, 1, 1),
).join(","); ).join(",");
// const foo = config.cameras["doorbell"].zones["outside"].objects;
let objectQueries = objects let objectQueries = objects
.map( .map(
@ -263,7 +226,6 @@ export default function ZoneEditPane({
// deleting objects // deleting objects
if (!objectQueries && !same_objects && !renamingZone) { if (!objectQueries && !same_objects && !renamingZone) {
// console.log("deleting objects");
objectQueries = `&cameras.${polygon?.camera}.zones.${zoneName}.objects`; objectQueries = `&cameras.${polygon?.camera}.zones.${zoneName}.objects`;
} }
@ -278,14 +240,6 @@ export default function ZoneEditPane({
.required_zones || [], .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 axios
.put( .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}`, `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.`, { toast.success(`Zone (${zoneName}) has been saved.`, {
position: "top-center", position: "top-center",
}); });
// setChangedValue(false);
updateConfig(); updateConfig();
} else { } else {
toast.error(`Failed to save config changes: ${res.statusText}`, { toast.error(`Failed to save config changes: ${res.statusText}`, {
@ -330,16 +283,6 @@ export default function ZoneEditPane({
return; return;
} }
setIsLoading(true); 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( saveToConfig(
values as ZoneFormValuesType, values as ZoneFormValuesType,

View File

@ -5,7 +5,6 @@ import {
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
// import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer";
import MotionTuner from "@/components/settings/MotionTuner"; import MotionTuner from "@/components/settings/MotionTuner";
@ -13,7 +12,6 @@ import MasksAndZones from "@/components/settings/MasksAndZones";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import useOptimisticState from "@/hooks/use-optimistic-state"; import useOptimisticState from "@/hooks/use-optimistic-state";
import Logo from "@/components/Logo";
import { isMobile } from "react-device-detect"; import { isMobile } from "react-device-detect";
import { FaVideo } from "react-icons/fa"; import { FaVideo } from "react-icons/fa";
import { CameraConfig, FrigateConfig } from "@/types/frigateConfig"; import { CameraConfig, FrigateConfig } from "@/types/frigateConfig";
@ -22,6 +20,7 @@ import General from "@/components/settings/General";
import FilterSwitch from "@/components/filter/FilterSwitch"; import FilterSwitch from "@/components/filter/FilterSwitch";
import { ZoneMaskFilterButton } from "@/components/filter/ZoneMaskFilter"; import { ZoneMaskFilterButton } from "@/components/filter/ZoneMaskFilter";
import { PolygonType } from "@/types/canvas"; import { PolygonType } from "@/types/canvas";
import ObjectSettings from "@/components/settings/ObjectSettings";
export default function Settings() { export default function Settings() {
const settingsViews = [ const settingsViews = [
@ -37,7 +36,7 @@ export default function Settings() {
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
const [isEditing, setIsEditing] = useState(false); // TODO: confirm leave page
const [unsavedChanges, setUnsavedChanges] = useState(false); const [unsavedChanges, setUnsavedChanges] = useState(false);
const cameras = useMemo(() => { const cameras = useMemo(() => {
@ -50,7 +49,7 @@ export default function Settings() {
.sort((aConf, bConf) => aConf.ui.order - bConf.ui.order); .sort((aConf, bConf) => aConf.ui.order - bConf.ui.order);
}, [config]); }, [config]);
const [selectedCamera, setSelectedCamera] = useState<string>(); const [selectedCamera, setSelectedCamera] = useState<string>("");
const [filterZoneMask, setFilterZoneMask] = useState<PolygonType[]>(); const [filterZoneMask, setFilterZoneMask] = useState<PolygonType[]>();
@ -58,6 +57,8 @@ export default function Settings() {
if (cameras.length) { if (cameras.length) {
setSelectedCamera(cameras[0].name); setSelectedCamera(cameras[0].name);
} }
// only run once
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
return ( return (
@ -77,7 +78,7 @@ export default function Settings() {
{Object.values(settingsViews).map((item) => ( {Object.values(settingsViews).map((item) => (
<ToggleGroupItem <ToggleGroupItem
key={item} key={item}
className={`flex items-center justify-between gap-2 ${pageToggle == item ? "" : "*:text-gray-500"}`} className={`flex items-center justify-between gap-2 ${pageToggle == item ? "" : "*:text-muted-foreground"}`}
value={item} value={item}
aria-label={`Select ${item}`} aria-label={`Select ${item}`}
> >
@ -105,19 +106,21 @@ export default function Settings() {
</div> </div>
<div className="mt-2 flex flex-col items-start w-full h-full md:h-dvh md:pb-24"> <div className="mt-2 flex flex-col items-start w-full h-full md:h-dvh md:pb-24">
{page == "general" && <General />} {page == "general" && <General />}
{page == "objects" && <></>} {page == "objects" && (
<ObjectSettings selectedCamera={selectedCamera} />
)}
{page == "masks / zones" && ( {page == "masks / zones" && (
<MasksAndZones <MasksAndZones
selectedCamera={selectedCamera} selectedCamera={selectedCamera}
selectedZoneMask={filterZoneMask} selectedZoneMask={filterZoneMask}
isEditing={isEditing}
setIsEditing={setIsEditing}
unsavedChanges={unsavedChanges}
setUnsavedChanges={setUnsavedChanges} setUnsavedChanges={setUnsavedChanges}
/> />
)} )}
{page == "motion tuner" && ( {page == "motion tuner" && (
<MotionTuner selectedCamera={selectedCamera} /> <MotionTuner
selectedCamera={selectedCamera}
setUnsavedChanges={setUnsavedChanges}
/>
)} )}
</div> </div>
</div> </div>

View File

@ -10,24 +10,9 @@ export const reviewQueries = (
let detectionQueries = ""; let detectionQueries = "";
let same_alerts = false; let same_alerts = false;
let same_detections = 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<string>(alertsZones || []); const alerts = new Set<string>(alertsZones || []);
// config?.cameras[camera].review.alerts.required_zones.forEach((zone) => {
// alerts.add(zone);
// });
if (review_alerts) { if (review_alerts) {
alerts.add(name); alerts.add(name);
} else { } else {
@ -40,9 +25,6 @@ export const reviewQueries = (
.join(""); .join("");
const detections = new Set<string>(detectionsZones || []); const detections = new Set<string>(detectionsZones || []);
// config?.cameras[camera].review.detections.required_zones.forEach((zone) => {
// detections.add(zone);
// });
if (review_detections) { if (review_detections) {
detections.add(name); detections.add(name);
@ -57,36 +39,10 @@ export const reviewQueries = (
) )
.join(""); .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) { if (!alertQueries && !same_alerts) {
// console.log("deleting alerts");
alertQueries = `&cameras.${camera}.review.alerts`; alertQueries = `&cameras.${camera}.review.alerts`;
} }
if (!detectionQueries && !same_detections) { if (!detectionQueries && !same_detections) {
// console.log("deleting detection");
detectionQueries = `&cameras.${camera}.review.detections`; detectionQueries = `&cameras.${camera}.review.detections`;
} }