clean up now obsolete namespaces

This commit is contained in:
Josh Hawkins
2026-02-27 09:40:20 -06:00
parent 3f7f5e3253
commit 5e8de5a911
62 changed files with 27 additions and 1561 deletions
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const AudioSection = createConfigSection({
sectionPath: "audio",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: [
"enabled",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const AudioTranscriptionSection = createConfigSection({
sectionPath: "audio_transcription",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["enabled", "language", "device", "model_size", "live_enabled"],
hiddenFields: ["enabled_in_config"],
@@ -81,8 +81,6 @@ export interface BaseSectionProps {
export interface CreateSectionOptions {
/** The config path for this section (e.g., "detect", "record") */
sectionPath: string;
/** i18n namespace for this section (e.g., "config/detect") */
i18nNamespace: string;
/** Default section configuration */
defaultConfig: SectionConfig;
}
@@ -92,7 +90,6 @@ export interface CreateSectionOptions {
*/
export function createConfigSection({
sectionPath,
i18nNamespace,
defaultConfig,
}: CreateSectionOptions) {
const cameraUpdateTopicMap: Record<string, string> = {
@@ -131,7 +128,7 @@ export function createConfigSection({
showTitle,
}: BaseSectionProps) {
const { t, i18n } = useTranslation([
i18nNamespace,
level === "camera" ? "config/cameras" : "config/global",
"config/cameras",
"views/settings",
"common",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const BirdseyeSection = createConfigSection({
sectionPath: "birdseye",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["enabled", "mode", "order"],
hiddenFields: [],
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const CameraMqttSection = createConfigSection({
sectionPath: "mqtt",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: [
"enabled",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const CameraUiSection = createConfigSection({
sectionPath: "ui",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["dashboard", "order"],
hiddenFields: [],
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const DetectSection = createConfigSection({
sectionPath: "detect",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: [
"enabled",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const FaceRecognitionSection = createConfigSection({
sectionPath: "face_recognition",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["enabled", "min_area"],
hiddenFields: [],
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const FfmpegSection = createConfigSection({
sectionPath: "ffmpeg",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: [
"inputs",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const LiveSection = createConfigSection({
sectionPath: "live",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["stream_name", "height", "quality"],
fieldGroups: {},
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const LprSection = createConfigSection({
sectionPath: "lpr",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["enabled", "expire_time", "min_area", "enhancement"],
hiddenFields: [],
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const MotionSection = createConfigSection({
sectionPath: "motion",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: [
"enabled",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const NotificationsSection = createConfigSection({
sectionPath: "notifications",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["enabled", "email"],
fieldGroups: {},
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const ObjectsSection = createConfigSection({
sectionPath: "objects",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["track", "alert", "detect", "filters"],
fieldGroups: {
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const OnvifSection = createConfigSection({
sectionPath: "onvif",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: [
"host",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const RecordSection = createConfigSection({
sectionPath: "record",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: [
"enabled",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const ReviewSection = createConfigSection({
sectionPath: "review",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["alerts", "detections", "genai"],
fieldGroups: {},
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const SemanticSearchSection = createConfigSection({
sectionPath: "semantic_search",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["triggers"],
hiddenFields: [],
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const SnapshotsSection = createConfigSection({
sectionPath: "snapshots",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: [
"enabled",
@@ -5,7 +5,6 @@ import { createConfigSection } from "./BaseSection";
export const TimestampSection = createConfigSection({
sectionPath: "timestamp_style",
i18nNamespace: "config/global",
defaultConfig: {
fieldOrder: ["position", "format", "color", "thickness"],
hiddenFields: ["effect", "enabled_in_config"],
@@ -11,13 +11,9 @@ export function DescriptionFieldTemplate(props: DescriptionFieldProps) {
const isCameraLevel = formContext?.level === "camera";
const sectionI18nPrefix = formContext?.sectionI18nPrefix;
const i18nNamespace = formContext?.i18nNamespace;
const effectiveNamespace = isCameraLevel ? "config/cameras" : i18nNamespace;
const effectiveNamespace = isCameraLevel ? "config/cameras" : "config/global";
const { t, i18n } = useTranslation([
effectiveNamespace || i18nNamespace || "common",
i18nNamespace || "common",
]);
const { t, i18n } = useTranslation([effectiveNamespace, "common"]);
let resolvedDescription = description;
@@ -69,14 +69,11 @@ export function ObjectFieldTemplate(props: ObjectFieldTemplateProps) {
const [isOpen, setIsOpen] = useState(true);
const isCameraLevel = formContext?.level === "camera";
const effectiveNamespace = isCameraLevel
? "config/cameras"
: formContext?.i18nNamespace;
const effectiveNamespace = isCameraLevel ? "config/cameras" : "config/global";
const sectionI18nPrefix = formContext?.sectionI18nPrefix;
const { t, i18n } = useTranslation([
effectiveNamespace || formContext?.i18nNamespace || "common",
formContext?.i18nNamespace || "common",
effectiveNamespace,
"config/groups",
"common",
]);
-2
View File
@@ -52,10 +52,8 @@ i18n
"views/system",
"views/exports",
"views/explore",
// Config namespaces: single consolidated global file + camera-level keys
"config/global",
"config/cameras",
// keep these for backwards compatibility with explicit ns usage
"config/validation",
"config/groups",
],
+2 -19
View File
@@ -203,98 +203,81 @@ const CameraConfigContent = memo(function CameraConfigContent({
const sections: Array<{
key: string;
i18nNamespace: string;
component: typeof DetectSection;
showOverrideIndicator?: boolean;
}> = [
{
key: "detect",
i18nNamespace: "config/cameras",
component: DetectSection,
},
{
key: "ffmpeg",
i18nNamespace: "config/cameras",
component: FfmpegSection,
showOverrideIndicator: true,
},
{
key: "record",
i18nNamespace: "config/cameras",
component: RecordSection,
},
{
key: "snapshots",
i18nNamespace: "config/cameras",
component: SnapshotsSection,
},
{
key: "motion",
i18nNamespace: "config/cameras",
component: MotionSection,
},
{
key: "objects",
i18nNamespace: "config/cameras",
component: ObjectsSection,
},
{
key: "review",
i18nNamespace: "config/cameras",
component: ReviewSection,
},
{ key: "audio", i18nNamespace: "config/cameras", component: AudioSection },
{ key: "audio", component: AudioSection },
{
key: "audio_transcription",
i18nNamespace: "config/cameras",
component: AudioTranscriptionSection,
showOverrideIndicator: true,
},
{
key: "notifications",
i18nNamespace: "config/cameras",
component: NotificationsSection,
},
{ key: "live", i18nNamespace: "config/cameras", component: LiveSection },
{ key: "live", component: LiveSection },
{
key: "birdseye",
i18nNamespace: "config/cameras",
component: BirdseyeSection,
showOverrideIndicator: true,
},
{
key: "face_recognition",
i18nNamespace: "config/cameras",
component: FaceRecognitionSection,
showOverrideIndicator: true,
},
{
key: "lpr",
i18nNamespace: "config/cameras",
component: LprSection,
showOverrideIndicator: true,
},
{
key: "mqtt",
i18nNamespace: "config/cameras",
component: CameraMqttSection,
showOverrideIndicator: false,
},
{
key: "onvif",
i18nNamespace: "config/cameras",
component: OnvifSection,
showOverrideIndicator: false,
},
{
key: "ui",
i18nNamespace: "config/cameras",
component: CameraUiSection,
showOverrideIndicator: false,
},
{
key: "timestamp_style",
i18nNamespace: "config/cameras",
component: TimestampSection,
},
];
+20 -68
View File
@@ -30,25 +30,22 @@ import { cn } from "@/lib/utils";
// Shared sections that can be overridden at camera level
const sharedSections = [
{ key: "detect", i18nNamespace: "config/global", component: DetectSection },
{ key: "record", i18nNamespace: "config/global", component: RecordSection },
{ key: "detect", component: DetectSection },
{ key: "record", component: RecordSection },
{
key: "snapshots",
i18nNamespace: "config/global",
component: SnapshotsSection,
},
{ key: "motion", i18nNamespace: "config/global", component: MotionSection },
{ key: "motion", component: MotionSection },
{
key: "objects",
i18nNamespace: "config/global",
component: ObjectsSection,
},
{ key: "review", i18nNamespace: "config/global", component: ReviewSection },
{ key: "audio", i18nNamespace: "config/global", component: AudioSection },
{ key: "live", i18nNamespace: "config/global", component: LiveSection },
{ key: "review", component: ReviewSection },
{ key: "audio", component: AudioSection },
{ key: "live", component: LiveSection },
{
key: "timestamp_style",
i18nNamespace: "config/global",
component: TimestampSection,
},
];
@@ -61,12 +58,10 @@ const globalSectionConfigs: Record<
hiddenFields?: string[];
advancedFields?: string[];
liveValidate?: boolean;
i18nNamespace: string;
uiSchema?: Record<string, unknown>;
}
> = {
mqtt: {
i18nNamespace: "config/global",
fieldOrder: [
"enabled",
"host",
@@ -93,12 +88,10 @@ const globalSectionConfigs: Record<
liveValidate: true,
},
database: {
i18nNamespace: "config/global",
fieldOrder: ["path"],
advancedFields: [],
},
auth: {
i18nNamespace: "config/global",
fieldOrder: [
"enabled",
"reset_admin_password",
@@ -130,17 +123,14 @@ const globalSectionConfigs: Record<
},
},
tls: {
i18nNamespace: "config/global",
fieldOrder: ["enabled", "cert", "key"],
advancedFields: [],
},
networking: {
i18nNamespace: "config/global",
fieldOrder: ["ipv6"],
advancedFields: [],
},
proxy: {
i18nNamespace: "config/global",
fieldOrder: [
"header_map",
"logout_url",
@@ -152,7 +142,6 @@ const globalSectionConfigs: Record<
liveValidate: true,
},
ui: {
i18nNamespace: "config/global",
fieldOrder: [
"timezone",
"time_format",
@@ -163,22 +152,18 @@ const globalSectionConfigs: Record<
advancedFields: [],
},
logger: {
i18nNamespace: "config/global",
fieldOrder: ["default", "logs"],
advancedFields: ["logs"],
},
environment_vars: {
i18nNamespace: "config/global",
fieldOrder: [],
advancedFields: [],
},
telemetry: {
i18nNamespace: "config/global",
fieldOrder: ["network_interfaces", "stats", "version_check"],
advancedFields: [],
},
birdseye: {
i18nNamespace: "config/global",
fieldOrder: [
"enabled",
"restream",
@@ -193,7 +178,6 @@ const globalSectionConfigs: Record<
advancedFields: ["width", "height", "quality", "inactivity_threshold"],
},
ffmpeg: {
i18nNamespace: "config/global",
fieldOrder: [
"path",
"global_args",
@@ -253,12 +237,10 @@ const globalSectionConfigs: Record<
},
},
detectors: {
i18nNamespace: "config/global",
fieldOrder: [],
advancedFields: [],
},
model: {
i18nNamespace: "config/global",
fieldOrder: [
"path",
"labelmap_path",
@@ -278,7 +260,6 @@ const globalSectionConfigs: Record<
hiddenFields: ["labelmap", "attributes_map"],
},
genai: {
i18nNamespace: "config/global",
fieldOrder: [
"provider",
"api_key",
@@ -291,22 +272,18 @@ const globalSectionConfigs: Record<
hiddenFields: ["genai.enabled_in_config"],
},
classification: {
i18nNamespace: "config/global",
hiddenFields: ["custom"],
advancedFields: [],
},
semantic_search: {
i18nNamespace: "config/global",
fieldOrder: ["enabled", "reindex", "model", "model_size", "device"],
advancedFields: ["reindex", "device"],
},
audio_transcription: {
i18nNamespace: "config/global",
fieldOrder: ["enabled", "language", "device", "model_size", "live_enabled"],
advancedFields: ["language", "device", "model_size"],
},
face_recognition: {
i18nNamespace: "config/global",
fieldOrder: [
"enabled",
"model_size",
@@ -331,7 +308,6 @@ const globalSectionConfigs: Record<
],
},
lpr: {
i18nNamespace: "config/global",
fieldOrder: [
"enabled",
"model_size",
@@ -406,11 +382,7 @@ function GlobalConfigSection({
title,
}: GlobalConfigSectionProps) {
const sectionConfig = globalSectionConfigs[sectionKey];
const { t } = useTranslation([
sectionConfig?.i18nNamespace || "common",
"views/settings",
"common",
]);
const { t } = useTranslation(["config/global", "views/settings", "common"]);
const [pendingData, setPendingData] = useState<unknown | null>(null);
const [isSaving, setIsSaving] = useState(false);
const [formKey, setFormKey] = useState(0);
@@ -522,8 +494,8 @@ function GlobalConfigSection({
liveValidate={sectionConfig.liveValidate}
uiSchema={sectionConfig.uiSchema}
showSubmit={false}
formContext={{ sectionI18nPrefix: sectionKey }}
i18nNamespace="config/global"
formContext={{ level: "global", sectionI18nPrefix: sectionKey }}
disabled={isSaving}
/>
@@ -585,13 +557,11 @@ export default function GlobalConfigView() {
} else if (activeTab === "system") {
return systemSections.map((key) => ({
key,
i18nNamespace: globalSectionConfigs[key].i18nNamespace,
component: null, // Uses GlobalConfigSection instead
}));
} else {
return integrationSections.map((key) => ({
key,
i18nNamespace: globalSectionConfigs[key].i18nNamespace,
component: null,
}));
}
@@ -721,21 +691,12 @@ export default function GlobalConfigView() {
{activeTab === "system" && (
<>
{systemSections.map((sectionKey) => {
const ns = globalSectionConfigs[sectionKey].i18nNamespace;
const sectionTitle =
ns === "config/global"
? t(`${sectionKey}.label`, {
ns: "config/global",
defaultValue:
sectionKey.charAt(0).toUpperCase() +
sectionKey.slice(1).replace(/_/g, " "),
})
: t("label", {
ns,
defaultValue:
sectionKey.charAt(0).toUpperCase() +
sectionKey.slice(1).replace(/_/g, " "),
});
const sectionTitle = t(`${sectionKey}.label`, {
ns: "config/global",
defaultValue:
sectionKey.charAt(0).toUpperCase() +
sectionKey.slice(1).replace(/_/g, " "),
});
return (
<div
@@ -760,21 +721,12 @@ export default function GlobalConfigView() {
{activeTab === "integrations" && (
<>
{integrationSections.map((sectionKey) => {
const ns = globalSectionConfigs[sectionKey].i18nNamespace;
const sectionTitle =
ns === "config/global"
? t(`${sectionKey}.label`, {
ns: "config/global",
defaultValue:
sectionKey.charAt(0).toUpperCase() +
sectionKey.slice(1).replace(/_/g, " "),
})
: t("label", {
ns,
defaultValue:
sectionKey.charAt(0).toUpperCase() +
sectionKey.slice(1).replace(/_/g, " "),
});
const sectionTitle = t(`${sectionKey}.label`, {
ns: "config/global",
defaultValue:
sectionKey.charAt(0).toUpperCase() +
sectionKey.slice(1).replace(/_/g, " "),
});
return (
<div