diff --git a/src/panels/lovelace/editor/badge-editor/hui-dialog-create-badge.ts b/src/panels/lovelace/editor/badge-editor/hui-dialog-create-badge.ts index d14959e4fb..9388295802 100644 --- a/src/panels/lovelace/editor/badge-editor/hui-dialog-create-badge.ts +++ b/src/panels/lovelace/editor/badge-editor/hui-dialog-create-badge.ts @@ -4,11 +4,7 @@ import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { cache } from "lit/directives/cache"; import { classMap } from "lit/directives/class-map"; -import memoize from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { computeStateName } from "../../../../common/entity/compute_state_name"; -import type { DataTableRowData } from "../../../../components/data-table/ha-data-table"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; import "../../../../components/sl-tab-group"; @@ -137,7 +133,6 @@ export class HuiCreateDialogBadge no-label-float .hass=${this.hass} .narrow=${true} - .entities=${this._allEntities(this.hass.states)} @selected-changed=${this._handleSelectedChanged} > ` @@ -276,20 +271,6 @@ export class HuiCreateDialogBadge this.closeDialog(); } - - private _allEntities = memoize((entities) => - Object.keys(entities).map((entity) => { - const stateObj = this.hass.states[entity]; - return { - icon: "", - entity_id: entity, - stateObj, - name: computeStateName(stateObj), - domain: computeDomain(entity), - last_changed: stateObj!.last_changed, - } as DataTableRowData; - }) - ); } declare global { diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-create-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-create-card.ts index 314029fa0d..46927da9c8 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-create-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-create-card.ts @@ -5,11 +5,7 @@ import { customElement, property, state } from "lit/decorators"; import { cache } from "lit/directives/cache"; import { classMap } from "lit/directives/class-map"; import { ifDefined } from "lit/directives/if-defined"; -import memoize from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { computeStateName } from "../../../../common/entity/compute_state_name"; -import type { DataTableRowData } from "../../../../components/data-table/ha-data-table"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; import "../../../../components/sl-tab-group"; @@ -157,7 +153,6 @@ export class HuiCreateDialogCard no-label-float .hass=${this.hass} narrow - .entities=${this._allEntities(this.hass.states)} @selected-changed=${this._handleSelectedChanged} > ` @@ -340,20 +335,6 @@ export class HuiCreateDialogCard this.closeDialog(); } - - private _allEntities = memoize((entities) => - Object.keys(entities).map((entity) => { - const stateObj = this.hass.states[entity]; - return { - icon: "", - entity_id: entity, - stateObj, - name: computeStateName(stateObj), - domain: computeDomain(entity), - last_changed: stateObj!.last_changed, - } as DataTableRowData; - }) - ); } declare global { diff --git a/src/panels/lovelace/editor/card-editor/hui-entity-picker-table.ts b/src/panels/lovelace/editor/card-editor/hui-entity-picker-table.ts index 5918aafef6..dd0c3a549c 100644 --- a/src/panels/lovelace/editor/card-editor/hui-entity-picker-table.ts +++ b/src/panels/lovelace/editor/card-editor/hui-entity-picker-table.ts @@ -1,9 +1,17 @@ -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; +import type { PropertyValues, TemplateResult } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators"; +import { styleMap } from "lit/directives/style-map"; import memoizeOne from "memoize-one"; import type { HASSDomEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { computeAreaName } from "../../../../common/entity/compute_area_name"; +import { computeDeviceName } from "../../../../common/entity/compute_device_name"; +import { computeDomain } from "../../../../common/entity/compute_domain"; +import { computeEntityName } from "../../../../common/entity/compute_entity_name"; +import { getEntityContext } from "../../../../common/entity/context/get_entity_context"; +import type { LocalizeFunc } from "../../../../common/translations/localize"; +import { computeRTL } from "../../../../common/util/compute_rtl"; import "../../../../components/data-table/ha-data-table"; import type { DataTableColumnContainer, @@ -12,8 +20,26 @@ import type { } from "../../../../components/data-table/ha-data-table"; import "../../../../components/entity/state-badge"; import "../../../../components/ha-relative-time"; +import { domainToName } from "../../../../data/integration"; import type { HomeAssistant } from "../../../../types"; +const ENTITY_ID_STYLE = styleMap({ + fontFamily: "var(--ha-font-family-code)", + fontSize: "var(--ha-font-size-xs)", +}); + +interface EntityPickerTableRowData extends DataTableRowData { + icon: string; + entity_id: string; + stateObj: any; + name: string; + entity_name?: string; + device_name?: string; + area_name?: string; + domain_name: string; + last_changed: string; +} + @customElement("hui-entity-picker-table") export class HuiEntityPickerTable extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -23,16 +49,69 @@ export class HuiEntityPickerTable extends LitElement { @property({ type: Boolean, attribute: "no-label-float" }) public noLabelFloat? = false; - @property({ type: Array }) public entities!: DataTableRowData[]; + @property({ type: Array }) public entities?: string[]; + + protected firstUpdated(_changedProperties: PropertyValues): void { + super.firstUpdated(_changedProperties); + this.hass.loadBackendTranslation("title"); + } + + private _data = memoizeOne( + ( + states: HomeAssistant["states"], + localize: LocalizeFunc, + entities?: string[] + ): EntityPickerTableRowData[] => + (entities || Object.keys(states)).map( + (entity) => { + const stateObj = this.hass.states[entity]; + + const { area, device } = getEntityContext(stateObj, this.hass); + + const entityName = computeEntityName(stateObj, this.hass); + const deviceName = device ? computeDeviceName(device) : undefined; + const areaName = area ? computeAreaName(area) : undefined; + const name = [deviceName, entityName].filter(Boolean).join(" "); + const domain = computeDomain(entity); + + return { + icon: "", + entity_id: entity, + stateObj, + name: name, + entity_name: entityName, + device_name: deviceName, + area_name: areaName, + domain_name: domainToName(localize, domain), + last_changed: stateObj!.last_changed, + } satisfies EntityPickerTableRowData; + } + ) + ); protected render(): TemplateResult { + const data = this._data( + this.hass.states, + this.hass.localize, + this.entities + ); + + const showEntityId = Boolean(this.hass.userData?.showEntityIdPicker); + + const columns = this._columns( + this.narrow, + computeRTL(this.hass), + showEntityId + ); + return html` { - const columns: DataTableColumnContainer = { - icon: { - title: "", - label: this.hass!.localize( - "ui.panel.lovelace.unused_entities.state_icon" + private _columns = memoizeOne( + (narrow: boolean, isRTL: boolean, showEntityId: boolean) => { + const columns: DataTableColumnContainer = { + icon: { + title: "", + label: this.hass!.localize( + "ui.panel.lovelace.unused_entities.state_icon" + ), + type: "icon", + template: (entity) => html` + + `, + }, + name: { + title: this.hass!.localize( + "ui.panel.lovelace.unused_entities.entity" + ), + sortable: true, + filterable: true, + flex: 2, + main: true, + direction: "asc", + template: (entity: any) => { + const primary = + entity.entity_name || entity.device_name || entity.entity_id; + const secondary = [ + entity.area_name, + entity.entity_name ? entity.device_name : undefined, + ] + .filter(Boolean) + .join(isRTL ? " ◂ " : " ▸ "); + return html` +
+ ${primary} + ${secondary + ? html`
${secondary}
` + : nothing} + ${narrow && showEntityId + ? html` +
+ ${entity.entity_id} +
+ ` + : nothing} +
+ `; + }, + }, + }; + + columns.entity_name = { + title: "entity_name", + filterable: true, + hidden: true, + }; + + columns.device_name = { + title: "device_name", + filterable: true, + hidden: true, + }; + + columns.area_name = { + title: "area_name", + filterable: true, + hidden: true, + }; + + columns.entity_id = { + title: this.hass!.localize( + "ui.panel.lovelace.unused_entities.entity_id" ), - type: "icon", - template: (entity) => html` - - `, - }, - name: { - title: this.hass!.localize("ui.panel.lovelace.unused_entities.entity"), sortable: true, filterable: true, - flex: 2, - main: true, - direction: "asc", - template: (entity: any) => html` -
- ${entity.name} - ${narrow - ? html`
${entity.entity_id}
` - : ""} -
+ hidden: narrow || !showEntityId, + }; + + columns.domain_name = { + title: this.hass!.localize("ui.panel.lovelace.unused_entities.domain"), + sortable: true, + filterable: true, + hidden: narrow || showEntityId, + }; + + columns.last_changed = { + title: this.hass!.localize( + "ui.panel.lovelace.unused_entities.last_changed" + ), + type: "numeric", + sortable: true, + hidden: narrow, + template: (entity) => html` + `, - }, - }; + }; - columns.entity_id = { - title: this.hass!.localize("ui.panel.lovelace.unused_entities.entity_id"), - sortable: true, - filterable: true, - hidden: narrow, - }; - - columns.domain = { - title: this.hass!.localize("ui.panel.lovelace.unused_entities.domain"), - sortable: true, - filterable: true, - hidden: narrow, - }; - - columns.last_changed = { - title: this.hass!.localize( - "ui.panel.lovelace.unused_entities.last_changed" - ), - type: "numeric", - sortable: true, - hidden: narrow, - template: (entity) => html` - - `, - }; - - return columns; - }); + return columns; + } + ); private _handleSelectionChanged( ev: HASSDomEvent @@ -134,6 +254,9 @@ export class HuiEntityPickerTable extends LitElement { --data-table-border-width: 0; height: 100%; } + ha-data-table.show-entity-id { + --data-table-row-height: 64px; + } `; } diff --git a/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts b/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts index a63d3e3a50..392f439f73 100644 --- a/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts +++ b/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts @@ -3,22 +3,19 @@ import type { PropertyValues } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { computeStateName } from "../../../../common/entity/compute_state_name"; -import type { DataTableRowData } from "../../../../components/data-table/ha-data-table"; import "../../../../components/ha-fab"; import "../../../../components/ha-svg-icon"; +import type { LovelaceConfig } from "../../../../data/lovelace/config/types"; import type { HomeAssistant } from "../../../../types"; import { computeUnusedEntities } from "../../common/compute-unused-entities"; -import type { Lovelace } from "../../types"; -import "../card-editor/hui-entity-picker-table"; -import { showSuggestCardDialog } from "../card-editor/show-suggest-card-dialog"; -import { showSelectViewDialog } from "../select-view/show-select-view-dialog"; -import type { LovelaceConfig } from "../../../../data/lovelace/config/types"; import { computeCards, computeSection, } from "../../common/generate-lovelace-config"; +import type { Lovelace } from "../../types"; +import "../card-editor/hui-entity-picker-table"; +import { showSuggestCardDialog } from "../card-editor/show-suggest-card-dialog"; +import { showSelectViewDialog } from "../select-view/show-select-view-dialog"; @customElement("hui-unused-entities") export class HuiUnusedEntities extends LitElement { @@ -80,17 +77,7 @@ export class HuiUnusedEntities extends LitElement { { - const stateObj = this.hass!.states[entity]; - return { - icon: "", - entity_id: entity, - stateObj, - name: stateObj ? computeStateName(stateObj) : "Unavailable", - domain: computeDomain(entity), - last_changed: stateObj?.last_changed, - }; - }) as DataTableRowData[]} + .entities=${this._unusedEntities} @selected-changed=${this._handleSelectedChanged} >