diff --git a/gallery/src/pages/components/ha-form.ts b/gallery/src/pages/components/ha-form.ts index 5ddf38b765..0bc1ff458d 100644 --- a/gallery/src/pages/components/ha-form.ts +++ b/gallery/src/pages/components/ha-form.ts @@ -99,16 +99,19 @@ const AREAS = [ area_id: "backyard", name: "Backyard", picture: null, + aliases: [], }, { area_id: "bedroom", name: "Bedroom", picture: null, + aliases: [], }, { area_id: "livingroom", name: "Livingroom", picture: null, + aliases: [], }, ]; diff --git a/gallery/src/pages/components/ha-selector.ts b/gallery/src/pages/components/ha-selector.ts index b794d15671..9ac7959635 100644 --- a/gallery/src/pages/components/ha-selector.ts +++ b/gallery/src/pages/components/ha-selector.ts @@ -95,16 +95,19 @@ const AREAS = [ area_id: "backyard", name: "Backyard", picture: null, + aliases: [], }, { area_id: "bedroom", name: "Bedroom", picture: null, + aliases: [], }, { area_id: "livingroom", name: "Livingroom", picture: null, + aliases: [], }, ]; diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts index d45f4fdb89..9557836e4a 100644 --- a/src/components/ha-area-picker.ts +++ b/src/components/ha-area-picker.ts @@ -126,6 +126,7 @@ export class HaAreaPicker extends LitElement { area_id: "no_areas", name: this.hass.localize("ui.components.area-picker.no_areas"), picture: null, + aliases: [], }, ]; } @@ -256,6 +257,7 @@ export class HaAreaPicker extends LitElement { area_id: "no_areas", name: this.hass.localize("ui.components.area-picker.no_match"), picture: null, + aliases: [], }, ]; } @@ -268,6 +270,7 @@ export class HaAreaPicker extends LitElement { area_id: "add_new", name: this.hass.localize("ui.components.area-picker.add_new"), picture: null, + aliases: [], }, ]; } diff --git a/src/data/area_registry.ts b/src/data/area_registry.ts index c316785cfc..4c53f218eb 100644 --- a/src/data/area_registry.ts +++ b/src/data/area_registry.ts @@ -10,6 +10,7 @@ export interface AreaRegistryEntry { area_id: string; name: string; picture: string | null; + aliases: string[]; } export interface AreaEntityLookup { @@ -23,6 +24,7 @@ export interface AreaDeviceLookup { export interface AreaRegistryEntryMutableParams { name: string; picture?: string | null; + aliases?: string[]; } export const createAreaRegistryEntry = ( diff --git a/src/panels/config/entities/entity-aliases/dialog-entity-aliases.ts b/src/dialogs/aliases/dialog-aliases.ts similarity index 68% rename from src/panels/config/entities/entity-aliases/dialog-entity-aliases.ts rename to src/dialogs/aliases/dialog-aliases.ts index 87f3e7cd85..5f0c987cae 100644 --- a/src/panels/config/entities/entity-aliases/dialog-entity-aliases.ts +++ b/src/dialogs/aliases/dialog-aliases.ts @@ -2,35 +2,34 @@ import "@material/mwc-button/mwc-button"; import { mdiDeleteOutline, mdiPlus } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; -import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeStateName } from "../../../../common/entity/compute_state_name"; -import "../../../../components/ha-alert"; -import "../../../../components/ha-area-picker"; -import "../../../../components/ha-dialog"; -import "../../../../components/ha-textfield"; -import type { HaTextField } from "../../../../components/ha-textfield"; -import { haStyle, haStyleDialog } from "../../../../resources/styles"; -import { HomeAssistant } from "../../../../types"; -import { EntityAliasesDialogParams } from "./show-dialog-entity-aliases"; +import { fireEvent } from "../../common/dom/fire_event"; +import "../../components/ha-alert"; +import "../../components/ha-area-picker"; +import "../../components/ha-dialog"; +import "../../components/ha-textfield"; +import type { HaTextField } from "../../components/ha-textfield"; +import { haStyle, haStyleDialog } from "../../resources/styles"; +import { HomeAssistant } from "../../types"; +import { AliasesDialogParams } from "./show-dialog-aliases"; -@customElement("dialog-entity-aliases") -class DialogEntityAliases extends LitElement { +@customElement("dialog-aliases") +class DialogAliases extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @state() private _error?: string; - @state() private _params?: EntityAliasesDialogParams; + @state() private _params?: AliasesDialogParams; @state() private _aliases!: string[]; @state() private _submitting = false; - public async showDialog(params: EntityAliasesDialogParams): Promise { + public async showDialog(params: AliasesDialogParams): Promise { this._params = params; this._error = undefined; this._aliases = - this._params.entity.aliases?.length > 0 - ? [...this._params.entity.aliases].sort() + this._params.aliases?.length > 0 + ? [...this._params.aliases].sort() : [""]; await this.updateComplete; } @@ -46,23 +45,17 @@ class DialogEntityAliases extends LitElement { return html``; } - const entityId = this._params.entity.entity_id; - const stateObj = entityId ? this.hass.states[entityId] : undefined; - - const name = (stateObj && computeStateName(stateObj)) || entityId; - return html`
${this._error - ? html`${this._error} ` + ? html`${this._error}` : ""}
${this._aliases.map( @@ -73,7 +66,7 @@ class DialogEntityAliases extends LitElement { .index=${index} class="flex-auto" .label=${this.hass!.localize( - "ui.dialogs.entity_registry.editor.aliases.input_label", + "ui.dialogs.aliases.input_label", { number: index + 1 } )} .value=${alias} @@ -85,7 +78,7 @@ class DialogEntityAliases extends LitElement { .index=${index} slot="navigationIcon" label=${this.hass!.localize( - "ui.dialogs.entity_registry.editor.aliases.remove_alias", + "ui.dialogs.aliases.remove_alias", { number: index + 1 } )} @click=${this._removeAlias} @@ -96,9 +89,7 @@ class DialogEntityAliases extends LitElement { )}
- ${this.hass!.localize( - "ui.dialogs.entity_registry.editor.aliases.add_alias" - )} + ${this.hass!.localize("ui.dialogs.aliases.add_alias")}
@@ -113,12 +104,10 @@ class DialogEntityAliases extends LitElement { - ${this.hass.localize( - "ui.dialogs.entity_registry.editor.aliases.save" - )} + ${this.hass.localize("ui.dialogs.aliases.save")} `; @@ -152,23 +141,18 @@ class DialogEntityAliases extends LitElement { this._aliases = aliases; } - private async _updateEntry(): Promise { + private async _updateAliases(): Promise { this._submitting = true; const noEmptyAliases = this._aliases .map((alias) => alias.trim()) .filter((alias) => alias); try { - await this._params!.updateEntry({ - aliases: noEmptyAliases, - }); + await this._params!.updateAliases(noEmptyAliases); this.closeDialog(); } catch (err: any) { this._error = - err.message || - this.hass.localize( - "ui.dialogs.entity_registry.editor.aliases.unknown_error" - ); + err.message || this.hass.localize("ui.dialogs.aliases.unknown_error"); } finally { this._submitting = false; } @@ -207,6 +191,6 @@ class DialogEntityAliases extends LitElement { declare global { interface HTMLElementTagNameMap { - "dialog-entity-aliases": DialogEntityAliases; + "dialog-aliases": DialogAliases; } } diff --git a/src/dialogs/aliases/show-dialog-aliases.ts b/src/dialogs/aliases/show-dialog-aliases.ts new file mode 100644 index 0000000000..ad820319e6 --- /dev/null +++ b/src/dialogs/aliases/show-dialog-aliases.ts @@ -0,0 +1,20 @@ +import { fireEvent } from "../../common/dom/fire_event"; + +export interface AliasesDialogParams { + name: string; + aliases: string[]; + updateAliases: (aliases: string[]) => Promise; +} + +export const loadAliasesDialog = () => import("./dialog-aliases"); + +export const showAliasesDialog = ( + element: HTMLElement, + aliasesParams: AliasesDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-aliases", + dialogImport: loadAliasesDialog, + dialogParams: aliasesParams, + }); +}; diff --git a/src/panels/config/areas/dialog-area-registry-detail.ts b/src/panels/config/areas/dialog-area-registry-detail.ts index c2fadae31d..5e16de8202 100644 --- a/src/panels/config/areas/dialog-area-registry-detail.ts +++ b/src/panels/config/areas/dialog-area-registry-detail.ts @@ -1,13 +1,17 @@ import "@material/mwc-button"; +import "@material/mwc-list/mwc-list"; +import { mdiPencil } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; -import { createCloseHeading } from "../../../components/ha-dialog"; +import { stringCompare } from "../../../common/string/compare"; import "../../../components/ha-alert"; -import "../../../components/ha-textfield"; +import { createCloseHeading } from "../../../components/ha-dialog"; import "../../../components/ha-picture-upload"; import type { HaPictureUpload } from "../../../components/ha-picture-upload"; +import "../../../components/ha-textfield"; import { AreaRegistryEntryMutableParams } from "../../../data/area_registry"; +import { showAliasesDialog } from "../../../dialogs/aliases/show-dialog-aliases"; import { CropOptions } from "../../../dialogs/image-cropper-dialog/show-image-cropper-dialog"; import { PolymerChangedEvent } from "../../../polymer-types"; import { haStyleDialog } from "../../../resources/styles"; @@ -26,6 +30,8 @@ class DialogAreaDetail extends LitElement { @state() private _name!: string; + @state() private _aliases!: string[]; + @state() private _picture!: string | null; @state() private _error?: string; @@ -40,6 +46,7 @@ class DialogAreaDetail extends LitElement { this._params = params; this._error = undefined; this._name = this._params.entry ? this._params.entry.name : ""; + this._aliases = this._params.entry ? this._params.entry.aliases : []; this._picture = this._params.entry?.picture || null; await this.updateComplete; } @@ -93,6 +100,40 @@ class DialogAreaDetail extends LitElement { .invalid=${nameInvalid} dialogInitialFocus > + +
+ ${this.hass.localize( + "ui.panel.config.areas.editor.aliases_section" + )} +
+ + 0} hasMeta> + + ${this._aliases.length > 0 + ? this.hass.localize( + "ui.panel.config.areas.editor.configured_aliases", + { count: this._aliases.length } + ) + : this.hass.localize( + "ui.panel.config.areas.editor.no_aliases" + )} + + + ${[...this._aliases] + .sort((a, b) => + stringCompare(a, b, this.hass.locale.language) + ) + .join(", ")} + + + + +
+ ${this.hass.localize( + "ui.panel.config.areas.editor.aliases_description" + )} +
+ { + this._aliases = aliases; + }, + }); + } + private _isNameValid() { return this._name.trim() !== ""; } @@ -147,6 +198,7 @@ class DialogAreaDetail extends LitElement { const values: AreaRegistryEntryMutableParams = { name: this._name.trim(), picture: this._picture, + aliases: this._aliases, }; if (this._params!.entry) { await this._params!.updateEntry!(values); diff --git a/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts b/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts index c11ad9c82f..48beb15d12 100644 --- a/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts +++ b/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts @@ -55,7 +55,7 @@ import "../../../../layouts/hass-subpage"; import { buttonLinkStyle, haStyle } from "../../../../resources/styles"; import type { HomeAssistant } from "../../../../types"; import { showToast } from "../../../../util/toast"; -import { showEntityAliasesDialog } from "../../entities/entity-aliases/show-dialog-entity-aliases"; +import { showAliasesDialog } from "../../../../dialogs/aliases/show-dialog-aliases"; const DEFAULT_CONFIG_EXPOSE = true; @@ -422,15 +422,17 @@ class CloudGoogleAssistant extends LitElement { if (!entry) { return; } - showEntityAliasesDialog(this, { - entity: entry, - updateEntry: async (updates) => { - const { entity_entry } = await updateEntityRegistryEntry( - this.hass, - entry.entity_id, - updates - ); - this._entries![entity_entry.entity_id] = entity_entry; + const stateObj = this.hass.states[entityId]; + const name = (stateObj && computeStateName(stateObj)) || entityId; + + showAliasesDialog(this, { + name, + aliases: entry.aliases, + updateAliases: async (aliases: string[]) => { + const result = await updateEntityRegistryEntry(this.hass, entityId, { + aliases, + }); + this._entries![entityId] = result.entity_entry; }, }); } diff --git a/src/panels/config/entities/entity-aliases/show-dialog-entity-aliases.ts b/src/panels/config/entities/entity-aliases/show-dialog-entity-aliases.ts deleted file mode 100644 index 0e9cbd9357..0000000000 --- a/src/panels/config/entities/entity-aliases/show-dialog-entity-aliases.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { fireEvent } from "../../../../common/dom/fire_event"; -import { - EntityRegistryEntryUpdateParams, - ExtEntityRegistryEntry, -} from "../../../../data/entity_registry"; - -export interface EntityAliasesDialogParams { - entity: ExtEntityRegistryEntry; - updateEntry: ( - updates: Partial - ) => Promise; -} - -export const loadEntityAliasesDialog = () => import("./dialog-entity-aliases"); - -export const showEntityAliasesDialog = ( - element: HTMLElement, - entityAliasesParams: EntityAliasesDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-entity-aliases", - dialogImport: loadEntityAliasesDialog, - dialogParams: entityAliasesParams, - }); -}; diff --git a/src/panels/config/entities/entity-registry-basic-editor.ts b/src/panels/config/entities/entity-registry-basic-editor.ts index 680a66bf7b..a7fff4d82b 100644 --- a/src/panels/config/entities/entity-registry-basic-editor.ts +++ b/src/panels/config/entities/entity-registry-basic-editor.ts @@ -7,6 +7,7 @@ import { css, html, LitElement, PropertyValues, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeDomain } from "../../../common/entity/compute_domain"; +import { computeStateName } from "../../../common/entity/compute_state_name"; import { stringCompare } from "../../../common/string/compare"; import "../../../components/ha-area-picker"; import "../../../components/ha-expansion-panel"; @@ -26,7 +27,7 @@ import { import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import type { HomeAssistant } from "../../../types"; -import { showEntityAliasesDialog } from "./entity-aliases/show-dialog-entity-aliases"; +import { showAliasesDialog } from "../../../dialogs/aliases/show-dialog-aliases"; @customElement("ha-registry-basic-editor") export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) { @@ -52,13 +53,18 @@ export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) { private _handleAliasesClicked(ev: CustomEvent) { if (ev.detail.index !== 0) return; - showEntityAliasesDialog(this, { - entity: this.entry!, - updateEntry: async (updates) => { + const stateObj = this.hass.states[this.entry.entity_id]; + const name = + (stateObj && computeStateName(stateObj)) || this.entry.entity_id; + + showAliasesDialog(this, { + name, + aliases: this.entry!.aliases, + updateAliases: async (aliases: string[]) => { const result = await updateEntityRegistryEntry( this.hass, this.entry.entity_id, - updates + { aliases } ); fireEvent(this, "entity-entry-updated", result.entity_entry); }, @@ -296,7 +302,7 @@ export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) {
${this.hass.localize( - "ui.dialogs.entity_registry.editor.aliases.description" + "ui.dialogs.entity_registry.editor.aliases_description" )}
diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts index f6897d1f43..60c1f62dc4 100644 --- a/src/panels/config/entities/entity-registry-settings.ts +++ b/src/panels/config/entities/entity-registry-settings.ts @@ -17,6 +17,7 @@ import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { fireEvent } from "../../../common/dom/fire_event"; import { stopPropagation } from "../../../common/dom/stop_propagation"; import { computeDomain } from "../../../common/entity/compute_domain"; +import { computeStateName } from "../../../common/entity/compute_state_name"; import { domainIcon } from "../../../common/entity/domain_icon"; import { supportsFeature } from "../../../common/entity/supports-feature"; import { stringCompare } from "../../../common/string/compare"; @@ -80,7 +81,7 @@ import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; import { showDeviceRegistryDetailDialog } from "../devices/device-registry-detail/show-dialog-device-registry-detail"; -import { showEntityAliasesDialog } from "./entity-aliases/show-dialog-entity-aliases"; +import { showAliasesDialog } from "../../../dialogs/aliases/show-dialog-aliases"; const OVERRIDE_DEVICE_CLASSES = { cover: [ @@ -861,7 +862,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
${this.hass.localize( - "ui.dialogs.entity_registry.editor.aliases.description" + "ui.dialogs.entity_registry.editor.aliases_description" )}
${this.entry.device_id @@ -1055,13 +1056,19 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { private _handleAliasesClicked(ev: CustomEvent) { if (ev.detail.index !== 0) return; - showEntityAliasesDialog(this, { - entity: this.entry!, - updateEntry: async (updates) => { + + const stateObj = this.hass.states[this.entry.entity_id]; + const name = + (stateObj && computeStateName(stateObj)) || this.entry.entity_id; + + showAliasesDialog(this, { + name, + aliases: this.entry!.aliases, + updateAliases: async (aliases: string[]) => { const result = await updateEntityRegistryEntry( this.hass, this.entry.entity_id, - updates + { aliases } ); fireEvent(this, "entity-entry-updated", result.entity_entry); }, diff --git a/src/translations/en.json b/src/translations/en.json index fc202a9cde..772462f2a2 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1016,19 +1016,19 @@ "aliases_section": "Aliases", "no_aliases": "No configured aliases", "configured_aliases": "{count} configured {count, plural,\n one {alias}\n other {aliases}\n}", - "aliases": { - "heading": "{name} aliases", - "description": "Aliases are alternative names used in voice assistants to refer to this entity.", - "remove_alias": "Remove alias {number}", - "input_label": "Alias {number}", - "save": "Save", - "add_alias": "Add alias", - "no_aliases": "No aliases have been added yet", - "update": "Update", - "unknown_error": "Unknown error" - } + "aliases_description": "Aliases are alternative names used in voice assistants to refer to this entity." } }, + "aliases": { + "heading": "{name} aliases", + "remove_alias": "Remove alias {number}", + "input_label": "Alias {number}", + "save": "Save", + "add_alias": "Add alias", + "no_aliases": "No aliases have been added yet", + "update": "Update", + "unknown_error": "Unknown error" + }, "helper_settings": { "platform_not_loaded": "The {platform} integration is not loaded. Please add it to your configuration either by adding 'default_config:' or ''{platform}:''.", "yaml_not_editable": "The settings of this entity cannot be edited from the UI. Only entities set up from the UI are configurable from the UI.", @@ -1435,7 +1435,11 @@ "area_id": "Area ID", "unknown_error": "Unknown error", "linked_entities_caption": "Entities", - "no_linked_entities": "There are no entities linked to this area." + "no_linked_entities": "There are no entities linked to this area.", + "aliases_section": "Aliases", + "no_aliases": "No configured aliases", + "configured_aliases": "{count} configured {count, plural,\n one {alias}\n other {aliases}\n}", + "aliases_description": "Aliases are alternative names used in voice assistants to refer to this area." }, "delete": { "confirmation_title": "Delete {name}?",