diff --git a/demo/src/ha-demo.ts b/demo/src/ha-demo.ts index 37a707952a..070fea8b44 100644 --- a/demo/src/ha-demo.ts +++ b/demo/src/ha-demo.ts @@ -71,7 +71,6 @@ class HaDemo extends HomeAssistantAppEl { entity_category: null, has_entity_name: false, unique_id: "co2_intensity", - aliases: [], }, { config_entry_id: "co2signal", @@ -87,7 +86,6 @@ class HaDemo extends HomeAssistantAppEl { entity_category: null, has_entity_name: false, unique_id: "grid_fossil_fuel_percentage", - aliases: [], }, ]); diff --git a/gallery/src/pages/misc/integration-card.ts b/gallery/src/pages/misc/integration-card.ts index 8bd6acf6c8..56de4308e8 100644 --- a/gallery/src/pages/misc/integration-card.ts +++ b/gallery/src/pages/misc/integration-card.ts @@ -197,7 +197,6 @@ const createEntityRegistryEntries = ( platform: "updater", has_entity_name: false, unique_id: "updater", - aliases: [], }, ]; diff --git a/pyproject.toml b/pyproject.toml index 5095848ad9..776a80fa6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20221230.0" +version = "20230102.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/components/entity/state-info.ts b/src/components/entity/state-info.ts index 7ee6c6ba39..9db1bae9f7 100644 --- a/src/components/entity/state-info.ts +++ b/src/components/entity/state-info.ts @@ -28,7 +28,7 @@ class StateInfo extends LitElement { const name = computeStateName(this.stateObj); - return html` ${super.renderHeading()} `; } + protected firstUpdated(): void { + super.firstUpdated(); + this.suppressDefaultPressSelector = [ + this.suppressDefaultPressSelector, + SUPPRESS_DEFAULT_PRESS_SELECTOR, + ].join(", "); + } + static override styles = [ styles, css` diff --git a/src/components/ha-form/ha-form-integer.ts b/src/components/ha-form/ha-form-integer.ts index f09821e3d7..86de2d310c 100644 --- a/src/components/ha-form/ha-form-integer.ts +++ b/src/components/ha-form/ha-form-integer.ts @@ -67,6 +67,9 @@ export class HaFormInteger extends LitElement implements HaFormElement { @change=${this._valueChanged} > + ${this.helper + ? html`${this.helper}` + : ""} `; } diff --git a/src/data/entity_registry.ts b/src/data/entity_registry.ts index c402f2afd7..e75bba06ff 100644 --- a/src/data/entity_registry.ts +++ b/src/data/entity_registry.ts @@ -22,7 +22,6 @@ export interface EntityRegistryEntry { original_name?: string; unique_id: string; translation_key?: string; - aliases: string[]; } export interface ExtEntityRegistryEntry extends EntityRegistryEntry { @@ -30,6 +29,7 @@ export interface ExtEntityRegistryEntry extends EntityRegistryEntry { original_icon?: string; device_class?: string; original_device_class?: string; + aliases: string[]; } export interface UpdateEntityRegistryEntryResult { diff --git a/src/panels/calendar/ha-recurrence-rule-editor.ts b/src/panels/calendar/ha-recurrence-rule-editor.ts index d2965e0284..5d8af6c2a9 100644 --- a/src/panels/calendar/ha-recurrence-rule-editor.ts +++ b/src/panels/calendar/ha-recurrence-rule-editor.ts @@ -6,6 +6,7 @@ import type { Options, WeekdayStr } from "rrule"; import { ByWeekday, RRule, Weekday } from "rrule"; import { firstWeekdayIndex } from "../../common/datetime/first_weekday"; import { stopPropagation } from "../../common/dom/stop_propagation"; +import { LocalizeKeys } from "../../common/translations/localize"; import "../../components/ha-chip"; import "../../components/ha-list-item"; import "../../components/ha-select"; @@ -19,12 +20,10 @@ import { getWeekday, getWeekdays, getMonthlyRepeatItems, - intervalSuffix, RepeatEnd, RepeatFrequency, ruleByWeekDay, untilValue, - WEEKDAY_NAME, MonthlyRepeatItem, getMonthlyRepeatWeekdayFromRule, getMonthdayRepeatFromRule, @@ -174,18 +173,36 @@ export class RecurrenceRuleEditor extends LitElement { return html` - None - Yearly - Monthly - Weekly - Daily + + ${this.hass.localize("ui.components.calendar.event.repeat.freq.none")} + + + ${this.hass.localize( + "ui.components.calendar.event.repeat.freq.yearly" + )} + + + ${this.hass.localize( + "ui.components.calendar.event.repeat.freq.monthly" + )} + + + ${this.hass.localize( + "ui.components.calendar.event.repeat.freq.weekly" + )} + + + ${this.hass.localize( + "ui.components.calendar.event.repeat.freq.daily" + )} + `; } @@ -196,7 +213,9 @@ export class RecurrenceRuleEditor extends LitElement { ${this._monthlyRepeatItems.length > 0 ? html`${WEEKDAY_NAME[item]}${this.hass.localize( + `ui.components.calendar.event.repeat.weekly.weekday.${ + item.toLowerCase() as Lowercase + }` + )} ` )} @@ -241,11 +264,16 @@ export class RecurrenceRuleEditor extends LitElement { return html` `; @@ -255,26 +283,38 @@ export class RecurrenceRuleEditor extends LitElement { return html` - Never - After - On + + ${this.hass.localize("ui.components.calendar.event.repeat.end.never")} + + + ${this.hass.localize("ui.components.calendar.event.repeat.end.after")} + + + ${this.hass.localize("ui.components.calendar.event.repeat.end.on")} + ${this._end === "after" ? html` ` @@ -283,7 +323,9 @@ export class RecurrenceRuleEditor extends LitElement { ? html` - ${entity.interfaces - .filter((ifc) => !IGNORE_INTERFACES.includes(ifc)) - .map((ifc) => ifc.replace(/(Alexa.|Controller)/g, "")) - .join(", ")} + ${entity.entity_id in this.hass.entities + ? html`` + : ""} ${!emptyFilter ? html`${iconButton}` @@ -323,23 +329,33 @@ class CloudAlexa extends SubscribeMixin(LitElement) { if (changedProps.has("cloudStatus")) { this._entityConfigs = this.cloudStatus.prefs.alexa_entity_configs; } + if ( + changedProps.has("hass") && + changedProps.get("hass")?.entities !== this.hass.entities + ) { + const categories = {}; + + for (const entry of Object.values(this.hass.entities)) { + categories[entry.entity_id] = entry.entity_category; + } + + this._entityCategories = categories; + } } - protected override hassSubscribe(): ( - | UnsubscribeFunc - | Promise - )[] { - return [ - subscribeEntityRegistry(this.hass.connection, (entries) => { - const categories = {}; - - for (const entry of entries) { - categories[entry.entity_id] = entry.entity_category; - } - - this._entityCategories = categories; - }), - ]; + private async _openAliasesSettings(ev) { + ev.stopPropagation(); + const entityId = ev.target.entityId; + const entry = await getExtendedEntityRegistryEntry(this.hass, entityId); + if (!entry) { + return; + } + showEntityAliasesDialog(this, { + entity: entry, + updateEntry: async (updates) => { + await updateEntityRegistryEntry(this.hass, entry.entity_id, updates); + }, + }); } private async _fetchData() { 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 75d14227cc..92bf480175 100644 --- a/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts +++ b/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts @@ -9,7 +9,6 @@ import { mdiFormatListChecks, mdiSync, } from "@mdi/js"; -import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; @@ -41,7 +40,8 @@ import { } from "../../../../data/cloud"; import { EntityRegistryEntry, - subscribeEntityRegistry, + getExtendedEntityRegistryEntry, + updateEntityRegistryEntry, } from "../../../../data/entity_registry"; import { fetchCloudGoogleEntities, @@ -51,15 +51,15 @@ import { showDomainTogglerDialog } from "../../../../dialogs/domain-toggler/show import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box"; import "../../../../layouts/hass-loading-screen"; import "../../../../layouts/hass-subpage"; -import { SubscribeMixin } from "../../../../mixins/subscribe-mixin"; -import { haStyle } from "../../../../resources/styles"; +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"; const DEFAULT_CONFIG_EXPOSE = true; @customElement("cloud-google-assistant") -class CloudGoogleAssistant extends SubscribeMixin(LitElement) { +class CloudGoogleAssistant extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @property() public cloudStatus!: CloudStatusLoggedIn; @@ -174,15 +174,23 @@ class CloudGoogleAssistant extends SubscribeMixin(LitElement) { secondary-line @click=${this._showMoreInfo} > - ${entity.traits - .map((trait) => trait.substr(trait.lastIndexOf(".") + 1)) - .join(", ")} + ${entity.entity_id in this.hass.entities + ? html`` + : ""} ${!emptyFilter ? html`${iconButton}` : html` ${iconButton} @@ -308,7 +316,7 @@ class CloudGoogleAssistant extends SubscribeMixin(LitElement) { ${!this.narrow ? this.hass!.localize( - "ui.panel.config.cloud.alexa.exposed", + "ui.panel.config.cloud.google.exposed", "selected", selected ) @@ -329,7 +337,7 @@ class CloudGoogleAssistant extends SubscribeMixin(LitElement) { ${!this.narrow ? this.hass!.localize( - "ui.panel.config.cloud.alexa.not_exposed", + "ui.panel.config.cloud.google.not_exposed", "selected", this._entities.length - selected ) @@ -354,23 +362,33 @@ class CloudGoogleAssistant extends SubscribeMixin(LitElement) { if (changedProps.has("cloudStatus")) { this._entityConfigs = this.cloudStatus.prefs.google_entity_configs; } + if ( + changedProps.has("hass") && + changedProps.get("hass")?.entities !== this.hass.entities + ) { + const categories = {}; + + for (const entry of Object.values(this.hass.entities)) { + categories[entry.entity_id] = entry.entity_category; + } + + this._entityCategories = categories; + } } - protected override hassSubscribe(): ( - | UnsubscribeFunc - | Promise - )[] { - return [ - subscribeEntityRegistry(this.hass.connection, (entries) => { - const categories = {}; - - for (const entry of entries) { - categories[entry.entity_id] = entry.entity_category; - } - - this._entityCategories = categories; - }), - ]; + private async _openAliasesSettings(ev) { + ev.stopPropagation(); + const entityId = ev.target.entityId; + const entry = await getExtendedEntityRegistryEntry(this.hass, entityId); + if (!entry) { + return; + } + showEntityAliasesDialog(this, { + entity: entry, + updateEntry: async (updates) => { + await updateEntityRegistryEntry(this.hass, entry.entity_id, updates); + }, + }); } private _configIsDomainExposed( @@ -583,6 +601,7 @@ class CloudGoogleAssistant extends SubscribeMixin(LitElement) { static get styles(): CSSResultGroup { return [ haStyle, + buttonLinkStyle, css` mwc-list-item > [slot="meta"] { margin-left: 4px; diff --git a/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts b/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts index 0ad83b15df..59b6471cc4 100644 --- a/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts +++ b/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts @@ -57,7 +57,13 @@ export class EntityRegistrySettingsHelper extends LitElement { super.updated(changedProperties); if (changedProperties.has("entry")) { this._error = undefined; - this._item = undefined; + if ( + this.entry.unique_id !== + (changedProperties.get("entry") as ExtEntityRegistryEntry)?.unique_id + ) { + this._item = undefined; + } + this._getItem(); } } diff --git a/src/panels/config/entities/entity-aliases/dialog-entity-aliases.ts b/src/panels/config/entities/entity-aliases/dialog-entity-aliases.ts index 29e3e012cc..9859bcf602 100644 --- a/src/panels/config/entities/entity-aliases/dialog-entity-aliases.ts +++ b/src/panels/config/entities/entity-aliases/dialog-entity-aliases.ts @@ -72,16 +72,21 @@ class DialogEntityAliases extends LitElement { dialogInitialFocus=${index} .index=${index} class="flex-auto" - label="Alias" + .label=${this.hass!.localize( + "ui.dialogs.entity_registry.editor.aliases.input_label", + { number: index + 1 } + )} .value=${alias} ?data-last=${index === this._aliases.length - 1} - @change=${this._editAlias} + @input=${this._editAlias} + @keydown=${this._keyDownAlias} > ) => Promise; diff --git a/src/panels/config/entities/entity-registry-basic-editor.ts b/src/panels/config/entities/entity-registry-basic-editor.ts index 3d915e2db4..946e3bf90a 100644 --- a/src/panels/config/entities/entity-registry-basic-editor.ts +++ b/src/panels/config/entities/entity-registry-basic-editor.ts @@ -1,7 +1,11 @@ import "@material/mwc-formfield/mwc-formfield"; +import "@material/mwc-list/mwc-list"; +import "@material/mwc-list/mwc-list-item"; +import { mdiPencil } from "@mdi/js"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; 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 "../../../components/ha-area-picker"; import "../../../components/ha-expansion-panel"; @@ -21,6 +25,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"; @customElement("ha-registry-basic-editor") export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) { @@ -44,6 +49,21 @@ export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) { @state() private _submitting = false; + private _handleAliasesClicked(ev: CustomEvent) { + if (ev.detail.index !== 0) return; + showEntityAliasesDialog(this, { + entity: this.entry!, + updateEntry: async (updates) => { + const result = await updateEntityRegistryEntry( + this.hass, + this.entry.entity_id, + updates + ); + fireEvent(this, "entity-entry-updated", result.entity_entry); + }, + }); + } + public async updateEntry(): Promise { this._submitting = true; const params: Partial = { @@ -247,6 +267,33 @@ export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) { ` : ""} + +
+ ${this.hass.localize( + "ui.dialogs.entity_registry.editor.aliases_section" + )} +
+ + 0} hasMeta> + + ${this.entry.aliases.length > 0 + ? this.hass.localize( + "ui.dialogs.entity_registry.editor.configured_aliases", + { count: this.entry.aliases.length } + ) + : this.hass.localize( + "ui.dialogs.entity_registry.editor.no_aliases" + )} + + ${this.entry.aliases.join(", ")} + + + +
+ ${this.hass.localize( + "ui.dialogs.entity_registry.editor.aliases.description" + )} +
`; } @@ -300,6 +347,13 @@ export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) { .label { margin-top: 16px; } + .aliases { + border-radius: 4px; + margin-top: 4px; + margin-bottom: 4px; + --mdc-icon-button-size: 24px; + overflow: hidden; + } `; } } diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts index 72f80712fe..5a318ff9ed 100644 --- a/src/panels/config/entities/entity-registry-settings.ts +++ b/src/panels/config/entities/entity-registry-settings.ts @@ -119,6 +119,42 @@ const OVERRIDE_NUMBER_UNITS = { const OVERRIDE_SENSOR_UNITS = { current: ["A", "mA"], + data_rate: [ + "bit/s", + "kbit/s", + "Mbit/s", + "Gbit/s", + "B/s", + "kB/s", + "MB/s", + "GB/s", + "KiB/s", + "MiB/s", + "GiB/s", + ], + data_size: [ + "bit", + "kbit", + "Mbit", + "Gbit", + "B", + "kB", + "MB", + "GB", + "TB", + "PB", + "EB", + "ZB", + "YB", + "KiB", + "MiB", + "GiB", + "TiB", + "PiB", + "EiB", + "ZiB", + "YiB", + ], distance: ["cm", "ft", "in", "km", "m", "mi", "mm", "yd"], gas: ["CCF", "ft³", "m³"], precipitation: ["cm", "in", "mm"], @@ -771,12 +807,8 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { "ui.dialogs.entity_registry.editor.aliases_section" )} - - 0} - hasMeta - @click=${this._openAliasesSettings} - > + + 0} hasMeta> ${this.entry.aliases.length > 0 ? this.hass.localize( @@ -979,7 +1011,8 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { }); } - private _openAliasesSettings() { + private _handleAliasesClicked(ev: CustomEvent) { + if (ev.detail.index !== 0) return; showEntityAliasesDialog(this, { entity: this.entry!, updateEntry: async (updates) => { diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index cafff74d14..5fb9d6bf9c 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -728,7 +728,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { selectable: false, entity_category: null, has_entity_name: false, - aliases: [], }); } if (changed) { diff --git a/src/panels/config/script/ha-script-trace.ts b/src/panels/config/script/ha-script-trace.ts index ae001665ca..a8addf7bd8 100644 --- a/src/panels/config/script/ha-script-trace.ts +++ b/src/panels/config/script/ha-script-trace.ts @@ -527,15 +527,10 @@ export class HaScriptTrace extends LitElement { :host([narrow]) .graph { max-width: 100%; } - .info { flex: 1; background-color: var(--card-background-color); } - - .linkButton { - color: var(--primary-text-color); - } .trace-link { text-decoration: none; } diff --git a/src/translations/en.json b/src/translations/en.json index f0b5e00104..df3e8b1c90 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -644,6 +644,33 @@ "monthly": "months", "weekly": "weeks", "daily": "days" + }, + "monthly": { + "label": "Repeat Monthly" + }, + "weekly": { + "weekday": { + "su": "Sun", + "mo": "Mon", + "tu": "Tue", + "we": "Wed", + "th": "Thu", + "fr": "Fri", + "sa": "Sat" + } + }, + "end": { + "label": "End", + "never": "Never", + "after": "After", + "on": "On" + }, + "end_on": { + "label": "End On" + }, + "end_after": { + "label": "End After", + "ocurrences": "ocurrences" } }, "rrule": { @@ -976,7 +1003,8 @@ "aliases": { "heading": "{name} aliases", "description": "Aliases are alternative names used in voice assistants to refer to this entity.", - "remove_alias": "Remove alias", + "remove_alias": "Remove alias {number}", + "input_label": "Alias {number}", "save": "Save", "add_alias": "Add alias", "no_aliases": "No aliases have been added yet", @@ -2634,7 +2662,7 @@ "enable_state_reporting": "Enable State Reporting", "info_state_reporting": "If you enable state reporting, Home Assistant will send all state changes of exposed entities to Amazon. This allows you to always see the latest states in the Alexa app and use the state changes to create routines.", "state_reporting_error": "Unable to {enable_disable} report state.", - "manage_entities": "Manage Entities", + "manage_entities": "[%key:ui::panel::config::cloud::account::google::manage_entities%]", "enable": "enable", "disable": "disable", "not_configured_title": "Alexa is not activated", @@ -2685,6 +2713,7 @@ "follow_domain": "[%key:ui::panel::config::cloud::google::follow_domain%]", "exposed": "[%key:ui::panel::config::cloud::google::exposed%]", "not_exposed": "[%key:ui::panel::config::cloud::google::not_exposed%]", + "manage_aliases": "[%key:ui::panel::config::cloud::google::manage_aliases%]", "expose": "Expose to Alexa", "sync_entities": "Synchronize entities", "sync_entities_error": "Failed to sync entities:" @@ -2710,6 +2739,7 @@ "follow_domain": "Follow domain", "exposed": "{selected} exposed", "not_exposed": "{selected} not exposed", + "manage_aliases": "Manage aliases", "sync_to_google": "Synchronizing changes to Google.", "sync_entities": "Synchronize entities", "sync_entities_error": "Failed to sync entities:",