This commit is contained in:
Josh Hawkins 2026-01-26 19:56:43 -06:00
parent 25aaa2d9f7
commit 42a594984d
8 changed files with 66 additions and 57 deletions

View File

@ -60,7 +60,7 @@ export function ConfigForm({
advancedFields,
disabled = false,
readonly = false,
showSubmit = true,
showSubmit = false,
className,
liveValidate = true,
formContext,

View File

@ -21,6 +21,11 @@ export const AudioSection = createConfigSection({
},
hiddenFields: ["enabled_in_config"],
advancedFields: ["min_volume", "max_not_heard", "num_threads"],
uiSchema: {
listen: {
"ui:widget": "audioLabels",
},
},
},
});

View File

@ -12,7 +12,12 @@ export const ObjectsSection = createConfigSection({
tracking: ["track", "alert", "detect"],
filtering: ["filters"],
},
hiddenFields: ["enabled_in_config", "mask", "raw_mask"],
hiddenFields: [
"enabled_in_config",
"mask",
"raw_mask",
"genai.enabled_in_config",
],
advancedFields: ["filters"],
uiSchema: {
track: {
@ -34,6 +39,9 @@ export const ObjectsSection = createConfigSection({
suppressMultiSchema: true,
},
},
enabled_in_config: {
"ui:widget": "hidden",
},
},
},
},

View File

@ -21,7 +21,7 @@ export const RecordSection = createConfigSection({
retention: ["continuous", "motion"],
events: ["alerts", "detections"],
},
hiddenFields: ["enabled_in_config"],
hiddenFields: ["enabled_in_config", "sync_recordings"],
advancedFields: ["expire_interval", "preview", "export"],
},
});

View File

@ -20,6 +20,7 @@ import { ColorWidget } from "./widgets/ColorWidget";
import { TextareaWidget } from "./widgets/TextareaWidget";
import { SwitchesWidget } from "./widgets/SwitchesWidget";
import { ObjectLabelSwitchesWidget } from "./widgets/ObjectLabelSwitchesWidget";
import { AudioLabelSwitchesWidget } from "./widgets/AudioLabelSwitchesWidget";
import { ZoneSwitchesWidget } from "./widgets/ZoneSwitchesWidget";
import { FieldTemplate } from "./templates/FieldTemplate";
@ -29,7 +30,6 @@ import { BaseInputTemplate } from "./templates/BaseInputTemplate";
import { DescriptionFieldTemplate } from "./templates/DescriptionFieldTemplate";
import { TitleFieldTemplate } from "./templates/TitleFieldTemplate";
import { ErrorListTemplate } from "./templates/ErrorListTemplate";
import { SubmitButton } from "./templates/SubmitButton";
import { MultiSchemaFieldTemplate } from "./templates/MultiSchemaFieldTemplate";
export interface FrigateTheme {
@ -58,6 +58,7 @@ export const frigateTheme: FrigateTheme = {
textarea: TextareaWidget,
switches: SwitchesWidget,
objectLabels: ObjectLabelSwitchesWidget,
audioLabels: AudioLabelSwitchesWidget,
zoneNames: ZoneSwitchesWidget,
},
templates: {
@ -72,7 +73,6 @@ export const frigateTheme: FrigateTheme = {
MultiSchemaFieldTemplate: MultiSchemaFieldTemplate,
ButtonTemplates: {
...defaultRegistry.templates.ButtonTemplates,
SubmitButton: SubmitButton,
},
},
fields: {

View File

@ -1,27 +0,0 @@
// Submit Button Template
import type { SubmitButtonProps } from "@rjsf/utils";
import { Button } from "@/components/ui/button";
import { useTranslation } from "react-i18next";
import { LuSave } from "react-icons/lu";
export function SubmitButton(props: SubmitButtonProps) {
const { uiSchema } = props;
const { t } = useTranslation(["common"]);
const shouldHide = uiSchema?.["ui:submitButtonOptions"]?.norender === true;
if (shouldHide) {
return null;
}
const submitText =
(uiSchema?.["ui:options"]?.submitText as string) ||
t("save", { ns: "common" });
return (
<Button type="submit" className="gap-2">
<LuSave className="h-4 w-4" />
{submitText}
</Button>
);
}

View File

@ -0,0 +1,48 @@
// Object Label Switches Widget - For selecting objects via switches
import type { WidgetProps } from "@rjsf/utils";
import { SwitchesWidget } from "./SwitchesWidget";
import type { FormContext } from "./SwitchesWidget";
import { getTranslatedLabel } from "@/utils/i18n";
function getAudioLabels(context: FormContext): string[] {
let cameraLabels: string[] = [];
let globalLabels: string[] = [];
if (context) {
// context.cameraValue and context.globalValue should be the entire objects section
const trackValue = context.cameraValue?.listen;
if (Array.isArray(trackValue)) {
cameraLabels = trackValue.filter(
(item): item is string => typeof item === "string",
);
}
const globalTrackValue = context.globalValue?.listen;
if (Array.isArray(globalTrackValue)) {
globalLabels = globalTrackValue.filter(
(item): item is string => typeof item === "string",
);
}
}
const sourceLabels = cameraLabels.length > 0 ? cameraLabels : globalLabels;
return [...sourceLabels].sort();
}
function getAudioLabelDisplayName(label: string): string {
return getTranslatedLabel(label, "audio");
}
export function AudioLabelSwitchesWidget(props: WidgetProps) {
return (
<SwitchesWidget
{...props}
options={{
...props.options,
getEntities: getAudioLabels,
getDisplayLabel: getAudioLabelDisplayName,
i18nKey: "audioLabels",
}}
/>
);
}

View File

@ -14,7 +14,6 @@ import { MotionSection } from "@/components/config-form/sections/MotionSection";
import { ObjectsSection } from "@/components/config-form/sections/ObjectsSection";
import { ReviewSection } from "@/components/config-form/sections/ReviewSection";
import { AudioSection } from "@/components/config-form/sections/AudioSection";
import { NotificationsSection } from "@/components/config-form/sections/NotificationsSection";
import { LiveSection } from "@/components/config-form/sections/LiveSection";
import { TimestampSection } from "@/components/config-form/sections/TimestampSection";
import type { RJSFSchema } from "@rjsf/utils";
@ -46,11 +45,6 @@ const sharedSections = [
},
{ key: "review", i18nNamespace: "config/review", component: ReviewSection },
{ key: "audio", i18nNamespace: "config/audio", component: AudioSection },
{
key: "notifications",
i18nNamespace: "config/notifications",
component: NotificationsSection,
},
{ key: "live", i18nNamespace: "config/live", component: LiveSection },
{
key: "timestamp_style",
@ -127,7 +121,6 @@ const globalSectionConfigs: Record<
"trusted_proxies",
"hash_iterations",
"roles",
"admin_first_time_login",
],
},
tls: {
@ -330,21 +323,6 @@ const globalSectionConfigs: Record<
fieldOrder: [],
advancedFields: [],
},
camera_groups: {
i18nNamespace: "config/camera_groups",
fieldOrder: ["cameras", "icon", "order"],
advancedFields: [],
},
safe_mode: {
i18nNamespace: "config/safe_mode",
fieldOrder: [],
advancedFields: [],
},
version: {
i18nNamespace: "config/version",
fieldOrder: [],
advancedFields: [],
},
};
// System sections (global only)
@ -364,9 +342,6 @@ const systemSections = [
"model",
"classification",
"go2rtc",
"camera_groups",
"safe_mode",
"version",
];
// Integration sections (global only)