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/create-element/create-picture-element.ts b/src/panels/lovelace/create-element/create-picture-element.ts index ce848b3bd0..e1775a8497 100644 --- a/src/panels/lovelace/create-element/create-picture-element.ts +++ b/src/panels/lovelace/create-element/create-picture-element.ts @@ -35,7 +35,7 @@ export const createPictureElementElement = (config: LovelaceElementConfig) => 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-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/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/translations/en.json b/src/translations/en.json index 6e28e4e91c..7524fc65c3 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -6323,7 +6323,8 @@ "footer": "Footer editor", "row": "Entity row editor", "feature": "Feature editor", - "element": "Element editor" + "element": "Element editor", + "element_type": "{type} element editor" } } },