1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-05-08 17:28:46 +01:00

Use entity naming in cards and badges (#27428)

This commit is contained in:
Paul Bottein
2025-10-13 15:43:17 +02:00
committed by GitHub
parent 29bc894dbd
commit ad2ba63155
31 changed files with 402 additions and 172 deletions
@@ -9,6 +9,11 @@ import { getEntityContext } from "./context/get_entity_context";
const DEFAULT_SEPARATOR = " ";
export const DEFAULT_ENTITY_NAME = [
{ type: "device" },
{ type: "entity" },
] satisfies EntityNameItem[];
export type EntityNameItem =
| {
type: "entity" | "device" | "area" | "floor";
@@ -24,14 +29,14 @@ export interface EntityNameOptions {
export const computeEntityNameDisplay = (
stateObj: HassEntity,
name: EntityNameItem | EntityNameItem[],
name: EntityNameItem | EntityNameItem[] | undefined,
entities: HomeAssistant["entities"],
devices: HomeAssistant["devices"],
areas: HomeAssistant["areas"],
floors: HomeAssistant["floors"],
options?: EntityNameOptions
) => {
let items = ensureArray(name);
let items = ensureArray(name || DEFAULT_ENTITY_NAME);
const separator = options?.separator ?? DEFAULT_SEPARATOR;
@@ -9,9 +9,9 @@ import { computeCssColor } from "../../../common/color/compute-color";
import { hsv2rgb, rgb2hex, rgb2hsv } from "../../../common/color/convert-color";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateActive } from "../../../common/entity/state_active";
import { stateColorCss } from "../../../common/entity/state_color";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import "../../../components/ha-badge";
import "../../../components/ha-ripple";
import "../../../components/ha-state-icon";
@@ -189,7 +189,11 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
</state-display>
`;
const name = this._config.name || computeStateName(stateObj);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
const showState = this._config.show_state;
const showName = this._config.show_name;
+2 -1
View File
@@ -1,3 +1,4 @@
import type { EntityNameItem } from "../../../common/entity/compute_entity_name_display";
import type { ActionConfig } from "../../../data/lovelace/config/action";
import type { LovelaceBadgeConfig } from "../../../data/lovelace/config/badge";
import type { LegacyStateFilter } from "../common/evaluate-filter";
@@ -31,7 +32,7 @@ export interface StateLabelBadgeConfig extends LovelaceBadgeConfig {
export interface EntityBadgeConfig extends LovelaceBadgeConfig {
type: "entity";
entity?: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
icon?: string;
color?: string;
show_name?: boolean;
@@ -28,6 +28,7 @@ import {
subscribeEntityRegistry,
} from "../../../data/entity_registry";
import type { HomeAssistant } from "../../../types";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard } from "../types";
@@ -232,12 +233,16 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
const defaultCode = this._entry?.options?.alarm_control_panel?.default_code;
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
return html`
<ha-card>
<h1 class="card-header">
${this._config.name ||
stateObj.attributes.friendly_name ||
stateLabel}
${name}
<ha-assist-chip
filled
style=${styleMap({
+6 -2
View File
@@ -8,7 +8,6 @@ import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import {
stateColorBrightness,
stateColorCss,
@@ -27,6 +26,7 @@ import { CLIMATE_HVAC_ACTION_TO_MODE } from "../../../data/climate";
import { isUnavailableState } from "../../../data/entity";
import type { HomeAssistant } from "../../../types";
import { computeCardSize } from "../common/compute-card-size";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@@ -125,7 +125,11 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
? this._config.attribute in stateObj.attributes
: !isUnavailableState(stateObj.state);
const name = this._config.name || computeStateName(stateObj);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
const colored = stateObj && this._getStateColor(stateObj, this._config);
+10 -4
View File
@@ -2,11 +2,10 @@ import type { HassEntity } from "home-assistant-js-websocket/dist/types";
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { getNumberFormatOptions } from "../../../common/number/format_number";
import "../../../components/ha-card";
@@ -15,6 +14,7 @@ import { UNAVAILABLE } from "../../../data/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action";
import { hasAction, hasAnyAction } from "../common/has-action";
@@ -126,13 +126,19 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
`;
}
const name = this._config.name ?? computeStateName(stateObj);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
// Use `stateObj.state` as value to keep formatting (e.g trailing zeros)
// for consistent value display across gauge, entity, entity-row, etc.
return html`
<ha-card
class=${classMap({ action: hasAnyAction(this._config) })}
class=${classMap({
action: hasAnyAction(this._config),
})}
@action=${this._handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(this._config.hold_action),
@@ -6,7 +6,6 @@ import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
@@ -15,6 +14,7 @@ import "../../../state-control/humidifier/ha-state-control-humidifier-humidity";
import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features";
import type { LovelaceCardFeatureContext } from "../card-features/types";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type {
@@ -133,7 +133,11 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard {
`;
}
const name = this._config!.name || computeStateName(stateObj);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
const color = stateColorCss(stateObj);
+6 -2
View File
@@ -7,7 +7,6 @@ import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateColorBrightness } from "../../../common/entity/state_color";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
@@ -18,6 +17,7 @@ import { lightSupportsBrightness } from "../../../data/light";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
@@ -92,7 +92,11 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
((stateObj.attributes.brightness || 0) / 255) * 100
);
const name = this._config.name ?? computeStateName(stateObj);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
return html`
<ha-card>
@@ -12,7 +12,6 @@ import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { supportsFeature } from "../../../common/entity/supports-feature";
import { extractColors } from "../../../common/image/extract_color";
import { stateActive } from "../../../common/entity/state_active";
@@ -36,6 +35,7 @@ import {
mediaPlayerPlayMedia,
} from "../../../data/media-player";
import type { HomeAssistant } from "../../../types";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-marquee";
@@ -242,8 +242,11 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
.hass=${this.hass}
></ha-state-icon>
<div>
${this._config!.name ||
computeStateName(this.hass!.states[this._config!.entity])}
${computeLovelaceEntityName(
this.hass,
this.hass!.states[this._config!.entity],
this._config.name
)}
</div>
</div>
<div>
@@ -5,7 +5,6 @@ import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import "../../../components/ha-card";
import type { CameraEntity } from "../../../data/camera";
import type { ImageEntity } from "../../../data/image";
@@ -14,6 +13,7 @@ import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { PersonEntity } from "../../../data/person";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
@@ -126,7 +126,11 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
`;
}
const name = this._config.name || computeStateName(stateObj);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
const entityState = this.hass.formatEntityState(stateObj);
let footer: TemplateResult | string = "";
@@ -11,11 +11,11 @@ import { customElement, property, state } from "lit/decorators";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { batteryLevelIcon } from "../../../common/entity/battery_icon";
import { computeStateName } from "../../../common/entity/compute_state_name";
import "../../../components/ha-card";
import "../../../components/ha-svg-icon";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@@ -119,7 +119,7 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
style="background-image:url(${stateObj.attributes.entity_picture})"
>
<div class="header">
${this._config.name || computeStateName(stateObj)}
${computeLovelaceEntityName(this.hass, stateObj, this._config.name)}
</div>
</div>
<div class="content">
@@ -7,7 +7,6 @@ import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
@@ -16,6 +15,7 @@ import "../../../state-control/water_heater/ha-state-control-water_heater-temper
import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features";
import type { LovelaceCardFeatureContext } from "../card-features/types";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type {
@@ -132,7 +132,11 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
}
const domain = computeDomain(stateObj.entity_id);
const name = this._config!.name || computeStateName(stateObj);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
const color = stateColorCss(stateObj);
+8 -14
View File
@@ -9,7 +9,6 @@ import { computeCssColor } from "../../../common/color/compute-color";
import { hsv2rgb, rgb2hex, rgb2hsv } from "../../../common/color/convert-color";
import { DOMAINS_TOGGLE } from "../../../common/const";
import { computeDomain } from "../../../common/entity/compute_domain";
import type { EntityNameItem } from "../../../common/entity/compute_entity_name_display";
import { stateActive } from "../../../common/entity/state_active";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-card";
@@ -26,6 +25,7 @@ import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features";
import type { LovelaceCardFeatureContext } from "../card-features/types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
@@ -47,11 +47,6 @@ export const getEntityDefaultTileIconAction = (entityId: string) => {
return supportsIconAction ? "toggle" : "none";
};
export const DEFAULT_NAME = [
{ type: "device" },
{ type: "entity" },
] satisfies EntityNameItem[];
@customElement("hui-tile-card")
export class HuiTileCard extends LitElement implements LovelaceCard {
public static async getConfigElement(): Promise<LovelaceCardEditor> {
@@ -260,12 +255,11 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
const contentClasses = { vertical: Boolean(this._config.vertical) };
const nameConfig = this._config.name;
const nameDisplay =
typeof nameConfig === "string"
? nameConfig
: this.hass.formatEntityName(stateObj, nameConfig || DEFAULT_NAME);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
const active = stateActive(stateObj);
const color = this._computeStateColor(stateObj, this._config.color);
@@ -278,7 +272,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
.stateObj=${stateObj}
.hass=${this.hass}
.content=${this._config.state_content}
.name=${nameDisplay}
.name=${name}
>
</state-display>
`;
@@ -337,7 +331,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
${renderTileBadge(stateObj, this.hass)}
</ha-tile-icon>
<ha-tile-info id="info">
<span slot="primary" class="primary">${nameDisplay}</span>
<span slot="primary" class="primary">${name}</span>
${stateDisplay
? html`<span slot="secondary">${stateDisplay}</span>`
: nothing}
@@ -7,7 +7,6 @@ import { classMap } from "lit/directives/class-map";
import { formatDateWeekdayShort } from "../../../common/datetime/format_date";
import { formatTime } from "../../../common/datetime/format_time";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { formatNumber } from "../../../common/number/format_number";
import "../../../components/ha-card";
@@ -27,6 +26,7 @@ import {
} from "../../../data/weather";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { computeLovelaceEntityName } from "../common/entity/compute-lovelace-entity-name";
import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
@@ -229,7 +229,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
return html`
<ha-card class="unavailable" @click=${this._handleAction}>
${this.hass.localize("ui.panel.lovelace.warning.entity_unavailable", {
entity: `${computeStateName(stateObj)} (${this._config.entity})`,
entity: `${computeLovelaceEntityName(this.hass, stateObj, this._config.name)} (${this._config.entity})`,
})}
</ha-card>
`;
@@ -260,7 +260,11 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
const dayNight = forecastData?.type === "twice_daily";
const weatherStateIcon = getWeatherStateIcon(stateObj.state, this);
const name = this._config.name ?? computeStateName(stateObj);
const name = computeLovelaceEntityName(
this.hass,
stateObj,
this._config.name
);
return html`
<ha-card
+16 -10
View File
@@ -40,7 +40,7 @@ export type AlarmPanelCardConfigState =
export interface AlarmPanelCardConfig extends LovelaceCardConfig {
entity: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
states?: AlarmPanelCardConfigState[];
theme?: string;
}
@@ -63,6 +63,9 @@ export interface EmptyStateCardConfig extends LovelaceCardConfig {
}
export interface EntityCardConfig extends LovelaceCardConfig {
entity: string;
name?: string | EntityNameItem | EntityNameItem[];
icon?: string;
attribute?: string;
unit?: string;
theme?: string;
@@ -258,7 +261,7 @@ export interface GaugeSegment {
export interface GaugeCardConfig extends LovelaceCardConfig {
entity: string;
attribute?: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
unit?: string;
min?: number;
max?: number;
@@ -271,12 +274,14 @@ export interface GaugeCardConfig extends LovelaceCardConfig {
double_tap_action?: ActionConfig;
}
export interface ConfigEntity extends EntityConfig {
export interface ActionsConfig {
tap_action?: ActionConfig;
hold_action?: ActionConfig;
double_tap_action?: ActionConfig;
}
export interface ConfigEntity extends EntityConfig, ActionsConfig {}
export interface PictureGlanceEntityConfig extends ConfigEntity {
show_state?: boolean;
attribute?: string;
@@ -306,7 +311,7 @@ export interface GlanceCardConfig extends LovelaceCardConfig {
export interface HumidifierCardConfig extends LovelaceCardConfig {
entity: string;
theme?: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
show_current_as_primary?: boolean;
features?: LovelaceCardFeatureConfig[];
}
@@ -322,7 +327,7 @@ export interface IframeCardConfig extends LovelaceCardConfig {
export interface LightCardConfig extends LovelaceCardConfig {
entity: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
theme?: string;
icon?: string;
tap_action?: ActionConfig;
@@ -394,6 +399,7 @@ export interface ClockCardConfig extends LovelaceCardConfig {
export interface MediaControlCardConfig extends LovelaceCardConfig {
entity: string;
name?: string | EntityNameItem | EntityNameItem[];
theme?: string;
}
@@ -469,7 +475,7 @@ export interface PictureElementsCardConfig extends LovelaceCardConfig {
export interface PictureEntityCardConfig extends LovelaceCardConfig {
entity: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
image?: string;
camera_image?: string;
camera_view?: HuiImage["cameraView"];
@@ -509,14 +515,14 @@ export interface PlantAttributeTarget extends EventTarget {
}
export interface PlantStatusCardConfig extends LovelaceCardConfig {
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
entity: string;
theme?: string;
}
export interface SensorCardConfig extends LovelaceCardConfig {
entity: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
icon?: string;
graph?: string;
unit?: string;
@@ -552,14 +558,14 @@ export interface GridCardConfig extends StackCardConfig {
export interface ThermostatCardConfig extends LovelaceCardConfig {
entity: string;
theme?: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
show_current_as_primary?: boolean;
features?: LovelaceCardFeatureConfig[];
}
export interface WeatherForecastCardConfig extends LovelaceCardConfig {
entity: string;
name?: string;
name?: string | EntityNameItem | EntityNameItem[];
show_current?: boolean;
show_forecast?: boolean;
forecast_type?: ForecastType;
@@ -0,0 +1,23 @@
import type { HassEntity } from "home-assistant-js-websocket";
import {
DEFAULT_ENTITY_NAME,
type EntityNameItem,
} from "../../../../common/entity/compute_entity_name_display";
import type { HomeAssistant } from "../../../../types";
/**
* Computes the display name for an entity in Lovelace (cards and badges).
*
* @param hass - The Home Assistant instance
* @param stateObj - The entity state object
* @param nameConfig - The name configuration (string for override, or EntityNameItem[] for structured naming)
* @returns The computed entity name
*/
export const computeLovelaceEntityName = (
hass: HomeAssistant,
stateObj: HassEntity,
nameConfig: string | EntityNameItem | EntityNameItem[] | undefined
): string =>
typeof nameConfig === "string"
? nameConfig
: hass.formatEntityName(stateObj, nameConfig || DEFAULT_ENTITY_NAME);
+2 -2
View File
@@ -1,11 +1,11 @@
import type { ActionConfig } from "../../../data/lovelace/config/action";
import type { ConfigEntity } from "../cards/types";
import type { ActionsConfig } from "../cards/types";
export function hasAction(config?: ActionConfig): boolean {
return config !== undefined && config.action !== "none";
}
export function hasAnyAction(config: ConfigEntity): boolean {
export function hasAnyAction(config: ActionsConfig): boolean {
return (
!config.tap_action ||
hasAction(config.tap_action) ||
@@ -1,32 +1,34 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { array, assert, assign, object, optional, string } from "superstruct";
import type { HassEntity } from "home-assistant-js-websocket";
import { fireEvent } from "../../../../common/dom/fire_event";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import { supportsFeature } from "../../../../common/entity/supports-feature";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import "../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import { ALARM_MODES } from "../../../../data/alarm_control_panel";
import type { HomeAssistant } from "../../../../types";
import {
ALARM_MODE_STATE_MAP,
DEFAULT_STATES,
filterSupportedAlarmStates,
} from "../../cards/hui-alarm-panel-card";
import type {
AlarmPanelCardConfig,
AlarmPanelCardConfigState,
} from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import {
DEFAULT_STATES,
ALARM_MODE_STATE_MAP,
filterSupportedAlarmStates,
} from "../../cards/hui-alarm-panel-card";
import { supportsFeature } from "../../../../common/entity/supports-feature";
import { ALARM_MODES } from "../../../../data/alarm_control_panel";
import { entityNameStruct } from "../structs/entity-name-struct";
const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
entity: optional(string()),
name: optional(string()),
name: optional(entityNameStruct),
states: optional(array()),
theme: optional(string()),
})
@@ -61,13 +63,15 @@ export class HuiAlarmPanelCardEditor
selector: { entity: { domain: "alarm_control_panel" } },
},
{
type: "grid",
name: "",
schema: [
{ name: "name", selector: { text: {} } },
{ name: "theme", selector: { theme: {} } },
],
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{ name: "theme", selector: { theme: {} } },
{
name: "states",
selector: {
@@ -13,6 +13,7 @@ import {
string,
union,
} from "superstruct";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import { fireEvent } from "../../../../common/dom/fire_event";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import "../../../../components/ha-form/ha-form";
@@ -31,6 +32,7 @@ import type { LovelaceBadgeEditor } from "../../types";
import "../hui-sub-element-editor";
import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceBadgeConfig } from "../structs/base-badge-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
import { configElementStyle } from "./config-elements-style";
import "./hui-card-features-editor";
@@ -39,7 +41,7 @@ const badgeConfigStruct = assign(
object({
entity: optional(string()),
display_type: optional(enums(DISPLAY_TYPES)),
name: optional(string()),
name: optional(entityNameStruct),
icon: optional(string()),
state_content: optional(union([string(), array(string())])),
color: optional(string()),
@@ -81,16 +83,19 @@ export class HuiEntityBadgeEditor
flatten: true,
iconPath: mdiTextShort,
schema: [
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{
name: "",
type: "grid",
schema: [
{
name: "name",
selector: {
text: {},
},
},
{
name: "color",
selector: {
@@ -1,16 +1,17 @@
import { assert, assign, boolean, object, optional, string } from "superstruct";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import type { HaFormSchema } from "../../../../components/ha-form/types";
import type { EntityCardConfig } from "../../cards/types";
import { headerFooterConfigStructs } from "../../header-footer/structs";
import type { LovelaceConfigForm } from "../../types";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
const struct = assign(
baseLovelaceCardConfig,
object({
entity: optional(string()),
name: optional(string()),
name: optional(entityNameStruct),
icon: optional(string()),
attribute: optional(string()),
unit: optional(string()),
@@ -22,11 +23,19 @@ const struct = assign(
const SCHEMA = [
{ name: "entity", required: true, selector: { entity: {} } },
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{
type: "grid",
name: "",
schema: [
{ name: "name", selector: { text: {} } },
{
name: "icon",
selector: {
@@ -54,7 +63,7 @@ const SCHEMA = [
const entityCardConfigForm: LovelaceConfigForm = {
schema: SCHEMA,
assertConfig: (config: EntityCardConfig) => assert(config, struct),
assertConfig: (config) => assert(config, struct),
computeLabel: (schema: HaFormSchema, localize: LocalizeFunc) => {
if (schema.name === "theme") {
return `${localize(
@@ -14,8 +14,10 @@ import {
string,
} from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import "../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import { NON_NUMERIC_ATTRIBUTES } from "../../../../data/entity_attributes";
import type { HomeAssistant } from "../../../../types";
import { DEFAULT_MAX, DEFAULT_MIN } from "../../cards/hui-gauge-card";
import type { GaugeCardConfig } from "../../cards/types";
@@ -23,7 +25,7 @@ import type { UiAction } from "../../components/hui-action-editor";
import type { LovelaceCardEditor } from "../../types";
import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { NON_NUMERIC_ATTRIBUTES } from "../../../../data/entity_attributes";
import { entityNameStruct } from "../structs/entity-name-struct";
const TAP_ACTIONS: UiAction[] = [
"more-info",
@@ -43,7 +45,7 @@ const gaugeSegmentStruct = object({
const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
name: optional(string()),
name: optional(entityNameStruct),
entity: optional(string()),
attribute: optional(string()),
unit: optional(string()),
@@ -98,13 +100,15 @@ export class HuiGaugeCardEditor
},
},
{
name: "",
type: "grid",
schema: [
{ name: "name", selector: { text: {} } },
{ name: "unit", selector: { text: {} } },
],
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{ name: "unit", selector: { text: {} } },
{ name: "theme", selector: { theme: {} } },
{
name: "",
@@ -14,6 +14,7 @@ import {
} from "superstruct";
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
import { fireEvent } from "../../../../common/dom/fire_event";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-form/ha-form";
import type {
@@ -29,6 +30,7 @@ import type {
import type { HumidifierCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
import type { EditDetailElementEvent, EditSubElementEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
import "./hui-card-features-editor";
@@ -43,7 +45,7 @@ const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
entity: optional(string()),
name: optional(string()),
name: optional(entityNameStruct),
theme: optional(string()),
show_current_as_primary: optional(boolean()),
features: optional(array(any())),
@@ -56,13 +58,19 @@ const SCHEMA = [
required: true,
selector: { entity: { domain: "humidifier" } },
},
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{
type: "grid",
name: "",
schema: [
{ name: "name", selector: { text: {} } },
{ name: "theme", selector: { theme: {} } },
],
schema: [{ name: "theme", selector: { theme: {} } }],
},
{
name: "show_current_as_primary",
@@ -4,6 +4,7 @@ import { customElement, property, state } from "lit/decorators";
import { assert, assign, object, optional, string } from "superstruct";
import { mdiGestureTap } from "@mdi/js";
import { fireEvent } from "../../../../common/dom/fire_event";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import "../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types";
@@ -11,12 +12,13 @@ import type { LightCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
name: optional(string()),
name: optional(entityNameStruct),
entity: optional(string()),
theme: optional(string()),
icon: optional(string()),
@@ -32,11 +34,19 @@ const SCHEMA = [
required: true,
selector: { entity: { domain: "light" } },
},
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{
type: "grid",
name: "",
schema: [
{ name: "name", selector: { text: {} } },
{
name: "icon",
selector: {
@@ -2,23 +2,45 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { assert, assign, object, optional, string } from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/entity/ha-entity-picker";
import "../../../../components/ha-theme-picker";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import "../../../../components/ha-form/ha-form";
import type {
HaFormSchema,
SchemaUnion,
} from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types";
import type { MediaControlCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import type { EditorTarget, EntitiesEditorEvent } from "../types";
import { entityNameStruct } from "../structs/entity-name-struct";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
entity: optional(string()),
name: optional(entityNameStruct),
theme: optional(string()),
})
);
const includeDomains = ["media_player"];
const SCHEMA = [
{
name: "entity",
required: true,
selector: { entity: { domain: "media_player" } },
},
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{ name: "theme", selector: { theme: {} } },
] as const satisfies readonly HaFormSchema[];
@customElement("hui-media-control-card-editor")
export class HuiMediaControlCardEditor
@@ -34,69 +56,40 @@ export class HuiMediaControlCardEditor
this._config = config;
}
get _entity(): string {
return this._config!.entity || "";
}
get _theme(): string {
return this._config!.theme || "";
}
protected render() {
if (!this.hass || !this._config) {
return nothing;
}
return html`
<div class="card-config">
<ha-entity-picker
.label=${this.hass.localize(
"ui.panel.lovelace.editor.card.generic.entity"
)}
.hass=${this.hass}
.value=${this._entity}
.configValue=${"entity"}
.includeDomains=${includeDomains}
.required=${true}
@value-changed=${this._valueChanged}
allow-custom-entity
></ha-entity-picker>
<ha-theme-picker
.label=${`${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`}
.hass=${this.hass}
.value=${this._theme}
.configValue=${"theme"}
@value-changed=${this._valueChanged}
></ha-theme-picker>
</div>
<ha-form
.hass=${this.hass}
.data=${this._config}
.schema=${SCHEMA}
.computeLabel=${this._computeLabelCallback}
@value-changed=${this._valueChanged}
></ha-form>
`;
}
private _valueChanged(ev: EntitiesEditorEvent): void {
if (!this._config || !this.hass) {
return;
}
const target = ev.target! as EditorTarget;
if (this[`_${target.configValue}`] === target.value) {
return;
}
if (target.configValue) {
if (target.value === "") {
this._config = { ...this._config };
delete this._config[target.configValue!];
} else {
this._config = {
...this._config,
[target.configValue!]: target.value,
};
}
}
fireEvent(this, "config-changed", { config: this._config });
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
}
private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
if (schema.name === "theme") {
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
}
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
);
};
static styles = configElementStyle;
}
declare global {
@@ -14,6 +14,7 @@ import {
} from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import { computeDomain } from "../../../../common/entity/compute_domain";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import "../../../../components/ha-form/ha-form";
import type {
@@ -26,6 +27,7 @@ import type { PictureEntityCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = assign(
@@ -33,7 +35,7 @@ const cardConfigStruct = assign(
object({
entity: optional(string()),
image: optional(string()),
name: optional(string()),
name: optional(entityNameStruct),
camera_image: optional(string()),
camera_view: optional(enums(["auto", "live"])),
aspect_ratio: optional(string()),
@@ -65,7 +67,15 @@ export class HuiPictureEntityCardEditor
(localize: LocalizeFunc) =>
[
{ name: "entity", required: true, selector: { entity: {} } },
{ name: "name", selector: { text: {} } },
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{ name: "image", selector: { image: {} } },
{ name: "camera_image", selector: { entity: { domain: "camera" } } },
{
@@ -2,25 +2,35 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { assert, assign, object, optional, string } from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import "../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types";
import type { PlantStatusCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
entity: optional(string()),
name: optional(string()),
name: optional(entityNameStruct),
theme: optional(string()),
})
);
const SCHEMA = [
{ name: "entity", required: true, selector: { entity: { domain: "plant" } } },
{ name: "name", selector: { text: {} } },
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{ name: "theme", selector: { theme: {} } },
] as const;
@@ -12,6 +12,7 @@ import {
string,
union,
} from "superstruct";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-form/ha-form";
@@ -20,6 +21,7 @@ import type { HomeAssistant } from "../../../../types";
import type { SensorCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
import { configElementStyle } from "./config-elements-style";
import { DEFAULT_HOURS_TO_SHOW } from "../../cards/hui-sensor-card";
@@ -27,7 +29,7 @@ const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
entity: optional(string()),
name: optional(string()),
name: optional(entityNameStruct),
icon: optional(string()),
graph: optional(union([literal("line"), literal("none")])),
unit: optional(string()),
@@ -66,7 +68,15 @@ export class HuiSensorCardEditor
entity: { domain: ["counter", "input_number", "number", "sensor"] },
},
},
{ name: "name", selector: { text: {} } },
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{
type: "grid",
name: "",
@@ -14,6 +14,7 @@ import {
} from "superstruct";
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
import { fireEvent } from "../../../../common/dom/fire_event";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-form/ha-form";
import type {
@@ -29,6 +30,7 @@ import type {
import type { ThermostatCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
import type { EditDetailElementEvent, EditSubElementEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
import "./hui-card-features-editor";
@@ -50,7 +52,7 @@ const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
entity: optional(string()),
name: optional(string()),
name: optional(entityNameStruct),
theme: optional(string()),
show_current_as_primary: optional(boolean()),
features: optional(array(any())),
@@ -84,13 +86,19 @@ export class HuiThermostatCardEditor
name: "entity",
selector: { entity: { domain: ["climate", "water_heater"] } },
},
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{
type: "grid",
name: "",
schema: [
{ name: "name", selector: { text: {} } },
{ name: "theme", selector: { theme: {} } },
],
schema: [{ name: "theme", selector: { theme: {} } }],
},
...(domain === "climate"
? [
@@ -16,6 +16,7 @@ import {
} from "superstruct";
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
import { fireEvent } from "../../../../common/dom/fire_event";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import { orderProperties } from "../../../../common/util/order-properties";
import "../../../../components/ha-expansion-panel";
@@ -30,10 +31,7 @@ import type {
LovelaceCardFeatureConfig,
LovelaceCardFeatureContext,
} from "../../card-features/types";
import {
DEFAULT_NAME,
getEntityDefaultTileIconAction,
} from "../../cards/hui-tile-card";
import { getEntityDefaultTileIconAction } from "../../cards/hui-tile-card";
import type { TileCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { actionConfigStruct } from "../structs/action-struct";
@@ -105,7 +103,7 @@ export class HuiTileCardEditor
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_NAME,
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
@@ -12,6 +12,7 @@ import {
string,
} from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import { DEFAULT_ENTITY_NAME } from "../../../../common/entity/compute_entity_name_display";
import { supportsFeature } from "../../../../common/entity/supports-feature";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import "../../../../components/ha-form/ha-form";
@@ -24,12 +25,13 @@ import type { WeatherForecastCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entityNameStruct } from "../structs/entity-name-struct";
const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
entity: optional(string()),
name: optional(string()),
name: optional(entityNameStruct),
theme: optional(string()),
show_current: optional(boolean()),
show_forecast: optional(boolean()),
@@ -148,7 +150,15 @@ export class HuiWeatherForecastCardEditor
required: true,
selector: { entity: { domain: "weather" } },
},
{ name: "name", selector: { text: {} } },
{
name: "name",
selector: {
entity_name: {
default_name: DEFAULT_ENTITY_NAME,
},
},
context: { entity: "entity" },
},
{
name: "",
type: "grid",
@@ -0,0 +1,80 @@
import { describe, expect, it, vi } from "vitest";
import { DEFAULT_ENTITY_NAME } from "../../../../../src/common/entity/compute_entity_name_display";
import { computeLovelaceEntityName } from "../../../../../src/panels/lovelace/common/entity/compute-lovelace-entity-name";
import type { HomeAssistant } from "../../../../../src/types";
import { mockStateObj } from "../../../../common/entity/context/context-mock";
const createMockHass = (
mockFormatEntityName: ReturnType<typeof vi.fn>
): HomeAssistant =>
({
formatEntityName: mockFormatEntityName,
}) as unknown as HomeAssistant;
describe("computeLovelaceEntityName", () => {
it("returns the string directly when nameConfig is a string", () => {
const mockFormatEntityName = vi.fn();
const hass = createMockHass(mockFormatEntityName);
const stateObj = mockStateObj({ entity_id: "light.kitchen" });
const result = computeLovelaceEntityName(hass, stateObj, "Custom Name");
expect(result).toBe("Custom Name");
expect(mockFormatEntityName).not.toHaveBeenCalled();
});
it("returns empty string when nameConfig is empty string", () => {
const mockFormatEntityName = vi.fn();
const hass = createMockHass(mockFormatEntityName);
const stateObj = mockStateObj({ entity_id: "light.kitchen" });
const result = computeLovelaceEntityName(hass, stateObj, "");
expect(result).toBe("");
expect(mockFormatEntityName).not.toHaveBeenCalled();
});
it("calls formatEntityName with DEFAULT_ENTITY_NAME when nameConfig is undefined", () => {
const mockFormatEntityName = vi.fn(() => "Formatted Name");
const hass = createMockHass(mockFormatEntityName);
const stateObj = mockStateObj({ entity_id: "light.kitchen" });
const result = computeLovelaceEntityName(hass, stateObj, undefined);
expect(result).toBe("Formatted Name");
expect(mockFormatEntityName).toHaveBeenCalledTimes(1);
expect(mockFormatEntityName).toHaveBeenCalledWith(
stateObj,
DEFAULT_ENTITY_NAME
);
});
it("calls formatEntityName with EntityNameItem config", () => {
const mockFormatEntityName = vi.fn(() => "Formatted Name");
const hass = createMockHass(mockFormatEntityName);
const stateObj = mockStateObj({ entity_id: "light.bedroom" });
const nameConfig = { type: "device" as const };
const result = computeLovelaceEntityName(hass, stateObj, nameConfig);
expect(result).toBe("Formatted Name");
expect(mockFormatEntityName).toHaveBeenCalledTimes(1);
expect(mockFormatEntityName).toHaveBeenCalledWith(stateObj, nameConfig);
});
it("calls formatEntityName with array of EntityNameItems", () => {
const mockFormatEntityName = vi.fn(() => "Formatted Name");
const hass = createMockHass(mockFormatEntityName);
const stateObj = mockStateObj({ entity_id: "light.kitchen" });
const nameConfig = [
{ type: "device" as const },
{ type: "entity" as const },
];
const result = computeLovelaceEntityName(hass, stateObj, nameConfig);
expect(result).toBe("Formatted Name");
expect(mockFormatEntityName).toHaveBeenCalledTimes(1);
expect(mockFormatEntityName).toHaveBeenCalledWith(stateObj, nameConfig);
});
});