Use new entity naming in card entity picker (#25316)

This commit is contained in:
Paul Bottein 2025-05-05 19:37:47 +02:00 committed by GitHub
parent 9081441d95
commit 7434b12d9f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 195 additions and 123 deletions

View File

@ -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}
></hui-entity-picker-table>
`
@ -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 {

View File

@ -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}
></hui-entity-picker-table>
`
@ -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 {

View File

@ -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<EntityPickerTableRowData>(
(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`
<ha-data-table
class=${showEntityId ? "show-entity-id" : ""}
.hass=${this.hass}
selectable
.id=${"entity_id"}
.columns=${this._columns(this.narrow!)}
.data=${this.entities}
.columns=${columns}
.data=${data}
.searchLabel=${this.hass.localize(
"ui.panel.lovelace.unused_entities.search"
)}
@ -45,72 +124,113 @@ export class HuiEntityPickerTable extends LitElement {
`;
}
private _columns = memoizeOne((narrow: boolean) => {
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`
<state-badge
@click=${this._handleEntityClicked}
.hass=${this.hass!}
.stateObj=${entity.stateObj}
></state-badge>
`,
},
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`
<div @click=${this._handleEntityClicked} style="cursor: pointer;">
${primary}
${secondary
? html`<div class="secondary">${secondary}</div>`
: nothing}
${narrow && showEntityId
? html`
<div class="secondary" style=${ENTITY_ID_STYLE}>
${entity.entity_id}
</div>
`
: nothing}
</div>
`;
},
},
};
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`
<state-badge
@click=${this._handleEntityClicked}
.hass=${this.hass!}
.stateObj=${entity.stateObj}
></state-badge>
`,
},
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`
<div @click=${this._handleEntityClicked} style="cursor: pointer;">
${entity.name}
${narrow
? html` <div class="secondary">${entity.entity_id}</div> `
: ""}
</div>
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`
<ha-relative-time
.hass=${this.hass!}
.datetime=${entity.last_changed}
capitalize
></ha-relative-time>
`,
},
};
};
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`
<ha-relative-time
.hass=${this.hass!}
.datetime=${entity.last_changed}
capitalize
></ha-relative-time>
`,
};
return columns;
});
return columns;
}
);
private _handleSelectionChanged(
ev: HASSDomEvent<SelectionChangedEvent>
@ -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;
}
`;
}

View File

@ -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 {
<hui-entity-picker-table
.hass=${this.hass}
.narrow=${this.narrow}
.entities=${this._unusedEntities.map((entity) => {
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}
></hui-entity-picker-table>
</div>