From a97333d881a89541d623ba98c91029c833841eaa Mon Sep 17 00:00:00 2001
From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
Date: Sun, 1 Feb 2026 11:35:04 -0600
Subject: [PATCH] refactor configs to use individual files with a template
---
.../config-form/section-configs/audio.ts | 27 +
.../section-configs/audio_transcription.ts | 16 +
.../config-form/section-configs/auth.ts | 37 +
.../config-form/section-configs/birdseye.ts | 26 +
.../section-configs/classification.ts | 10 +
.../config-form/section-configs/database.ts | 10 +
.../config-form/section-configs/detect.ts | 29 +
.../config-form/section-configs/detectors.ts | 10 +
.../section-configs/environment_vars.ts | 10 +
.../section-configs/face_recognition.ts | 36 +
.../config-form/section-configs/ffmpeg.ts | 192 ++++
.../config-form/section-configs/genai.ts | 18 +
.../config-form/section-configs/live.ts | 12 +
.../config-form/section-configs/logger.ts | 10 +
.../config-form/section-configs/lpr.ts | 41 +
.../config-form/section-configs/model.ts | 25 +
.../config-form/section-configs/motion.ts | 32 +
.../config-form/section-configs/mqtt.ts | 52 +
.../config-form/section-configs/networking.ts | 10 +
.../section-configs/notifications.ts | 12 +
.../config-form/section-configs/objects.ts | 57 ++
.../config-form/section-configs/onvif.ts | 33 +
.../config-form/section-configs/proxy.ts | 17 +
.../config-form/section-configs/record.ts | 24 +
.../config-form/section-configs/review.ts | 31 +
.../section-configs/semantic_search.ts | 21 +
.../config-form/section-configs/snapshots.ts | 29 +
.../config-form/section-configs/telemetry.ts | 10 +
.../section-configs/timestamp_style.ts | 11 +
.../config-form/section-configs/tls.ts | 10 +
.../config-form/section-configs/types.ts | 7 +
.../config-form/section-configs/ui.ts | 22 +
.../components/config-form/sectionConfigs.ts | 887 ++----------------
.../config-form/sectionConfigsUtils.ts | 32 +
.../sections/ConfigSectionTemplate.tsx | 40 +
.../components/config-form/sections/index.ts | 38 +-
web/src/pages/Settings.tsx | 6 -
web/src/views/settings/CameraConfigView.tsx | 144 +--
web/src/views/settings/GlobalConfigView.tsx | 123 +--
web/src/views/settings/SingleSectionPage.tsx | 11 +-
40 files changed, 1111 insertions(+), 1057 deletions(-)
create mode 100644 web/src/components/config-form/section-configs/audio.ts
create mode 100644 web/src/components/config-form/section-configs/audio_transcription.ts
create mode 100644 web/src/components/config-form/section-configs/auth.ts
create mode 100644 web/src/components/config-form/section-configs/birdseye.ts
create mode 100644 web/src/components/config-form/section-configs/classification.ts
create mode 100644 web/src/components/config-form/section-configs/database.ts
create mode 100644 web/src/components/config-form/section-configs/detect.ts
create mode 100644 web/src/components/config-form/section-configs/detectors.ts
create mode 100644 web/src/components/config-form/section-configs/environment_vars.ts
create mode 100644 web/src/components/config-form/section-configs/face_recognition.ts
create mode 100644 web/src/components/config-form/section-configs/ffmpeg.ts
create mode 100644 web/src/components/config-form/section-configs/genai.ts
create mode 100644 web/src/components/config-form/section-configs/live.ts
create mode 100644 web/src/components/config-form/section-configs/logger.ts
create mode 100644 web/src/components/config-form/section-configs/lpr.ts
create mode 100644 web/src/components/config-form/section-configs/model.ts
create mode 100644 web/src/components/config-form/section-configs/motion.ts
create mode 100644 web/src/components/config-form/section-configs/mqtt.ts
create mode 100644 web/src/components/config-form/section-configs/networking.ts
create mode 100644 web/src/components/config-form/section-configs/notifications.ts
create mode 100644 web/src/components/config-form/section-configs/objects.ts
create mode 100644 web/src/components/config-form/section-configs/onvif.ts
create mode 100644 web/src/components/config-form/section-configs/proxy.ts
create mode 100644 web/src/components/config-form/section-configs/record.ts
create mode 100644 web/src/components/config-form/section-configs/review.ts
create mode 100644 web/src/components/config-form/section-configs/semantic_search.ts
create mode 100644 web/src/components/config-form/section-configs/snapshots.ts
create mode 100644 web/src/components/config-form/section-configs/telemetry.ts
create mode 100644 web/src/components/config-form/section-configs/timestamp_style.ts
create mode 100644 web/src/components/config-form/section-configs/tls.ts
create mode 100644 web/src/components/config-form/section-configs/types.ts
create mode 100644 web/src/components/config-form/section-configs/ui.ts
create mode 100644 web/src/components/config-form/sectionConfigsUtils.ts
create mode 100644 web/src/components/config-form/sections/ConfigSectionTemplate.tsx
diff --git a/web/src/components/config-form/section-configs/audio.ts b/web/src/components/config-form/section-configs/audio.ts
new file mode 100644
index 000000000..99e6131a0
--- /dev/null
+++ b/web/src/components/config-form/section-configs/audio.ts
@@ -0,0 +1,27 @@
+import type { SectionConfigOverrides } from "./types";
+
+const audio: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "enabled",
+ "listen",
+ "filters",
+ "min_volume",
+ "max_not_heard",
+ "num_threads",
+ ],
+ fieldGroups: {
+ detection: ["enabled", "listen", "filters"],
+ sensitivity: ["min_volume", "max_not_heard"],
+ },
+ hiddenFields: ["enabled_in_config"],
+ advancedFields: ["min_volume", "max_not_heard", "num_threads"],
+ uiSchema: {
+ listen: {
+ "ui:widget": "audioLabels",
+ },
+ },
+ },
+};
+
+export default audio;
diff --git a/web/src/components/config-form/section-configs/audio_transcription.ts b/web/src/components/config-form/section-configs/audio_transcription.ts
new file mode 100644
index 000000000..f9d822a0d
--- /dev/null
+++ b/web/src/components/config-form/section-configs/audio_transcription.ts
@@ -0,0 +1,16 @@
+import type { SectionConfigOverrides } from "./types";
+
+const audioTranscription: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["enabled", "language", "device", "model_size", "live_enabled"],
+ hiddenFields: ["enabled_in_config"],
+ advancedFields: ["language", "device", "model_size"],
+ overrideFields: ["enabled", "live_enabled"],
+ },
+ global: {
+ fieldOrder: ["enabled", "language", "device", "model_size", "live_enabled"],
+ advancedFields: ["language", "device", "model_size"],
+ },
+};
+
+export default audioTranscription;
diff --git a/web/src/components/config-form/section-configs/auth.ts b/web/src/components/config-form/section-configs/auth.ts
new file mode 100644
index 000000000..bc7374c6c
--- /dev/null
+++ b/web/src/components/config-form/section-configs/auth.ts
@@ -0,0 +1,37 @@
+import type { SectionConfigOverrides } from "./types";
+
+const auth: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "enabled",
+ "reset_admin_password",
+ "cookie_name",
+ "cookie_secure",
+ "session_length",
+ "refresh_time",
+ "native_oauth_url",
+ "failed_login_rate_limit",
+ "trusted_proxies",
+ "hash_iterations",
+ "roles",
+ ],
+ hiddenFields: ["admin_first_time_login"],
+ advancedFields: [
+ "cookie_name",
+ "cookie_secure",
+ "session_length",
+ "refresh_time",
+ "failed_login_rate_limit",
+ "trusted_proxies",
+ "hash_iterations",
+ "roles",
+ ],
+ uiSchema: {
+ reset_admin_password: {
+ "ui:widget": "switch",
+ },
+ },
+ },
+};
+
+export default auth;
diff --git a/web/src/components/config-form/section-configs/birdseye.ts b/web/src/components/config-form/section-configs/birdseye.ts
new file mode 100644
index 000000000..9b0fa5ce7
--- /dev/null
+++ b/web/src/components/config-form/section-configs/birdseye.ts
@@ -0,0 +1,26 @@
+import type { SectionConfigOverrides } from "./types";
+
+const birdseye: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["enabled", "mode", "order"],
+ hiddenFields: [],
+ advancedFields: [],
+ overrideFields: ["enabled", "mode"],
+ },
+ global: {
+ fieldOrder: [
+ "enabled",
+ "restream",
+ "width",
+ "height",
+ "quality",
+ "mode",
+ "layout",
+ "inactivity_threshold",
+ "idle_heartbeat_fps",
+ ],
+ advancedFields: ["width", "height", "quality", "inactivity_threshold"],
+ },
+};
+
+export default birdseye;
diff --git a/web/src/components/config-form/section-configs/classification.ts b/web/src/components/config-form/section-configs/classification.ts
new file mode 100644
index 000000000..c76697a4f
--- /dev/null
+++ b/web/src/components/config-form/section-configs/classification.ts
@@ -0,0 +1,10 @@
+import type { SectionConfigOverrides } from "./types";
+
+const classification: SectionConfigOverrides = {
+ base: {
+ hiddenFields: ["custom"],
+ advancedFields: [],
+ },
+};
+
+export default classification;
diff --git a/web/src/components/config-form/section-configs/database.ts b/web/src/components/config-form/section-configs/database.ts
new file mode 100644
index 000000000..6170a157f
--- /dev/null
+++ b/web/src/components/config-form/section-configs/database.ts
@@ -0,0 +1,10 @@
+import type { SectionConfigOverrides } from "./types";
+
+const database: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["path"],
+ advancedFields: [],
+ },
+};
+
+export default database;
diff --git a/web/src/components/config-form/section-configs/detect.ts b/web/src/components/config-form/section-configs/detect.ts
new file mode 100644
index 000000000..29353ab3f
--- /dev/null
+++ b/web/src/components/config-form/section-configs/detect.ts
@@ -0,0 +1,29 @@
+import type { SectionConfigOverrides } from "./types";
+
+const detect: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "enabled",
+ "fps",
+ "width",
+ "height",
+ "min_initialized",
+ "max_disappeared",
+ "annotation_offset",
+ "stationary",
+ ],
+ fieldGroups: {
+ resolution: ["enabled", "width", "height"],
+ tracking: ["min_initialized", "max_disappeared"],
+ },
+ hiddenFields: ["enabled_in_config"],
+ advancedFields: [
+ "min_initialized",
+ "max_disappeared",
+ "annotation_offset",
+ "stationary",
+ ],
+ },
+};
+
+export default detect;
diff --git a/web/src/components/config-form/section-configs/detectors.ts b/web/src/components/config-form/section-configs/detectors.ts
new file mode 100644
index 000000000..a8259015b
--- /dev/null
+++ b/web/src/components/config-form/section-configs/detectors.ts
@@ -0,0 +1,10 @@
+import type { SectionConfigOverrides } from "./types";
+
+const detectors: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [],
+ advancedFields: [],
+ },
+};
+
+export default detectors;
diff --git a/web/src/components/config-form/section-configs/environment_vars.ts b/web/src/components/config-form/section-configs/environment_vars.ts
new file mode 100644
index 000000000..e8bdcad1e
--- /dev/null
+++ b/web/src/components/config-form/section-configs/environment_vars.ts
@@ -0,0 +1,10 @@
+import type { SectionConfigOverrides } from "./types";
+
+const environmentVars: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [],
+ advancedFields: [],
+ },
+};
+
+export default environmentVars;
diff --git a/web/src/components/config-form/section-configs/face_recognition.ts b/web/src/components/config-form/section-configs/face_recognition.ts
new file mode 100644
index 000000000..ab76379c7
--- /dev/null
+++ b/web/src/components/config-form/section-configs/face_recognition.ts
@@ -0,0 +1,36 @@
+import type { SectionConfigOverrides } from "./types";
+
+const faceRecognition: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["enabled", "min_area"],
+ hiddenFields: [],
+ advancedFields: ["min_area"],
+ overrideFields: ["enabled", "min_area"],
+ },
+ global: {
+ fieldOrder: [
+ "enabled",
+ "model_size",
+ "unknown_score",
+ "detection_threshold",
+ "recognition_threshold",
+ "min_area",
+ "min_faces",
+ "save_attempts",
+ "blur_confidence_filter",
+ "device",
+ ],
+ advancedFields: [
+ "unknown_score",
+ "detection_threshold",
+ "recognition_threshold",
+ "min_area",
+ "min_faces",
+ "save_attempts",
+ "blur_confidence_filter",
+ "device",
+ ],
+ },
+};
+
+export default faceRecognition;
diff --git a/web/src/components/config-form/section-configs/ffmpeg.ts b/web/src/components/config-form/section-configs/ffmpeg.ts
new file mode 100644
index 000000000..e725a88c0
--- /dev/null
+++ b/web/src/components/config-form/section-configs/ffmpeg.ts
@@ -0,0 +1,192 @@
+import type { SectionConfigOverrides } from "./types";
+
+const ffmpeg: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "inputs",
+ "path",
+ "global_args",
+ "hwaccel_args",
+ "input_args",
+ "output_args",
+ "retry_interval",
+ "apple_compatibility",
+ "gpu",
+ ],
+ hiddenFields: [],
+ advancedFields: [
+ "global_args",
+ "hwaccel_args",
+ "input_args",
+ "output_args",
+ "retry_interval",
+ "apple_compatibility",
+ "gpu",
+ ],
+ overrideFields: [
+ "path",
+ "global_args",
+ "hwaccel_args",
+ "input_args",
+ "output_args",
+ "retry_interval",
+ "apple_compatibility",
+ "gpu",
+ ],
+ uiSchema: {
+ global_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ hwaccel_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ input_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ output_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ detect: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ record: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ items: {
+ detect: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ record: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ },
+ },
+ inputs: {
+ items: {
+ global_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ hwaccel_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ input_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ output_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ items: {
+ detect: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ record: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ global: {
+ fieldOrder: [
+ "path",
+ "global_args",
+ "hwaccel_args",
+ "input_args",
+ "output_args",
+ "retry_interval",
+ "apple_compatibility",
+ "gpu",
+ ],
+ advancedFields: [
+ "global_args",
+ "hwaccel_args",
+ "input_args",
+ "output_args",
+ "retry_interval",
+ "apple_compatibility",
+ "gpu",
+ ],
+ uiSchema: {
+ global_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ hwaccel_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ input_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ output_args: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ detect: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ record: {
+ "ui:widget": "ArrayAsTextWidget",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ },
+ },
+ },
+};
+
+export default ffmpeg;
diff --git a/web/src/components/config-form/section-configs/genai.ts b/web/src/components/config-form/section-configs/genai.ts
new file mode 100644
index 000000000..d6627fbac
--- /dev/null
+++ b/web/src/components/config-form/section-configs/genai.ts
@@ -0,0 +1,18 @@
+import type { SectionConfigOverrides } from "./types";
+
+const genai: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "provider",
+ "api_key",
+ "base_url",
+ "model",
+ "provider_options",
+ "runtime_options",
+ ],
+ advancedFields: ["base_url", "provider_options", "runtime_options"],
+ hiddenFields: ["genai.enabled_in_config"],
+ },
+};
+
+export default genai;
diff --git a/web/src/components/config-form/section-configs/live.ts b/web/src/components/config-form/section-configs/live.ts
new file mode 100644
index 000000000..bec5c0d7e
--- /dev/null
+++ b/web/src/components/config-form/section-configs/live.ts
@@ -0,0 +1,12 @@
+import type { SectionConfigOverrides } from "./types";
+
+const live: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["stream_name", "height", "quality"],
+ fieldGroups: {},
+ hiddenFields: ["enabled_in_config"],
+ advancedFields: ["quality"],
+ },
+};
+
+export default live;
diff --git a/web/src/components/config-form/section-configs/logger.ts b/web/src/components/config-form/section-configs/logger.ts
new file mode 100644
index 000000000..75322e7b0
--- /dev/null
+++ b/web/src/components/config-form/section-configs/logger.ts
@@ -0,0 +1,10 @@
+import type { SectionConfigOverrides } from "./types";
+
+const logger: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["default", "logs"],
+ advancedFields: ["logs"],
+ },
+};
+
+export default logger;
diff --git a/web/src/components/config-form/section-configs/lpr.ts b/web/src/components/config-form/section-configs/lpr.ts
new file mode 100644
index 000000000..15c5ec7a8
--- /dev/null
+++ b/web/src/components/config-form/section-configs/lpr.ts
@@ -0,0 +1,41 @@
+import type { SectionConfigOverrides } from "./types";
+
+const lpr: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["enabled", "expire_time", "min_area", "enhancement"],
+ hiddenFields: [],
+ advancedFields: ["expire_time", "min_area", "enhancement"],
+ overrideFields: ["enabled", "min_area", "enhancement"],
+ },
+ global: {
+ fieldOrder: [
+ "enabled",
+ "model_size",
+ "detection_threshold",
+ "min_area",
+ "recognition_threshold",
+ "min_plate_length",
+ "format",
+ "match_distance",
+ "known_plates",
+ "enhancement",
+ "debug_save_plates",
+ "device",
+ "replace_rules",
+ ],
+ advancedFields: [
+ "detection_threshold",
+ "recognition_threshold",
+ "min_plate_length",
+ "format",
+ "match_distance",
+ "known_plates",
+ "enhancement",
+ "debug_save_plates",
+ "device",
+ "replace_rules",
+ ],
+ },
+};
+
+export default lpr;
diff --git a/web/src/components/config-form/section-configs/model.ts b/web/src/components/config-form/section-configs/model.ts
new file mode 100644
index 000000000..81867dc0a
--- /dev/null
+++ b/web/src/components/config-form/section-configs/model.ts
@@ -0,0 +1,25 @@
+import type { SectionConfigOverrides } from "./types";
+
+const model: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "path",
+ "labelmap_path",
+ "width",
+ "height",
+ "input_pixel_format",
+ "input_tensor",
+ "input_dtype",
+ "model_type",
+ ],
+ advancedFields: [
+ "input_pixel_format",
+ "input_tensor",
+ "input_dtype",
+ "model_type",
+ ],
+ hiddenFields: ["labelmap", "attributes_map"],
+ },
+};
+
+export default model;
diff --git a/web/src/components/config-form/section-configs/motion.ts b/web/src/components/config-form/section-configs/motion.ts
new file mode 100644
index 000000000..b22bebb0a
--- /dev/null
+++ b/web/src/components/config-form/section-configs/motion.ts
@@ -0,0 +1,32 @@
+import type { SectionConfigOverrides } from "./types";
+
+const motion: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "enabled",
+ "threshold",
+ "lightning_threshold",
+ "improve_contrast",
+ "contour_area",
+ "delta_alpha",
+ "frame_alpha",
+ "frame_height",
+ "mask",
+ "mqtt_off_delay",
+ ],
+ fieldGroups: {
+ sensitivity: ["enabled", "threshold", "contour_area"],
+ algorithm: ["improve_contrast", "delta_alpha", "frame_alpha"],
+ },
+ hiddenFields: ["enabled_in_config", "mask", "raw_mask"],
+ advancedFields: [
+ "lightning_threshold",
+ "delta_alpha",
+ "frame_alpha",
+ "frame_height",
+ "mqtt_off_delay",
+ ],
+ },
+};
+
+export default motion;
diff --git a/web/src/components/config-form/section-configs/mqtt.ts b/web/src/components/config-form/section-configs/mqtt.ts
new file mode 100644
index 000000000..0c9e3c34e
--- /dev/null
+++ b/web/src/components/config-form/section-configs/mqtt.ts
@@ -0,0 +1,52 @@
+import type { SectionConfigOverrides } from "./types";
+
+const mqtt: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "enabled",
+ "timestamp",
+ "bounding_box",
+ "crop",
+ "height",
+ "required_zones",
+ "quality",
+ ],
+ hiddenFields: [],
+ advancedFields: ["height", "quality"],
+ overrideFields: [],
+ uiSchema: {
+ required_zones: {
+ "ui:widget": "zoneNames",
+ },
+ },
+ },
+ global: {
+ fieldOrder: [
+ "enabled",
+ "host",
+ "port",
+ "user",
+ "password",
+ "topic_prefix",
+ "client_id",
+ "stats_interval",
+ "qos",
+ "tls_ca_certs",
+ "tls_client_cert",
+ "tls_client_key",
+ "tls_insecure",
+ ],
+ advancedFields: [
+ "stats_interval",
+ "qos",
+ "tls_ca_certs",
+ "tls_client_cert",
+ "tls_client_key",
+ "tls_insecure",
+ ],
+ liveValidate: true,
+ uiSchema: {},
+ },
+};
+
+export default mqtt;
diff --git a/web/src/components/config-form/section-configs/networking.ts b/web/src/components/config-form/section-configs/networking.ts
new file mode 100644
index 000000000..4abe60451
--- /dev/null
+++ b/web/src/components/config-form/section-configs/networking.ts
@@ -0,0 +1,10 @@
+import type { SectionConfigOverrides } from "./types";
+
+const networking: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [],
+ advancedFields: [],
+ },
+};
+
+export default networking;
diff --git a/web/src/components/config-form/section-configs/notifications.ts b/web/src/components/config-form/section-configs/notifications.ts
new file mode 100644
index 000000000..b0e436cba
--- /dev/null
+++ b/web/src/components/config-form/section-configs/notifications.ts
@@ -0,0 +1,12 @@
+import type { SectionConfigOverrides } from "./types";
+
+const notifications: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["enabled", "email"],
+ fieldGroups: {},
+ hiddenFields: ["enabled_in_config"],
+ advancedFields: [],
+ },
+};
+
+export default notifications;
diff --git a/web/src/components/config-form/section-configs/objects.ts b/web/src/components/config-form/section-configs/objects.ts
new file mode 100644
index 000000000..7652aff22
--- /dev/null
+++ b/web/src/components/config-form/section-configs/objects.ts
@@ -0,0 +1,57 @@
+import type { SectionConfigOverrides } from "./types";
+
+const objects: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["track", "alert", "detect", "filters"],
+ fieldGroups: {
+ tracking: ["track", "alert", "detect"],
+ filtering: ["filters"],
+ },
+ hiddenFields: [
+ "enabled_in_config",
+ "mask",
+ "raw_mask",
+ "genai.enabled_in_config",
+ "filters.*.mask",
+ "filters.*.raw_mask",
+ ],
+ advancedFields: ["filters"],
+ uiSchema: {
+ "filters.*.min_area": {
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ "filters.*.max_area": {
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ track: {
+ "ui:widget": "objectLabels",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ genai: {
+ objects: {
+ "ui:widget": "objectLabels",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ required_zones: {
+ "ui:widget": "zoneNames",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ enabled_in_config: {
+ "ui:widget": "hidden",
+ },
+ },
+ },
+ },
+};
+
+export default objects;
diff --git a/web/src/components/config-form/section-configs/onvif.ts b/web/src/components/config-form/section-configs/onvif.ts
new file mode 100644
index 000000000..973945275
--- /dev/null
+++ b/web/src/components/config-form/section-configs/onvif.ts
@@ -0,0 +1,33 @@
+import type { SectionConfigOverrides } from "./types";
+
+const onvif: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "host",
+ "port",
+ "user",
+ "password",
+ "tls_insecure",
+ "ignore_time_mismatch",
+ "autotracking",
+ ],
+ hiddenFields: [
+ "autotracking.enabled_in_config",
+ "autotracking.movement_weights",
+ ],
+ advancedFields: ["tls_insecure", "ignore_time_mismatch"],
+ overrideFields: [],
+ uiSchema: {
+ autotracking: {
+ required_zones: {
+ "ui:widget": "zoneNames",
+ },
+ track: {
+ "ui:widget": "objectLabels",
+ },
+ },
+ },
+ },
+};
+
+export default onvif;
diff --git a/web/src/components/config-form/section-configs/proxy.ts b/web/src/components/config-form/section-configs/proxy.ts
new file mode 100644
index 000000000..2530f0a98
--- /dev/null
+++ b/web/src/components/config-form/section-configs/proxy.ts
@@ -0,0 +1,17 @@
+import type { SectionConfigOverrides } from "./types";
+
+const proxy: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "header_map",
+ "logout_url",
+ "auth_secret",
+ "default_role",
+ "separator",
+ ],
+ advancedFields: ["header_map", "auth_secret", "separator"],
+ liveValidate: true,
+ },
+};
+
+export default proxy;
diff --git a/web/src/components/config-form/section-configs/record.ts b/web/src/components/config-form/section-configs/record.ts
new file mode 100644
index 000000000..1a15631d6
--- /dev/null
+++ b/web/src/components/config-form/section-configs/record.ts
@@ -0,0 +1,24 @@
+import type { SectionConfigOverrides } from "./types";
+
+const record: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "enabled",
+ "expire_interval",
+ "continuous",
+ "motion",
+ "alerts",
+ "detections",
+ "preview",
+ "export",
+ ],
+ fieldGroups: {
+ retention: ["enabled", "continuous", "motion"],
+ events: ["alerts", "detections"],
+ },
+ hiddenFields: ["enabled_in_config", "sync_recordings"],
+ advancedFields: ["expire_interval", "preview", "export"],
+ },
+};
+
+export default record;
diff --git a/web/src/components/config-form/section-configs/review.ts b/web/src/components/config-form/section-configs/review.ts
new file mode 100644
index 000000000..98301512f
--- /dev/null
+++ b/web/src/components/config-form/section-configs/review.ts
@@ -0,0 +1,31 @@
+import type { SectionConfigOverrides } from "./types";
+
+const review: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["alerts", "detections", "genai"],
+ fieldGroups: {},
+ hiddenFields: [
+ "enabled_in_config",
+ "alerts.labels",
+ "alerts.enabled_in_config",
+ "alerts.required_zones",
+ "detections.labels",
+ "detections.enabled_in_config",
+ "detections.required_zones",
+ "genai.enabled_in_config",
+ ],
+ advancedFields: [],
+ uiSchema: {
+ genai: {
+ additional_concerns: {
+ "ui:widget": "textarea",
+ },
+ activity_context_prompt: {
+ "ui:widget": "textarea",
+ },
+ },
+ },
+ },
+};
+
+export default review;
diff --git a/web/src/components/config-form/section-configs/semantic_search.ts b/web/src/components/config-form/section-configs/semantic_search.ts
new file mode 100644
index 000000000..a85a5bc5b
--- /dev/null
+++ b/web/src/components/config-form/section-configs/semantic_search.ts
@@ -0,0 +1,21 @@
+import type { SectionConfigOverrides } from "./types";
+
+const semanticSearch: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["triggers"],
+ hiddenFields: [],
+ advancedFields: [],
+ overrideFields: [],
+ uiSchema: {
+ enabled: {
+ "ui:after": { render: "SemanticSearchReindex" },
+ },
+ },
+ },
+ global: {
+ fieldOrder: ["enabled", "reindex", "model", "model_size", "device"],
+ advancedFields: ["reindex", "device"],
+ },
+};
+
+export default semanticSearch;
diff --git a/web/src/components/config-form/section-configs/snapshots.ts b/web/src/components/config-form/section-configs/snapshots.ts
new file mode 100644
index 000000000..6b496083b
--- /dev/null
+++ b/web/src/components/config-form/section-configs/snapshots.ts
@@ -0,0 +1,29 @@
+import type { SectionConfigOverrides } from "./types";
+
+const snapshots: SectionConfigOverrides = {
+ base: {
+ fieldOrder: [
+ "enabled",
+ "bounding_box",
+ "crop",
+ "quality",
+ "timestamp",
+ "retain",
+ ],
+ fieldGroups: {
+ display: ["enabled", "bounding_box", "crop", "quality", "timestamp"],
+ },
+ hiddenFields: ["enabled_in_config"],
+ advancedFields: ["quality", "retain"],
+ uiSchema: {
+ required_zones: {
+ "ui:widget": "zoneNames",
+ "ui:options": {
+ suppressMultiSchema: true,
+ },
+ },
+ },
+ },
+};
+
+export default snapshots;
diff --git a/web/src/components/config-form/section-configs/telemetry.ts b/web/src/components/config-form/section-configs/telemetry.ts
new file mode 100644
index 000000000..838258d59
--- /dev/null
+++ b/web/src/components/config-form/section-configs/telemetry.ts
@@ -0,0 +1,10 @@
+import type { SectionConfigOverrides } from "./types";
+
+const telemetry: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["network_interfaces", "stats", "version_check"],
+ advancedFields: [],
+ },
+};
+
+export default telemetry;
diff --git a/web/src/components/config-form/section-configs/timestamp_style.ts b/web/src/components/config-form/section-configs/timestamp_style.ts
new file mode 100644
index 000000000..85d4fd9f5
--- /dev/null
+++ b/web/src/components/config-form/section-configs/timestamp_style.ts
@@ -0,0 +1,11 @@
+import type { SectionConfigOverrides } from "./types";
+
+const timestampStyle: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["position", "format", "color", "thickness"],
+ hiddenFields: ["effect", "enabled_in_config"],
+ advancedFields: [],
+ },
+};
+
+export default timestampStyle;
diff --git a/web/src/components/config-form/section-configs/tls.ts b/web/src/components/config-form/section-configs/tls.ts
new file mode 100644
index 000000000..6f8b64c0b
--- /dev/null
+++ b/web/src/components/config-form/section-configs/tls.ts
@@ -0,0 +1,10 @@
+import type { SectionConfigOverrides } from "./types";
+
+const tls: SectionConfigOverrides = {
+ base: {
+ fieldOrder: ["enabled", "cert", "key"],
+ advancedFields: [],
+ },
+};
+
+export default tls;
diff --git a/web/src/components/config-form/section-configs/types.ts b/web/src/components/config-form/section-configs/types.ts
new file mode 100644
index 000000000..600a3ca50
--- /dev/null
+++ b/web/src/components/config-form/section-configs/types.ts
@@ -0,0 +1,7 @@
+import type { SectionConfig } from "../sections/BaseSection";
+
+export type SectionConfigOverrides = {
+ base?: SectionConfig;
+ global?: Partial