Compare commits

...

3 Commits

Author SHA1 Message Date
Aidan Timson 73e05237a4 C 2026-05-21 14:44:20 +01:00
Aidan Timson 6137d7ffff Add target UI 2026-05-21 14:42:18 +01:00
Aidan Timson 625324846f Add target UI 2026-05-21 14:39:37 +01:00
5 changed files with 500 additions and 168 deletions
+44 -12
View File
@@ -51,25 +51,59 @@ interface ActionDefinition {
icon: string;
}
const ADD_TO_TARGET_PLACEHOLDER = "__HA_ADD_TO_TARGET__";
export const ADD_TO_ACTION_ICONS: Record<AddToActionKey, string> = {
automation_trigger: "mdi:robot-outline",
automation_condition: "mdi:playlist-check",
automation_action: "mdi:play-circle-outline",
script_action: "mdi:script-text-outline",
scene: "mdi:palette",
};
export const DEFAULT_ACTION_DEFS: ActionDefinition[] = [
{
translation_key: "automation_trigger",
icon: "mdi:robot-outline",
icon: ADD_TO_ACTION_ICONS.automation_trigger,
},
{
translation_key: "automation_condition",
icon: "mdi:playlist-check",
icon: ADD_TO_ACTION_ICONS.automation_condition,
},
{
translation_key: "automation_action",
icon: "mdi:play-circle-outline",
icon: ADD_TO_ACTION_ICONS.automation_action,
},
{
translation_key: "script_action",
icon: "mdi:script-text-outline",
icon: ADD_TO_ACTION_ICONS.script_action,
},
];
export const getAddToActionLabel = (
localize: LocalizeFunc,
key: AddToActionKey,
target: string
): string =>
localize(`ui.dialogs.more_info_control.add_to.actions.${key}`, { target });
export const getAddToActionLabelParts = (
localize: LocalizeFunc,
key: AddToActionKey
): [string, string] => {
const label = getAddToActionLabel(localize, key, ADD_TO_TARGET_PLACEHOLDER);
const placeholderIndex = label.indexOf(ADD_TO_TARGET_PLACEHOLDER);
if (placeholderIndex === -1) {
return [label, ""];
}
return [
label.slice(0, placeholderIndex),
label.slice(placeholderIndex + ADD_TO_TARGET_PLACEHOLDER.length),
];
};
export const getDefaultAddToActions = (
states: HomeAssistant["states"],
localize: LocalizeFunc,
@@ -81,14 +115,12 @@ export const getDefaultAddToActions = (
type: "default",
key: def.translation_key,
enabled: true,
name: localize(
`ui.dialogs.more_info_control.add_to.actions.${def.translation_key}`,
{
target:
states[entityId] !== undefined
? formatEntityName(states[entityId], undefined)
: entityId,
}
name: getAddToActionLabel(
localize,
def.translation_key,
states[entityId] !== undefined
? formatEntityName(states[entityId], undefined)
: entityId
),
icon: def.icon,
})
+61 -17
View File
@@ -5,17 +5,17 @@ import "../../components/ha-icon";
import "../../components/ha-spinner";
import "../../components/item/ha-list-item-button";
import "../../components/list/ha-list-base";
import type { HaListItemButton } from "../../components/item/ha-list-item-button";
import "../../panels/config/automation/target/ha-automation-target-badge";
import { showToast } from "../../util/toast";
import type { HASSDomCurrentTargetEvent } from "../../common/dom/fire_event";
import { fireEvent } from "../../common/dom/fire_event";
import type { HomeAssistant } from "../../types";
import {
type EntityAddToAction,
type AddToActionKey,
type EntityAddToActions,
addToActionHandler,
getDefaultAddToActions,
getAddToActionLabelParts,
} from "./add-to";
@customElement("ha-more-info-add-to")
@@ -65,14 +65,18 @@ export class HaMoreInfoAddTo extends LitElement {
}
}
private async _actionSelected(
ev: HASSDomCurrentTargetEvent<
HaListItemButton & {
action: EntityAddToAction;
}
>
) {
const action = ev.currentTarget.action;
private async _actionSelected(ev: Event) {
const item = ev.currentTarget as HTMLElement;
const actions =
item.dataset.actionSource === "external"
? this._externalActions
: this._defaultActions;
const action = actions[Number(item.dataset.actionIndex)];
if (!action) {
return;
}
if (!action.enabled) {
return;
}
@@ -110,16 +114,25 @@ export class HaMoreInfoAddTo extends LitElement {
addToActionHandler(action.key, { entity_id: this.entityId });
}
private _renderActionItems(actions: EntityAddToActions) {
private _renderActionItems(
actions: EntityAddToActions,
source: "default" | "external"
) {
return actions.map(
(action) => html`
(action, index) => html`
<ha-list-item-button
aria-label=${action.name}
data-action-index=${index}
data-action-source=${source}
.disabled=${!action.enabled}
.action=${action}
@click=${this._actionSelected}
>
<ha-icon slot="start" .icon=${action.icon}></ha-icon>
<span slot="headline">${action.name}</span>
<span slot="headline" class="action-label">
${action.type === "default"
? this._renderDefaultActionLabel(action.key)
: action.name}
</span>
${action.description
? html`<span slot="supporting-text">${action.description}</span>`
: nothing}
@@ -128,6 +141,30 @@ export class HaMoreInfoAddTo extends LitElement {
);
}
private _renderDefaultActionLabel(key: AddToActionKey) {
const [beforeTarget, afterTarget] = getAddToActionLabelParts(
this.hass.localize,
key
);
return html`${beforeTarget}${this._renderTarget()}${afterTarget}`;
}
private _renderTarget() {
return html`<ha-automation-target-badge
target-type="entity"
.targetId=${this.entityId}
.label=${this._targetLabel}
></ha-automation-target-badge>`;
}
private get _targetLabel(): string {
const stateObj = this.hass.states[this.entityId];
return stateObj
? this.hass.formatEntityName(stateObj, undefined)
: this.entityId;
}
protected async firstUpdated() {
await this._loadActions();
this._loading = false;
@@ -154,7 +191,7 @@ export class HaMoreInfoAddTo extends LitElement {
return html`
<ha-list-base>
${this._renderActionItems(this._defaultActions)}
${this._renderActionItems(this._defaultActions, "default")}
</ha-list-base>
${this._externalActions.length
? html`
@@ -164,7 +201,7 @@ export class HaMoreInfoAddTo extends LitElement {
)}
</h2>
<ha-list-base>
${this._renderActionItems(this._externalActions)}
${this._renderActionItems(this._externalActions, "external")}
</ha-list-base>
`
: nothing}
@@ -197,6 +234,13 @@ export class HaMoreInfoAddTo extends LitElement {
display: flex;
align-items: center;
}
.action-label {
display: inline-flex;
align-items: center;
gap: var(--ha-space-1);
flex-wrap: wrap;
}
`;
}
@@ -9,7 +9,6 @@ import {
} from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event";
import { stopPropagation } from "../../../../common/dom/stop_propagation";
import "../../../../components/ha-svg-icon";
@@ -21,7 +20,7 @@ import type { LabelRegistryEntry } from "../../../../data/label/label_registry";
import { haStyleScrollbar } from "../../../../resources/styles";
import type { HomeAssistant } from "../../../../types";
import type { AddAutomationElementListItem } from "../add-automation-element-dialog";
import { getTargetIcon } from "../target/get_target_icon";
import "../target/ha-automation-target-badge";
type Target = [string, string | undefined, string | undefined];
@@ -108,7 +107,10 @@ export class HaAutomationAddItems extends LitElement {
items,
(item) => item.key,
(item) => html`
<ha-list-item-button .value=${item.key} @click=${this._selected}>
<ha-list-item-button
data-value=${item.key}
@click=${this._selected}
>
<div slot="headline" class=${this.target ? "item-headline" : ""}>
${item.name}${this._renderTarget(this.target)}
</div>
@@ -154,33 +156,22 @@ export class HaAutomationAddItems extends LitElement {
`;
}
private _renderTarget = memoizeOne((target?: Target) => {
private _renderTarget(target?: Target) {
if (!target) {
return nothing;
}
return html`<div class="selected-target">
${getTargetIcon(
{
entities: this.hass.entities,
devices: this.hass.devices,
areas: this.hass.areas,
floors: this.hass.floors,
},
this.hass.states,
target[0],
target[1],
this.configEntryLookup,
this.getLabel
)}
<div class="label">${target[2]}</div>
</div>`;
});
return html`<ha-automation-target-badge
.targetType=${target[0]}
.targetId=${target[1]}
.label=${target[2]}
></ha-automation-target-badge>`;
}
private _selected(ev) {
const item = ev.currentTarget;
const item = ev.currentTarget as HTMLElement;
fireEvent(this, "value-changed", {
value: item.value,
value: item.dataset.value,
});
}
@@ -301,42 +292,6 @@ export class HaAutomationAddItems extends LitElement {
ha-svg-icon.plus {
color: var(--primary-color);
}
.selected-target {
display: inline-flex;
gap: var(--ha-space-1);
justify-content: center;
align-items: center;
border-radius: var(--ha-border-radius-md);
background: var(--ha-color-fill-neutral-normal-resting);
padding: 0 var(--ha-space-2) 0 var(--ha-space-1);
border: var(--ha-border-width-sm) solid
var(--ha-color-border-neutral-quiet);
color: var(--ha-color-on-neutral-normal);
overflow: hidden;
}
.selected-target .label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.selected-target ha-icon,
.selected-target ha-svg-icon,
.selected-target ha-domain-icon {
display: flex;
padding: var(--ha-space-1) 0;
}
.selected-target ha-floor-icon {
display: flex;
height: 32px;
width: 32px;
align-items: center;
}
.selected-target ha-domain-icon {
filter: grayscale(100%);
}
`,
];
}
@@ -0,0 +1,251 @@
import { consume, type ContextType } from "@lit/context";
import { mdiAlert, mdiCodeBraces, mdiShape } from "@mdi/js";
import { css, html, LitElement, nothing, type TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { transform } from "../../../../common/decorators/transform";
import { isTemplate } from "../../../../common/string/has-template";
import "../../../../components/ha-svg-icon";
import type { ConfigEntry } from "../../../../data/config_entries";
import {
configEntriesContext,
internationalizationContext,
labelsContext,
registriesContext,
statesContext,
} from "../../../../data/context";
import type { LabelRegistryEntry } from "../../../../data/label/label_registry";
import type { TargetType } from "../../../../data/target";
import { getTargetIcon } from "./get_target_icon";
import { getTargetText } from "./get_target_text";
const TARGET_TYPES = ["entity", "device", "area", "label", "floor"] as const;
const isTargetType = (targetType: string): targetType is TargetType =>
TARGET_TYPES.includes(targetType as TargetType);
@customElement("ha-automation-target-badge")
export class HaAutomationTargetBadge extends LitElement {
@property({ attribute: "target-type" })
public targetType!: string;
@property({ attribute: "target-id" })
public targetId?: string;
@property()
public label?: string;
@property({ type: Boolean })
public warning = false;
@property({ type: Boolean })
public error = false;
@property({ type: Boolean })
public interactive = false;
@property({ attribute: false })
public countTemplate: unknown = nothing;
@state()
@consume({ context: internationalizationContext, subscribe: true })
private _i18n!: ContextType<typeof internationalizationContext>;
@state()
@consume({ context: registriesContext, subscribe: true })
private _registries!: ContextType<typeof registriesContext>;
@state()
@consume({ context: labelsContext, subscribe: true })
private _labelRegistry!: LabelRegistryEntry[];
@state()
@consume({ context: configEntriesContext, subscribe: true })
@transform<ConfigEntry[], Record<string, ConfigEntry>>({
transformer: function (value) {
return value
? Object.fromEntries(value.map((entry) => [entry.entry_id, entry]))
: undefined;
},
})
private _configEntryLookup?: Record<string, ConfigEntry>;
@consume({ context: statesContext, subscribe: true })
private _states!: ContextType<typeof statesContext>;
protected render() {
const { icon, label, warning } = this._targetInfo();
return html`<div
class=${classMap({
target: true,
warning,
error: this.error,
interactive: this.interactive,
})}
>
${icon}
<div class="label">${label}${this.countTemplate}</div>
</div>`;
}
private _targetInfo(): {
icon: TemplateResult | typeof nothing;
label: string;
warning: boolean;
} {
const targetId = this.targetId;
if (!targetId) {
return {
icon: nothing,
label: this.label || "",
warning: this.warning,
};
}
let iconPath: string | undefined;
let label = this.label;
let warning = this.warning;
if (!isTargetType(this.targetType)) {
return {
icon: nothing,
label: label || targetId,
warning,
};
}
if (this.targetType === "entity" && ["all", "none"].includes(targetId)) {
iconPath = mdiShape;
label = this._i18n.localize(
`ui.panel.config.automation.editor.target_summary.${targetId as "all" | "none"}_entities`
);
} else if (isTemplate(targetId)) {
iconPath = mdiCodeBraces;
label = this._i18n.localize(
"ui.panel.config.automation.editor.target_summary.template"
);
} else if (!this._checkTargetExists(targetId)) {
iconPath = mdiAlert;
label = label || this._targetText(this.targetType, targetId);
warning = true;
} else {
label = label || this._targetText(this.targetType, targetId);
}
const icon = iconPath
? html`<ha-svg-icon .path=${iconPath}></ha-svg-icon>`
: getTargetIcon(
this._registries,
this._states,
this.targetType,
targetId,
this._configEntryLookup || {},
this._getLabel
);
return {
icon,
label: label || targetId,
warning,
};
}
private _targetText(targetType: TargetType, targetId: string): string {
return getTargetText(
this._registries,
this._states,
this._i18n.localize,
targetType,
targetId,
this._getLabel
);
}
private _getLabel = (id: string) =>
this._labelRegistry?.find(({ label_id }) => label_id === id);
private _checkTargetExists(targetId: string): boolean {
if (this.targetType === "floor") {
return !!this._registries.floors[targetId];
}
if (this.targetType === "area") {
return !!this._registries.areas[targetId];
}
if (this.targetType === "device") {
return !!this._registries.devices[targetId];
}
if (this.targetType === "entity") {
return !!this._states[targetId];
}
return !!this._getLabel(targetId);
}
static styles = css`
:host {
display: inline-flex;
max-width: 100%;
vertical-align: middle;
}
.target {
display: inline-flex;
gap: var(--ha-space-1);
justify-content: center;
align-items: center;
border-radius: var(--ha-border-radius-md);
background: var(--ha-color-fill-neutral-normal-resting);
padding: 0 var(--ha-space-2) 0 var(--ha-space-1);
color: var(--ha-color-on-neutral-normal);
border: var(--ha-border-width-sm) solid
var(--ha-color-border-neutral-quiet);
overflow: hidden;
height: 32px;
max-width: 100%;
}
.target.warning {
background: var(--ha-color-fill-warning-normal-resting);
color: var(--ha-color-on-warning-normal);
}
.target.error {
background: var(--ha-color-fill-danger-normal-resting);
color: var(--ha-color-on-danger-normal);
}
.label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.target ha-icon,
.target ha-svg-icon,
.target ha-domain-icon {
display: flex;
padding: var(--ha-space-1) 0;
}
.target ha-floor-icon {
display: flex;
height: 32px;
align-items: center;
}
.target.interactive {
cursor: pointer;
}
.target.interactive:hover {
background: var(--ha-color-fill-neutral-normal-hover);
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-target-badge": HaAutomationTargetBadge;
}
}
@@ -2,16 +2,10 @@ import { css, html, LitElement, nothing } from "lit";
import type { CSSResultGroup, PropertyValues } from "lit";
import { consume, type ContextType } from "@lit/context";
import { customElement, state } from "lit/decorators";
import {
mdiPalette,
mdiPlayCircleOutline,
mdiPlaylistCheck,
mdiRobotOutline,
mdiScriptTextOutline,
} from "@mdi/js";
import { computeDeviceNameDisplay } from "../../../../common/entity/compute_device_name";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-adaptive-dialog";
import "../../../../components/ha-icon";
import "../../../../components/ha-list";
import "../../../../components/ha-list-item";
import "../../../../components/ha-spinner";
@@ -38,10 +32,14 @@ import { showScriptEditor } from "../../../../data/script";
import type { SceneEntities } from "../../../../data/scene";
import { showSceneEditor } from "../../../../data/scene";
import {
ADD_TO_ACTION_ICONS,
addToActionHandler,
type AddToActionKey,
getAddToActionLabel,
getAddToActionLabelParts,
} from "../../../../dialogs/more-info/add-to";
import { haStyle, haStyleDialog } from "../../../../resources/styles";
import "../../automation/target/ha-automation-target-badge";
import type { DeviceAddToDialogParams } from "./show-dialog-device-add-to";
@customElement("dialog-device-add-to")
@@ -151,11 +149,7 @@ export class DialogDeviceAddTo extends LitElement {
if (!this._params) {
return nothing;
}
const deviceName = computeDeviceNameDisplay(
this._params.device,
this._i18n.localize,
this._states
);
const deviceName = this._deviceName;
return html`
<h3 class="section-header">
@@ -169,39 +163,51 @@ export class DialogDeviceAddTo extends LitElement {
data-type="automation_trigger"
@click=${this._handleNewAction}
data-dialog="close"
>
<ha-svg-icon slot="graphic" .path=${mdiRobotOutline}></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.automation_trigger",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"automation_trigger",
deviceName
)}
>
<ha-icon
slot="graphic"
.icon=${ADD_TO_ACTION_ICONS.automation_trigger}
></ha-icon>
${this._renderActionLabel("automation_trigger")}
</ha-list-item>
<ha-list-item
graphic="icon"
data-type="automation_condition"
@click=${this._handleNewAction}
data-dialog="close"
>
<ha-svg-icon slot="graphic" .path=${mdiPlaylistCheck}></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.automation_condition",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"automation_condition",
deviceName
)}
>
<ha-icon
slot="graphic"
.icon=${ADD_TO_ACTION_ICONS.automation_condition}
></ha-icon>
${this._renderActionLabel("automation_condition")}
</ha-list-item>
<ha-list-item
graphic="icon"
data-type="automation_action"
@click=${this._handleNewAction}
data-dialog="close"
>
<ha-svg-icon
slot="graphic"
.path=${mdiPlayCircleOutline}
></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.automation_action",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"automation_action",
deviceName
)}
>
<ha-icon
slot="graphic"
.icon=${ADD_TO_ACTION_ICONS.automation_action}
></ha-icon>
${this._renderActionLabel("automation_action")}
</ha-list-item>
</ha-list>
<h3 class="section-header">
@@ -213,15 +219,17 @@ export class DialogDeviceAddTo extends LitElement {
data-type="script_action"
@click=${this._handleNewAction}
data-dialog="close"
>
<ha-svg-icon
slot="graphic"
.path=${mdiScriptTextOutline}
></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.script_action",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"script_action",
deviceName
)}
>
<ha-icon
slot="graphic"
.icon=${ADD_TO_ACTION_ICONS.script_action}
></ha-icon>
${this._renderActionLabel("script_action")}
</ha-list-item>
</ha-list>
${this._renderSceneSection(deviceName)}
@@ -242,11 +250,7 @@ export class DialogDeviceAddTo extends LitElement {
return nothing;
}
const deviceName = computeDeviceNameDisplay(
this._params.device,
this._i18n.localize,
this._states
);
const deviceName = this._deviceName;
const hasTriggers = Boolean(this._triggers?.length);
const hasConditions = Boolean(this._conditions?.length);
@@ -279,15 +283,17 @@ export class DialogDeviceAddTo extends LitElement {
data-type="trigger"
@click=${this._handleLegacyAction}
data-dialog="close"
>
<ha-svg-icon
slot="graphic"
.path=${mdiRobotOutline}
></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.automation_trigger",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"automation_trigger",
deviceName
)}
>
<ha-icon
slot="graphic"
.icon=${ADD_TO_ACTION_ICONS.automation_trigger}
></ha-icon>
${this._renderActionLabel("automation_trigger")}
</ha-list-item>
`
: nothing}
@@ -298,15 +304,17 @@ export class DialogDeviceAddTo extends LitElement {
data-type="condition"
@click=${this._handleLegacyAction}
data-dialog="close"
>
<ha-svg-icon
slot="graphic"
.path=${mdiPlaylistCheck}
></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.automation_condition",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"automation_condition",
deviceName
)}
>
<ha-icon
slot="graphic"
.icon=${ADD_TO_ACTION_ICONS.automation_condition}
></ha-icon>
${this._renderActionLabel("automation_condition")}
</ha-list-item>
`
: nothing}
@@ -317,15 +325,17 @@ export class DialogDeviceAddTo extends LitElement {
data-type="automation_action"
@click=${this._handleLegacyAction}
data-dialog="close"
>
<ha-svg-icon
slot="graphic"
.path=${mdiPlayCircleOutline}
></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.automation_action",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"automation_action",
deviceName
)}
>
<ha-icon
slot="graphic"
.icon=${ADD_TO_ACTION_ICONS.automation_action}
></ha-icon>
${this._renderActionLabel("automation_action")}
</ha-list-item>
`
: nothing}
@@ -351,15 +361,17 @@ export class DialogDeviceAddTo extends LitElement {
data-type="script_action"
@click=${this._handleLegacyAction}
data-dialog="close"
>
<ha-svg-icon
slot="graphic"
.path=${mdiScriptTextOutline}
></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.script_action",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"script_action",
deviceName
)}
>
<ha-icon
slot="graphic"
.icon=${ADD_TO_ACTION_ICONS.script_action}
></ha-icon>
${this._renderActionLabel("script_action")}
</ha-list-item>
</ha-list>
`
@@ -390,17 +402,48 @@ export class DialogDeviceAddTo extends LitElement {
graphic="icon"
@click=${this._handleCreateScene}
data-dialog="close"
>
<ha-svg-icon slot="graphic" .path=${mdiPalette}></ha-svg-icon>
${this._i18n.localize(
"ui.dialogs.more_info_control.add_to.actions.scene",
{ target: deviceName }
aria-label=${getAddToActionLabel(
this._i18n.localize,
"scene",
deviceName
)}
>
<ha-icon slot="graphic" .icon=${ADD_TO_ACTION_ICONS.scene}></ha-icon>
${this._renderActionLabel("scene")}
</ha-list-item>
</ha-list>
`;
}
private _renderActionLabel(key: AddToActionKey) {
const [beforeTarget, afterTarget] = getAddToActionLabelParts(
this._i18n.localize,
key
);
return html`<span class="action-label">
${beforeTarget}${this._renderDeviceTarget()}${afterTarget}
</span>`;
}
private _renderDeviceTarget() {
return html`<ha-automation-target-badge
target-type="device"
.targetId=${this._params?.device.id}
.label=${this._deviceName}
></ha-automation-target-badge>`;
}
private get _deviceName(): string {
return this._params
? computeDeviceNameDisplay(
this._params.device,
this._i18n.localize,
this._states
)
: "";
}
private _handleNewAction(ev: Event) {
if (!this._params) {
return;
@@ -477,6 +520,13 @@ export class DialogDeviceAddTo extends LitElement {
font-weight: var(--ha-font-weight-medium);
color: var(--secondary-text-color);
}
.action-label {
display: inline-flex;
align-items: center;
gap: var(--ha-space-1);
flex-wrap: wrap;
}
`,
];
}