mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-26 05:39:04 +03:00
Add attributes to UI filters list (#23250)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* preserve user-set min_score on attribute filters instead of bumping any 0.5 value use model_fields_set to distinguish "user explicitly set min_score" from "Pydantic applied the generic FilterConfig default of 0.5" * add config test for attributes * fix attributes frontend type * add expanded hidden field context * extend schema modification * special case for attributes * i18n for attributes * handle dedicated lpr mode * strip unrendered FilterConfig fields from attribute filter form data to fix validation errors
This commit is contained in:
+74
-11
@@ -19,9 +19,10 @@ import {
|
||||
sanitizeOverridesForSection,
|
||||
} from "@/components/config-form/sections/section-special-cases";
|
||||
import type { RJSFSchema } from "@rjsf/utils";
|
||||
import type { FrigateConfig } from "@/types/frigateConfig";
|
||||
import type { CameraConfig, FrigateConfig } from "@/types/frigateConfig";
|
||||
import type {
|
||||
ConfigSectionData,
|
||||
HiddenFieldContext,
|
||||
JsonObject,
|
||||
JsonValue,
|
||||
} from "@/types/configForm";
|
||||
@@ -568,6 +569,17 @@ export function prepareSectionSavePayload(opts: {
|
||||
schemaSection,
|
||||
level,
|
||||
sectionSchema,
|
||||
config
|
||||
? {
|
||||
fullConfig: config,
|
||||
fullCameraConfig:
|
||||
level === "camera" && cameraName
|
||||
? config.cameras?.[cameraName]
|
||||
: undefined,
|
||||
level,
|
||||
cameraName,
|
||||
}
|
||||
: undefined,
|
||||
);
|
||||
|
||||
// Compute rawFormData (the current stored value for this section)
|
||||
@@ -615,10 +627,16 @@ export function prepareSectionSavePayload(opts: {
|
||||
// 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).
|
||||
const resolvedHidden = resolveHiddenFieldEntries(
|
||||
sectionConfig.hiddenFields,
|
||||
config,
|
||||
);
|
||||
const resolvedHidden = resolveHiddenFieldEntries(sectionConfig.hiddenFields, {
|
||||
fullConfig: config,
|
||||
fullCameraConfig:
|
||||
level === "camera" && cameraName
|
||||
? config.cameras?.[cameraName]
|
||||
: undefined,
|
||||
level,
|
||||
cameraName,
|
||||
formData: rawFormData as ConfigSectionData,
|
||||
});
|
||||
const hiddenFieldsForSanitize =
|
||||
profileInfo.isProfile && sectionConfig.restartRequired?.length
|
||||
? [...new Set([...resolvedHidden, ...sectionConfig.restartRequired])]
|
||||
@@ -731,32 +749,77 @@ export function getSectionConfig(
|
||||
return mergeSectionConfig(entry.base, overrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the effective attribute label set at a given scope. At camera
|
||||
* (and replay) scope on a dedicated LPR camera (`camera.type === "lpr"`),
|
||||
* `license_plate` is treated as a regular tracked object — not an
|
||||
* attribute — to match the backend's per-camera carve-out in
|
||||
* `frigate/video/detect.py`. Returns the full attribute list at global
|
||||
* scope and for non-LPR cameras.
|
||||
*/
|
||||
export function getEffectiveAttributeLabels(
|
||||
fullConfig: FrigateConfig | undefined,
|
||||
fullCameraConfig: CameraConfig | undefined,
|
||||
level: "global" | "camera" | "replay" | undefined,
|
||||
): string[] {
|
||||
const all = fullConfig?.model?.all_attributes ?? [];
|
||||
if (level !== "global" && fullCameraConfig?.type === "lpr") {
|
||||
return all.filter((attr) => attr !== "license_plate");
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a `HiddenFieldContext` for the common case where a callsite has
|
||||
* `config`, an optional `cameraName`, and a level, but no per-section
|
||||
* saved form data to thread through. Resolvers that don't read `formData`
|
||||
* (which is most of them) just fall through to `fullCameraConfig` /
|
||||
* `fullConfig`.
|
||||
*/
|
||||
export function buildHiddenFieldContext(
|
||||
config: FrigateConfig | undefined,
|
||||
level: "global" | "camera" | "replay",
|
||||
cameraName?: string,
|
||||
): HiddenFieldContext | undefined {
|
||||
if (!config) return undefined;
|
||||
return {
|
||||
fullConfig: config,
|
||||
fullCameraConfig:
|
||||
level !== "global" && cameraName
|
||||
? config.cameras?.[cameraName]
|
||||
: undefined,
|
||||
level,
|
||||
cameraName,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the effective hidden-field patterns for a section. Each entry in
|
||||
* `hiddenFields` is either a literal pattern or a function that produces
|
||||
* patterns from the loaded config (e.g. `filters.<attr>` for each
|
||||
* `model.all_attributes` entry on the objects section).
|
||||
* patterns from the loaded config and scope (e.g. `filters.<attr>` for each
|
||||
* `model.all_attributes` entry on the objects section, gated by the
|
||||
* effective `objects.track` list at the current scope).
|
||||
*/
|
||||
export function getEffectiveHiddenFields(
|
||||
sectionKey: string,
|
||||
level: "global" | "camera" | "replay",
|
||||
config: FrigateConfig | undefined,
|
||||
ctx: HiddenFieldContext | undefined,
|
||||
): string[] {
|
||||
return resolveHiddenFieldEntries(
|
||||
getSectionConfig(sectionKey, level).hiddenFields,
|
||||
config,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveHiddenFieldEntries(
|
||||
entries: SectionConfig["hiddenFields"] | undefined,
|
||||
config: FrigateConfig | undefined,
|
||||
ctx: HiddenFieldContext | undefined,
|
||||
): string[] {
|
||||
if (!entries || entries.length === 0) return [];
|
||||
const result: string[] = [];
|
||||
for (const entry of entries) {
|
||||
if (typeof entry === "function") {
|
||||
if (config) result.push(...entry(config));
|
||||
if (ctx) result.push(...entry(ctx));
|
||||
} else {
|
||||
result.push(entry);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user