diff --git a/src/components/ha-selector/ha-selector-icon.ts b/src/components/ha-selector/ha-selector-icon.ts index e10969fbcb..1a5d10cf72 100644 --- a/src/components/ha-selector/ha-selector-icon.ts +++ b/src/components/ha-selector/ha-selector-icon.ts @@ -1,6 +1,8 @@ import { html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; +import { computeDomain } from "../../common/entity/compute_domain"; +import { domainIcon } from "../../common/entity/domain_icon"; import { IconSelector } from "../../data/selector"; import { HomeAssistant } from "../../types"; import "../ha-icon-picker"; @@ -21,7 +23,22 @@ export class HaIconSelector extends LitElement { @property({ type: Boolean }) public required = true; + @property() public context?: { + icon_entity?: string; + }; + protected render() { + const iconEntity = this.context?.icon_entity; + + const stateObj = iconEntity ? this.hass.states[iconEntity] : undefined; + + const placeholder = + this.selector.icon?.placeholder || stateObj?.attributes.icon; + const fallbackPath = + !placeholder && stateObj + ? domainIcon(computeDomain(iconEntity!), stateObj) + : undefined; + return html` `; diff --git a/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts index da8436cf5b..5256fe846b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts @@ -1,11 +1,7 @@ -import type { HassEntity } from "home-assistant-js-websocket"; import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; import { assert, assign, boolean, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { domainIcon } from "../../../../common/entity/domain_icon"; import { entityId } from "../../../../common/structs/is-entity-id"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; @@ -32,6 +28,52 @@ const cardConfigStruct = assign( }) ); +const SCHEMA = [ + { name: "entity", selector: { entity: {} } }, + { + name: "", + type: "grid", + schema: [ + { name: "name", selector: { text: {} } }, + { + name: "icon", + selector: { + icon: {}, + }, + context: { + icon_entity: "entity", + }, + }, + ], + }, + { + name: "", + type: "grid", + column_min_width: "100px", + schema: [ + { name: "show_name", selector: { boolean: {} } }, + { name: "show_state", selector: { boolean: {} } }, + { name: "show_icon", selector: { boolean: {} } }, + ], + }, + { + name: "", + type: "grid", + schema: [ + { name: "icon_height", selector: { text: { suffix: "px" } } }, + { name: "theme", selector: { theme: {} } }, + ], + }, + { + name: "tap_action", + selector: { "ui-action": {} }, + }, + { + name: "hold_action", + selector: { "ui-action": {} }, + }, +] as const; + @customElement("hui-button-card-editor") export class HuiButtonCardEditor extends LitElement @@ -46,76 +88,11 @@ export class HuiButtonCardEditor this._config = config; } - private _schema = memoizeOne( - (entity?: string, icon?: string, entityState?: HassEntity) => - [ - { name: "entity", selector: { entity: {} } }, - { - name: "", - type: "grid", - schema: [ - { name: "name", selector: { text: {} } }, - { - name: "icon", - selector: { - icon: { - placeholder: icon || entityState?.attributes.icon, - fallbackPath: - !icon && - !entityState?.attributes.icon && - entityState && - entity - ? domainIcon(computeDomain(entity), entityState) - : undefined, - }, - }, - }, - ], - }, - { - name: "", - type: "grid", - column_min_width: "100px", - schema: [ - { name: "show_name", selector: { boolean: {} } }, - { name: "show_state", selector: { boolean: {} } }, - { name: "show_icon", selector: { boolean: {} } }, - ], - }, - { - name: "", - type: "grid", - schema: [ - { name: "icon_height", selector: { text: { suffix: "px" } } }, - { name: "theme", selector: { theme: {} } }, - ], - }, - { - name: "tap_action", - selector: { "ui-action": {} }, - }, - { - name: "hold_action", - selector: { "ui-action": {} }, - }, - ] as const - ); - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } - const entityState = this._config.entity - ? this.hass.states[this._config.entity] - : undefined; - - const schema = this._schema( - this._config.entity, - this._config.icon, - entityState - ); - const data = { show_name: true, show_icon: true, @@ -130,7 +107,7 @@ export class HuiButtonCardEditor > - ) => { + private _computeHelperCallback = (schema: SchemaUnion) => { switch (schema.name) { case "tap_action": case "hold_action": @@ -162,9 +137,7 @@ export class HuiButtonCardEditor } }; - private _computeLabelCallback = ( - schema: SchemaUnion> - ) => { + private _computeLabelCallback = (schema: SchemaUnion) => { switch (schema.name) { case "theme": case "tap_action": diff --git a/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts index 37e3c34874..4b1df3306d 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts @@ -1,11 +1,7 @@ -import type { HassEntity } from "home-assistant-js-websocket/dist/types"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; import { assert, assign, boolean, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { domainIcon } from "../../../../common/entity/domain_icon"; import { entityId } from "../../../../common/structs/is-entity-id"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; @@ -29,6 +25,38 @@ const cardConfigStruct = assign( }) ); +const SCHEMA = [ + { name: "entity", required: true, selector: { entity: {} } }, + { + type: "grid", + name: "", + schema: [ + { name: "name", selector: { text: {} } }, + { + name: "icon", + selector: { + icon: {}, + }, + context: { + icon_entity: "entity", + }, + }, + { + name: "attribute", + selector: { + attribute: {}, + }, + context: { + filter_entity: "entity", + }, + }, + { name: "unit", selector: { text: {} } }, + { name: "theme", selector: { theme: {} } }, + { name: "state_color", selector: { boolean: {} } }, + ], + }, +] as const; + @customElement("hui-entity-card-editor") export class HuiEntityCardEditor extends LitElement @@ -43,58 +71,16 @@ export class HuiEntityCardEditor this._config = config; } - private _schema = memoizeOne( - (entity: string, icon: string, entityState: HassEntity) => - [ - { name: "entity", required: true, selector: { entity: {} } }, - { - type: "grid", - name: "", - schema: [ - { name: "name", selector: { text: {} } }, - { - name: "icon", - selector: { - icon: { - placeholder: icon || entityState?.attributes.icon, - fallbackPath: - !icon && !entityState?.attributes.icon && entityState - ? domainIcon(computeDomain(entity), entityState) - : undefined, - }, - }, - }, - - { - name: "attribute", - selector: { attribute: { entity_id: entity } }, - }, - { name: "unit", selector: { text: {} } }, - { name: "theme", selector: { theme: {} } }, - { name: "state_color", selector: { boolean: {} } }, - ], - }, - ] as const - ); - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } - const entityState = this.hass.states[this._config.entity]; - - const schema = this._schema( - this._config.entity, - this._config.icon, - entityState - ); - return html` @@ -107,9 +93,7 @@ export class HuiEntityCardEditor fireEvent(this, "config-changed", { config }); } - private _computeLabelCallback = ( - schema: SchemaUnion> - ) => { + private _computeLabelCallback = (schema: SchemaUnion) => { if (schema.name === "entity") { return this.hass!.localize( "ui.panel.lovelace.editor.card.generic.entity" diff --git a/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts b/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts index f02e3a8908..af2598f69d 100644 --- a/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts @@ -1,13 +1,11 @@ -import "../../../../components/ha-form/ha-form"; -import type { HassEntity } from "home-assistant-js-websocket"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { assert } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; -import { domainIcon } from "../../../../common/entity/domain_icon"; import type { LocalizeFunc } from "../../../../common/translations/localize"; +import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { EntitiesCardEntityConfig } from "../../cards/types"; @@ -39,73 +37,56 @@ export class HuiGenericEntityRowEditor this._config = config; } - private _schema = memoizeOne( - ( - entity: string, - icon: string | undefined, - entityState: HassEntity, - localize: LocalizeFunc - ) => { - const domain = computeDomain(entity); + private _schema = memoizeOne((entity: string, localize: LocalizeFunc) => { + const domain = computeDomain(entity); - return [ - { name: "entity", required: true, selector: { entity: {} } }, - { - type: "grid", - name: "", - schema: [ - { name: "name", selector: { text: {} } }, - { - name: "icon", - selector: { - icon: { - placeholder: icon || entityState?.attributes.icon, - fallbackPath: - !icon && !entityState?.attributes.icon && entityState - ? domainIcon(domain, entityState) - : undefined, - }, - }, + return [ + { name: "entity", required: true, selector: { entity: {} } }, + { + type: "grid", + name: "", + schema: [ + { name: "name", selector: { text: {} } }, + { + name: "icon", + selector: { + icon: {}, }, - ], - }, - { - name: "secondary_info", - selector: { - select: { - options: ( - Object.keys(SecondaryInfoValues).filter( - (info) => - !("domains" in SecondaryInfoValues[info]) || - ("domains" in SecondaryInfoValues[info] && - SecondaryInfoValues[info].domains!.includes(domain)) - ) as Array - ).map((info) => ({ - value: info, - label: localize( - `ui.panel.lovelace.editor.card.entities.secondary_info_values.${info}` - ), - })), + context: { + icon_entity: "entity", }, }, + ], + }, + { + name: "secondary_info", + selector: { + select: { + options: ( + Object.keys(SecondaryInfoValues).filter( + (info) => + !("domains" in SecondaryInfoValues[info]) || + ("domains" in SecondaryInfoValues[info] && + SecondaryInfoValues[info].domains!.includes(domain)) + ) as Array + ).map((info) => ({ + value: info, + label: localize( + `ui.panel.lovelace.editor.card.entities.secondary_info_values.${info}` + ), + })), + }, }, - ] as const; - } - ); + }, + ] as const; + }); protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } - const entityState = this.hass.states[this._config.entity]; - - const schema = this._schema( - this._config.entity, - this._config.icon, - entityState, - this.hass.localize - ); + const schema = this._schema(this._config.entity, this.hass.localize); return html` - [ - { - name: "entity", - required: true, - selector: { entity: { domain: "light" } }, - }, - { - type: "grid", - name: "", - schema: [ - { name: "name", selector: { text: {} } }, - { - name: "icon", - selector: { - icon: { - placeholder: icon || entityState?.attributes.icon, - fallbackPath: - !icon && !entityState?.attributes.icon && entityState - ? domainIcon(computeDomain(entity), entityState) - : undefined, - }, - }, - }, - ], - }, - { name: "theme", selector: { theme: {} } }, - { - name: "hold_action", - selector: { "ui-action": {} }, - }, - { - name: "double_tap_action", - selector: { "ui-action": {} }, - }, - ] as const - ); - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } - const entityState = this.hass.states[this._config.entity]; - const schema = this._schema( - this._config.entity, - this._config.icon, - entityState - ); - return html` @@ -108,9 +91,7 @@ export class HuiLightCardEditor fireEvent(this, "config-changed", { config: ev.detail.value }); } - private _computeLabelCallback = ( - schema: SchemaUnion> - ) => { + private _computeLabelCallback = (schema: SchemaUnion) => { switch (schema.name) { case "theme": case "hold_action": diff --git a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts index d9c6d314a7..7f8d0b8dc3 100644 --- a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts @@ -1,7 +1,5 @@ -import type { HassEntity } from "home-assistant-js-websocket"; import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; import { assert, assign, @@ -13,8 +11,6 @@ import { union, } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { domainIcon } from "../../../../common/entity/domain_icon"; import { entityId } from "../../../../common/structs/is-entity-id"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; @@ -38,6 +34,55 @@ const cardConfigStruct = assign( }) ); +const SCHEMA = [ + { + name: "entity", + selector: { + entity: { domain: ["counter", "input_number", "number", "sensor"] }, + }, + }, + { name: "name", selector: { text: {} } }, + { + type: "grid", + name: "", + schema: [ + { + name: "icon", + selector: { + icon: {}, + }, + context: { + icon_entity: "entity", + }, + }, + { + name: "graph", + selector: { + select: { + options: [ + { + value: "none", + label: "None", + }, + { + value: "line", + label: "Line", + }, + ], + }, + }, + }, + { name: "unit", selector: { text: {} } }, + { name: "detail", selector: { boolean: {} } }, + { name: "theme", selector: { theme: {} } }, + { + name: "hours_to_show", + selector: { number: { min: 1, mode: "box" } }, + }, + ], + }, +] as const; + @customElement("hui-sensor-card-editor") export class HuiSensorCardEditor extends LitElement @@ -52,74 +97,11 @@ export class HuiSensorCardEditor this._config = config; } - private _schema = memoizeOne( - (entity: string, icon: string | undefined, entityState: HassEntity) => - [ - { - name: "entity", - selector: { - entity: { domain: ["counter", "input_number", "number", "sensor"] }, - }, - }, - { name: "name", selector: { text: {} } }, - { - type: "grid", - name: "", - schema: [ - { - name: "icon", - selector: { - icon: { - placeholder: icon || entityState?.attributes.icon, - fallbackPath: - !icon && !entityState?.attributes.icon && entityState - ? domainIcon(computeDomain(entity), entityState) - : undefined, - }, - }, - }, - { - name: "graph", - selector: { - select: { - options: [ - { - value: "none", - label: "None", - }, - { - value: "line", - label: "Line", - }, - ], - }, - }, - }, - { name: "unit", selector: { text: {} } }, - { name: "detail", selector: { boolean: {} } }, - { name: "theme", selector: { theme: {} } }, - { - name: "hours_to_show", - selector: { number: { min: 1, mode: "box" } }, - }, - ], - }, - ] as const - ); - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } - const entityState = this.hass.states[this._config.entity]; - - const schema = this._schema( - this._config.entity, - this._config.icon, - entityState - ); - const data = { hours_to_show: 24, graph: "none", @@ -131,7 +113,7 @@ export class HuiSensorCardEditor @@ -144,9 +126,7 @@ export class HuiSensorCardEditor fireEvent(this, "config-changed", { config }); } - private _computeLabelCallback = ( - schema: SchemaUnion> - ) => { + private _computeLabelCallback = (schema: SchemaUnion) => { switch (schema.name) { case "theme": return `${this.hass!.localize( diff --git a/src/panels/lovelace/editor/config-elements/hui-statistic-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-statistic-card-editor.ts index aa89edb420..03e58aecc0 100644 --- a/src/panels/lovelace/editor/config-elements/hui-statistic-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-statistic-card-editor.ts @@ -1,11 +1,8 @@ -import type { HassEntity } from "home-assistant-js-websocket/dist/types"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { any, assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { domainIcon } from "../../../../common/entity/domain_icon"; import { LocalizeFunc } from "../../../../common/translations/localize"; import { deepEqual } from "../../../../common/util/deep-equal"; import "../../../../components/ha-form/ha-form"; @@ -100,10 +97,7 @@ export class HuiStatisticCardEditor private _schema = memoizeOne( ( - entity: string, - icon: string, selectedPeriodKey: string | undefined, - entityState: HassEntity, localize: LocalizeFunc, metadata?: StatisticsMetaData ) => @@ -155,13 +149,10 @@ export class HuiStatisticCardEditor { name: "icon", selector: { - icon: { - placeholder: icon || entityState?.attributes.icon, - fallbackPath: - !icon && !entityState?.attributes.icon && entityState - ? domainIcon(computeDomain(entity), entityState) - : undefined, - }, + icon: {}, + }, + context: { + icon_entity: "entity", }, }, { name: "unit", selector: { text: {} } }, @@ -176,15 +167,10 @@ export class HuiStatisticCardEditor return html``; } - const entityState = this.hass.states[this._config.entity]; - const data = this._data(this._config); const schema = this._schema( - this._config.entity, - this._config.icon, typeof data.period === "string" ? data.period : undefined, - entityState, this.hass.localize, this._metadata ); diff --git a/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts index d62f0e071e..348ace3f33 100644 --- a/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts @@ -14,9 +14,8 @@ import { string, } from "superstruct"; import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { domainIcon } from "../../../../common/entity/domain_icon"; import { entityId } from "../../../../common/structs/is-entity-id"; +import { LocalizeFunc } from "../../../../common/translations/localize"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; @@ -65,16 +64,14 @@ export class HuiTileCardEditor } private _schema = memoizeOne( - (entity: string, icon?: string, stateObj?: HassEntity) => + (localize: LocalizeFunc) => [ { name: "entity", selector: { entity: {} } }, { name: "", type: "expandable", iconPath: mdiPalette, - title: this.hass!.localize( - `ui.panel.lovelace.editor.card.tile.appearance` - ), + title: localize(`ui.panel.lovelace.editor.card.tile.appearance`), schema: [ { name: "", @@ -84,14 +81,9 @@ export class HuiTileCardEditor { name: "icon", selector: { - icon: { - placeholder: icon || stateObj?.attributes.icon, - fallbackPath: - !icon && !stateObj?.attributes.icon && stateObj - ? domainIcon(computeDomain(entity), stateObj) - : undefined, - }, + icon: {}, }, + context: { icon_entity: "entity" }, }, { name: "color", @@ -118,9 +110,7 @@ export class HuiTileCardEditor { name: "", type: "expandable", - title: this.hass!.localize( - `ui.panel.lovelace.editor.card.tile.actions` - ), + title: localize(`ui.panel.lovelace.editor.card.tile.actions`), iconPath: mdiGestureTap, schema: [ { @@ -153,11 +143,7 @@ export class HuiTileCardEditor | HassEntity | undefined; - const schema = this._schema( - this._config.entity, - this._config.icon, - stateObj - ); + const schema = this._schema(this.hass!.localize); if (this._subElementEditorConfig) { return html`