Compare commits

...
5 changed files with 111 additions and 31 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ export const computeEntityEntryName = (
fallbackStateObj?: HassEntity
): string | undefined => {
const name =
entry.name ||
entry.name ??
("original_name" in entry && entry.original_name != null
? String(entry.original_name)
: undefined);
+5 -3
View File
@@ -604,9 +604,11 @@ export class MoreInfoDialog extends DirtyStateProviderMixin<
? this.hass.localize("ui.dialogs.more_info_control.details")
: this._currView === "related"
? this.hass.localize("ui.dialogs.more_info_control.related")
: this._currView === "add_to"
? addToMenuItem
: this._childView?.viewTitle;
: this._currView === "settings"
? this.hass.localize("ui.dialogs.more_info_control.settings")
: this._currView === "add_to"
? addToMenuItem
: this._childView?.viewTitle;
const defaultTitle = breadcrumb[breadcrumb.length - 1] || entityId;
if (!viewTitle) {
breadcrumb.pop();
@@ -8,6 +8,8 @@ import { until } from "lit/directives/until";
import memoizeOne from "memoize-one";
import { consume } from "@lit/context";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import type { HASSDomCurrentTargetEvent } from "../../../common/dom/fire_event";
import { computeDeviceNameDisplay } from "../../../common/entity/compute_device_name";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeObjectId } from "../../../common/entity/compute_object_id";
import { supportsFeature } from "../../../common/entity/supports-feature";
@@ -25,6 +27,7 @@ import "../../../components/ha-color-picker";
import "../../../components/ha-dropdown-item";
import "../../../components/entity/ha-entity-picker";
import "../../../components/ha-icon";
import "../../../components/ha-icon-button";
import "../../../components/ha-icon-button-next";
import "../../../components/ha-icon-picker";
import "../../../components/ha-labels-picker";
@@ -193,6 +196,8 @@ export class EntityRegistrySettingsEditor extends LitElement {
@state() private _name!: string;
@state() private _useDeviceName = false;
@state() private _icon!: string;
@state() private _entityId!: EntitySettingsState["entityId"];
@@ -254,6 +259,9 @@ export class EntityRegistrySettingsEditor extends LitElement {
protected willUpdate(changedProperties: PropertyValues<this>) {
super.willUpdate(changedProperties);
this._device = this.entry.device_id
? this.hass.devices[this.entry.device_id]
: undefined;
if (
!changedProperties.has("entry") ||
changedProperties.get("entry")?.id === this.entry.id
@@ -261,7 +269,9 @@ export class EntityRegistrySettingsEditor extends LitElement {
return;
}
this._name = this.entry.name || "";
this._name = this.entry.name || this._originalName;
this._useDeviceName =
!!this._device && !(this.entry.name ?? this._originalName);
this._icon = this.entry.icon || "";
this._deviceClass =
this.entry.device_class || this.entry.original_device_class;
@@ -271,9 +281,6 @@ export class EntityRegistrySettingsEditor extends LitElement {
this._entityId = this.entry.entity_id;
this._disabledBy = this.entry.disabled_by;
this._hiddenBy = this.entry.hidden_by;
this._device = this.entry.device_id
? this.hass.devices[this.entry.device_id]
: undefined;
this._switchAsInvert = this.entry.options?.switch_as_x?.invert === true;
const domain = computeDomain(this.entry.entity_id);
@@ -386,7 +393,7 @@ export class EntityRegistrySettingsEditor extends LitElement {
this._dirtyState?.setState(
{
name: this._name || null,
name: this._computeName(),
icon: this._icon || null,
entityId: this._entityId,
areaId: this._areaId ?? null,
@@ -464,10 +471,48 @@ export class EntityRegistrySettingsEditor extends LitElement {
const defaultPrecision =
this.entry.options?.sensor?.suggested_display_precision ?? undefined;
const defaultName = this._originalName;
return html`
${
this.hideName
!this.hideName && this._device
? html`<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.use_device_name"
)}
(${computeDeviceNameDisplay(
this._device,
this.hass.localize,
this.hass.states
)})</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.change_device_settings",
{
link: html`<button
class="link"
@click=${this._openDeviceSettings}
>
${this.hass.localize(
"ui.dialogs.entity_registry.editor.change_device_name_link"
)}
</button>`,
}
)}</span
>
<ha-switch
slot="end"
.checked=${this._useDeviceName}
.disabled=${this.disabled}
@change=${this._useDeviceNameChanged}
></ha-switch>
</ha-md-list-item>`
: nothing
}
${
this.hideName || (this._device && this._useDeviceName)
? nothing
: html`<ha-input
inset-label
@@ -480,22 +525,16 @@ export class EntityRegistrySettingsEditor extends LitElement {
@input=${this._nameChanged}
>
${
this._device
? html`<span slot="hint"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.device_name_tip",
{
link: html`<button
class="link"
@click=${this._resetNameAndOpenDeviceSettings}
>
${this.hass.localize(
"ui.dialogs.entity_registry.editor.open_device_settings"
)}
</button>`,
}
)}</span
>`
this._name !== defaultName
? html`<ha-icon-button
slot="end"
.path=${mdiRestore}
.label=${this.hass.localize(
"ui.dialogs.entity_registry.editor.restore_name"
)}
.disabled=${this.disabled}
@click=${this._restoreName}
></ha-icon-button>`
: nothing
}
</ha-input>`
@@ -1245,7 +1284,7 @@ export class EntityRegistrySettingsEditor extends LitElement {
}
const params: Partial<EntityRegistryEntryUpdateParams> = {
name: this._name.trim() || null,
name: this._computeName(),
icon: this._icon.trim() || null,
area_id: this._areaId || null,
labels: this._labels || [],
@@ -1692,9 +1731,30 @@ export class EntityRegistrySettingsEditor extends LitElement {
}
}
private _resetNameAndOpenDeviceSettings() {
this._name = this.entry.name || "";
this._openDeviceSettings();
private _useDeviceNameChanged(ev: HASSDomCurrentTargetEvent<HaSwitch>): void {
this._useDeviceName = ev.currentTarget.checked;
}
private get _originalName(): string {
return String(this.entry.original_name ?? "");
}
private _restoreName(): void {
this._name = this._originalName;
if (this._device && !this._originalName) {
this._useDeviceName = true;
}
}
private _computeName(): string | null {
if (this.hideName) {
return this.entry.name;
}
if (this._device && this._useDeviceName) {
return this._originalName ? "" : null;
}
const name = this._name.trim();
return name && name !== this._originalName ? name : null;
}
private _openDeviceSettings() {
@@ -1805,6 +1865,7 @@ export class EntityRegistrySettingsEditor extends LitElement {
ha-input.name {
--ha-input-start-max-width: 35%;
--ha-input-padding-bottom: 0;
}
ha-input.entityId ha-icon-button:last-child {
margin-inline-start: 0;
+3 -1
View File
@@ -1939,6 +1939,9 @@
"faq": "documentation",
"editor": {
"name": "Name",
"use_device_name": "Use device name",
"change_device_name_link": "change the device name",
"restore_name": "Restore default name",
"icon": "Icon",
"icon_error": "Icons should be in the format 'prefix:iconname', like 'mdi:home'",
"default_code": "Default code",
@@ -2025,7 +2028,6 @@
"entity_disabled": "This entity is disabled.",
"enable_entity": "Enable",
"open_device_settings": "Open device settings",
"device_name_tip": "Consider renaming the device instead to update all its entities at once. {link}",
"switch_as_x_confirm": "This switch will be hidden and a new {domain} will be added. Your existing configurations using the switch will continue to work.",
"switch_as_x_remove_confirm": "This {domain} will be removed and the original switch will be visible again. Your existing configurations using the {domain} will no longer work!",
"switch_as_x_change_confirm": "This {domain_1} will be removed and will be replaced by a new {domain_2}. Your existing configurations using the {domain_1} will no longer work!",
@@ -8,6 +8,7 @@ import * as computeStateNameModule from "../../../src/common/entity/compute_stat
import * as stripPrefixModule from "../../../src/common/entity/strip_prefix_from_entity_name";
import type { HomeAssistant } from "../../../src/types";
import {
mockDevice,
mockEntity,
mockEntityEntry,
mockStateObj,
@@ -132,6 +133,20 @@ describe("computeEntityEntryName", () => {
expect(computeEntityEntryName(entry, hass.devices)).toBe("Old Name");
});
it("preserves an explicitly empty name instead of the integration name", () => {
const entry = mockEntityEntry({
device_id: "dev1",
name: "",
original_name: "Temperature",
});
const devices = { dev1: mockDevice({ id: "dev1", name: "Living room" }) };
expect(computeEntityEntryName(entry, devices)).toBe("");
expect(computeEntityEntryName({ ...entry, name: null }, devices)).toBe(
"Temperature"
);
});
it("returns undefined if no name, original_name, or device", () => {
const entry = mockEntity({ entity_id: "light.kitchen" });
const hass = {