diff --git a/pyproject.toml b/pyproject.toml index fde7ccb12f..495a03d0fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240805.0" +version = "20240805.1" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/components/entity/ha-entity-state-content-picker.ts b/src/components/entity/ha-entity-state-content-picker.ts index b4e1001932..bdc75c9c3a 100644 --- a/src/components/entity/ha-entity-state-content-picker.ts +++ b/src/components/entity/ha-entity-state-content-picker.ts @@ -81,6 +81,9 @@ class HaEntityStatePicker extends LitElement { @property({ type: Boolean }) public required = false; + @property({ type: Boolean, attribute: "allow-name" }) public allowName = + false; + @property() public label?: string; @property() public value?: string[] | string; @@ -95,43 +98,55 @@ class HaEntityStatePicker extends LitElement { return !(!changedProps.has("_opened") && this._opened); } - private options = memoizeOne((entityId?: string, stateObj?: HassEntity) => { - const domain = entityId ? computeDomain(entityId) : undefined; - return [ - { - label: this.hass.localize("ui.components.state-content-picker.state"), - value: "state", - }, - { - label: this.hass.localize( - "ui.components.state-content-picker.last_changed" - ), - value: "last_changed", - }, - { - label: this.hass.localize( - "ui.components.state-content-picker.last_updated" - ), - value: "last_updated", - }, - ...(domain - ? STATE_DISPLAY_SPECIAL_CONTENT.filter((content) => - STATE_DISPLAY_SPECIAL_CONTENT_DOMAINS[domain]?.includes(content) - ).map((content) => ({ - label: this.hass.localize( - `ui.components.state-content-picker.${content}` - ), - value: content, - })) - : []), - ...Object.keys(stateObj?.attributes ?? {}) - .filter((a) => !HIDDEN_ATTRIBUTES.includes(a)) - .map((attribute) => ({ - value: attribute, - label: this.hass.formatEntityAttributeName(stateObj!, attribute), - })), - ]; - }); + private options = memoizeOne( + (entityId?: string, stateObj?: HassEntity, allowName?: boolean) => { + const domain = entityId ? computeDomain(entityId) : undefined; + return [ + { + label: this.hass.localize("ui.components.state-content-picker.state"), + value: "state", + }, + ...(allowName + ? [ + { + label: this.hass.localize( + "ui.components.state-content-picker.name" + ), + value: "name", + }, + ] + : []), + { + label: this.hass.localize( + "ui.components.state-content-picker.last_changed" + ), + value: "last_changed", + }, + { + label: this.hass.localize( + "ui.components.state-content-picker.last_updated" + ), + value: "last_updated", + }, + ...(domain + ? STATE_DISPLAY_SPECIAL_CONTENT.filter((content) => + STATE_DISPLAY_SPECIAL_CONTENT_DOMAINS[domain]?.includes(content) + ).map((content) => ({ + label: this.hass.localize( + `ui.components.state-content-picker.${content}` + ), + value: content, + })) + : []), + ...Object.keys(stateObj?.attributes ?? {}) + .filter((a) => !HIDDEN_ATTRIBUTES.includes(a)) + .map((attribute) => ({ + value: attribute, + label: this.hass.formatEntityAttributeName(stateObj!, attribute), + })), + ]; + } + ); private _filter = ""; @@ -146,7 +161,7 @@ class HaEntityStatePicker extends LitElement { ? this.hass.states[this.entityId] : undefined; - const options = this.options(this.entityId, stateObj); + const options = this.options(this.entityId, stateObj, this.allowName); const optionItems = options.filter( (option) => !this._value.includes(option.value) ); diff --git a/src/components/ha-selector/ha-selector-ui-state-content.ts b/src/components/ha-selector/ha-selector-ui-state-content.ts index c0d521b939..179671e84f 100644 --- a/src/components/ha-selector/ha-selector-ui-state-content.ts +++ b/src/components/ha-selector/ha-selector-ui-state-content.ts @@ -36,6 +36,7 @@ export class HaSelectorUiStateContent extends SubscribeMixin(LitElement) { .helper=${this.helper} .disabled=${this.disabled} .required=${this.required} + .allowName=${this.selector.ui_state_content?.allow_name} > `; } diff --git a/src/data/lovelace/config/badge.ts b/src/data/lovelace/config/badge.ts index b6b5d7c207..e3f92b1ac4 100644 --- a/src/data/lovelace/config/badge.ts +++ b/src/data/lovelace/config/badge.ts @@ -13,6 +13,7 @@ export const ensureBadgeConfig = ( return { type: "entity", entity: config, + display_type: "complete", }; } if ("type" in config && config.type) { diff --git a/src/data/selector.ts b/src/data/selector.ts index c4b385b136..13aa16647e 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -461,6 +461,7 @@ export interface UiStateContentSelector { // eslint-disable-next-line @typescript-eslint/ban-types ui_state_content: { entity_id?: string; + allow_name?: boolean; } | null; } diff --git a/src/panels/lovelace/badges/hui-badge.ts b/src/panels/lovelace/badges/hui-badge.ts index a6eee87ec2..bbcd083c55 100644 --- a/src/panels/lovelace/badges/hui-badge.ts +++ b/src/panels/lovelace/badges/hui-badge.ts @@ -58,7 +58,7 @@ export class HuiBadge extends ReactiveElement { private _updateElement(config: LovelaceBadgeConfig) { if (config.type === "state-label") { - config = { ...config, type: "entity" }; + config = { display_type: "complete", ...config, type: "entity" }; } if (!this._element) { return; @@ -70,7 +70,7 @@ export class HuiBadge extends ReactiveElement { private _loadElement(config: LovelaceBadgeConfig) { if (config.type === "state-label") { - config = { ...config, type: "entity" }; + config = { display_type: "complete", ...config, type: "entity" }; } this._element = createBadgeElement(config); this._elementConfig = config; diff --git a/src/panels/lovelace/badges/hui-entity-badge.ts b/src/panels/lovelace/badges/hui-entity-badge.ts index 05a6839da0..e448646ab0 100644 --- a/src/panels/lovelace/badges/hui-entity-badge.ts +++ b/src/panels/lovelace/badges/hui-entity-badge.ts @@ -144,6 +144,7 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge { .stateObj=${stateObj} .hass=${this.hass} .content=${this._config.state_content} + .name=${this._config.name} > `; diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index d4e0c2aacc..4370516653 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -23,7 +23,7 @@ import type { HomeAssistant } from "../../../types"; import { actionHandler } from "../common/directives/action-handler-directive"; import { findEntities } from "../common/find-entities"; import { handleAction } from "../common/handle-action"; -import { hasAction } from "../common/has-action"; +import { hasAction, hasAnyAction } from "../common/has-action"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import { createEntityNotFoundWarning } from "../components/hui-warning"; import type { LovelaceCard, LovelaceCardEditor } from "../types"; @@ -128,24 +128,20 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { const name = this._config.name ?? computeStateName(stateObj); - const hasAnyAction = - !this._config.tap_action || - hasAction(this._config.tap_action) || - hasAction(this._config.hold_action) || - hasAction(this._config.double_tap_action); - // Use `stateObj.state` as value to keep formatting (e.g trailing zeros) // for consistent value display across gauge, entity, entity-row, etc. return html` `; diff --git a/src/panels/lovelace/cards/picture-elements/create-styled-hui-element.ts b/src/panels/lovelace/cards/picture-elements/create-styled-hui-element.ts index 181412bc98..6371572cf0 100644 --- a/src/panels/lovelace/cards/picture-elements/create-styled-hui-element.ts +++ b/src/panels/lovelace/cards/picture-elements/create-styled-hui-element.ts @@ -12,7 +12,7 @@ export function createStyledHuiElement( if (elementConfig.style) { Object.keys(elementConfig.style).forEach((prop) => { - element.style.setProperty(prop, elementConfig.style[prop]); + element.style.setProperty(prop, elementConfig.style![prop]); }); } diff --git a/src/panels/lovelace/common/has-action.ts b/src/panels/lovelace/common/has-action.ts index a6df67f4fe..7d9ec25a51 100644 --- a/src/panels/lovelace/common/has-action.ts +++ b/src/panels/lovelace/common/has-action.ts @@ -1,5 +1,15 @@ import { ActionConfig } from "../../../data/lovelace/config/action"; +import { ConfigEntity } from "../cards/types"; export function hasAction(config?: ActionConfig): boolean { return config !== undefined && config.action !== "none"; } + +export function hasAnyAction(config: ConfigEntity): boolean { + return ( + !config.tap_action || + hasAction(config.tap_action) || + hasAction(config.hold_action) || + hasAction(config.double_tap_action) + ); +} diff --git a/src/panels/lovelace/components/hui-generic-entity-row.ts b/src/panels/lovelace/components/hui-generic-entity-row.ts index ce683a6a68..f5e2d123cb 100644 --- a/src/panels/lovelace/components/hui-generic-entity-row.ts +++ b/src/panels/lovelace/components/hui-generic-entity-row.ts @@ -20,7 +20,7 @@ import { HomeAssistant } from "../../../types"; import { EntitiesCardEntityConfig } from "../cards/types"; import { actionHandler } from "../common/directives/action-handler-directive"; import { handleAction } from "../common/handle-action"; -import { hasAction } from "../common/has-action"; +import { hasAction, hasAnyAction } from "../common/has-action"; import { createEntityNotFoundWarning } from "./hui-warning"; @customElement("hui-generic-entity-row") @@ -60,9 +60,7 @@ export class HuiGenericEntityRow extends LitElement { // By default, we always show a pointer, since if there is no explicit configuration provided, // the frontend always assumes "more-info" in the action handler. We only need to hide the pointer // if the tap action is explicitly set to "none". - const pointer = !( - this.config.tap_action && this.config.tap_action.action === "none" - ); + const pointer = hasAnyAction(this.config); const hasSecondary = this.secondaryText || this.config.secondary_info; const name = this.config.name ?? computeStateName(stateObj); @@ -82,7 +80,11 @@ export class HuiGenericEntityRow extends LitElement { hasHold: hasAction(this.config!.hold_action), hasDoubleClick: hasAction(this.config!.double_tap_action), })} - tabindex=${ifDefined(pointer ? "0" : undefined)} + tabindex=${ifDefined( + !this.config.tap_action || hasAction(this.config.tap_action) + ? "0" + : undefined + )} > ${!this.hideName ? html`
export const getPictureElementClass = (type: string) => getLovelaceElementClass( - type, + type === "action-button" ? "service-button" : type, "element", ALWAYS_LOADED_TYPES, LAZY_LOAD_TYPES diff --git a/src/panels/lovelace/editor/config-elements/elements/hui-conditional-element-editor.ts b/src/panels/lovelace/editor/config-elements/elements/hui-conditional-element-editor.ts index 94809079c6..7b65ce4da8 100644 --- a/src/panels/lovelace/editor/config-elements/elements/hui-conditional-element-editor.ts +++ b/src/panels/lovelace/editor/config-elements/elements/hui-conditional-element-editor.ts @@ -106,12 +106,23 @@ export class HuiConditionalElementEditor private _elementsChanged(ev: CustomEvent): void { ev.stopPropagation(); + const oldLength = this._config?.elements?.length || 0; const config = { ...this._config, elements: ev.detail.elements as LovelaceElementConfig[], } as LovelaceCardConfig; fireEvent(this, "config-changed", { config }); + + const newLength = ev.detail.elements?.length || 0; + if (newLength === oldLength + 1) { + const index = newLength - 1; + this._subElementEditorConfig = { + index, + type: "element", + elementConfig: { ...ev.detail.elements[index] }, + }; + } } private _handleSubElementChanged(ev: CustomEvent): void { diff --git a/src/panels/lovelace/editor/config-elements/hui-entity-badge-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entity-badge-editor.ts index d1000fbb5d..64944fbe2f 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entity-badge-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entity-badge-editor.ts @@ -122,7 +122,9 @@ export class HuiEntityBadgeEditor { name: "state_content", selector: { - ui_state_content: {}, + ui_state_content: { + allow_name: true, + }, }, context: { filter_entity: "entity", diff --git a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts index b1db02d715..b2e6bd3543 100644 --- a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts @@ -23,7 +23,7 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { DEFAULT_MIN, DEFAULT_MAX } from "../../cards/hui-gauge-card"; import { UiAction } from "../../components/hui-action-editor"; -const TAP_ACTIONS: UiAction[] = ["navigate", "url", "call-service", "none"]; +const TAP_ACTIONS: UiAction[] = ["navigate", "url", "perform-action", "none"]; const gaugeSegmentStruct = object({ from: number(), diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-elements-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-elements-card-editor.ts index a2d16716ff..c0c8c72960 100644 --- a/src/panels/lovelace/editor/config-elements/hui-picture-elements-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-picture-elements-card-editor.ts @@ -138,12 +138,23 @@ export class HuiPictureElementsCardEditor private _elementsChanged(ev: CustomEvent): void { ev.stopPropagation(); + const oldLength = this._config?.elements?.length || 0; const config = { ...this._config, elements: ev.detail.elements as LovelaceElementConfig[], } as LovelaceCardConfig; fireEvent(this, "config-changed", { config }); + + const newLength = ev.detail.elements?.length || 0; + if (newLength === oldLength + 1) { + const index = newLength - 1; + this._subElementEditorConfig = { + index, + type: "element", + elementConfig: { ...ev.detail.elements[index] }, + }; + } } private _handleSubElementChanged(ev: CustomEvent): void { diff --git a/src/panels/lovelace/editor/get-element-stub-config.ts b/src/panels/lovelace/editor/get-element-stub-config.ts new file mode 100644 index 0000000000..dbd48d023d --- /dev/null +++ b/src/panels/lovelace/editor/get-element-stub-config.ts @@ -0,0 +1,30 @@ +import { LovelaceElementConfig } from "../elements/types"; +import { HomeAssistant } from "../../../types"; +import { getPictureElementClass } from "../create-element/create-picture-element"; + +export const getElementStubConfig = async ( + hass: HomeAssistant, + type: string, + entities: string[], + entitiesFallback: string[] +): Promise => { + let elementConfig: LovelaceElementConfig = { type }; + + if (type !== "conditional") { + elementConfig.style = { left: "50%", top: "50%" }; + } + + const elClass = await getPictureElementClass(type); + + if (elClass && elClass.getStubConfig) { + const classStubConfig = await elClass.getStubConfig( + hass, + entities, + entitiesFallback + ); + + elementConfig = { ...elementConfig, ...classStubConfig }; + } + + return elementConfig; +}; diff --git a/src/panels/lovelace/editor/hui-picture-elements-card-row-editor.ts b/src/panels/lovelace/editor/hui-picture-elements-card-row-editor.ts index baebcbbc19..d013cb8f81 100644 --- a/src/panels/lovelace/editor/hui-picture-elements-card-row-editor.ts +++ b/src/panels/lovelace/editor/hui-picture-elements-card-row-editor.ts @@ -1,3 +1,4 @@ +import deepClone from "deep-clone-simple"; import { mdiClose, mdiPencil, mdiContentDuplicate } from "@mdi/js"; import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property, query } from "lit/decorators"; @@ -9,6 +10,7 @@ import { HomeAssistant } from "../../../types"; import "../../../components/ha-select"; import type { HaSelect } from "../../../components/ha-select"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; +import { getElementStubConfig } from "./get-element-stub-config"; import { ConditionalElementConfig, IconElementConfig, @@ -171,17 +173,14 @@ export class HuiPictureElementsCardRowEditor extends LitElement { if (value === "") { return; } - const newElements = this.elements!.concat({ - type: value! as string, - ...(value !== "conditional" - ? { - style: { - top: "50%", - left: "50%", - }, - } - : {}), - } as LovelaceElementConfig); + const newElements = this.elements!.concat( + await getElementStubConfig( + this.hass!, + value, + Object.keys(this.hass!.entities), + [] + ) + ); fireEvent(this, "elements-changed", { elements: newElements }); this._select.select(-1); } @@ -225,7 +224,7 @@ export class HuiPictureElementsCardRowEditor extends LitElement { private _duplicateRow(ev: CustomEvent): void { const index = (ev.currentTarget as any).index; - const newElements = [...this.elements!, this.elements![index]]; + const newElements = [...this.elements!, deepClone(this.elements![index])]; fireEvent(this, "elements-changed", { elements: newElements }); } diff --git a/src/panels/lovelace/editor/hui-sub-element-editor.ts b/src/panels/lovelace/editor/hui-sub-element-editor.ts index df6ed4308d..1755144d88 100644 --- a/src/panels/lovelace/editor/hui-sub-element-editor.ts +++ b/src/panels/lovelace/editor/hui-sub-element-editor.ts @@ -53,9 +53,19 @@ export class HuiSubElementEditor extends LitElement { @click=${this._goBack} > ${this.hass.localize( - `ui.panel.lovelace.editor.sub-element-editor.types.${this.config?.type}` - )}${this.config?.type === "element" + ? this.hass.localize( + `ui.panel.lovelace.editor.sub-element-editor.types.element_type`, + { + type: + this.hass.localize( + `ui.panel.lovelace.editor.card.picture-elements.element_types.${this.config?.elementConfig?.type}` + ) || this.config?.elementConfig?.type, + } + ) + : this.hass.localize( + `ui.panel.lovelace.editor.sub-element-editor.types.${this.config?.type}` + )}
+ !isUnavailableState(stateObj.state); + const foundEntities = findEntities( + hass, + maxEntities, + entities, + entitiesFallback, + includeDomains, + entityFilter + ); + + return { type: "state-badge", entity: foundEntities[0] || "" }; + } + @property({ attribute: false }) public hass?: HomeAssistant; @state() private _config?: StateBadgeElementConfig; diff --git a/src/panels/lovelace/elements/hui-state-icon-element.ts b/src/panels/lovelace/elements/hui-state-icon-element.ts index 84e0a7add6..6175ba77fe 100644 --- a/src/panels/lovelace/elements/hui-state-icon-element.ts +++ b/src/panels/lovelace/elements/hui-state-icon-element.ts @@ -1,3 +1,4 @@ +import type { HassEntity } from "home-assistant-js-websocket"; import { css, CSSResultGroup, @@ -8,12 +9,14 @@ import { } from "lit"; import { customElement, property, state } from "lit/decorators"; import { ifDefined } from "lit/directives/if-defined"; +import { findEntities } from "../common/find-entities"; import "../../../components/entity/state-badge"; import { HomeAssistant } from "../../../types"; import { computeTooltip } from "../common/compute-tooltip"; import { actionHandler } from "../common/directives/action-handler-directive"; import { handleAction } from "../common/handle-action"; import { hasAction } from "../common/has-action"; +import { isUnavailableState } from "../../../data/entity"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import { createEntityNotFoundWarning } from "../components/hui-warning"; import "../components/hui-warning-element"; @@ -30,6 +33,27 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement { return document.createElement("hui-state-icon-element-editor"); } + public static getStubConfig( + hass: HomeAssistant, + entities: string[], + entitiesFallback: string[] + ): StateIconElementConfig { + const includeDomains = ["light", "switch", "sensor"]; + const maxEntities = 1; + const entityFilter = (stateObj: HassEntity): boolean => + !isUnavailableState(stateObj.state); + const foundEntities = findEntities( + hass, + maxEntities, + entities, + entitiesFallback, + includeDomains, + entityFilter + ); + + return { type: "state-icon", entity: foundEntities[0] || "" }; + } + @property({ attribute: false }) public hass?: HomeAssistant; @state() private _config?: StateIconElementConfig; diff --git a/src/panels/lovelace/elements/hui-state-label-element.ts b/src/panels/lovelace/elements/hui-state-label-element.ts index ef699bf6a6..bb85408e1e 100644 --- a/src/panels/lovelace/elements/hui-state-label-element.ts +++ b/src/panels/lovelace/elements/hui-state-label-element.ts @@ -1,3 +1,4 @@ +import type { HassEntity } from "home-assistant-js-websocket"; import { CSSResultGroup, LitElement, @@ -8,12 +9,14 @@ import { } from "lit"; import { customElement, property, state } from "lit/decorators"; import { ifDefined } from "lit/directives/if-defined"; +import { findEntities } from "../common/find-entities"; import { ActionHandlerEvent } from "../../../data/lovelace/action_handler"; import { HomeAssistant } from "../../../types"; import { computeTooltip } from "../common/compute-tooltip"; import { actionHandler } from "../common/directives/action-handler-directive"; import { handleAction } from "../common/handle-action"; import { hasAction } from "../common/has-action"; +import { isUnavailableState } from "../../../data/entity"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import { createEntityNotFoundWarning } from "../components/hui-warning"; import "../components/hui-warning-element"; @@ -29,6 +32,27 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement { return document.createElement("hui-state-label-element-editor"); } + public static getStubConfig( + hass: HomeAssistant, + entities: string[], + entitiesFallback: string[] + ): StateLabelElementConfig { + const includeDomains = ["light", "switch", "sensor"]; + const maxEntities = 1; + const entityFilter = (stateObj: HassEntity): boolean => + !isUnavailableState(stateObj.state); + const foundEntities = findEntities( + hass, + maxEntities, + entities, + entitiesFallback, + includeDomains, + entityFilter + ); + + return { type: "state-label", entity: foundEntities[0] || "" }; + } + @property({ attribute: false }) public hass?: HomeAssistant; @state() private _config?: StateLabelElementConfig; diff --git a/src/panels/lovelace/elements/types.ts b/src/panels/lovelace/elements/types.ts index fcd9a44865..e968081ca2 100644 --- a/src/panels/lovelace/elements/types.ts +++ b/src/panels/lovelace/elements/types.ts @@ -6,7 +6,7 @@ import { HuiImage } from "../components/hui-image"; interface LovelaceElementConfigBase { type: string; - style: Record; + style?: Record; } export type LovelaceElementConfig = diff --git a/src/panels/lovelace/entity-rows/hui-number-entity-row.ts b/src/panels/lovelace/entity-rows/hui-number-entity-row.ts index 2002450499..d9ff7fd367 100644 --- a/src/panels/lovelace/entity-rows/hui-number-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-number-entity-row.ts @@ -123,7 +123,6 @@ class HuiNumberEntityRow extends LitElement implements LovelaceRow { static get styles(): CSSResultGroup { return css` :host { - cursor: pointer; display: block; } .flex { diff --git a/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts b/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts index 3e539272a2..5d1646d9b2 100644 --- a/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts @@ -70,9 +70,6 @@ class HuiSceneEntityRow extends LitElement implements LovelaceRow { margin-inline-end: -0.57em; margin-inline-start: initial; } - :host { - cursor: pointer; - } `; } diff --git a/src/panels/lovelace/entity-rows/hui-simple-entity-row.ts b/src/panels/lovelace/entity-rows/hui-simple-entity-row.ts index 604c632820..220b931e05 100644 --- a/src/panels/lovelace/entity-rows/hui-simple-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-simple-entity-row.ts @@ -58,9 +58,6 @@ class HuiSimpleEntityRow extends LitElement implements LovelaceRow { div { text-align: right; } - .pointer { - cursor: pointer; - } `; } } diff --git a/src/panels/lovelace/entity-rows/hui-update-entity-row.ts b/src/panels/lovelace/entity-rows/hui-update-entity-row.ts index 6a8b8d81ee..2cc5ecb9ed 100644 --- a/src/panels/lovelace/entity-rows/hui-update-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-update-entity-row.ts @@ -61,9 +61,6 @@ class HuiUpdateEntityRow extends LitElement implements LovelaceRow { div { text-align: right; } - .pointer { - cursor: pointer; - } `; } } diff --git a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts index e6b8ca4357..8b32a65a16 100644 --- a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts @@ -26,7 +26,7 @@ import type { HomeAssistant } from "../../../types"; import type { EntitiesCardEntityConfig } from "../cards/types"; import { actionHandler } from "../common/directives/action-handler-directive"; import { handleAction } from "../common/handle-action"; -import { hasAction } from "../common/has-action"; +import { hasAction, hasAnyAction } from "../common/has-action"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import "../components/hui-generic-entity-row"; import { createEntityNotFoundWarning } from "../components/hui-warning"; @@ -118,9 +118,7 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow { `; } - const pointer = !( - this._config.tap_action && this._config.tap_action.action !== "none" - ); + const pointer = hasAnyAction(this._config); const hasSecondary = this._config.secondary_info; const weatherStateIcon = getWeatherStateIcon(stateObj.state, this); @@ -138,7 +136,11 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow { hasHold: hasAction(this._config!.hold_action), hasDoubleClick: hasAction(this._config!.double_tap_action), })} - tabindex=${ifDefined(pointer ? "0" : undefined)} + tabindex=${ifDefined( + !this._config.tap_action || hasAction(this._config.tap_action) + ? "0" + : undefined + )} > ${weatherStateIcon || html` diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts index d99f52112f..92a2658e2e 100644 --- a/src/panels/lovelace/types.ts +++ b/src/panels/lovelace/types.ts @@ -109,6 +109,11 @@ export interface LovelaceRowConstructor extends Constructor { export interface LovelaceElementConstructor extends Constructor { getConfigElement?: () => LovelacePictureElementEditor; + getStubConfig?: ( + hass: HomeAssistant, + entities: string[], + entitiesFallback: string[] + ) => LovelaceElementConfig; } export interface LovelaceHeaderFooter extends HTMLElement { diff --git a/src/state-display/state-display.ts b/src/state-display/state-display.ts index a1042681a8..aaf54014d2 100644 --- a/src/state-display/state-display.ts +++ b/src/state-display/state-display.ts @@ -55,6 +55,8 @@ class StateDisplay extends LitElement { @property({ attribute: false }) public content?: StateContent; + @property({ attribute: false }) public name?: string; + protected createRenderRoot() { return this; } @@ -88,6 +90,9 @@ class StateDisplay extends LitElement { return this.hass!.formatEntityState(stateObj); } + if (content === "name") { + return html`${this.name || stateObj.attributes.friendly_name}`; + } // Check last-changed for backwards compatibility if (content === "last_changed" || content === "last-changed") { return html` diff --git a/src/translations/en.json b/src/translations/en.json index 6e28e4e91c..f6e588e775 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1026,6 +1026,7 @@ }, "state-content-picker": { "state": "State", + "name": "Name", "last_changed": "Last changed", "last_updated": "Last updated", "remaining_time": "Remaining time", @@ -6323,7 +6324,8 @@ "footer": "Footer editor", "row": "Entity row editor", "feature": "Feature editor", - "element": "Element editor" + "element": "Element editor", + "element_type": "{type} element editor" } } },