mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-13 03:47:34 +03:00
fix profile config inheritance bug where Pydantic defaults override base values
The /config API was dumping profile overrides with model_dump() which included all Pydantic defaults. When the frontend merged these over the camera's base config, explicitly-set base values were lost. Now profile overrides are re-dumped with exclude_unset=True so only user-specified fields are returned. Also fixes the Save All path generating spurious deletion markers for restart-required fields that are hidden during profile editing but not excluded from the raw data sanitization in prepareSectionSavePayload.
This commit is contained in:
parent
091e0b80d2
commit
12e9bb3944
@ -158,6 +158,18 @@ def config(request: Request):
|
||||
for zone_name, zone in config_obj.cameras[camera_name].zones.items():
|
||||
camera_dict["zones"][zone_name]["color"] = zone.color
|
||||
|
||||
# Re-dump profile overrides with exclude_unset so that only
|
||||
# explicitly-set fields are returned (not Pydantic defaults).
|
||||
# Without this, the frontend merges defaults (e.g. threshold=30)
|
||||
# over the camera's actual base values (e.g. threshold=20).
|
||||
if camera.profiles:
|
||||
for profile_name, profile_config in camera.profiles.items():
|
||||
camera_dict.setdefault("profiles", {})[profile_name] = (
|
||||
profile_config.model_dump(
|
||||
mode="json", warnings="none", exclude_unset=True
|
||||
)
|
||||
)
|
||||
|
||||
# remove go2rtc stream passwords
|
||||
go2rtc: dict[str, Any] = config_obj.go2rtc.model_dump(
|
||||
mode="json", warnings="none", exclude_none=True
|
||||
@ -229,9 +241,7 @@ def set_profile(request: Request, body: ProfileSetBody):
|
||||
content={"success": False, "message": err},
|
||||
status_code=400,
|
||||
)
|
||||
request.app.dispatcher.publish(
|
||||
"profile/state", body.profile or "none", retain=True
|
||||
)
|
||||
request.app.dispatcher.publish("profile/state", body.profile or "none", retain=True)
|
||||
return JSONResponse(
|
||||
content={
|
||||
"success": True,
|
||||
|
||||
@ -101,7 +101,9 @@ class ProfileManager:
|
||||
"""
|
||||
if profile_name is not None:
|
||||
if profile_name not in self.config.profiles:
|
||||
return f"Profile '{profile_name}' is not defined in the profiles section"
|
||||
return (
|
||||
f"Profile '{profile_name}' is not defined in the profiles section"
|
||||
)
|
||||
|
||||
# Track which camera/section pairs get changed for ZMQ publishing
|
||||
changed: dict[str, set[str]] = {}
|
||||
|
||||
@ -533,10 +533,21 @@ export function prepareSectionSavePayload(opts: {
|
||||
? {}
|
||||
: rawSectionValue;
|
||||
|
||||
// For profile sections, also hide restart-required fields to match
|
||||
// effectiveHiddenFields in BaseSection (prevents spurious deletion markers
|
||||
// for fields that are hidden from the form during profile editing).
|
||||
let hiddenFieldsForSanitize = sectionConfig.hiddenFields;
|
||||
if (profileInfo.isProfile && sectionConfig.restartRequired?.length) {
|
||||
const base = sectionConfig.hiddenFields ?? [];
|
||||
hiddenFieldsForSanitize = [
|
||||
...new Set([...base, ...sectionConfig.restartRequired]),
|
||||
];
|
||||
}
|
||||
|
||||
// Sanitize raw form data
|
||||
const rawData = sanitizeSectionData(
|
||||
rawFormData as ConfigSectionData,
|
||||
sectionConfig.hiddenFields,
|
||||
hiddenFieldsForSanitize,
|
||||
);
|
||||
|
||||
// Compute schema defaults
|
||||
|
||||
Loading…
Reference in New Issue
Block a user