From b116f61055f71ae699c7ed213af85dbced7a8e4b Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:53:20 -0500 Subject: [PATCH] require all masks and zones to be on the base config --- web/public/locales/en/views/settings.json | 1 + web/src/components/settings/PolygonItem.tsx | 96 ++++++++++++++++---- web/src/views/settings/MasksAndZonesView.tsx | 87 ++++++++++-------- 3 files changed, 131 insertions(+), 53 deletions(-) diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index 18c277cfce..fb0eb09bc2 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -539,6 +539,7 @@ }, "restart_required": "Restart required (masks/zones changed)", "disabledInConfig": "Item is disabled in the config file", + "addDisabledProfile": "Add to the base config first, then override in the profile", "profileBase": "(base)", "profileOverride": "(override)", "toast": { diff --git a/web/src/components/settings/PolygonItem.tsx b/web/src/components/settings/PolygonItem.tsx index 04030656d8..4740e48fb6 100644 --- a/web/src/components/settings/PolygonItem.tsx +++ b/web/src/components/settings/PolygonItem.tsx @@ -154,7 +154,19 @@ export default function PolygonItem({ cameraConfig?.review.alerts.required_zones || [], cameraConfig?.review.detections.required_zones || [], ); - url = `cameras.${polygon.camera}.zones.${polygon.name}${alertQueries}${detectionQueries}`; + // Also delete from profiles that have overrides for this zone + let profileQueries = ""; + if (allProfileNames && cameraConfig) { + for (const profileName of allProfileNames) { + if ( + cameraConfig.profiles?.[profileName]?.zones?.[polygon.name] !== + undefined + ) { + profileQueries += `&cameras.${polygon.camera}.profiles.${profileName}.zones.${polygon.name}`; + } + } + } + url = `cameras.${polygon.camera}.zones.${polygon.name}${alertQueries}${detectionQueries}${profileQueries}`; } await axios @@ -214,11 +226,41 @@ export default function PolygonItem({ }, }; + let cameraUpdate: Record; + if (editingProfile) { + cameraUpdate = { profiles: { [editingProfile]: deleteSection } }; + } else { + // Base mode: also delete from profiles that have overrides for this mask + const profileDeletes: Record = {}; + if (allProfileNames && cameraConfig) { + for (const profileName of allProfileNames) { + const profileData = cameraConfig.profiles?.[profileName]; + if (!profileData) continue; + + const hasMask = + polygon.type === "motion_mask" + ? profileData.motion?.mask?.[polygon.name] !== undefined + : polygon.type === "object_mask" + ? profileData.objects?.mask?.[polygon.name] !== undefined || + Object.values(profileData.objects?.filters || {}).some( + (f) => f?.mask?.[polygon.name] !== undefined, + ) + : false; + + if (hasMask) { + profileDeletes[profileName] = deleteSection; + } + } + } + cameraUpdate = + Object.keys(profileDeletes).length > 0 + ? { ...deleteSection, profiles: profileDeletes } + : deleteSection; + } + const configUpdate = { cameras: { - [polygon.camera]: editingProfile - ? { profiles: { [editingProfile]: deleteSection } } - : deleteSection, + [polygon.camera]: cameraUpdate, }, }; @@ -271,6 +313,7 @@ export default function PolygonItem({ index, setLoadingPolygonIndex, editingProfile, + allProfileNames, onDeleted, ], ); @@ -430,22 +473,41 @@ export default function PolygonItem({ - {t("masksAndZones.form.polygonDrawing.delete.title")} + {polygon.polygonSource === "override" + ? t( + "masksAndZones.form.polygonDrawing.revertOverride.title", + ) + : t("masksAndZones.form.polygonDrawing.delete.title")} - - masksAndZones.form.polygonDrawing.delete.desc - + {polygon.polygonSource === "override" ? ( + + masksAndZones.form.polygonDrawing.revertOverride.desc + + ) : ( + + masksAndZones.form.polygonDrawing.delete.desc + + )} diff --git a/web/src/views/settings/MasksAndZonesView.tsx b/web/src/views/settings/MasksAndZonesView.tsx index cab607c474..84b27d51af 100644 --- a/web/src/views/settings/MasksAndZonesView.tsx +++ b/web/src/views/settings/MasksAndZonesView.tsx @@ -816,20 +816,25 @@ export default function MasksAndZonesView({ - + + + - {t("masksAndZones.zones.add")} + {currentEditingProfile + ? t("masksAndZones.addDisabledProfile") + : t("masksAndZones.zones.add")} @@ -891,20 +896,25 @@ export default function MasksAndZonesView({ - + + + - {t("masksAndZones.motionMasks.add")} + {currentEditingProfile + ? t("masksAndZones.addDisabledProfile") + : t("masksAndZones.motionMasks.add")} @@ -968,20 +978,25 @@ export default function MasksAndZonesView({ - + + + - {t("masksAndZones.objectMasks.add")} + {currentEditingProfile + ? t("masksAndZones.addDisabledProfile") + : t("masksAndZones.objectMasks.add")}