mirror of
https://github.com/home-assistant/frontend.git
synced 2026-09-17 23:50:41 +00:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04bd49b7ab | ||
|
|
ca4efc0bf4 | ||
|
|
4556dc357d | ||
|
|
5791f434b8 | ||
|
|
f2d7a4ed8e | ||
|
|
92b6a36a31 |
@@ -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);
|
||||
|
||||
@@ -358,6 +358,24 @@ export class MoreInfoDialog extends DirtyStateProviderMixin<
|
||||
this._setView("settings");
|
||||
}
|
||||
|
||||
private _computeViewTitle(): string | undefined {
|
||||
switch (this._currView) {
|
||||
case "details":
|
||||
return this.hass.localize("ui.dialogs.more_info_control.details");
|
||||
case "related":
|
||||
return this.hass.localize("ui.dialogs.more_info_control.related");
|
||||
case "add_to":
|
||||
return this.hass.localize("ui.dialogs.more_info_control.add_to.item");
|
||||
case "settings":
|
||||
return (
|
||||
this._childView?.viewTitle ||
|
||||
this.hass.localize("ui.dialogs.more_info_control.settings")
|
||||
);
|
||||
default:
|
||||
return this._childView?.viewTitle;
|
||||
}
|
||||
}
|
||||
|
||||
private _showChildView(ev: CustomEvent): void {
|
||||
this._pushChildView(ev.detail as ChildView);
|
||||
}
|
||||
@@ -590,14 +608,7 @@ export class MoreInfoDialog extends DirtyStateProviderMixin<
|
||||
const addToMenuItem = this.hass.localize(
|
||||
"ui.dialogs.more_info_control.add_to.item"
|
||||
);
|
||||
const viewTitle =
|
||||
this._currView === "details"
|
||||
? 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;
|
||||
const viewTitle = this._computeViewTitle();
|
||||
const defaultTitle = breadcrumb[breadcrumb.length - 1] || entityId;
|
||||
if (!viewTitle) {
|
||||
breadcrumb.pop();
|
||||
|
||||
@@ -171,6 +171,9 @@ export class EntitySettingsHelperTab extends LitElement {
|
||||
);
|
||||
}
|
||||
const result = await this._registryEditor!.updateEntry();
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
this._dirtyState?.markClean();
|
||||
if (result.close) {
|
||||
fireEvent(this, "close-dialog");
|
||||
|
||||
@@ -5,9 +5,12 @@ import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { live } from "lit/directives/live";
|
||||
import { until } from "lit/directives/until";
|
||||
import memoizeOne from "memoize-one";
|
||||
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 +28,8 @@ import "../../../components/ha-area-picker";
|
||||
import "../../../components/ha-color-picker";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
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";
|
||||
import "../../../components/ha-select";
|
||||
@@ -194,6 +199,8 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
|
||||
@state() private _name!: string;
|
||||
|
||||
@state() private _useDeviceName = false;
|
||||
|
||||
@state() private _icon!: string;
|
||||
|
||||
@state() private _entityId!: EntitySettingsState["entityId"];
|
||||
@@ -255,6 +262,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
|
||||
@@ -262,7 +272,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;
|
||||
@@ -272,9 +284,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);
|
||||
@@ -387,10 +396,10 @@ 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,
|
||||
areaId: this._computeAreaId(),
|
||||
labels: this._labels ?? [],
|
||||
deviceClass: this._deviceClass,
|
||||
disabledBy: this._disabledBy,
|
||||
@@ -465,10 +474,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-row-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-row-item>`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.hideName || (this._device && this._useDeviceName)
|
||||
? nothing
|
||||
: html`<ha-input
|
||||
inset-label
|
||||
@@ -481,22 +528,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>`
|
||||
@@ -1176,7 +1217,7 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
${
|
||||
this.entry.device_id
|
||||
? html`
|
||||
<ha-row-item>
|
||||
<ha-row-item class="device-area">
|
||||
<span slot="headline"
|
||||
>${this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.use_device_area"
|
||||
@@ -1193,7 +1234,9 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
>
|
||||
<span slot="supporting-text"
|
||||
>${this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.change_device_settings",
|
||||
this._useDeviceArea
|
||||
? "ui.dialogs.entity_registry.editor.use_device_area_required"
|
||||
: "ui.dialogs.entity_registry.editor.change_device_settings",
|
||||
{
|
||||
link: html`<button
|
||||
class="link"
|
||||
@@ -1208,13 +1251,15 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
>
|
||||
<ha-switch
|
||||
slot="end"
|
||||
.checked=${!this._areaId || this._noDeviceArea}
|
||||
.disabled=${this.disabled}
|
||||
.checked=${live(
|
||||
this._useDeviceArea || !this._areaId || !!this._noDeviceArea
|
||||
)}
|
||||
.disabled=${this.disabled || this._useDeviceArea}
|
||||
@change=${this._useDeviceAreaChanged}
|
||||
></ha-switch>
|
||||
</ha-row-item>
|
||||
${
|
||||
this._areaId || this._noDeviceArea
|
||||
!this._useDeviceArea && (this._areaId || this._noDeviceArea)
|
||||
? html`<ha-area-picker
|
||||
.value=${this._areaId}
|
||||
.disabled=${this.disabled}
|
||||
@@ -1228,10 +1273,26 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
public async updateEntry(): Promise<{
|
||||
close: boolean;
|
||||
entry: ExtEntityRegistryEntry;
|
||||
}> {
|
||||
public async updateEntry(): Promise<
|
||||
{ close: boolean; entry: ExtEntityRegistryEntry } | undefined
|
||||
> {
|
||||
if (this._useDeviceArea && this._areaId) {
|
||||
const confirmed = await showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.use_device_area_confirm_title"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.use_device_area_confirm_text",
|
||||
{ area: this.hass.areas[this._areaId]?.name ?? this._areaId }
|
||||
),
|
||||
confirmText: this.hass.localize("ui.common.save"),
|
||||
dismissText: this.hass.localize("ui.common.cancel"),
|
||||
});
|
||||
if (!confirmed) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
let close = true;
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
let parent: HTMLElement = this;
|
||||
@@ -1240,9 +1301,9 @@ 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,
|
||||
area_id: this._computeAreaId(),
|
||||
labels: this._labels || [],
|
||||
new_entity_id: this._entityId.trim(),
|
||||
};
|
||||
@@ -1687,9 +1748,41 @@ 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 _useDeviceArea(): boolean {
|
||||
return !!this._device && this._useDeviceName;
|
||||
}
|
||||
|
||||
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 _computeAreaId(): string | null {
|
||||
if (this._useDeviceArea) {
|
||||
return null;
|
||||
}
|
||||
return this._areaId || null;
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -1800,11 +1893,15 @@ 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;
|
||||
}
|
||||
|
||||
ha-row-item.device-area::part(supporting-text) {
|
||||
white-space: normal;
|
||||
}
|
||||
ha-row-item {
|
||||
--ha-row-item-padding-inline: 0;
|
||||
}
|
||||
|
||||
@@ -221,6 +221,9 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
this._error = undefined;
|
||||
try {
|
||||
const result = await this._registryEditor!.updateEntry();
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
this._dirtyState?.markClean();
|
||||
if (result.close) {
|
||||
fireEvent(this, "close-dialog");
|
||||
|
||||
@@ -1958,6 +1958,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",
|
||||
@@ -2045,7 +2048,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!",
|
||||
@@ -2066,6 +2068,9 @@
|
||||
"update": "Update",
|
||||
"note": "Note: This might not work yet with all integrations.",
|
||||
"use_device_area": "Use device area",
|
||||
"use_device_area_confirm_title": "Use the area of the device?",
|
||||
"use_device_area_confirm_text": "This entity is in {area}. Because it uses the device name, it will use the area of its device instead.",
|
||||
"use_device_area_required": "An entity that uses the device name always uses the area of its device. You can {link} in the device settings.",
|
||||
"change_device_settings": "You can {link} in the device settings",
|
||||
"change_device_area_link": "change the device area",
|
||||
"configure_state": "{integration} options",
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user