mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-18 07:56:44 +01:00
Triggers/conditions Add usage and grouping to new multi domains (#51287)
This commit is contained in:
@@ -3,8 +3,10 @@ import {
|
|||||||
mdiAirFilter,
|
mdiAirFilter,
|
||||||
mdiAlert,
|
mdiAlert,
|
||||||
mdiAppleSafari,
|
mdiAppleSafari,
|
||||||
|
mdiBattery,
|
||||||
mdiBell,
|
mdiBell,
|
||||||
mdiBookmark,
|
mdiBookmark,
|
||||||
|
mdiBrightness6,
|
||||||
mdiBullhorn,
|
mdiBullhorn,
|
||||||
mdiButtonPointer,
|
mdiButtonPointer,
|
||||||
mdiCalendar,
|
mdiCalendar,
|
||||||
@@ -16,13 +18,18 @@ import {
|
|||||||
mdiCog,
|
mdiCog,
|
||||||
mdiCommentAlert,
|
mdiCommentAlert,
|
||||||
mdiCounter,
|
mdiCounter,
|
||||||
|
mdiDoorOpen,
|
||||||
mdiEye,
|
mdiEye,
|
||||||
|
mdiFlash,
|
||||||
mdiFlower,
|
mdiFlower,
|
||||||
mdiFormatListBulleted,
|
mdiFormatListBulleted,
|
||||||
mdiFormTextbox,
|
mdiFormTextbox,
|
||||||
mdiForumOutline,
|
mdiForumOutline,
|
||||||
|
mdiGarageOpen,
|
||||||
|
mdiGate,
|
||||||
mdiGoogleAssistant,
|
mdiGoogleAssistant,
|
||||||
mdiGoogleCirclesCommunities,
|
mdiGoogleCirclesCommunities,
|
||||||
|
mdiHomeAccount,
|
||||||
mdiHomeAutomation,
|
mdiHomeAutomation,
|
||||||
mdiImage,
|
mdiImage,
|
||||||
mdiImageFilterFrames,
|
mdiImageFilterFrames,
|
||||||
@@ -30,6 +37,7 @@ import {
|
|||||||
mdiLightbulb,
|
mdiLightbulb,
|
||||||
mdiMapMarkerRadius,
|
mdiMapMarkerRadius,
|
||||||
mdiMicrophoneMessage,
|
mdiMicrophoneMessage,
|
||||||
|
mdiMotionSensor,
|
||||||
mdiPalette,
|
mdiPalette,
|
||||||
mdiRayVertex,
|
mdiRayVertex,
|
||||||
mdiRemote,
|
mdiRemote,
|
||||||
@@ -41,10 +49,14 @@ import {
|
|||||||
mdiSpeakerMessage,
|
mdiSpeakerMessage,
|
||||||
mdiStarFourPoints,
|
mdiStarFourPoints,
|
||||||
mdiThermostat,
|
mdiThermostat,
|
||||||
|
mdiThermometer,
|
||||||
mdiTimerOutline,
|
mdiTimerOutline,
|
||||||
mdiToggleSwitch,
|
mdiToggleSwitch,
|
||||||
|
mdiWater,
|
||||||
|
mdiWaterPercent,
|
||||||
mdiWeatherPartlyCloudy,
|
mdiWeatherPartlyCloudy,
|
||||||
mdiWhiteBalanceSunny,
|
mdiWhiteBalanceSunny,
|
||||||
|
mdiWindowClosed,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||||
@@ -75,6 +87,7 @@ export const FALLBACK_DOMAIN_ICONS = {
|
|||||||
air_quality: mdiAirFilter,
|
air_quality: mdiAirFilter,
|
||||||
alert: mdiAlert,
|
alert: mdiAlert,
|
||||||
automation: mdiRobot,
|
automation: mdiRobot,
|
||||||
|
battery: mdiBattery,
|
||||||
calendar: mdiCalendar,
|
calendar: mdiCalendar,
|
||||||
climate: mdiThermostat,
|
climate: mdiThermostat,
|
||||||
configurator: mdiCog,
|
configurator: mdiCog,
|
||||||
@@ -84,10 +97,15 @@ export const FALLBACK_DOMAIN_ICONS = {
|
|||||||
datetime: mdiCalendarClock,
|
datetime: mdiCalendarClock,
|
||||||
demo: mdiHomeAssistant,
|
demo: mdiHomeAssistant,
|
||||||
device_tracker: mdiAccount,
|
device_tracker: mdiAccount,
|
||||||
|
door: mdiDoorOpen,
|
||||||
|
garage_door: mdiGarageOpen,
|
||||||
|
gate: mdiGate,
|
||||||
google_assistant: mdiGoogleAssistant,
|
google_assistant: mdiGoogleAssistant,
|
||||||
group: mdiGoogleCirclesCommunities,
|
group: mdiGoogleCirclesCommunities,
|
||||||
homeassistant: mdiHomeAssistant,
|
homeassistant: mdiHomeAssistant,
|
||||||
homekit: mdiHomeAutomation,
|
homekit: mdiHomeAutomation,
|
||||||
|
humidity: mdiWaterPercent,
|
||||||
|
illuminance: mdiBrightness6,
|
||||||
image_processing: mdiImageFilterFrames,
|
image_processing: mdiImageFilterFrames,
|
||||||
image: mdiImage,
|
image: mdiImage,
|
||||||
infrared: mdiLedOn,
|
infrared: mdiLedOn,
|
||||||
@@ -99,11 +117,15 @@ export const FALLBACK_DOMAIN_ICONS = {
|
|||||||
input_text: mdiFormTextbox,
|
input_text: mdiFormTextbox,
|
||||||
lawn_mower: mdiRobotMower,
|
lawn_mower: mdiRobotMower,
|
||||||
light: mdiLightbulb,
|
light: mdiLightbulb,
|
||||||
|
moisture: mdiWater,
|
||||||
|
motion: mdiMotionSensor,
|
||||||
notify: mdiCommentAlert,
|
notify: mdiCommentAlert,
|
||||||
number: mdiRayVertex,
|
number: mdiRayVertex,
|
||||||
|
occupancy: mdiHomeAccount,
|
||||||
persistent_notification: mdiBell,
|
persistent_notification: mdiBell,
|
||||||
person: mdiAccount,
|
person: mdiAccount,
|
||||||
plant: mdiFlower,
|
plant: mdiFlower,
|
||||||
|
power: mdiFlash,
|
||||||
proximity: mdiAppleSafari,
|
proximity: mdiAppleSafari,
|
||||||
remote: mdiRemote,
|
remote: mdiRemote,
|
||||||
scene: mdiPalette,
|
scene: mdiPalette,
|
||||||
@@ -115,6 +137,7 @@ export const FALLBACK_DOMAIN_ICONS = {
|
|||||||
siren: mdiBullhorn,
|
siren: mdiBullhorn,
|
||||||
stt: mdiMicrophoneMessage,
|
stt: mdiMicrophoneMessage,
|
||||||
sun: mdiWhiteBalanceSunny,
|
sun: mdiWhiteBalanceSunny,
|
||||||
|
temperature: mdiThermometer,
|
||||||
text: mdiFormTextbox,
|
text: mdiFormTextbox,
|
||||||
time: mdiClock,
|
time: mdiClock,
|
||||||
timer: mdiTimerOutline,
|
timer: mdiTimerOutline,
|
||||||
@@ -124,6 +147,7 @@ export const FALLBACK_DOMAIN_ICONS = {
|
|||||||
vacuum: mdiRobotVacuum,
|
vacuum: mdiRobotVacuum,
|
||||||
wake_word: mdiChatSleep,
|
wake_word: mdiChatSleep,
|
||||||
weather: mdiWeatherPartlyCloudy,
|
weather: mdiWeatherPartlyCloudy,
|
||||||
|
window: mdiWindowClosed,
|
||||||
zone: mdiMapMarkerRadius,
|
zone: mdiMapMarkerRadius,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { customElement, property, query, state } from "lit/decorators";
|
|||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { repeat } from "lit/directives/repeat";
|
import { repeat } from "lit/directives/repeat";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { ensureArray } from "../../../common/array/ensure-array";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { mainWindow } from "../../../common/dom/get_main_window";
|
import { mainWindow } from "../../../common/dom/get_main_window";
|
||||||
import { computeAreaName } from "../../../common/entity/compute_area_name";
|
import { computeAreaName } from "../../../common/entity/compute_area_name";
|
||||||
@@ -98,6 +99,7 @@ import {
|
|||||||
domainToName,
|
domainToName,
|
||||||
fetchIntegrationManifests,
|
fetchIntegrationManifests,
|
||||||
} from "../../../data/integration";
|
} from "../../../data/integration";
|
||||||
|
import { filterSelectorEntities } from "../../../data/selector";
|
||||||
import type { LabelRegistryEntry } from "../../../data/label/label_registry";
|
import type { LabelRegistryEntry } from "../../../data/label/label_registry";
|
||||||
import { subscribeLabFeature } from "../../../data/labs";
|
import { subscribeLabFeature } from "../../../data/labs";
|
||||||
import {
|
import {
|
||||||
@@ -412,6 +414,86 @@ class DialogAddAutomationElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _calculateActiveSystemDomains = memoizeOne(
|
||||||
|
(
|
||||||
|
descriptions: TriggerDescriptions | ConditionDescriptions,
|
||||||
|
manifests: DomainManifestLookup,
|
||||||
|
getDomain: (key: string) => string
|
||||||
|
): { active: Set<string>; byEntityDomain: Map<string, Set<string>> } => {
|
||||||
|
const active = new Set<string>();
|
||||||
|
// Group all entity filters by system domain
|
||||||
|
const domainFilters: Record<
|
||||||
|
string,
|
||||||
|
Parameters<typeof filterSelectorEntities>[0][]
|
||||||
|
> = {};
|
||||||
|
// Also collect which entity domains each system domain targets
|
||||||
|
const entityDomainsPerSystemDomain: Record<string, Set<string>> = {};
|
||||||
|
for (const [key, desc] of Object.entries(descriptions)) {
|
||||||
|
const domain = getDomain(key);
|
||||||
|
if (manifests[domain]?.integration_type !== "system") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!domainFilters[domain]) {
|
||||||
|
domainFilters[domain] = [];
|
||||||
|
entityDomainsPerSystemDomain[domain] = new Set();
|
||||||
|
}
|
||||||
|
const entityFilters = ensureArray(desc.target?.entity);
|
||||||
|
if (entityFilters) {
|
||||||
|
// target.entity can be EntitySelectorFilter | readonly EntitySelectorFilter[]
|
||||||
|
// ensureArray wraps it but each element may still be an array, so flatten
|
||||||
|
for (const filterOrArray of entityFilters) {
|
||||||
|
const filters = ensureArray(filterOrArray);
|
||||||
|
domainFilters[domain].push(...filters);
|
||||||
|
for (const filter of filters) {
|
||||||
|
for (const entityDomain of ensureArray(filter.domain) ?? []) {
|
||||||
|
entityDomainsPerSystemDomain[domain].add(entityDomain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check each entity in hass.states against the filters
|
||||||
|
for (const entity of Object.values(this.hass.states)) {
|
||||||
|
for (const [domain, filters] of Object.entries(domainFilters)) {
|
||||||
|
if (active.has(domain)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (filters.some((f) => filterSelectorEntities(f, entity))) {
|
||||||
|
active.add(domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Build reverse map: entity domain → set of system domains that cover it
|
||||||
|
const byEntityDomain = new Map<string, Set<string>>();
|
||||||
|
for (const [systemDomain, entityDomains] of Object.entries(
|
||||||
|
entityDomainsPerSystemDomain
|
||||||
|
)) {
|
||||||
|
for (const entityDomain of entityDomains) {
|
||||||
|
if (!byEntityDomain.has(entityDomain)) {
|
||||||
|
byEntityDomain.set(entityDomain, new Set());
|
||||||
|
}
|
||||||
|
byEntityDomain.get(entityDomain)!.add(systemDomain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { active, byEntityDomain };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
private get _systemDomains() {
|
||||||
|
if (!this._manifests) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const descriptions =
|
||||||
|
this._params?.type === "trigger"
|
||||||
|
? this._triggerDescriptions
|
||||||
|
: this._conditionDescriptions;
|
||||||
|
return this._calculateActiveSystemDomains(
|
||||||
|
descriptions,
|
||||||
|
this._manifests,
|
||||||
|
this._params?.type === "trigger" ? getTriggerDomain : getConditionDomain
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private async _loadConfigEntries() {
|
private async _loadConfigEntries() {
|
||||||
const configEntries = await getConfigEntries(this.hass);
|
const configEntries = await getConfigEntries(this.hass);
|
||||||
this._configEntryLookup = Object.fromEntries(
|
this._configEntryLookup = Object.fromEntries(
|
||||||
@@ -426,6 +508,11 @@ class DialogAddAutomationElement
|
|||||||
manifests[manifest.domain] = manifest;
|
manifests[manifest.domain] = manifest;
|
||||||
}
|
}
|
||||||
this._manifests = manifests;
|
this._manifests = manifests;
|
||||||
|
// If a target was already selected and items computed before manifests
|
||||||
|
// loaded, recompute so system domain grouping applies correctly.
|
||||||
|
if (this._selectedTarget && this._targetItems) {
|
||||||
|
this._getItemsByTarget();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public disconnectedCallback(): void {
|
public disconnectedCallback(): void {
|
||||||
@@ -905,7 +992,8 @@ class DialogAddAutomationElement
|
|||||||
this._domains,
|
this._domains,
|
||||||
this.hass.localize,
|
this.hass.localize,
|
||||||
this.hass.services,
|
this.hass.services,
|
||||||
this._manifests
|
this._manifests,
|
||||||
|
this._systemDomains?.byEntityDomain
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -954,10 +1042,17 @@ class DialogAddAutomationElement
|
|||||||
|
|
||||||
const items = flattenGroups(groups).flat();
|
const items = flattenGroups(groups).flat();
|
||||||
if (type === "trigger") {
|
if (type === "trigger") {
|
||||||
items.push(...this._triggers(localize, this._triggerDescriptions));
|
items.push(
|
||||||
|
...this._triggers(localize, this._triggerDescriptions, undefined)
|
||||||
|
);
|
||||||
} else if (type === "condition") {
|
} else if (type === "condition") {
|
||||||
items.push(
|
items.push(
|
||||||
...this._conditions(localize, this._conditionDescriptions, manifests)
|
...this._conditions(
|
||||||
|
localize,
|
||||||
|
this._conditionDescriptions,
|
||||||
|
manifests,
|
||||||
|
undefined
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} else if (type === "action") {
|
} else if (type === "action") {
|
||||||
items.push(...this._services(localize, services, manifests));
|
items.push(...this._services(localize, services, manifests));
|
||||||
@@ -1141,16 +1236,23 @@ class DialogAddAutomationElement
|
|||||||
domains: Set<string> | undefined,
|
domains: Set<string> | undefined,
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
services: HomeAssistant["services"],
|
services: HomeAssistant["services"],
|
||||||
manifests?: DomainManifestLookup
|
manifests?: DomainManifestLookup,
|
||||||
|
systemDomainsByEntityDomain?: Map<string, Set<string>>
|
||||||
): AddAutomationElementListItem[] => {
|
): AddAutomationElementListItem[] => {
|
||||||
if (type === "trigger" && isDynamic(group)) {
|
if (type === "trigger" && isDynamic(group)) {
|
||||||
return this._triggers(localize, this._triggerDescriptions, group);
|
return this._triggers(
|
||||||
|
localize,
|
||||||
|
this._triggerDescriptions,
|
||||||
|
systemDomainsByEntityDomain,
|
||||||
|
group
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (type === "condition" && isDynamic(group)) {
|
if (type === "condition" && isDynamic(group)) {
|
||||||
return this._conditions(
|
return this._conditions(
|
||||||
localize,
|
localize,
|
||||||
this._conditionDescriptions,
|
this._conditionDescriptions,
|
||||||
manifests,
|
manifests,
|
||||||
|
systemDomainsByEntityDomain,
|
||||||
group
|
group
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1250,6 +1352,38 @@ class DialogAddAutomationElement
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _domainMatchesGroupType(
|
||||||
|
domain: string,
|
||||||
|
manifest: DomainManifestLookup[string] | undefined,
|
||||||
|
domainUsed: boolean,
|
||||||
|
type: "helper" | "other" | undefined
|
||||||
|
): boolean {
|
||||||
|
if (type === undefined) {
|
||||||
|
return (
|
||||||
|
ENTITY_DOMAINS_MAIN.has(domain) ||
|
||||||
|
(manifest?.integration_type === "entity" &&
|
||||||
|
domainUsed &&
|
||||||
|
!ENTITY_DOMAINS_OTHER.has(domain)) ||
|
||||||
|
(manifest?.integration_type === "system" &&
|
||||||
|
(this._systemDomains?.active.has(domain) ?? false))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (type === "helper") {
|
||||||
|
return manifest?.integration_type === "helper";
|
||||||
|
}
|
||||||
|
// type === "other"
|
||||||
|
return (
|
||||||
|
!ENTITY_DOMAINS_MAIN.has(domain) &&
|
||||||
|
(ENTITY_DOMAINS_OTHER.has(domain) ||
|
||||||
|
(!domainUsed && manifest?.integration_type === "entity") ||
|
||||||
|
(manifest?.integration_type === "system" &&
|
||||||
|
!(this._systemDomains?.active.has(domain) ?? false)) ||
|
||||||
|
!["helper", "entity", "system"].includes(
|
||||||
|
manifest?.integration_type || ""
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private _triggerGroups = (
|
private _triggerGroups = (
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
triggers: TriggerDescriptions,
|
triggers: TriggerDescriptions,
|
||||||
@@ -1273,19 +1407,7 @@ class DialogAddAutomationElement
|
|||||||
const manifest = manifests[domain];
|
const manifest = manifests[domain];
|
||||||
const domainUsed = !domains ? true : domains.has(domain);
|
const domainUsed = !domains ? true : domains.has(domain);
|
||||||
|
|
||||||
if (
|
if (this._domainMatchesGroupType(domain, manifest, domainUsed, type)) {
|
||||||
(type === undefined &&
|
|
||||||
(ENTITY_DOMAINS_MAIN.has(domain) ||
|
|
||||||
(manifest?.integration_type === "entity" &&
|
|
||||||
domainUsed &&
|
|
||||||
!ENTITY_DOMAINS_OTHER.has(domain)))) ||
|
|
||||||
(type === "helper" && manifest?.integration_type === "helper") ||
|
|
||||||
(type === "other" &&
|
|
||||||
!ENTITY_DOMAINS_MAIN.has(domain) &&
|
|
||||||
(ENTITY_DOMAINS_OTHER.has(domain) ||
|
|
||||||
(!domainUsed && manifest?.integration_type === "entity") ||
|
|
||||||
!["helper", "entity"].includes(manifest?.integration_type || "")))
|
|
||||||
) {
|
|
||||||
result.push({
|
result.push({
|
||||||
icon: html`
|
icon: html`
|
||||||
<ha-domain-icon
|
<ha-domain-icon
|
||||||
@@ -1309,17 +1431,30 @@ class DialogAddAutomationElement
|
|||||||
(
|
(
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
triggers: TriggerDescriptions,
|
triggers: TriggerDescriptions,
|
||||||
|
systemDomainsByEntityDomain: Map<string, Set<string>> | undefined,
|
||||||
group?: string
|
group?: string
|
||||||
): AddAutomationElementListItem[] => {
|
): AddAutomationElementListItem[] => {
|
||||||
if (!triggers) {
|
if (!triggers) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const browsedEntityDomain =
|
||||||
|
group && isDynamic(group) ? getValueFromDynamic(group) : undefined;
|
||||||
|
|
||||||
|
// System domains that should be merged into this entity domain group
|
||||||
|
const systemDomainsForGroup = browsedEntityDomain
|
||||||
|
? systemDomainsByEntityDomain?.get(browsedEntityDomain)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return this._getTriggerListItems(
|
return this._getTriggerListItems(
|
||||||
localize,
|
localize,
|
||||||
Object.keys(triggers).filter((trigger) => {
|
Object.keys(triggers).filter((trigger) => {
|
||||||
const domain = getTriggerDomain(trigger);
|
const domain = getTriggerDomain(trigger);
|
||||||
return !group || group === `${DYNAMIC_PREFIX}${domain}`;
|
if (!group || group === `${DYNAMIC_PREFIX}${domain}`) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Also include system domain triggers that cover the browsed entity domain
|
||||||
|
return systemDomainsForGroup?.has(domain) ?? false;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1348,19 +1483,7 @@ class DialogAddAutomationElement
|
|||||||
const manifest = manifests[domain];
|
const manifest = manifests[domain];
|
||||||
const domainUsed = !domains ? true : domains.has(domain);
|
const domainUsed = !domains ? true : domains.has(domain);
|
||||||
|
|
||||||
if (
|
if (this._domainMatchesGroupType(domain, manifest, domainUsed, type)) {
|
||||||
(type === undefined &&
|
|
||||||
(ENTITY_DOMAINS_MAIN.has(domain) ||
|
|
||||||
(manifest?.integration_type === "entity" &&
|
|
||||||
domainUsed &&
|
|
||||||
!ENTITY_DOMAINS_OTHER.has(domain)))) ||
|
|
||||||
(type === "helper" && manifest?.integration_type === "helper") ||
|
|
||||||
(type === "other" &&
|
|
||||||
!ENTITY_DOMAINS_MAIN.has(domain) &&
|
|
||||||
(ENTITY_DOMAINS_OTHER.has(domain) ||
|
|
||||||
(!domainUsed && manifest?.integration_type === "entity") ||
|
|
||||||
!["helper", "entity"].includes(manifest?.integration_type || "")))
|
|
||||||
) {
|
|
||||||
result.push({
|
result.push({
|
||||||
icon: html`
|
icon: html`
|
||||||
<ha-domain-icon
|
<ha-domain-icon
|
||||||
@@ -1385,6 +1508,7 @@ class DialogAddAutomationElement
|
|||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
conditions: ConditionDescriptions,
|
conditions: ConditionDescriptions,
|
||||||
_manifests: DomainManifestLookup | undefined,
|
_manifests: DomainManifestLookup | undefined,
|
||||||
|
systemDomainsByEntityDomain: Map<string, Set<string>> | undefined,
|
||||||
group?: string
|
group?: string
|
||||||
): AddAutomationElementListItem[] => {
|
): AddAutomationElementListItem[] => {
|
||||||
if (!conditions) {
|
if (!conditions) {
|
||||||
@@ -1392,10 +1516,21 @@ class DialogAddAutomationElement
|
|||||||
}
|
}
|
||||||
const result: AddAutomationElementListItem[] = [];
|
const result: AddAutomationElementListItem[] = [];
|
||||||
|
|
||||||
|
const browsedEntityDomain =
|
||||||
|
group && isDynamic(group) ? getValueFromDynamic(group) : undefined;
|
||||||
|
|
||||||
|
const systemDomainsForGroup = browsedEntityDomain
|
||||||
|
? systemDomainsByEntityDomain?.get(browsedEntityDomain)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
for (const condition of Object.keys(conditions)) {
|
for (const condition of Object.keys(conditions)) {
|
||||||
const domain = getConditionDomain(condition);
|
const domain = getConditionDomain(condition);
|
||||||
|
|
||||||
if (group && group !== `${DYNAMIC_PREFIX}${domain}`) {
|
if (
|
||||||
|
group &&
|
||||||
|
group !== `${DYNAMIC_PREFIX}${domain}` &&
|
||||||
|
!(systemDomainsForGroup?.has(domain) ?? false)
|
||||||
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1491,13 +1626,23 @@ class DialogAddAutomationElement
|
|||||||
);
|
);
|
||||||
|
|
||||||
private _getDomainType(domain: string) {
|
private _getDomainType(domain: string) {
|
||||||
return ENTITY_DOMAINS_MAIN.has(domain) ||
|
if (
|
||||||
(this._manifests?.[domain].integration_type === "entity" &&
|
ENTITY_DOMAINS_MAIN.has(domain) ||
|
||||||
|
(this._manifests?.[domain]?.integration_type === "entity" &&
|
||||||
!ENTITY_DOMAINS_OTHER.has(domain))
|
!ENTITY_DOMAINS_OTHER.has(domain))
|
||||||
? "dynamicGroups"
|
) {
|
||||||
: this._manifests?.[domain].integration_type === "helper"
|
return "dynamicGroups";
|
||||||
? "helpers"
|
}
|
||||||
: "other";
|
if (this._manifests?.[domain]?.integration_type === "helper") {
|
||||||
|
return "helpers";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this._manifests?.[domain]?.integration_type === "system" &&
|
||||||
|
this._systemDomains?.active.has(domain)
|
||||||
|
) {
|
||||||
|
return "dynamicGroups";
|
||||||
|
}
|
||||||
|
return "other";
|
||||||
}
|
}
|
||||||
|
|
||||||
private _sortDomainsByCollection(
|
private _sortDomainsByCollection(
|
||||||
@@ -1602,30 +1747,56 @@ class DialogAddAutomationElement
|
|||||||
iconPath: options.icon || TYPES[type].icons[key],
|
iconPath: options.icon || TYPES[type].icons[key],
|
||||||
});
|
});
|
||||||
|
|
||||||
private _getDomainGroupedTriggerListItems(
|
private _getDomainGroupedListItems(
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
triggerIds: string[]
|
ids: string[],
|
||||||
|
getDomain: (id: string) => string,
|
||||||
|
getListItem: (
|
||||||
|
localize: LocalizeFunc,
|
||||||
|
domain: string,
|
||||||
|
id: string
|
||||||
|
) => AddAutomationElementListItem
|
||||||
): { title: string; items: AddAutomationElementListItem[] }[] {
|
): { title: string; items: AddAutomationElementListItem[] }[] {
|
||||||
const items: Record<
|
const items: Record<
|
||||||
string,
|
string,
|
||||||
{ title: string; items: AddAutomationElementListItem[] }
|
{ title: string; items: AddAutomationElementListItem[] }
|
||||||
> = {};
|
> = {};
|
||||||
|
|
||||||
triggerIds.forEach((trigger) => {
|
// When a specific entity is selected, system domain items are merged
|
||||||
const domain = getTriggerDomain(trigger);
|
// under the entity's real domain rather than under their system domain name.
|
||||||
|
const targetEntityId = this._selectedTarget?.entity_id;
|
||||||
|
const targetEntityDomain =
|
||||||
|
targetEntityId &&
|
||||||
|
this._manifests?.[computeDomain(targetEntityId)]?.integration_type !==
|
||||||
|
"system"
|
||||||
|
? computeDomain(targetEntityId)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
if (!items[domain]) {
|
ids.forEach((id) => {
|
||||||
items[domain] = {
|
const itemDomain = getDomain(id);
|
||||||
title: domainToName(localize, domain, this._manifests?.[domain]),
|
const isSystemDomain =
|
||||||
|
this._manifests?.[itemDomain]?.integration_type === "system";
|
||||||
|
|
||||||
|
// System domain items are grouped under the entity's real domain (if
|
||||||
|
// a specific entity is selected), so they appear alongside that domain's
|
||||||
|
// own items rather than in a separate section.
|
||||||
|
const groupDomain =
|
||||||
|
isSystemDomain && targetEntityDomain ? targetEntityDomain : itemDomain;
|
||||||
|
|
||||||
|
if (!items[groupDomain]) {
|
||||||
|
items[groupDomain] = {
|
||||||
|
title: domainToName(
|
||||||
|
localize,
|
||||||
|
groupDomain,
|
||||||
|
this._manifests?.[groupDomain]
|
||||||
|
),
|
||||||
items: [],
|
items: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
items[domain].items.push(
|
items[groupDomain].items.push(getListItem(localize, itemDomain, id));
|
||||||
this._getTriggerListItem(localize, domain, trigger)
|
|
||||||
);
|
|
||||||
|
|
||||||
items[domain].items.sort((a, b) =>
|
items[groupDomain].items.sort((a, b) =>
|
||||||
stringCompare(a.name, b.name, this.hass.locale.language)
|
stringCompare(a.name, b.name, this.hass.locale.language)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1747,39 +1918,6 @@ class DialogAddAutomationElement
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getDomainGroupedConditionListItems(
|
|
||||||
localize: LocalizeFunc,
|
|
||||||
conditionIds: string[]
|
|
||||||
): { title: string; items: AddAutomationElementListItem[] }[] {
|
|
||||||
const items: Record<
|
|
||||||
string,
|
|
||||||
{ title: string; items: AddAutomationElementListItem[] }
|
|
||||||
> = {};
|
|
||||||
|
|
||||||
conditionIds.forEach((condition) => {
|
|
||||||
const domain = getConditionDomain(condition);
|
|
||||||
if (!items[domain]) {
|
|
||||||
items[domain] = {
|
|
||||||
title: domainToName(localize, domain, this._manifests?.[domain]),
|
|
||||||
items: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
items[domain].items.push(
|
|
||||||
this._getConditionListItem(localize, domain, condition)
|
|
||||||
);
|
|
||||||
|
|
||||||
items[domain].items.sort((a, b) =>
|
|
||||||
stringCompare(a.name, b.name, this.hass.locale.language)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return this._sortDomainsByCollection(
|
|
||||||
this._params!.type,
|
|
||||||
Object.entries(items)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// #endregion render prepare
|
// #endregion render prepare
|
||||||
|
|
||||||
// #region interaction
|
// #region interaction
|
||||||
@@ -1909,9 +2047,11 @@ class DialogAddAutomationElement
|
|||||||
this._selectedTarget
|
this._selectedTarget
|
||||||
);
|
);
|
||||||
|
|
||||||
const grouped = this._getDomainGroupedTriggerListItems(
|
const grouped = this._getDomainGroupedListItems(
|
||||||
this.hass.localize,
|
this.hass.localize,
|
||||||
items
|
items,
|
||||||
|
getTriggerDomain,
|
||||||
|
this._getTriggerListItem
|
||||||
);
|
);
|
||||||
if (this._selectedTarget.entity_id) {
|
if (this._selectedTarget.entity_id) {
|
||||||
grouped.push({
|
grouped.push({
|
||||||
@@ -1930,9 +2070,11 @@ class DialogAddAutomationElement
|
|||||||
this._selectedTarget
|
this._selectedTarget
|
||||||
);
|
);
|
||||||
|
|
||||||
const grouped = this._getDomainGroupedConditionListItems(
|
const grouped = this._getDomainGroupedListItems(
|
||||||
this.hass.localize,
|
this.hass.localize,
|
||||||
items
|
items,
|
||||||
|
getConditionDomain,
|
||||||
|
this._getConditionListItem
|
||||||
);
|
);
|
||||||
if (this._selectedTarget.entity_id) {
|
if (this._selectedTarget.entity_id) {
|
||||||
grouped.push({
|
grouped.push({
|
||||||
|
|||||||
Reference in New Issue
Block a user