Compare commits

...
Author SHA1 Message Date
Petar Petrov 06c2e1932c Drop hass from the device automation pickers
The device action, condition and trigger pickers read localization, states, formatters and the API from contexts.
2026-10-26 18:06:00 +02:00
7 changed files with 93 additions and 31 deletions

No files matched your search

@@ -9,13 +9,13 @@ import { HaDeviceAutomationPicker } from "./ha-device-automation-picker";
@customElement("ha-device-action-picker")
class HaDeviceActionPicker extends HaDeviceAutomationPicker<DeviceAction> {
protected get NO_AUTOMATION_TEXT() {
return this.hass.localize(
return this._i18n.localize(
"ui.panel.config.devices.automation.actions.no_actions"
);
}
protected get UNKNOWN_AUTOMATION_TEXT() {
return this.hass.localize(
return this._i18n.localize(
"ui.panel.config.devices.automation.actions.unknown_action"
);
}
@@ -1,21 +1,35 @@
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
import type { ContextType } from "@lit/context";
import type { HassEntities } from "home-assistant-js-websocket";
import type { PropertyValues } from "lit";
import { html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { consume } from "../../common/decorators/consume";
import { preserveUnchangedEntityStatesRecord } from "../../common/decorators/consume-context-entry";
import { transform } from "../../common/decorators/transform";
import { fireEvent } from "../../common/dom/fire_event";
import { caseInsensitiveStringCompare } from "../../common/string/compare";
import type { LocalizeFunc } from "../../common/translations/localize";
import { fullEntitiesContext } from "../../data/context";
import {
apiContext,
formattersContext,
fullEntitiesContext,
internationalizationContext,
statesContext,
} from "../../data/context";
import type { DeviceAutomation } from "../../data/device/device_automation";
import {
deviceAutomationsEqual,
sortDeviceAutomations,
} from "../../data/device/device_automation";
import type { EntityRegistryEntry } from "../../data/entity/entity_registry";
import type { CallWS, HomeAssistant, ValueChangedEvent } from "../../types";
import { entityRegistryById } from "../../data/entity/entity_registry";
import type {
CallWS,
HomeAssistantFormatters,
ValueChangedEvent,
} from "../../types";
import "../ha-combo-box-item";
import "../ha-generic-picker";
import {
@@ -29,8 +43,6 @@ const NO_AUTOMATION_KEY = "NO_AUTOMATION";
export abstract class HaDeviceAutomationPicker<
T extends DeviceAutomation,
> extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public label?: string;
@property({ attribute: false }) public deviceId?: string;
@@ -47,8 +59,49 @@ export abstract class HaDeviceAutomationPicker<
@consume({ context: fullEntitiesContext, subscribe: true })
_entityReg: EntityRegistryEntry[] = [];
@state()
@consume({ context: internationalizationContext, subscribe: true })
protected _i18n!: ContextType<typeof internationalizationContext>;
@state()
@consume({ context: statesContext, subscribe: true })
@transform<HassEntities, HassEntities>({
transformer: function (
this: HaDeviceAutomationPicker<DeviceAutomation>,
states
) {
const registryById = entityRegistryById(this._entityReg ?? []);
const picked: HassEntities = {};
[...(this._automations ?? []), this.value].forEach((automation) => {
const id = automation?.entity_id;
const entityId = id?.includes(".")
? id
: id && registryById[id]?.entity_id;
if (entityId && states?.[entityId]) {
picked[entityId] = states[entityId];
}
});
return preserveUnchangedEntityStatesRecord(this._states, picked);
},
watch: ["_automations", "value", "_entityReg"],
})
private _states: HassEntities = {};
@state()
@consume({ context: formattersContext, subscribe: true })
@transform<
HomeAssistantFormatters,
HomeAssistantFormatters["formatEntityName"]
>({
transformer: ({ formatEntityName }) => formatEntityName,
})
private _formatEntityName!: HomeAssistantFormatters["formatEntityName"];
@consume({ context: apiContext, subscribe: true })
private _api!: ContextType<typeof apiContext>;
protected get NO_AUTOMATION_TEXT() {
return this.hass.localize(
return this._i18n.localize(
"ui.panel.config.devices.automation.actions.no_actions"
);
}
@@ -56,7 +109,7 @@ export abstract class HaDeviceAutomationPicker<
private _localizeDeviceAutomation: (
localize: LocalizeFunc,
states: HassEntities,
formatEntityName: HomeAssistant["formatEntityName"],
formatEntityName: HomeAssistantFormatters["formatEntityName"],
entityRegistry: EntityRegistryEntry[],
automation: T
) => string;
@@ -109,11 +162,19 @@ export abstract class HaDeviceAutomationPicker<
.label=${this.label}
.value=${value}
.disabled=${!this._automations || this._automations.length === 0}
.getItems=${this._getItems(value, this._automations)}
.getItems=${this._getItems(
value,
this._automations,
this._i18n.localize,
this._i18n.locale.language,
this._states,
this._formatEntityName,
this._entityReg
)}
@value-changed=${this._automationChanged}
.rowRenderer=${this._rowRenderer}
.valueRenderer=${this._valueRenderer}
.unknownItemText=${this.hass.localize(
.unknownItemText=${this._i18n.localize(
"ui.panel.config.devices.automation.actions.unknown_action"
)}
hide-clear-icon
@@ -130,17 +191,25 @@ export abstract class HaDeviceAutomationPicker<
}
private _getItems = memoizeOne(
(value: string, automations: T[] | undefined) => {
(
value: string,
automations: T[] | undefined,
localize: LocalizeFunc,
language: string,
states: HassEntities,
formatEntityName: HomeAssistantFormatters["formatEntityName"],
entityReg: EntityRegistryEntry[]
) => {
if (!automations) {
return () => undefined;
}
const automationListItems = automations.map((automation, idx) => {
const primary = this._localizeDeviceAutomation(
this.hass.localize,
this.hass.states,
this.hass.formatEntityName,
this._entityReg,
localize,
states,
formatEntityName,
entityReg,
automation
);
return {
@@ -150,11 +219,7 @@ export abstract class HaDeviceAutomationPicker<
});
automationListItems.sort((a, b) =>
caseInsensitiveStringCompare(
a.primary,
b.primary,
this.hass.locale.language
)
caseInsensitiveStringCompare(a.primary, b.primary, language)
);
if (value === NO_AUTOMATION_KEY) {
@@ -185,9 +250,9 @@ export abstract class HaDeviceAutomationPicker<
const text = described
? this._localizeDeviceAutomation(
this.hass.localize,
this.hass.states,
this.hass.formatEntityName,
this._i18n.localize,
this._states,
this._formatEntityName,
this._entityReg,
described
)
@@ -204,7 +269,7 @@ export abstract class HaDeviceAutomationPicker<
this._automations = this.deviceId
? (
await this._fetchDeviceAutomations(
this.hass.callWS,
this._api.callWS,
this.deviceId
).catch(() => [] as T[])
).sort(sortDeviceAutomations)
@@ -9,13 +9,13 @@ import { HaDeviceAutomationPicker } from "./ha-device-automation-picker";
@customElement("ha-device-condition-picker")
class HaDeviceConditionPicker extends HaDeviceAutomationPicker<DeviceCondition> {
protected get NO_AUTOMATION_TEXT() {
return this.hass.localize(
return this._i18n.localize(
"ui.panel.config.devices.automation.conditions.no_conditions"
);
}
protected get UNKNOWN_AUTOMATION_TEXT() {
return this.hass.localize(
return this._i18n.localize(
"ui.panel.config.devices.automation.conditions.unknown_condition"
);
}
@@ -9,13 +9,13 @@ import { HaDeviceAutomationPicker } from "./ha-device-automation-picker";
@customElement("ha-device-trigger-picker")
class HaDeviceTriggerPicker extends HaDeviceAutomationPicker<DeviceTrigger> {
protected get NO_AUTOMATION_TEXT() {
return this.hass.localize(
return this._i18n.localize(
"ui.panel.config.devices.automation.triggers.no_triggers"
);
}
protected get UNKNOWN_AUTOMATION_TEXT() {
return this.hass.localize(
return this._i18n.localize(
"ui.panel.config.devices.automation.triggers.unknown_trigger"
);
}
@@ -146,7 +146,6 @@ export class HaDeviceAction extends LitElement {
.deviceId=${deviceId}
.disabled=${this.disabled}
@value-changed=${this._deviceActionPicked}
.hass=${this.hass}
label=${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.device_id.action"
)}
@@ -146,7 +146,6 @@ export class HaDeviceCondition extends LitElement {
.value=${this.condition}
.deviceId=${deviceId}
@value-changed=${this._deviceConditionPicked}
.hass=${this.hass}
.disabled=${this.disabled}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.device.condition"
@@ -150,7 +150,6 @@ export class HaDeviceTrigger extends LitElement {
.value=${this.trigger}
.deviceId=${deviceId}
@value-changed=${this._deviceTriggerPicked}
.hass=${this.hass}
.disabled=${this.disabled}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.type.device.trigger"