Compare commits

...
Author SHA1 Message Date
Paul Bottein c70e974759 Skip entities assigned to another area when resolving area targets 2026-08-18 14:13:53 +02:00
d5389b5bef Fall back to option key for untranslated repair menu options (#53681)
Repair fix flows build their menu from the suggestions the backend
reports. A suggestion this frontend has no translation for yet (e.g. a
newer Supervisor offering a new repair suggestion) rendered as an
empty, unlabeled menu entry. Show the raw option key instead, matching
the fallback the form step header already uses.

Co-authored-by: Claude Fable 5 <[email protected]>
2026-08-17 15:23:02 +02:00
3 changed files with 84 additions and 7 deletions
+10 -1
View File
@@ -1135,6 +1135,10 @@ export const resolveEntityIDs = (
expanded.areas.forEach((id) => targetAreas.add(id));
});
// Devices only reached through an area do not pull in entities that are
// explicitly assigned to another area, matching core.
const devicesNotViaArea = new Set(targetDevices);
targetAreas.forEach((areaId) => {
const expanded = expandAreaTarget(
hass,
@@ -1153,6 +1157,7 @@ export const resolveEntityIDs = (
Object.values(devices).forEach((device) => {
if (device.parent_device_id && directDevices.has(device.parent_device_id)) {
targetDevices.add(device.id);
devicesNotViaArea.add(device.id);
}
});
@@ -1163,7 +1168,11 @@ export const resolveEntityIDs = (
entities,
targetSelector
);
expanded.entities.forEach((id) => targetEntities.add(id));
expanded.entities.forEach((id) => {
if (devicesNotViaArea.has(deviceId) || !entities[id]?.area_id) {
targetEntities.add(id);
}
});
});
return Array.from(targetEntities);
@@ -291,11 +291,17 @@ export const showRepairsFlowDialog = (
},
renderMenuOption(hass, step, option) {
return hass.localize(
`component.${issue.domain}.issues.${
issue.translation_key || issue.issue_id
}.fix_flow.step.${step.step_id}.menu_options.${option}`,
mergePlaceholders(issue, step)
return (
hass.localize(
`component.${issue.domain}.issues.${
issue.translation_key || issue.issue_id
}.fix_flow.step.${step.step_id}.menu_options.${option}`,
mergePlaceholders(issue, step)
) ||
// Newer backends can offer options this frontend has no
// translation for yet — show the raw option key instead of
// an empty menu entry
option
);
},
+63 -1
View File
@@ -1,7 +1,10 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { describe, expect, it } from "vitest";
import type { DeviceRegistryEntry } from "../../src/data/device/device_registry";
import { filterSelectorEntities } from "../../src/data/selector";
import {
filterSelectorEntities,
resolveEntityIDs,
} from "../../src/data/selector";
import type { HomeAssistant } from "../../src/types";
const entity = {
@@ -132,3 +135,62 @@ describe("filterSelectorEntities device filter", () => {
).toBe(false);
});
});
describe("resolveEntityIDs", () => {
const areaHass = {
states: {
"light.kitchen": { entity_id: "light.kitchen", state: "on" },
"sensor.kitchen_hub_temp": {
entity_id: "sensor.kitchen_hub_temp",
state: "20",
},
"sensor.hallway_probe": { entity_id: "sensor.hallway_probe", state: "5" },
},
entities: {
"light.kitchen": { entity_id: "light.kitchen", device_id: "hub" },
"sensor.kitchen_hub_temp": {
entity_id: "sensor.kitchen_hub_temp",
device_id: "hub",
},
"sensor.hallway_probe": {
entity_id: "sensor.hallway_probe",
device_id: "hub",
area_id: "hallway",
},
},
devices: { hub: { id: "hub", area_id: "kitchen" } },
areas: { kitchen: { area_id: "kitchen" }, hallway: { area_id: "hallway" } },
} as unknown as HomeAssistant;
const resolve = (target) =>
resolveEntityIDs(
areaHass,
target,
areaHass.entities,
areaHass.devices,
areaHass.areas
).sort();
it("skips entities of an area device that are assigned to another area", () => {
expect(resolve({ area_id: "kitchen" })).toEqual([
"light.kitchen",
"sensor.kitchen_hub_temp",
]);
});
it("keeps every entity of a directly targeted device", () => {
expect(resolve({ device_id: "hub" })).toEqual([
"light.kitchen",
"sensor.hallway_probe",
"sensor.kitchen_hub_temp",
]);
});
it("keeps the entity when its own area is targeted as well", () => {
expect(resolve({ area_id: ["kitchen", "hallway"] })).toEqual([
"light.kitchen",
"sensor.hallway_probe",
"sensor.kitchen_hub_temp",
]);
});
});