diff --git a/pyproject.toml b/pyproject.toml index 8966ef67eb..1f2a5dc343 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20230502.0" +version = "20230503.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/components/ha-language-picker.ts b/src/components/ha-language-picker.ts index ac8a11579d..618709c980 100644 --- a/src/components/ha-language-picker.ts +++ b/src/components/ha-language-picker.ts @@ -68,10 +68,24 @@ export class HaLanguagePicker extends LitElement { if (nativeName) { const translations = this.hass.translationMetadata.translations; - options = languages.map((lang) => ({ - value: lang, - label: translations[lang]?.nativeName ?? lang, - })); + options = languages.map((lang) => { + let label = translations[lang]?.nativeName; + if (!label) { + try { + // this will not work if Intl.DisplayNames is polyfilled, it will return in the language of the user + label = new Intl.DisplayNames(lang, { + type: "language", + fallback: "code", + }).of(lang)!; + } catch (err) { + label = lang; + } + } + return { + value: lang, + label, + }; + }); } else { options = languages.map((lang) => ({ value: lang, diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts index 12a13a6cc5..bea76ba7b8 100644 --- a/src/panels/config/integrations/ha-integration-card.ts +++ b/src/panels/config/integrations/ha-integration-card.ts @@ -1003,7 +1003,7 @@ export class HaIntegrationCard extends LitElement { @media (min-width: 563px) { ha-card.group { position: relative; - min-height: 195px; + min-height: 200px; } mwc-list { position: absolute; diff --git a/src/panels/config/voice-assistants/assist-pref.ts b/src/panels/config/voice-assistants/assist-pref.ts index f16d13d11d..47149da4dd 100644 --- a/src/panels/config/voice-assistants/assist-pref.ts +++ b/src/panels/config/voice-assistants/assist-pref.ts @@ -51,8 +51,10 @@ export class AssistPref extends LitElement { private _exposedEntitiesCount = memoizeOne( (exposedEntities: Record) => - Object.values(exposedEntities).filter((expose) => expose.conversation) - .length + Object.entries(exposedEntities).filter( + ([entityId, expose]) => + expose.conversation && entityId in this.hass.states + ).length ); protected render() { diff --git a/src/panels/config/voice-assistants/cloud-alexa-pref.ts b/src/panels/config/voice-assistants/cloud-alexa-pref.ts index a071eba07f..4f4eeef1cf 100644 --- a/src/panels/config/voice-assistants/cloud-alexa-pref.ts +++ b/src/panels/config/voice-assistants/cloud-alexa-pref.ts @@ -33,8 +33,10 @@ export class CloudAlexaPref extends LitElement { private _exposedEntitiesCount = memoizeOne( (exposedEntities: Record) => - Object.values(exposedEntities).filter((expose) => expose["cloud.alexa"]) - .length + Object.entries(exposedEntities).filter( + ([entityId, expose]) => + expose["cloud.alexa"] && entityId in this.hass.states + ).length ); protected willUpdate() { diff --git a/src/panels/config/voice-assistants/cloud-google-pref.ts b/src/panels/config/voice-assistants/cloud-google-pref.ts index 409319ffc9..ebdcdef163 100644 --- a/src/panels/config/voice-assistants/cloud-google-pref.ts +++ b/src/panels/config/voice-assistants/cloud-google-pref.ts @@ -45,8 +45,9 @@ export class CloudGooglePref extends LitElement { private _exposedEntitiesCount = memoizeOne( (exposedEntities: Record) => - Object.values(exposedEntities).filter( - (expose) => expose["cloud.google_assistant"] + Object.entries(exposedEntities).filter( + ([entityId, expose]) => + expose["cloud.google_assistant"] && entityId in this.hass.states ).length ); diff --git a/src/panels/config/voice-assistants/dialog-expose-entity.ts b/src/panels/config/voice-assistants/dialog-expose-entity.ts index 2f41470b49..17c56b2b85 100644 --- a/src/panels/config/voice-assistants/dialog-expose-entity.ts +++ b/src/panels/config/voice-assistants/dialog-expose-entity.ts @@ -176,7 +176,17 @@ class DialogExposeEntity extends LitElement { lit-virtualizer { height: 500px; } - @media all and (max-width: 500px), all and (max-height: 800px) { + @media all and (max-height: 800px) { + lit-virtualizer { + height: 334px; + } + } + @media all and (max-height: 600px) { + lit-virtualizer { + height: 238px; + } + } + @media all and (max-width: 500px), all and (max-height: 500px) { ha-dialog { --mdc-dialog-min-width: calc( 100vw - env(safe-area-inset-right) - env(safe-area-inset-left) diff --git a/src/panels/config/voice-assistants/dialog-voice-settings.ts b/src/panels/config/voice-assistants/dialog-voice-settings.ts index 1e3aac8da0..361b595390 100644 --- a/src/panels/config/voice-assistants/dialog-voice-settings.ts +++ b/src/panels/config/voice-assistants/dialog-voice-settings.ts @@ -1,9 +1,10 @@ import "@material/mwc-button/mwc-button"; +import { mdiClose, mdiTuneVertical } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, nothing } 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 { createCloseHeading } from "../../../components/ha-dialog"; +import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog"; import { haStyle, haStyleDialog } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import "./entity-voice-settings"; @@ -24,22 +25,41 @@ class DialogVoiceSettings extends LitElement { fireEvent(this, "dialog-closed", { dialog: this.localName }); } + private _viewMoreInfo(): void { + showMoreInfoDialog(this, { + entityId: this._params!.entityId, + }); + this.closeDialog(); + } + protected render() { if (!this._params) { return nothing; } + const title = + computeStateName(this.hass.states[this._params.entityId]) || + this.hass.localize("ui.panel.config.entities.picker.unnamed_entity"); + return html` - + + + +
${title}
+ +
({ + ( + narrow: boolean, + availableAssistants: string[], + supportedEntities: + | Record< + "cloud.google_assistant" | "cloud.alexa" | "conversation", + string[] | undefined + > + | undefined, + _language: string + ): DataTableColumnContainer => ({ icon: { title: "", type: "icon", @@ -166,8 +176,8 @@ export class VoiceAssistantsExpose extends LitElement { template: (assistants, entry) => html`${availableAssistants.map((key) => { const supported = - !this._supportedEntities?.[key] || - this._supportedEntities[key].includes(entry.entity_id); + !supportedEntities?.[key] || + supportedEntities[key].includes(entry.entity_id); const manual = entry.manAssistants?.includes(key); return assistants.includes(key) ? html` @@ -450,6 +460,10 @@ export class VoiceAssistantsExpose extends LitElement { this.hass, Object.keys(this._entities) ); + this._fetchSupportedEntities(); + } + + private async _fetchSupportedEntities() { let alexaEntitiesProm: Promise | undefined; let googleEntitiesProm: Promise | undefined; if (this.cloudStatus?.logged_in && this.cloudStatus.prefs.alexa_enabled) { @@ -467,7 +481,7 @@ export class VoiceAssistantsExpose extends LitElement { "cloud.google_assistant": googleEntities?.map( (entity) => entity.entity_id ), - // TODO add supported entity for assit + // TODO add supported entity for assist conversation: undefined, }; } @@ -475,6 +489,14 @@ export class VoiceAssistantsExpose extends LitElement { public willUpdate(changedProperties: PropertyValues): void { if (changedProperties.has("_entities")) { this._fetchEntities(); + return; + } + if ( + changedProperties.has("hass") && + this.hass.config.state === "RUNNING" && + changedProperties.get("hass")?.config.state !== this.hass.config.state + ) { + this._fetchSupportedEntities(); } } @@ -505,6 +527,7 @@ export class VoiceAssistantsExpose extends LitElement { .columns=${this._columns( this.narrow, this._availableAssistants(this.cloudStatus), + this._supportedEntities, this.hass.language )} .data=${filteredEntities} diff --git a/src/translations/en.json b/src/translations/en.json index 6bdbb08f21..aef348483a 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1088,7 +1088,8 @@ "aliases_no_unique_id": "Aliases are not supported for entities without an unique id. See the {faq_link} for more detail.", "ask_pin": "Ask for PIN", "manual_config": "Managed in configuration.yaml", - "unsupported": "Unsupported" + "unsupported": "Unsupported", + "view_entity": "More info about entity" }, "restart": { "heading": "Restart Home Assistant", @@ -2838,7 +2839,7 @@ "access_is_being_prepared": "Remote control is being prepared. We will notify you when it's ready.", "cerificate_loading": "Your certificate is loading.", "cerificate_loaded": "Your certificate is loaded, waiting for validation.", - "cerificate_error": "There was an error generating the certficate, check your logs.", + "cerificate_error": "There was an error generating the certificate, check your logs.", "info": "Home Assistant Cloud provides a secure remote connection to your instance while away from home.", "instance_is_available": "Your instance is available at your", "instance_will_be_available": "Your instance will be available at your", @@ -2863,19 +2864,19 @@ "not_configured_text": "Before you can use Alexa, you need to activate the Home Assistant skill for Alexa in the Alexa app.", "link_learn_how_it_works": "[%key:ui::panel::config::cloud::account::remote::link_learn_how_it_works%]", "expose_new_entities": "[%key:ui::panel::config::cloud::account::google::expose_new_entities%]", - "expose_new_entities_info": "Should new entities, that are supported and have no security risks be exposed to Alexa automatically?" + "expose_new_entities_info": "Should new entities be exposed to Alexa automatically? Exposes supported devices that are not classified as security devices." }, "google": { "title": "Google Assistant", - "info": "With the Google Assistant integration for Home Assistant Cloud you'll be able to control all your Home Assistant devices via any Google Assistant-enabled device.", + "info": "With the Google Assistant integration for Home Assistant Cloud, you'll be able to control all your Home Assistant devices via any Google Assistant-enabled device.", "http_use_ssl_warning_title": "Local communication unavailable", - "http_use_ssl_warning_text": "Google devices will not be able to talk locally with Home Assistant because you have configured an SSL certificate for your HTTP integration.", + "http_use_ssl_warning_text": "Google devices will not be able to talk locally with Home Assistant, because you have configured an SSL certificate for your HTTP integration.", "enable_ha_skill": "Activate the Home Assistant Cloud skill for Google Assistant", "config_documentation": "Configuration documentation", - "enable_state_reporting": "Enable State Reporting", + "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 Google. This speeds up voice commands and allows you to always see the latest states in the Google app.", - "security_devices": "Security Devices", - "enter_pin_info": "Please enter a PIN to interact with security devices. Security devices are doors, garage doors and locks. You will be asked to say/enter this PIN when interacting with such devices via Google Assistant.", + "security_devices": "Security devices", + "enter_pin_info": "Please enter a PIN to interact with security devices. Security devices are doors, garage doors, and locks. You will be asked to say/enter this PIN when interacting with security devices via Google Assistant.", "devices_pin": "Security Devices PIN", "enter_pin_hint": "Enter a PIN to use security devices", "show_entities": "Show Entities", @@ -2886,7 +2887,7 @@ "not_configured_text": "Before you can use Google Assistant, you need to activate the Home Assistant Cloud skill for Google Assistant in the Google Home app.", "link_learn_how_it_works": "[%key:ui::panel::config::cloud::account::remote::link_learn_how_it_works%]", "expose_new_entities": "Expose new entities", - "expose_new_entities_info": "Should new entities, that are supported and have no security risks be exposed to Google Assistant automatically?" + "expose_new_entities_info": "Should new entities be exposed to Google Assistant automatically? Exposes supported devices that are not classified as security devices." }, "webhooks": { "title": "Webhooks",