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:
@@ -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;
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user