From 279f3e1183815abd82ded9b53fb5e04770b504a4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 25 Oct 2021 03:56:33 -0700 Subject: [PATCH] Trim device name from entities on device page (#10285) --- .../entity/strip_prefix_from_entity_name.ts | 24 +++++++++++++++++++ .../device-detail/ha-device-entities-card.ts | 23 +++++++++++++++--- .../config/devices/ha-config-device-page.ts | 8 +++---- .../common/generate-lovelace-config.ts | 22 +++++++---------- 4 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 src/common/entity/strip_prefix_from_entity_name.ts diff --git a/src/common/entity/strip_prefix_from_entity_name.ts b/src/common/entity/strip_prefix_from_entity_name.ts new file mode 100644 index 0000000000..1efa3704d5 --- /dev/null +++ b/src/common/entity/strip_prefix_from_entity_name.ts @@ -0,0 +1,24 @@ +/** + * Strips a device name from an entity name. + * @param entityName the entity name + * @param lowerCasedPrefixWithSpaceSuffix the prefix to strip, lower cased with a space suffix + * @returns + */ +export const stripPrefixFromEntityName = ( + entityName: string, + lowerCasedPrefixWithSpaceSuffix: string +) => { + if (!entityName.toLowerCase().startsWith(lowerCasedPrefixWithSpaceSuffix)) { + return undefined; + } + + const newName = entityName.substring(lowerCasedPrefixWithSpaceSuffix.length); + + // If first word already has an upper case letter (e.g. from brand name) + // leave as-is, otherwise capitalize the first word. + return hasUpperCase(newName.substr(0, newName.indexOf(" "))) + ? newName + : newName[0].toUpperCase() + newName.slice(1); +}; + +const hasUpperCase = (str: string): boolean => str.toLowerCase() !== str; diff --git a/src/panels/config/devices/device-detail/ha-device-entities-card.ts b/src/panels/config/devices/device-detail/ha-device-entities-card.ts index a943914264..5c749d927b 100644 --- a/src/panels/config/devices/device-detail/ha-device-entities-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-entities-card.ts @@ -15,18 +15,23 @@ import { domainIcon } from "../../../../common/entity/domain_icon"; import "../../../../components/entity/state-badge"; import "../../../../components/ha-card"; import "../../../../components/ha-icon"; -import { HomeAssistant } from "../../../../types"; -import { HuiErrorCard } from "../../../lovelace/cards/hui-error-card"; +import type { LovelaceRowConfig } from "../../../lovelace/entity-rows/types"; +import type { HomeAssistant } from "../../../../types"; +import type { HuiErrorCard } from "../../../lovelace/cards/hui-error-card"; import { createRowElement } from "../../../lovelace/create-element/create-row-element"; import { addEntitiesToLovelaceView } from "../../../lovelace/editor/add-entities-to-view"; import { LovelaceRow } from "../../../lovelace/entity-rows/types"; import { showEntityEditorDialog } from "../../entities/show-dialog-entity-editor"; import { EntityRegistryStateEntry } from "../ha-config-device-page"; +import { computeStateName } from "../../../../common/entity/compute_state_name"; +import { stripPrefixFromEntityName } from "../../../../common/entity/strip_prefix_from_entity_name"; @customElement("ha-device-entities-card") export class HaDeviceEntitiesCard extends LitElement { @property() public header!: string; + @property() public deviceName!: string; + @property({ attribute: false }) public hass!: HomeAssistant; @property() public entities!: EntityRegistryStateEntry[]; @@ -119,9 +124,21 @@ export class HaDeviceEntitiesCard extends LitElement { } private _renderEntity(entry: EntityRegistryStateEntry): TemplateResult { - const element = createRowElement({ entity: entry.entity_id }); + const config: LovelaceRowConfig = { + entity: entry.entity_id, + }; + + const element = createRowElement(config); if (this.hass) { element.hass = this.hass; + const state = this.hass.states[entry.entity_id]; + const name = stripPrefixFromEntityName( + computeStateName(state), + `${this.deviceName} `.toLowerCase() + ); + if (name) { + config.name = name; + } } // @ts-ignore element.entry = entry; diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index 9be745ae4e..f1b6c60837 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -179,6 +179,7 @@ export class HaConfigDevicePage extends LitElement { `; } + const deviceName = computeDeviceName(device, this.hass); const integrations = this._integrations(device, this.entries); const entities = this._entities(this.deviceId, this.entities); const entitiesByCategory = this._entitiesByCategory(entities); @@ -204,9 +205,7 @@ export class HaConfigDevicePage extends LitElement { ${ this.narrow ? html` - - ${computeDeviceName(device, this.hass)} - + ${deviceName}
-

${computeDeviceName(device, this.hass)}

+

${deviceName}

${area ? html` diff --git a/src/panels/lovelace/common/generate-lovelace-config.ts b/src/panels/lovelace/common/generate-lovelace-config.ts index 5edc9e313e..2860ca6dff 100644 --- a/src/panels/lovelace/common/generate-lovelace-config.ts +++ b/src/panels/lovelace/common/generate-lovelace-config.ts @@ -3,6 +3,7 @@ import { computeDomain } from "../../../common/entity/compute_domain"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { splitByGroups } from "../../../common/entity/split_by_groups"; +import { stripPrefixFromEntityName } from "../../../common/entity/strip_prefix_from_entity_name"; import { stringCompare } from "../../../common/string/compare"; import { LocalizeFunc } from "../../../common/translations/localize"; import type { AreaRegistryEntry } from "../../../data/area_registry"; @@ -92,7 +93,7 @@ export const computeCards = ( const entities: Array = []; const titlePrefix = entityCardOptions.title - ? `${entityCardOptions.title} ` + ? `${entityCardOptions.title} `.toLowerCase() : undefined; for (const [entityId, stateObj] of states) { @@ -153,16 +154,18 @@ export const computeCards = ( ) { // Do nothing. } else { - let name: string; + let name: string | undefined; const entityConf = titlePrefix && stateObj && // eslint-disable-next-line no-cond-assign - (name = computeStateName(stateObj)) !== titlePrefix && - name.startsWith(titlePrefix) + (name = stripPrefixFromEntityName( + computeStateName(stateObj), + titlePrefix + )) ? { entity: entityId, - name: adjustName(name.substr(titlePrefix.length)), + name, } : entityId; @@ -181,15 +184,6 @@ export const computeCards = ( return cards; }; -const hasUpperCase = (str: string): boolean => str.toLowerCase() !== str; - -const adjustName = (name: string): string => - // If first word already has an upper case letter (e.g. from brand name) - // leave as-is, otherwise capitalize the first word. - hasUpperCase(name.substr(0, name.indexOf(" "))) - ? name - : name[0].toUpperCase() + name.slice(1); - const computeDefaultViewStates = ( entities: HassEntities, entityEntries: EntityRegistryEntry[]