remove emptySelectionHintKey from switches widget

use the new messages framework and revert the changes made in #22664
This commit is contained in:
Josh Hawkins 2026-03-29 13:19:08 -05:00
parent 6ee5e70005
commit 42ef23642f
4 changed files with 29 additions and 21 deletions

View File

@ -1433,8 +1433,7 @@
},
"reviewLabels": {
"summary": "{{count}} labels selected",
"empty": "No labels available",
"allNonAlertDetections": "All non-alert activity will be included as detections."
"empty": "No labels available"
},
"filters": {
"objectFieldLabel": "{{field}} for {{label}}"
@ -1610,7 +1609,8 @@
"configMessages": {
"review": {
"recordDisabled": "Recording is disabled, review items will not be generated.",
"detectDisabled": "Object detection is disabled. Review items require detected objects to categorize alerts and detections."
"detectDisabled": "Object detection is disabled. Review items require detected objects to categorize alerts and detections.",
"allNonAlertDetections": "All non-alert activity will be included as detections."
},
"audio": {
"noAudioRole": "No streams have the audio role defined. You must enable the audio role for audio detection to function."

View File

@ -27,6 +27,21 @@ const review: SectionConfigOverrides = {
},
},
],
fieldMessages: [
{
key: "detections-all-non-alert",
field: "detections.labels",
messageKey: "configMessages.review.allNonAlertDetections",
severity: "info",
position: "after",
condition: (ctx) => {
const labels = (
ctx.formData?.detections as Record<string, unknown> | undefined
)?.labels;
return !Array.isArray(labels) || labels.length === 0;
},
},
],
fieldDocs: {
"alerts.labels": "/configuration/review/#alerts-and-detections",
"detections.labels": "/configuration/review/#alerts-and-detections",
@ -59,8 +74,6 @@ const review: SectionConfigOverrides = {
"ui:widget": "reviewLabels",
"ui:options": {
suppressMultiSchema: true,
emptySelectionHintKey:
"configForm.reviewLabels.allNonAlertDetections",
},
},
required_zones: {

View File

@ -573,8 +573,16 @@ export function ConfigSection({
if (activeFieldMessages.length === 0) return sectionConfig.uiSchema;
const merged = { ...(sectionConfig.uiSchema ?? {}) };
for (const msg of activeFieldMessages) {
const fieldKey = msg.field;
const existing = merged[fieldKey] as Record<string, unknown> | undefined;
const segments = msg.field.split(".");
// Navigate to the nested uiSchema node, shallow-cloning along the way
let node = merged;
for (let i = 0; i < segments.length - 1; i++) {
const seg = segments[i];
node[seg] = { ...(node[seg] as Record<string, unknown>) };
node = node[seg] as Record<string, unknown>;
}
const leafKey = segments[segments.length - 1];
const existing = node[leafKey] as Record<string, unknown> | undefined;
const existingMessages = ((existing?.["ui:messages"] as unknown[]) ??
[]) as Array<{
key: string;
@ -582,7 +590,7 @@ export function ConfigSection({
severity: string;
position?: string;
}>;
merged[fieldKey] = {
node[leafKey] = {
...existing,
"ui:messages": [
...existingMessages,

View File

@ -45,8 +45,6 @@ export type SwitchesWidgetOptions = {
enableSearch?: boolean;
/** Allow users to add custom entries not in the predefined list */
allowCustomEntries?: boolean;
/** i18n key for a hint shown when no entities are selected */
emptySelectionHintKey?: string;
};
function normalizeValue(value: unknown): string[] {
@ -131,11 +129,6 @@ export function SwitchesWidget(props: WidgetProps) {
[props.options],
);
const emptySelectionHintKey = useMemo(
() => props.options?.emptySelectionHintKey as string | undefined,
[props.options],
);
const selectedEntities = useMemo(() => normalizeValue(value), [value]);
const [isOpen, setIsOpen] = useState(selectedEntities.length > 0);
const [searchTerm, setSearchTerm] = useState("");
@ -215,12 +208,6 @@ export function SwitchesWidget(props: WidgetProps) {
</Button>
</CollapsibleTrigger>
{emptySelectionHintKey && selectedEntities.length === 0 && t && (
<div className="mt-0 pb-2 text-sm text-success">
{t(emptySelectionHintKey, { ns: namespace })}
</div>
)}
<CollapsibleContent className="rounded-lg border border-input bg-secondary pb-1 pr-0 pt-2 md:max-w-md">
{allEntities.length === 0 && !allowCustomEntries ? (
<div className="text-sm text-muted-foreground">{emptyMessage}</div>