diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index 1ff14f63c..1c69fe4b5 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -1609,13 +1609,34 @@ }, "configMessages": { "review": { - "recordDisabled": "Recording is disabled, review items will not be generated." + "recordDisabled": "Recording is disabled, review items will not be generated.", + "detectDisabled": "Object detection is disabled. Review items require detected objects to categorize alerts and detections." }, "audio": { "noAudioRole": "No streams have the audio role defined. You must enable the audio role for audio detection to function." }, + "audioTranscription": { + "audioDetectionDisabled": "Audio detection is not enabled for this camera. Audio transcription requires audio detection to be active." + }, "detect": { "fpsGreaterThanFive": "Setting the detect FPS higher than 5 is not recommended." + }, + "faceRecognition": { + "globalDisabled": "Face recognition is not enabled at the global level. Enable it in global settings for camera-level face recognition to function.", + "personNotTracked": "Face recognition requires the 'person' object to be tracked. Ensure 'person' is in the object tracking list." + }, + "lpr": { + "globalDisabled": "License plate recognition is not enabled at the global level. Enable it in global settings for camera-level LPR to function.", + "vehicleNotTracked": "License plate recognition requires 'car' or 'motorcycle' to be tracked." + }, + "record": { + "noRecordRole": "No streams have the record role defined. Recording will not function." + }, + "birdseye": { + "objectsModeDetectDisabled": "Birdseye is set to 'objects' mode, but object detection is disabled for this camera. The camera will not appear in Birdseye." + }, + "snapshots": { + "detectDisabled": "Object detection is disabled. Snapshots are generated from tracked objects and will not be created." } } } diff --git a/web/src/components/config-form/ConfigMessageBanner.tsx b/web/src/components/config-form/ConfigMessageBanner.tsx index 15455705d..f5b828000 100644 --- a/web/src/components/config-form/ConfigMessageBanner.tsx +++ b/web/src/components/config-form/ConfigMessageBanner.tsx @@ -36,12 +36,12 @@ export function ConfigMessageBanner({ messages }: ConfigMessageBannerProps) { if (messages.length === 0) return null; return ( -
+
{messages.map((msg) => ( {t(msg.messageKey)} diff --git a/web/src/components/config-form/section-configs/audio_transcription.ts b/web/src/components/config-form/section-configs/audio_transcription.ts index 169a77954..8e8e70d77 100644 --- a/web/src/components/config-form/section-configs/audio_transcription.ts +++ b/web/src/components/config-form/section-configs/audio_transcription.ts @@ -3,6 +3,19 @@ import type { SectionConfigOverrides } from "./types"; const audioTranscription: SectionConfigOverrides = { base: { sectionDocs: "/configuration/audio_detectors#audio-transcription", + messages: [ + { + key: "audio-detection-disabled", + messageKey: "configMessages.audioTranscription.audioDetectionDisabled", + severity: "warning", + condition: (ctx) => { + if (ctx.level === "camera" && ctx.fullCameraConfig) { + return ctx.fullCameraConfig.audio.enabled === false; + } + return false; + }, + }, + ], restartRequired: [], fieldOrder: ["enabled", "language", "device", "model_size"], hiddenFields: ["enabled_in_config", "live_enabled"], diff --git a/web/src/components/config-form/section-configs/birdseye.ts b/web/src/components/config-form/section-configs/birdseye.ts index 63fae75d9..d621c9203 100644 --- a/web/src/components/config-form/section-configs/birdseye.ts +++ b/web/src/components/config-form/section-configs/birdseye.ts @@ -3,6 +3,20 @@ import type { SectionConfigOverrides } from "./types"; const birdseye: SectionConfigOverrides = { base: { sectionDocs: "/configuration/birdseye", + messages: [ + { + key: "objects-mode-detect-disabled", + messageKey: "configMessages.birdseye.objectsModeDetectDisabled", + severity: "info", + condition: (ctx) => { + if (ctx.level !== "camera" || !ctx.fullCameraConfig) return false; + return ( + ctx.formData?.mode === "objects" && + ctx.fullCameraConfig.detect?.enabled === false + ); + }, + }, + ], restartRequired: [], fieldOrder: ["enabled", "mode", "order"], hiddenFields: [], diff --git a/web/src/components/config-form/section-configs/face_recognition.ts b/web/src/components/config-form/section-configs/face_recognition.ts index ef9e43506..822f6ffe0 100644 --- a/web/src/components/config-form/section-configs/face_recognition.ts +++ b/web/src/components/config-form/section-configs/face_recognition.ts @@ -3,6 +3,26 @@ import type { SectionConfigOverrides } from "./types"; const faceRecognition: SectionConfigOverrides = { base: { sectionDocs: "/configuration/face_recognition", + messages: [ + { + key: "global-disabled", + messageKey: "configMessages.faceRecognition.globalDisabled", + severity: "warning", + condition: (ctx) => { + if (ctx.level !== "camera") return false; + return ctx.fullConfig.face_recognition?.enabled === false; + }, + }, + { + key: "person-not-tracked", + messageKey: "configMessages.faceRecognition.personNotTracked", + severity: "info", + condition: (ctx) => { + if (ctx.level !== "camera" || !ctx.fullCameraConfig) return false; + return !ctx.fullCameraConfig.objects?.track?.includes("person"); + }, + }, + ], restartRequired: [], fieldOrder: ["enabled", "min_area"], hiddenFields: [], diff --git a/web/src/components/config-form/section-configs/lpr.ts b/web/src/components/config-form/section-configs/lpr.ts index 514dba9be..4997d766f 100644 --- a/web/src/components/config-form/section-configs/lpr.ts +++ b/web/src/components/config-form/section-configs/lpr.ts @@ -3,6 +3,28 @@ import type { SectionConfigOverrides } from "./types"; const lpr: SectionConfigOverrides = { base: { sectionDocs: "/configuration/license_plate_recognition", + messages: [ + { + key: "global-disabled", + messageKey: "configMessages.lpr.globalDisabled", + severity: "warning", + condition: (ctx) => { + if (ctx.level !== "camera") return false; + return ctx.fullConfig.lpr?.enabled === false; + }, + }, + { + key: "vehicle-not-tracked", + messageKey: "configMessages.lpr.vehicleNotTracked", + severity: "info", + condition: (ctx) => { + if (ctx.level !== "camera" || !ctx.fullCameraConfig) return false; + if (ctx.fullCameraConfig.type === "lpr") return false; + const tracked = ctx.fullCameraConfig.objects?.track ?? []; + return !tracked.some((o) => ["car", "motorcycle"].includes(o)); + }, + }, + ], fieldDocs: { enhancement: "/configuration/license_plate_recognition#enhancement", }, diff --git a/web/src/components/config-form/section-configs/record.ts b/web/src/components/config-form/section-configs/record.ts index 05a21f224..35f3b1ef7 100644 --- a/web/src/components/config-form/section-configs/record.ts +++ b/web/src/components/config-form/section-configs/record.ts @@ -3,6 +3,19 @@ import type { SectionConfigOverrides } from "./types"; const record: SectionConfigOverrides = { base: { sectionDocs: "/configuration/record", + messages: [ + { + key: "no-record-role", + messageKey: "configMessages.record.noRecordRole", + severity: "warning", + condition: (ctx) => { + if (ctx.level !== "camera" || !ctx.fullCameraConfig) return false; + return !ctx.fullCameraConfig.ffmpeg?.inputs?.some((i) => + i.roles?.includes("record"), + ); + }, + }, + ], restartRequired: [], fieldOrder: [ "enabled", diff --git a/web/src/components/config-form/section-configs/review.ts b/web/src/components/config-form/section-configs/review.ts index 6805e8cc3..8b8fdc5af 100644 --- a/web/src/components/config-form/section-configs/review.ts +++ b/web/src/components/config-form/section-configs/review.ts @@ -15,6 +15,17 @@ const review: SectionConfigOverrides = { return ctx.fullConfig.record?.enabled === false; }, }, + { + key: "detect-disabled", + messageKey: "configMessages.review.detectDisabled", + severity: "info", + condition: (ctx) => { + if (ctx.level === "camera" && ctx.fullCameraConfig) { + return ctx.fullCameraConfig.detect?.enabled === false; + } + return false; + }, + }, ], fieldDocs: { "alerts.labels": "/configuration/review/#alerts-and-detections", diff --git a/web/src/components/config-form/section-configs/snapshots.ts b/web/src/components/config-form/section-configs/snapshots.ts index 126ecd496..7d08cc728 100644 --- a/web/src/components/config-form/section-configs/snapshots.ts +++ b/web/src/components/config-form/section-configs/snapshots.ts @@ -3,6 +3,17 @@ import type { SectionConfigOverrides } from "./types"; const snapshots: SectionConfigOverrides = { base: { sectionDocs: "/configuration/snapshots", + messages: [ + { + key: "detect-disabled", + messageKey: "configMessages.snapshots.detectDisabled", + severity: "info", + condition: (ctx) => { + if (ctx.level !== "camera" || !ctx.fullCameraConfig) return false; + return ctx.fullCameraConfig.detect?.enabled === false; + }, + }, + ], restartRequired: [], fieldOrder: [ "enabled",