From b076301513fd16d9af5730a3cf4769dd404b6b20 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Tue, 11 Apr 2023 14:32:18 +0200
Subject: [PATCH 001/112] Add sample rate to assist pipeline debug (#16135)
---
src/data/voice_assistant.ts | 15 +++++++++++----
.../assist/assist-pipeline-debug.ts | 3 +++
.../assist/assist-render-pipeline-run.ts | 5 +++--
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/data/voice_assistant.ts b/src/data/voice_assistant.ts
index 9b5ae8f65d..5500effdf7 100644
--- a/src/data/voice_assistant.ts
+++ b/src/data/voice_assistant.ts
@@ -84,14 +84,21 @@ type PipelineRunEvent =
| PipelineTTSStartEvent
| PipelineTTSEndEvent;
-export interface PipelineRunOptions {
- start_stage: "stt" | "intent" | "tts";
+export type PipelineRunOptions = (
+ | {
+ start_stage: "intent" | "tts";
+ input: { text: string };
+ }
+ | {
+ start_stage: "stt";
+ input: { sample_rate: number };
+ }
+) & {
end_stage: "stt" | "intent" | "tts";
language?: string;
pipeline?: string;
- input?: { text: string };
conversation_id?: string | null;
-}
+};
export interface PipelineRun {
init_options: PipelineRunOptions;
diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
index 49906ad2a9..8defe120d5 100644
--- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
+++ b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
@@ -255,6 +255,9 @@ export class AssistPipelineDebug extends LitElement {
{
start_stage: "stt",
end_stage: "tts",
+ input: {
+ sample_rate: context.sampleRate,
+ },
}
);
}
diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts
index 596b7f7560..0238395bbc 100644
--- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts
+++ b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts
@@ -135,8 +135,9 @@ export class AssistPipelineDebug extends LitElement {
const messages: Array<{ from: string; text: string }> = [];
const userMessage =
- this.pipelineRun.init_options.input?.text ||
- this.pipelineRun?.stt?.stt_output?.text;
+ ("text" in this.pipelineRun.init_options.input
+ ? this.pipelineRun.init_options.input.text
+ : undefined) || this.pipelineRun?.stt?.stt_output?.text;
if (userMessage) {
messages.push({
From deb53eb1806166f0deb56bb959cb31abacdb81df Mon Sep 17 00:00:00 2001
From: akston <169469+akston@users.noreply.github.com>
Date: Tue, 11 Apr 2023 09:08:29 -0400
Subject: [PATCH 002/112] Fix cropped person image transparency (#16112)
---
src/panels/config/person/dialog-person-detail.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/panels/config/person/dialog-person-detail.ts b/src/panels/config/person/dialog-person-detail.ts
index 5b35fb18d6..88c627c808 100644
--- a/src/panels/config/person/dialog-person-detail.ts
+++ b/src/panels/config/person/dialog-person-detail.ts
@@ -33,7 +33,6 @@ const includeDomains = ["device_tracker"];
const cropOptions: CropOptions = {
round: true,
- type: "image/jpeg",
quality: 0.75,
aspectRatio: 1,
};
From 6a5568ad4f1bb79487a500d7505f0a9f96591636 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Tue, 11 Apr 2023 15:16:47 +0200
Subject: [PATCH 003/112] Optimize app entrypoint (#16048)
* Optimize app entrypoint
* review
* remove legacy support
---
src/components/ha-drawer.ts | 37 ++++++++++++++++---------------
src/entrypoints/app.ts | 1 -
src/layouts/ha-init-page.ts | 20 ++++++++---------
src/layouts/hass-router-page.ts | 4 ++--
src/layouts/home-assistant.ts | 4 ++--
src/resources/hammer.ts | 6 +++++
src/util/legacy-support.js | 39 ---------------------------------
7 files changed, 39 insertions(+), 72 deletions(-)
create mode 100644 src/resources/hammer.ts
delete mode 100644 src/util/legacy-support.js
diff --git a/src/components/ha-drawer.ts b/src/components/ha-drawer.ts
index 5fcfd031c6..62930305d3 100644
--- a/src/components/ha-drawer.ts
+++ b/src/components/ha-drawer.ts
@@ -1,9 +1,3 @@
-import {
- DIRECTION_LEFT,
- DIRECTION_RIGHT,
- Manager,
- Swipe,
-} from "@egjs/hammerjs";
import { DrawerBase } from "@material/mwc-drawer/mwc-drawer-base";
import { styles } from "@material/mwc-drawer/mwc-drawer.css";
import { css, PropertyValues } from "lit";
@@ -40,24 +34,31 @@ export class HaDrawer extends DrawerBase {
this.mdcRoot.dir = this.direction;
}
if (changedProps.has("open") && this.open && this.type === "modal") {
- this._mc = new Manager(document, {
- touchAction: "pan-y",
- });
- this._mc.add(
- new Swipe({
- direction:
- this.direction === "rtl" ? DIRECTION_RIGHT : DIRECTION_LEFT,
- })
- );
- this._mc.on("swipeleft swiperight", () => {
- fireEvent(this, "hass-toggle-menu", { open: false });
- });
+ this._setupSwipe();
} else if (this._mc) {
this._mc.destroy();
this._mc = undefined;
}
}
+ private async _setupSwipe() {
+ const hammer = await import("../resources/hammer");
+ this._mc = new hammer.Manager(document, {
+ touchAction: "pan-y",
+ });
+ this._mc.add(
+ new hammer.Swipe({
+ direction:
+ this.direction === "rtl"
+ ? hammer.DIRECTION_RIGHT
+ : hammer.DIRECTION_LEFT,
+ })
+ );
+ this._mc.on("swipeleft swiperight", () => {
+ fireEvent(this, "hass-toggle-menu", { open: false });
+ });
+ }
+
static override styles = [
styles,
css`
diff --git a/src/entrypoints/app.ts b/src/entrypoints/app.ts
index f7f607720b..458fc850c2 100644
--- a/src/entrypoints/app.ts
+++ b/src/entrypoints/app.ts
@@ -6,7 +6,6 @@ import "@webcomponents/scoped-custom-element-registry/scoped-custom-element-regi
import "../layouts/home-assistant";
import "../resources/ha-style";
import "../resources/roboto";
-import "../util/legacy-support";
setPassiveTouchGestures(true);
setCancelSyntheticClickEvents(false);
diff --git a/src/layouts/ha-init-page.ts b/src/layouts/ha-init-page.ts
index 42df3b8d69..4d815bcfdd 100644
--- a/src/layouts/ha-init-page.ts
+++ b/src/layouts/ha-init-page.ts
@@ -1,12 +1,9 @@
-import "@material/mwc-button";
-import { css, CSSResultGroup, html, LitElement } from "lit";
+import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
import { property, state } from "lit/decorators";
class HaInitPage extends LitElement {
@property({ type: Boolean }) public error = false;
- @state() private _showProgressIndicator = false;
-
@state() private _retryInSeconds = 60;
private _showProgressIndicatorTimeout?: NodeJS.Timeout;
@@ -36,9 +33,7 @@ class HaInitPage extends LitElement {
`
: html`
- ${this._showProgressIndicator
- ? html` `
- : ""}
+
Loading data
`;
@@ -54,10 +49,15 @@ class HaInitPage extends LitElement {
}
}
+ protected willUpdate(changedProperties: PropertyValues) {
+ if (changedProperties.has("error") && this.error) {
+ import("@material/mwc-button");
+ }
+ }
+
protected firstUpdated() {
- this._showProgressIndicatorTimeout = setTimeout(async () => {
- await import("../components/ha-circular-progress");
- this._showProgressIndicator = true;
+ this._showProgressIndicatorTimeout = setTimeout(() => {
+ import("../components/ha-circular-progress");
}, 5000);
this._retryInterval = setInterval(() => {
diff --git a/src/layouts/hass-router-page.ts b/src/layouts/hass-router-page.ts
index 6fb01e521f..cf3aca4f78 100644
--- a/src/layouts/hass-router-page.ts
+++ b/src/layouts/hass-router-page.ts
@@ -3,8 +3,6 @@ import { property } from "lit/decorators";
import memoizeOne from "memoize-one";
import { navigate } from "../common/navigate";
import { Route } from "../types";
-import "./hass-error-screen";
-import "./hass-loading-screen";
const extractPage = (path: string, defaultPage: string) => {
if (path === "") {
@@ -256,10 +254,12 @@ export class HassRouterPage extends ReactiveElement {
}
protected createLoadingScreen() {
+ import("./hass-loading-screen");
return document.createElement("hass-loading-screen");
}
protected createErrorScreen(error: string) {
+ import("./hass-error-screen");
const errorEl = document.createElement("hass-error-screen");
errorEl.error = error;
return errorEl;
diff --git a/src/layouts/home-assistant.ts b/src/layouts/home-assistant.ts
index bcd99b762d..0e72bbd868 100644
--- a/src/layouts/home-assistant.ts
+++ b/src/layouts/home-assistant.ts
@@ -65,7 +65,7 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
`;
}
- update(changedProps) {
+ update(changedProps: PropertyValues) {
if (this.hass?.states && this.hass.config && this.hass.services) {
this.render = this.renderHass;
this.update = super.update;
@@ -74,7 +74,7 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
super.update(changedProps);
}
- protected firstUpdated(changedProps) {
+ protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this._initializeHass();
setTimeout(() => registerServiceWorker(this), 1000);
diff --git a/src/resources/hammer.ts b/src/resources/hammer.ts
new file mode 100644
index 0000000000..b7165f3361
--- /dev/null
+++ b/src/resources/hammer.ts
@@ -0,0 +1,6 @@
+export {
+ DIRECTION_LEFT,
+ DIRECTION_RIGHT,
+ Manager,
+ Swipe,
+} from "@egjs/hammerjs";
diff --git a/src/util/legacy-support.js b/src/util/legacy-support.js
deleted file mode 100644
index 869ecbb4f7..0000000000
--- a/src/util/legacy-support.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Provide legacy support to HTML imports by exposing Polymer and
- * Polymer.Element on the window object.
- */
-/* eslint-plugin-disable lit */
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-import { Polymer } from "@polymer/polymer/polymer-legacy";
-
-const message =
- "WARNING: Polymer will be removed from window in Home Assistant 2023.5. More info: https://developers.home-assistant.io/blog/2023/04/04/deprecating_polymer";
-
-const handler = {
- get(target, prop, receiver) {
- // eslint-disable-next-line no-console
- console.warn(message);
- document
- .querySelector("home-assistant")
- .dispatchEvent(
- new CustomEvent("write_log", { detail: { message, level: "warning" } })
- );
- return Reflect.get(target, prop, receiver);
- },
- apply: function (target, thisArg, argumentsList) {
- // eslint-disable-next-line no-console
- console.warn(message);
- document
- .querySelector("home-assistant")
- .dispatchEvent(
- new CustomEvent("write_log", { detail: { message, level: "warning" } })
- );
- return Reflect.apply(target, thisArg, argumentsList);
- },
-};
-
-Polymer.Element = PolymerElement;
-Polymer.html = html;
-
-window.Polymer = new Proxy(Polymer, handler);
From 49a14a7265f2233ab234abdf9e3a61e722d88f75 Mon Sep 17 00:00:00 2001
From: "J. Nick Koston"
Date: Tue, 11 Apr 2023 22:00:03 -1000
Subject: [PATCH 004/112] Avoid fetching unused stats state column for more
info (#16141)
---
src/dialogs/more-info/ha-more-info-history.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/dialogs/more-info/ha-more-info-history.ts b/src/dialogs/more-info/ha-more-info-history.ts
index f9e14f6338..464d0a0e09 100644
--- a/src/dialogs/more-info/ha-more-info-history.ts
+++ b/src/dialogs/more-info/ha-more-info-history.ts
@@ -27,7 +27,7 @@ declare global {
}
}
-const statTypes: StatisticsTypes = ["state", "min", "mean", "max"];
+const statTypes: StatisticsTypes = ["min", "mean", "max"];
@customElement("ha-more-info-history")
export class MoreInfoHistory extends LitElement {
From a5edb4caafa0f513095fb75b80bd45391c6f9ae2 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Wed, 12 Apr 2023 14:07:54 +0200
Subject: [PATCH 005/112] Prevent edit and move view button triggered in the
same time (#16143)
---
src/panels/lovelace/hui-root.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts
index 1797c30fae..a5fb2ded57 100644
--- a/src/panels/lovelace/hui-root.ts
+++ b/src/panels/lovelace/hui-root.ts
@@ -868,6 +868,7 @@ class HUIRoot extends LitElement {
}
private _handleViewSelected(ev) {
+ ev.preventDefault();
const viewIndex = ev.detail.selected as number;
if (viewIndex !== this._curView) {
From 442f73b8c586210fa38994f3c51bcfb549747a08 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Wed, 12 Apr 2023 18:33:40 +0200
Subject: [PATCH 006/112] Add initial expose UI (#16138)
Co-authored-by: Paul Bottein
---
hassio/src/addon-store/hassio-addon-store.ts | 2 +-
src/components/data-table/ha-data-table.ts | 11 +-
src/components/ha-aliases-editor.ts | 129 ++++
src/data/cloud.ts | 40 +-
src/data/google_assistant.ts | 9 +
src/data/voice.ts | 45 ++
src/dialogs/aliases/dialog-aliases.ts | 77 +-
.../domain-toggler/dialog-domain-toggler.ts | 117 ---
.../show-dialog-domain-toggler.ts | 23 -
.../ha-more-info-view-voice-assistants.ts | 49 ++
.../voice/show-view-voice-assistants.ts | 16 +
src/dialogs/more-info/ha-more-info-dialog.ts | 7 +-
.../config/blueprint/ha-blueprint-overview.ts | 2 +-
.../config/cloud/account/cloud-account.ts | 21 +-
.../config/cloud/account/cloud-alexa-pref.ts | 203 -----
.../config/cloud/account/cloud-google-pref.ts | 274 -------
src/panels/config/cloud/alexa/cloud-alexa.ts | 569 --------------
.../cloud-google-assistant.ts | 727 ------------------
src/panels/config/cloud/ha-config-cloud.ts | 8 -
.../core/ha-config-system-navigation.ts | 4 -
.../entities/entity-registry-settings.ts | 75 +-
src/panels/config/ha-panel-config.ts | 15 +
.../config/lovelace/ha-config-lovelace.ts | 3 +-
.../voice-assistants/cloud-alexa-pref.ts | 272 +++++++
.../voice-assistants/cloud-google-pref.ts | 352 +++++++++
.../voice-assistants/dialog-expose-entity.ts | 218 ++++++
.../voice-assistants/dialog-voice-settings.ts | 82 ++
.../voice-assistants/entity-voice-settings.ts | 327 ++++++++
.../ha-config-voice-assistants-assistants.ts | 111 +++
.../ha-config-voice-assistants-expose.ts | 710 +++++++++++++++++
.../ha-config-voice-assistants.ts | 29 +-
.../show-dialog-expose-entity.ts | 21 +
.../show-dialog-voice-settings.ts | 18 +
src/panels/my/ha-panel-my.ts | 3 +
src/translations/en.json | 100 ++-
35 files changed, 2514 insertions(+), 2155 deletions(-)
create mode 100644 src/components/ha-aliases-editor.ts
create mode 100644 src/data/voice.ts
delete mode 100644 src/dialogs/domain-toggler/dialog-domain-toggler.ts
delete mode 100644 src/dialogs/domain-toggler/show-dialog-domain-toggler.ts
create mode 100644 src/dialogs/more-info/components/voice/ha-more-info-view-voice-assistants.ts
create mode 100644 src/dialogs/more-info/components/voice/show-view-voice-assistants.ts
delete mode 100644 src/panels/config/cloud/account/cloud-alexa-pref.ts
delete mode 100644 src/panels/config/cloud/account/cloud-google-pref.ts
delete mode 100644 src/panels/config/cloud/alexa/cloud-alexa.ts
delete mode 100644 src/panels/config/cloud/google-assistant/cloud-google-assistant.ts
create mode 100644 src/panels/config/voice-assistants/cloud-alexa-pref.ts
create mode 100644 src/panels/config/voice-assistants/cloud-google-pref.ts
create mode 100644 src/panels/config/voice-assistants/dialog-expose-entity.ts
create mode 100644 src/panels/config/voice-assistants/dialog-voice-settings.ts
create mode 100644 src/panels/config/voice-assistants/entity-voice-settings.ts
create mode 100644 src/panels/config/voice-assistants/ha-config-voice-assistants-assistants.ts
create mode 100644 src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts
create mode 100644 src/panels/config/voice-assistants/show-dialog-expose-entity.ts
create mode 100644 src/panels/config/voice-assistants/show-dialog-voice-settings.ts
diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts
index ab434eb8ca..f6fdb1d6cb 100644
--- a/hassio/src/addon-store/hassio-addon-store.ts
+++ b/hassio/src/addon-store/hassio-addon-store.ts
@@ -216,7 +216,7 @@ export class HassioAddonStore extends LitElement {
});
}
- private async _filterChanged(e) {
+ private _filterChanged(e) {
this._filter = e.detail.value;
}
diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts
index f83244a3e4..518e554e4a 100644
--- a/src/components/data-table/ha-data-table.ts
+++ b/src/components/data-table/ha-data-table.ts
@@ -73,7 +73,7 @@ export interface DataTableColumnData extends DataTableSortColumnData {
main?: boolean;
title: TemplateResult | string;
label?: TemplateResult | string;
- type?: "numeric" | "icon" | "icon-button" | "overflow-menu";
+ type?: "numeric" | "icon" | "icon-button" | "overflow-menu" | "flex";
template?: (data: any, row: T) => TemplateResult | string | typeof nothing;
width?: string;
maxWidth?: string;
@@ -359,10 +359,10 @@ export class HaDataTable extends LitElement {
return nothing;
}
if (row.append) {
- return html` ${row.content}
`;
+ return html`${row.content}
`;
}
if (row.empty) {
- return html`
`;
+ return html`
`;
}
return html`
html`
+
+
+
+
+ `
+ )}
+
+
+ ${this.hass!.localize("ui.dialogs.aliases.add_alias")}
+
+
+
+ `;
+ }
+
+ private async _addAlias() {
+ this.aliases = [...this.aliases, ""];
+ this._fireChanged(this.aliases);
+ await this.updateComplete;
+ const field = this.shadowRoot?.querySelector(`ha-textfield[data-last]`) as
+ | HaTextField
+ | undefined;
+ field?.focus();
+ }
+
+ private async _editAlias(ev: Event) {
+ const index = (ev.target as any).index;
+ const aliases = [...this.aliases];
+ aliases[index] = (ev.target as any).value;
+ this._fireChanged(aliases);
+ }
+
+ private async _keyDownAlias(ev: KeyboardEvent) {
+ if (ev.key === "Enter") {
+ ev.stopPropagation();
+ this._addAlias();
+ }
+ }
+
+ private async _removeAlias(ev: Event) {
+ const index = (ev.target as any).index;
+ const aliases = [...this.aliases];
+ aliases.splice(index, 1);
+ this._fireChanged(aliases);
+ }
+
+ private _fireChanged(value) {
+ fireEvent(this, "value-changed", { value });
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ haStyle,
+ css`
+ .row {
+ margin-bottom: 8px;
+ }
+ ha-textfield {
+ display: block;
+ }
+ ha-icon-button {
+ display: block;
+ }
+ mwc-button {
+ margin-left: 8px;
+ }
+ #alias_input {
+ margin-top: 8px;
+ }
+ .alias {
+ border: 1px solid var(--divider-color);
+ border-radius: 4px;
+ margin-top: 4px;
+ --mdc-icon-button-size: 24px;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-aliases-editor": AliasesEditor;
+ }
+}
diff --git a/src/data/cloud.ts b/src/data/cloud.ts
index 58a747ffd0..353a5601a7 100644
--- a/src/data/cloud.ts
+++ b/src/data/cloud.ts
@@ -9,15 +9,6 @@ interface CloudStatusNotLoggedIn {
http_use_ssl: boolean;
}
-export interface GoogleEntityConfig {
- should_expose?: boolean | null;
- disable_2fa?: boolean;
-}
-
-export interface AlexaEntityConfig {
- should_expose?: boolean | null;
-}
-
export interface CertificateInformation {
common_name: string;
expire_date: string;
@@ -30,14 +21,6 @@ export interface CloudPreferences {
remote_enabled: boolean;
google_secure_devices_pin: string | undefined;
cloudhooks: { [webhookId: string]: CloudWebhook };
- google_default_expose: string[] | null;
- google_entity_configs: {
- [entityId: string]: GoogleEntityConfig;
- };
- alexa_default_expose: string[] | null;
- alexa_entity_configs: {
- [entityId: string]: AlexaEntityConfig;
- };
alexa_report_state: boolean;
google_report_state: boolean;
tts_default_voice: [string, string];
@@ -150,10 +133,8 @@ export const updateCloudPref = (
prefs: {
google_enabled?: CloudPreferences["google_enabled"];
alexa_enabled?: CloudPreferences["alexa_enabled"];
- alexa_default_expose?: CloudPreferences["alexa_default_expose"];
alexa_report_state?: CloudPreferences["alexa_report_state"];
google_report_state?: CloudPreferences["google_report_state"];
- google_default_expose?: CloudPreferences["google_default_expose"];
google_secure_devices_pin?: CloudPreferences["google_secure_devices_pin"];
tts_default_voice?: CloudPreferences["tts_default_voice"];
}
@@ -165,25 +146,14 @@ export const updateCloudPref = (
export const updateCloudGoogleEntityConfig = (
hass: HomeAssistant,
- entityId: string,
- values: GoogleEntityConfig
+ entity_id: string,
+ disable_2fa: boolean
) =>
- hass.callWS
({
+ hass.callWS({
type: "cloud/google_assistant/entities/update",
- entity_id: entityId,
- ...values,
+ entity_id,
+ disable_2fa,
});
export const cloudSyncGoogleAssistant = (hass: HomeAssistant) =>
hass.callApi("POST", "cloud/google_actions/sync");
-
-export const updateCloudAlexaEntityConfig = (
- hass: HomeAssistant,
- entityId: string,
- values: AlexaEntityConfig
-) =>
- hass.callWS({
- type: "cloud/alexa/entities/update",
- entity_id: entityId,
- ...values,
- });
diff --git a/src/data/google_assistant.ts b/src/data/google_assistant.ts
index 2665be90b3..1381e697ed 100644
--- a/src/data/google_assistant.ts
+++ b/src/data/google_assistant.ts
@@ -9,5 +9,14 @@ export interface GoogleEntity {
export const fetchCloudGoogleEntities = (hass: HomeAssistant) =>
hass.callWS({ type: "cloud/google_assistant/entities" });
+export const fetchCloudGoogleEntity = (
+ hass: HomeAssistant,
+ entity_id: string
+) =>
+ hass.callWS({
+ type: "cloud/google_assistant/entities/get",
+ entity_id,
+ });
+
export const syncCloudGoogleEntities = (hass: HomeAssistant) =>
hass.callApi("POST", "cloud/google_actions/sync");
diff --git a/src/data/voice.ts b/src/data/voice.ts
new file mode 100644
index 0000000000..e2d12bdf49
--- /dev/null
+++ b/src/data/voice.ts
@@ -0,0 +1,45 @@
+import { HomeAssistant } from "../types";
+
+export const voiceAssistants = {
+ conversation: { domain: "conversation", name: "Assist" },
+ "cloud.alexa": {
+ domain: "alexa",
+ name: "Amazon Alexa",
+ },
+ "cloud.google_assistant": {
+ domain: "google_assistant",
+ name: "Google Assistant",
+ },
+} as const;
+
+export const voiceAssistantKeys = Object.keys(voiceAssistants);
+
+export const setExposeNewEntities = (
+ hass: HomeAssistant,
+ assistant: string,
+ expose_new: boolean
+) =>
+ hass.callWS({
+ type: "homeassistant/expose_new_entities/set",
+ assistant,
+ expose_new,
+ });
+
+export const getExposeNewEntities = (hass: HomeAssistant, assistant: string) =>
+ hass.callWS<{ expose_new: boolean }>({
+ type: "homeassistant/expose_new_entities/get",
+ assistant,
+ });
+
+export const exposeEntities = (
+ hass: HomeAssistant,
+ assistants: string[],
+ entity_ids: string[],
+ should_expose: boolean
+) =>
+ hass.callWS({
+ type: "homeassistant/expose_entity",
+ assistants,
+ entity_ids,
+ should_expose,
+ });
diff --git a/src/dialogs/aliases/dialog-aliases.ts b/src/dialogs/aliases/dialog-aliases.ts
index 27e94660ec..e2fe281b5e 100644
--- a/src/dialogs/aliases/dialog-aliases.ts
+++ b/src/dialogs/aliases/dialog-aliases.ts
@@ -1,16 +1,13 @@
import "@material/mwc-button/mwc-button";
-import { mdiDeleteOutline, mdiPlus } from "@mdi/js";
-import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
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";
+import "../../components/ha-aliases-editor";
@customElement("dialog-aliases")
class DialogAliases extends LitElement {
@@ -57,43 +54,11 @@ class DialogAliases extends LitElement {
${this._error
? html`${this._error} `
: ""}
-
+
{
diff --git a/src/dialogs/domain-toggler/dialog-domain-toggler.ts b/src/dialogs/domain-toggler/dialog-domain-toggler.ts
deleted file mode 100644
index 3b168d4002..0000000000
--- a/src/dialogs/domain-toggler/dialog-domain-toggler.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-import "@material/mwc-button/mwc-button";
-import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
-import { customElement, state } from "lit/decorators";
-import { fireEvent } from "../../common/dom/fire_event";
-import { createCloseHeading } from "../../components/ha-dialog";
-import "../../components/ha-formfield";
-import "../../components/ha-switch";
-import { domainToName } from "../../data/integration";
-import { haStyleDialog } from "../../resources/styles";
-import { HomeAssistant } from "../../types";
-import { HassDialog } from "../make-dialog-manager";
-import { HaDomainTogglerDialogParams } from "./show-dialog-domain-toggler";
-
-@customElement("dialog-domain-toggler")
-class DomainTogglerDialog
- extends LitElement
- implements HassDialog
-{
- public hass!: HomeAssistant;
-
- @state() private _params?: HaDomainTogglerDialogParams;
-
- public showDialog(params: HaDomainTogglerDialogParams): void {
- this._params = params;
- }
-
- public closeDialog() {
- this._params = undefined;
- fireEvent(this, "dialog-closed", { dialog: this.localName });
- }
-
- protected render() {
- if (!this._params) {
- return nothing;
- }
-
- const domains = this._params.domains
- .map((domain) => [domainToName(this.hass.localize, domain), domain])
- .sort();
-
- return html`
-
- ${this._params.description
- ? html`${this._params.description}
`
- : ""}
-
- ${domains.map(
- (domain) =>
- html`
-
-
-
-
-
- ${this.hass.localize(
- "ui.dialogs.domain_toggler.reset_entities"
- )}
-
- `
- )}
-
-
- `;
- }
-
- private _handleSwitch(ev) {
- this._params!.toggleDomain(ev.currentTarget.domain, ev.target.checked);
- ev.currentTarget.blur();
- }
-
- private _handleReset(ev) {
- this._params!.resetDomain(ev.currentTarget.domain);
- ev.currentTarget.blur();
- }
-
- static get styles(): CSSResultGroup {
- return [
- haStyleDialog,
- css`
- ha-dialog {
- --mdc-dialog-max-width: 500px;
- }
- .description {
- margin-bottom: 8px;
- }
- .domains {
- display: grid;
- grid-template-columns: auto auto;
- grid-row-gap: 8px;
- align-items: center;
- }
- `,
- ];
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "dialog-domain-toggler": DomainTogglerDialog;
- }
-}
diff --git a/src/dialogs/domain-toggler/show-dialog-domain-toggler.ts b/src/dialogs/domain-toggler/show-dialog-domain-toggler.ts
deleted file mode 100644
index 18426ba68e..0000000000
--- a/src/dialogs/domain-toggler/show-dialog-domain-toggler.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { fireEvent } from "../../common/dom/fire_event";
-
-export interface HaDomainTogglerDialogParams {
- title?: string;
- description?: string;
- domains: string[];
- exposedDomains: string[] | null;
- toggleDomain: (domain: string, turnOn: boolean) => void;
- resetDomain: (domain: string) => void;
-}
-
-export const loadDomainTogglerDialog = () => import("./dialog-domain-toggler");
-
-export const showDomainTogglerDialog = (
- element: HTMLElement,
- dialogParams: HaDomainTogglerDialogParams
-): void => {
- fireEvent(element, "show-dialog", {
- dialogTag: "dialog-domain-toggler",
- dialogImport: loadDomainTogglerDialog,
- dialogParams,
- });
-};
diff --git a/src/dialogs/more-info/components/voice/ha-more-info-view-voice-assistants.ts b/src/dialogs/more-info/components/voice/ha-more-info-view-voice-assistants.ts
new file mode 100644
index 0000000000..f43b7fc14e
--- /dev/null
+++ b/src/dialogs/more-info/components/voice/ha-more-info-view-voice-assistants.ts
@@ -0,0 +1,49 @@
+import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { customElement, property } from "lit/decorators";
+import { ExtEntityRegistryEntry } from "../../../../data/entity_registry";
+import "../../../../panels/config/voice-assistants/entity-voice-settings";
+import { HomeAssistant } from "../../../../types";
+
+@customElement("ha-more-info-view-voice-assistants")
+class MoreInfoViewVoiceAssistants extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ attribute: false }) public entry!: ExtEntityRegistryEntry;
+
+ @property() public params?;
+
+ protected render() {
+ if (!this.params) {
+ return nothing;
+ }
+ return html` `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ css`
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+ .content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 24px;
+ flex: 1;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-more-info-view-voice-assistants": MoreInfoViewVoiceAssistants;
+ }
+}
diff --git a/src/dialogs/more-info/components/voice/show-view-voice-assistants.ts b/src/dialogs/more-info/components/voice/show-view-voice-assistants.ts
new file mode 100644
index 0000000000..010bf20088
--- /dev/null
+++ b/src/dialogs/more-info/components/voice/show-view-voice-assistants.ts
@@ -0,0 +1,16 @@
+import { fireEvent } from "../../../../common/dom/fire_event";
+
+export const loadVoiceAssistantsView = () =>
+ import("./ha-more-info-view-voice-assistants");
+
+export const showVoiceAssistantsView = (
+ element: HTMLElement,
+ title: string
+): void => {
+ fireEvent(element, "show-child-view", {
+ viewTag: "ha-more-info-view-voice-assistants",
+ viewImport: loadVoiceAssistantsView,
+ viewTitle: title,
+ viewParams: {},
+ });
+};
diff --git a/src/dialogs/more-info/ha-more-info-dialog.ts b/src/dialogs/more-info/ha-more-info-dialog.ts
index 3bcc18b883..984136adb5 100644
--- a/src/dialogs/more-info/ha-more-info-dialog.ts
+++ b/src/dialogs/more-info/ha-more-info-dialog.ts
@@ -181,10 +181,10 @@ export class MoreInfoDialog extends LitElement {
this.setView("settings");
}
- private async _showChildView(ev: CustomEvent): Promise {
+ private _showChildView(ev: CustomEvent): void {
const view = ev.detail as ChildView;
if (view.viewImport) {
- await view.viewImport();
+ view.viewImport();
}
this._childView = view;
}
@@ -369,12 +369,14 @@ export class MoreInfoDialog extends LitElement {
tabindex="-1"
dialogInitialFocus
@show-child-view=${this._showChildView}
+ @entity-entry-updated=${this._entryUpdated}
>
${this._childView
? html`
${dynamicElement(this._childView.viewTag, {
hass: this.hass,
+ entry: this._entry,
params: this._childView.viewParams,
})}
@@ -401,7 +403,6 @@ export class MoreInfoDialog extends LitElement {
.hass=${this.hass}
.entityId=${this._entityId}
.entry=${this._entry}
- @entity-entry-updated=${this._entryUpdated}
>
`
: this._currView === "related"
diff --git a/src/panels/config/blueprint/ha-blueprint-overview.ts b/src/panels/config/blueprint/ha-blueprint-overview.ts
index 885a06a343..2436d5b039 100644
--- a/src/panels/config/blueprint/ha-blueprint-overview.ts
+++ b/src/panels/config/blueprint/ha-blueprint-overview.ts
@@ -196,7 +196,7 @@ class HaBlueprintOverview extends LitElement {
template: (_, blueprint: any) =>
blueprint.error
? ""
- : html`
-
-
-
+
+
+ ${this.hass.localize(
+ "ui.panel.config.cloud.account.tip_moved_voice_assistants"
+ )}
+
+
-
-
-
- ${this.hass!.localize("ui.panel.config.cloud.account.alexa.info")}
-
- ${!alexa_enabled
- ? ""
- : !alexa_registered
- ? html`
-
- ${this.hass.localize(
- "ui.panel.config.cloud.account.alexa.not_configured_text"
- )}
-
-
-
- `
- : html`
-
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.account.alexa.enable_state_reporting"
- )}
-
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.account.alexa.info_state_reporting"
- )}
-
-
-
- `}
-
-
-
- `;
- }
-
- private async _enabledToggleChanged(ev) {
- const toggle = ev.target as HaSwitch;
- try {
- await updateCloudPref(this.hass!, { alexa_enabled: toggle.checked! });
- fireEvent(this, "ha-refresh-cloud-status");
- } catch (err: any) {
- toggle.checked = !toggle.checked;
- }
- }
-
- private async _reportToggleChanged(ev) {
- const toggle = ev.target as HaSwitch;
- try {
- await updateCloudPref(this.hass!, {
- alexa_report_state: toggle.checked!,
- });
- fireEvent(this, "ha-refresh-cloud-status");
- } catch (err: any) {
- alert(
- `${this.hass!.localize(
- "ui.panel.config.cloud.account.alexa.state_reporting_error",
- "enable_disable",
- this.hass!.localize(
- toggle.checked
- ? "ui.panel.config.cloud.account.alexa.enable"
- : "ui.panel.config.cloud.account.alexa.disable"
- )
- )} ${err.message}`
- );
- toggle.checked = !toggle.checked;
- }
- }
-
- static get styles(): CSSResultGroup {
- return css`
- a {
- color: var(--primary-color);
- }
- ha-settings-row {
- padding: 0;
- }
- .header-actions {
- position: absolute;
- right: 24px;
- top: 24px;
- display: flex;
- flex-direction: row;
- }
- :host([dir="rtl"]) .header-actions {
- right: auto;
- left: 24px;
- }
- .header-actions .icon-link {
- margin-top: -16px;
- margin-inline-end: 8px;
- margin-right: 8px;
- direction: var(--direction);
- color: var(--secondary-text-color);
- }
- .card-actions {
- display: flex;
- }
- .card-actions a {
- text-decoration: none;
- }
- `;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "cloud-alexa-pref": CloudAlexaPref;
- }
-}
-
-customElements.define("cloud-alexa-pref", CloudAlexaPref);
diff --git a/src/panels/config/cloud/account/cloud-google-pref.ts b/src/panels/config/cloud/account/cloud-google-pref.ts
deleted file mode 100644
index 675e432eb8..0000000000
--- a/src/panels/config/cloud/account/cloud-google-pref.ts
+++ /dev/null
@@ -1,274 +0,0 @@
-import "@material/mwc-button";
-import { mdiHelpCircle } from "@mdi/js";
-import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
-import { property } from "lit/decorators";
-import { fireEvent } from "../../../../common/dom/fire_event";
-import "../../../../components/ha-alert";
-import "../../../../components/ha-card";
-import "../../../../components/ha-settings-row";
-import type { HaSwitch } from "../../../../components/ha-switch";
-import "../../../../components/ha-textfield";
-import type { HaTextField } from "../../../../components/ha-textfield";
-import { CloudStatusLoggedIn, updateCloudPref } from "../../../../data/cloud";
-import type { HomeAssistant } from "../../../../types";
-import { showSaveSuccessToast } from "../../../../util/toast-saved-success";
-
-export class CloudGooglePref extends LitElement {
- @property({ attribute: false }) public hass!: HomeAssistant;
-
- @property({ attribute: false }) public cloudStatus?: CloudStatusLoggedIn;
-
- protected render() {
- if (!this.cloudStatus) {
- return nothing;
- }
-
- const google_registered = this.cloudStatus.google_registered;
- const { google_enabled, google_report_state, google_secure_devices_pin } =
- this.cloudStatus.prefs;
-
- return html`
-
-
-
-
- ${this.hass.localize("ui.panel.config.cloud.account.google.info")}
-
- ${!google_enabled
- ? ""
- : !google_registered
- ? html`
-
- ${this.hass.localize(
- "ui.panel.config.cloud.account.google.not_configured_text"
- )}
-
-
-
- `
- : html`
- ${this.cloudStatus.http_use_ssl
- ? html`
-
- ${this.hass.localize(
- "ui.panel.config.cloud.account.google.http_use_ssl_warning_text"
- )}
- ${this.hass.localize(
- "ui.panel.config.common.learn_more"
- )}
-
- `
- : ""}
-
-
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.account.google.enable_state_reporting"
- )}
-
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.account.google.info_state_reporting"
- )}
-
-
-
-
-
-
- ${this.hass.localize(
- "ui.panel.config.cloud.account.google.security_devices"
- )}
-
-
- ${this.hass.localize(
- "ui.panel.config.cloud.account.google.enter_pin_info"
- )}
-
-
-
-
- `}
-
-
-
- `;
- }
-
- private async _enabledToggleChanged(ev) {
- const toggle = ev.target as HaSwitch;
- try {
- await updateCloudPref(this.hass, { google_enabled: toggle.checked! });
- fireEvent(this, "ha-refresh-cloud-status");
- } catch (err: any) {
- toggle.checked = !toggle.checked;
- }
- }
-
- private async _reportToggleChanged(ev) {
- const toggle = ev.target as HaSwitch;
- try {
- await updateCloudPref(this.hass, {
- google_report_state: toggle.checked!,
- });
- fireEvent(this, "ha-refresh-cloud-status");
- } catch (err: any) {
- alert(
- `Unable to ${toggle.checked ? "enable" : "disable"} report state. ${
- err.message
- }`
- );
- toggle.checked = !toggle.checked;
- }
- }
-
- private async _pinChanged(ev) {
- const input = ev.target as HaTextField;
- try {
- await updateCloudPref(this.hass, {
- [input.id]: input.value || null,
- });
- showSaveSuccessToast(this, this.hass);
- fireEvent(this, "ha-refresh-cloud-status");
- } catch (err: any) {
- alert(
- `${this.hass.localize(
- "ui.panel.config.cloud.account.google.enter_pin_error"
- )} ${err.message}`
- );
- input.value = this.cloudStatus!.prefs.google_secure_devices_pin || "";
- }
- }
-
- static get styles(): CSSResultGroup {
- return css`
- a {
- color: var(--primary-color);
- }
- .header-actions {
- position: absolute;
- right: 24px;
- top: 24px;
- display: flex;
- flex-direction: row;
- }
- :host([dir="rtl"]) .header-actions {
- right: auto;
- left: 24px;
- }
- .header-actions .icon-link {
- margin-top: -16px;
- margin-inline-end: 8px;
- margin-right: 8px;
- direction: var(--direction);
- color: var(--secondary-text-color);
- }
- ha-settings-row {
- padding: 0;
- }
- ha-textfield {
- width: 250px;
- display: block;
- margin-top: 8px;
- }
- .card-actions {
- display: flex;
- }
- .card-actions a {
- text-decoration: none;
- }
- .warning {
- color: var(--error-color);
- }
- `;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "cloud-google-pref": CloudGooglePref;
- }
-}
-
-customElements.define("cloud-google-pref", CloudGooglePref);
diff --git a/src/panels/config/cloud/alexa/cloud-alexa.ts b/src/panels/config/cloud/alexa/cloud-alexa.ts
deleted file mode 100644
index 6c8dbda913..0000000000
--- a/src/panels/config/cloud/alexa/cloud-alexa.ts
+++ /dev/null
@@ -1,569 +0,0 @@
-import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
-import "@material/mwc-list/mwc-list-item";
-import {
- mdiCheckboxMarked,
- mdiCheckboxMultipleMarked,
- mdiCloseBox,
- mdiCloseBoxMultiple,
- mdiDotsVertical,
- mdiFormatListChecks,
- mdiSync,
-} from "@mdi/js";
-import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
-import { customElement, property, state } from "lit/decorators";
-import { classMap } from "lit/directives/class-map";
-import memoizeOne from "memoize-one";
-import { fireEvent } from "../../../../common/dom/fire_event";
-import { computeDomain } from "../../../../common/entity/compute_domain";
-import { computeStateName } from "../../../../common/entity/compute_state_name";
-import {
- EntityFilter,
- generateFilter,
- isEmptyFilter,
-} from "../../../../common/entity/entity_filter";
-import { stringCompare } from "../../../../common/string/compare";
-import "../../../../components/entity/state-info";
-import "../../../../components/ha-button-menu";
-import "../../../../components/ha-card";
-import "../../../../components/ha-formfield";
-import "../../../../components/ha-icon-button";
-import "../../../../components/ha-switch";
-import {
- AlexaEntity,
- fetchCloudAlexaEntities,
- syncCloudAlexaEntities,
-} from "../../../../data/alexa";
-import {
- AlexaEntityConfig,
- CloudPreferences,
- CloudStatusLoggedIn,
- updateCloudAlexaEntityConfig,
- updateCloudPref,
-} from "../../../../data/cloud";
-import { EntityRegistryEntry } from "../../../../data/entity_registry";
-import { showDomainTogglerDialog } from "../../../../dialogs/domain-toggler/show-dialog-domain-toggler";
-import "../../../../layouts/hass-loading-screen";
-import "../../../../layouts/hass-subpage";
-import { haStyle } from "../../../../resources/styles";
-import type { HomeAssistant } from "../../../../types";
-
-const DEFAULT_CONFIG_EXPOSE = true;
-
-@customElement("cloud-alexa")
-class CloudAlexa extends LitElement {
- @property({ attribute: false }) public hass!: HomeAssistant;
-
- @property()
- public cloudStatus!: CloudStatusLoggedIn;
-
- @property({ type: Boolean }) public narrow!: boolean;
-
- @state() private _entities?: AlexaEntity[];
-
- @state() private _syncing = false;
-
- @state()
- private _entityConfigs: CloudPreferences["alexa_entity_configs"] = {};
-
- @state()
- private _entityCategories?: Record<
- string,
- EntityRegistryEntry["entity_category"]
- >;
-
- private _popstateSyncAttached = false;
-
- private _popstateReloadStatusAttached = false;
-
- private _isInitialExposed?: Set;
-
- private _getEntityFilterFunc = memoizeOne((filter: EntityFilter) =>
- generateFilter(
- filter.include_domains,
- filter.include_entities,
- filter.exclude_domains,
- filter.exclude_entities
- )
- );
-
- protected render(): TemplateResult {
- if (this._entities === undefined || this._entityCategories === undefined) {
- return html` `;
- }
- const emptyFilter = isEmptyFilter(this.cloudStatus.alexa_entities);
- const filterFunc = this._getEntityFilterFunc(
- this.cloudStatus.alexa_entities
- );
-
- // We will only generate `isInitialExposed` during first render.
- // On each subsequent render we will use the same set so that cards
- // will not jump around when we change the exposed setting.
- const showInExposed = this._isInitialExposed || new Set();
- const trackExposed = this._isInitialExposed === undefined;
-
- let selected = 0;
-
- // On first render we decide which cards show in which category.
- // That way cards won't jump around when changing values.
- const exposedCards: TemplateResult[] = [];
- const notExposedCards: TemplateResult[] = [];
-
- this._entities.forEach((entity) => {
- const stateObj = this.hass.states[entity.entity_id];
- const config = this._entityConfigs[entity.entity_id] || {
- should_expose: null,
- };
- const isExposed = emptyFilter
- ? this._configIsExposed(
- entity.entity_id,
- config,
- this._entityCategories![entity.entity_id]
- )
- : filterFunc(entity.entity_id);
- const isDomainExposed = emptyFilter
- ? this._configIsDomainExposed(
- entity.entity_id,
- this._entityCategories![entity.entity_id]
- )
- : filterFunc(entity.entity_id);
- if (isExposed) {
- selected++;
-
- if (trackExposed) {
- showInExposed.add(entity.entity_id);
- }
- }
-
- const target = showInExposed.has(entity.entity_id)
- ? exposedCards
- : notExposedCards;
-
- const iconButton = html` `;
-
- target.push(html`
-
-
-
-
-
- ${!emptyFilter
- ? html`${iconButton}`
- : html`
- ${iconButton}
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.alexa.expose_entity"
- )}
-
-
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.alexa.dont_expose_entity"
- )}
-
-
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.alexa.follow_domain"
- )}
-
-
- `}
-
-
-
- `);
- });
-
- if (trackExposed) {
- this._isInitialExposed = showInExposed;
- }
-
- return html`
-
-
-
-
-
- ${this.hass.localize("ui.panel.config.cloud.alexa.manage_defaults")}
-
-
-
-
- ${this.hass.localize("ui.panel.config.cloud.alexa.sync_entities")}
-
-
-
- ${!emptyFilter
- ? html`
-
- ${this.hass!.localize("ui.panel.config.cloud.alexa.banner")}
-
- `
- : ""}
- ${exposedCards.length > 0
- ? html`
-
- ${exposedCards}
- `
- : ""}
- ${notExposedCards.length > 0
- ? html`
-
- ${notExposedCards}
- `
- : ""}
-
- `;
- }
-
- protected firstUpdated(changedProps) {
- super.firstUpdated(changedProps);
- this._fetchData();
- }
-
- protected updated(changedProps) {
- super.updated(changedProps);
- 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;
- }
- }
-
- private async _fetchData() {
- const entities = await fetchCloudAlexaEntities(this.hass);
- entities.sort((a, b) => {
- const stateA = this.hass.states[a.entity_id];
- const stateB = this.hass.states[b.entity_id];
- return stringCompare(
- stateA ? computeStateName(stateA) : a.entity_id,
- stateB ? computeStateName(stateB) : b.entity_id,
- this.hass.locale.language
- );
- });
- this._entities = entities;
- }
-
- private _showMoreInfo(ev) {
- const entityId = ev.currentTarget.stateObj.entity_id;
- fireEvent(this, "hass-more-info", { entityId });
- }
-
- private _configIsDomainExposed(
- entityId: string,
- entityCategory: EntityRegistryEntry["entity_category"] | undefined
- ) {
- const domain = computeDomain(entityId);
- return this.cloudStatus.prefs.alexa_default_expose
- ? !entityCategory &&
- this.cloudStatus.prefs.alexa_default_expose.includes(domain)
- : DEFAULT_CONFIG_EXPOSE;
- }
-
- private _configIsExposed(
- entityId: string,
- config: AlexaEntityConfig,
- entityCategory: EntityRegistryEntry["entity_category"] | undefined
- ) {
- return (
- config.should_expose ??
- this._configIsDomainExposed(entityId, entityCategory)
- );
- }
-
- private async _exposeChanged(ev: CustomEvent) {
- const entityId = (ev.currentTarget as any).entityId;
- let newVal: boolean | null = null;
- switch (ev.detail.index) {
- case 0:
- newVal = true;
- break;
- case 1:
- newVal = false;
- break;
- case 2:
- newVal = null;
- break;
- }
- await this._updateExposed(entityId, newVal);
- }
-
- private async _updateExposed(entityId: string, newExposed: boolean | null) {
- await this._updateConfig(entityId, {
- should_expose: newExposed,
- });
- this._ensureEntitySync();
- }
-
- private async _updateConfig(entityId: string, values: AlexaEntityConfig) {
- const updatedConfig = await updateCloudAlexaEntityConfig(
- this.hass,
- entityId,
- values
- );
- this._entityConfigs = {
- ...this._entityConfigs,
- [entityId]: updatedConfig,
- };
- this._ensureStatusReload();
- }
-
- private _openDomainToggler() {
- showDomainTogglerDialog(this, {
- title: this.hass!.localize("ui.panel.config.cloud.alexa.manage_defaults"),
- description: this.hass!.localize(
- "ui.panel.config.cloud.alexa.manage_defaults_dialog_description"
- ),
- domains: this._entities!.map((entity) =>
- computeDomain(entity.entity_id)
- ).filter((value, idx, self) => self.indexOf(value) === idx),
- exposedDomains: this.cloudStatus.prefs.alexa_default_expose,
- toggleDomain: (domain, expose) => {
- this._updateDomainExposed(domain, expose);
- },
- resetDomain: (domain) => {
- this._entities!.forEach((entity) => {
- if (computeDomain(entity.entity_id) === domain) {
- this._updateExposed(entity.entity_id, null);
- }
- });
- },
- });
- }
-
- private async _handleSync() {
- this._syncing = true;
- try {
- await syncCloudAlexaEntities(this.hass!);
- } catch (err: any) {
- alert(
- `${this.hass!.localize(
- "ui.panel.config.cloud.alexa.sync_entities_error"
- )} ${err.body.message}`
- );
- } finally {
- this._syncing = false;
- }
- }
-
- private async _updateDomainExposed(domain: string, expose: boolean) {
- const defaultExpose =
- this.cloudStatus.prefs.alexa_default_expose ||
- this._entities!.map((entity) => computeDomain(entity.entity_id)).filter(
- (value, idx, self) => self.indexOf(value) === idx
- );
-
- if (
- (expose && defaultExpose.includes(domain)) ||
- (!expose && !defaultExpose.includes(domain))
- ) {
- return;
- }
-
- if (expose) {
- defaultExpose.push(domain);
- } else {
- defaultExpose.splice(defaultExpose.indexOf(domain), 1);
- }
-
- await updateCloudPref(this.hass!, {
- alexa_default_expose: defaultExpose,
- });
- fireEvent(this, "ha-refresh-cloud-status");
- }
-
- private _ensureStatusReload() {
- if (this._popstateReloadStatusAttached) {
- return;
- }
- this._popstateReloadStatusAttached = true;
- // Cache parent because by the time popstate happens,
- // this element is detached
- const parent = this.parentElement!;
- window.addEventListener(
- "popstate",
- () => fireEvent(parent, "ha-refresh-cloud-status"),
- { once: true }
- );
- }
-
- private _ensureEntitySync() {
- if (this._popstateSyncAttached) {
- return;
- }
- this._popstateSyncAttached = true;
- // Cache parent because by the time popstate happens,
- // this element is detached
- window.addEventListener(
- "popstate",
- () => {
- // We don't have anything yet.
- },
- { once: true }
- );
- }
-
- static get styles(): CSSResultGroup {
- return [
- haStyle,
- css`
- mwc-list-item > [slot="meta"] {
- margin-left: 4px;
- }
- .banner {
- color: var(--primary-text-color);
- background-color: var(
- --ha-card-background,
- var(--card-background-color, white)
- );
- padding: 16px 8px;
- text-align: center;
- }
- .content {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
- grid-gap: 8px 8px;
- padding: 8px;
- }
- .card-content {
- padding-bottom: 12px;
- }
- state-info {
- cursor: pointer;
- height: 40px;
- }
- ha-switch {
- padding: 8px 0;
- }
- .top-line {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 16px;
- border-bottom: 1px solid var(--divider-color);
- background: var(--app-header-background-color);
- }
- .header.second {
- border-top: 1px solid var(--divider-color);
- }
- .exposed {
- color: var(--success-color);
- }
- .not-exposed {
- color: var(--error-color);
- }
- @media all and (max-width: 450px) {
- ha-card {
- max-width: 100%;
- }
- }
- `,
- ];
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "cloud-alexa": CloudAlexa;
- }
-}
diff --git a/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts b/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts
deleted file mode 100644
index a2b4dada34..0000000000
--- a/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts
+++ /dev/null
@@ -1,727 +0,0 @@
-import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
-import "@material/mwc-list/mwc-list-item";
-import {
- mdiCheckboxMarked,
- mdiCheckboxMultipleMarked,
- mdiCloseBox,
- mdiCloseBoxMultiple,
- mdiDotsVertical,
- mdiFormatListChecks,
- mdiSync,
-} from "@mdi/js";
-import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
-import { customElement, property, state } from "lit/decorators";
-import { classMap } from "lit/directives/class-map";
-import memoizeOne from "memoize-one";
-import { fireEvent } from "../../../../common/dom/fire_event";
-import { computeDomain } from "../../../../common/entity/compute_domain";
-import { computeStateName } from "../../../../common/entity/compute_state_name";
-import {
- EntityFilter,
- generateFilter,
- isEmptyFilter,
-} from "../../../../common/entity/entity_filter";
-import { stringCompare } from "../../../../common/string/compare";
-import { computeRTLDirection } from "../../../../common/util/compute_rtl";
-import "../../../../components/entity/state-info";
-import "../../../../components/ha-button-menu";
-import "../../../../components/ha-card";
-import "../../../../components/ha-formfield";
-import "../../../../components/ha-icon-button";
-import "../../../../components/ha-switch";
-import type { HaSwitch } from "../../../../components/ha-switch";
-import {
- CloudPreferences,
- CloudStatusLoggedIn,
- cloudSyncGoogleAssistant,
- GoogleEntityConfig,
- updateCloudGoogleEntityConfig,
- updateCloudPref,
-} from "../../../../data/cloud";
-import {
- EntityRegistryEntry,
- ExtEntityRegistryEntry,
- getExtendedEntityRegistryEntries,
- updateEntityRegistryEntry,
-} from "../../../../data/entity_registry";
-import {
- fetchCloudGoogleEntities,
- GoogleEntity,
-} from "../../../../data/google_assistant";
-import { showDomainTogglerDialog } from "../../../../dialogs/domain-toggler/show-dialog-domain-toggler";
-import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
-import "../../../../layouts/hass-loading-screen";
-import "../../../../layouts/hass-subpage";
-import { buttonLinkStyle, haStyle } from "../../../../resources/styles";
-import type { HomeAssistant } from "../../../../types";
-import { showToast } from "../../../../util/toast";
-import { showAliasesDialog } from "../../../../dialogs/aliases/show-dialog-aliases";
-
-const DEFAULT_CONFIG_EXPOSE = true;
-
-@customElement("cloud-google-assistant")
-class CloudGoogleAssistant extends LitElement {
- @property({ attribute: false }) public hass!: HomeAssistant;
-
- @property() public cloudStatus!: CloudStatusLoggedIn;
-
- @property() public narrow!: boolean;
-
- @state() private _entities?: GoogleEntity[];
-
- @state() private _entries?: { [id: string]: ExtEntityRegistryEntry };
-
- @state() private _syncing = false;
-
- @state()
- private _entityConfigs: CloudPreferences["google_entity_configs"] = {};
-
- @state()
- private _entityCategories?: Record<
- string,
- EntityRegistryEntry["entity_category"]
- >;
-
- private _popstateSyncAttached = false;
-
- private _popstateReloadStatusAttached = false;
-
- private _isInitialExposed?: Set;
-
- private _getEntityFilterFunc = memoizeOne((filter: EntityFilter) =>
- generateFilter(
- filter.include_domains,
- filter.include_entities,
- filter.exclude_domains,
- filter.exclude_entities
- )
- );
-
- protected render(): TemplateResult {
- if (this._entities === undefined || this._entityCategories === undefined) {
- return html` `;
- }
- const emptyFilter = isEmptyFilter(this.cloudStatus.google_entities);
- const filterFunc = this._getEntityFilterFunc(
- this.cloudStatus.google_entities
- );
- const dir = computeRTLDirection(this.hass!);
-
- // We will only generate `isInitialExposed` during first render.
- // On each subsequent render we will use the same set so that cards
- // will not jump around when we change the exposed setting.
- const showInExposed = this._isInitialExposed || new Set();
- const trackExposed = this._isInitialExposed === undefined;
-
- let selected = 0;
-
- // On first render we decide which cards show in which category.
- // That way cards won't jump around when changing values.
- const exposedCards: TemplateResult[] = [];
- const notExposedCards: TemplateResult[] = [];
-
- this._entities.forEach((entity) => {
- const stateObj = this.hass.states[entity.entity_id];
- const config = this._entityConfigs[entity.entity_id] || {
- should_expose: null,
- };
- const isExposed = emptyFilter
- ? this._configIsExposed(
- entity.entity_id,
- config,
- this._entityCategories![entity.entity_id]
- )
- : filterFunc(entity.entity_id);
- const isDomainExposed = emptyFilter
- ? this._configIsDomainExposed(
- entity.entity_id,
- this._entityCategories![entity.entity_id]
- )
- : filterFunc(entity.entity_id);
- if (isExposed) {
- selected++;
-
- if (trackExposed) {
- showInExposed.add(entity.entity_id);
- }
- }
-
- const target = showInExposed.has(entity.entity_id)
- ? exposedCards
- : notExposedCards;
-
- const iconButton = html` `;
-
- const aliases = this._entries?.[entity.entity_id]?.aliases;
-
- target.push(html`
-
-
-
-
- ${aliases
- ? html`
-
- ${aliases.length > 0
- ? [...aliases]
- .sort((a, b) =>
- stringCompare(a, b, this.hass.locale.language)
- )
- .join(", ")
- : this.hass.localize(
- "ui.panel.config.cloud.google.no_aliases"
- )}
-
-
-
- ${this.hass.localize(
- `ui.panel.config.cloud.google.${
- aliases.length > 0
- ? "manage_aliases"
- : "add_aliases"
- }`
- )}
-
- `
- : html`
-
- ${this.hass.localize(
- "ui.panel.config.cloud.google.aliases_not_available"
- )}
-
-
-
- ${this.hass.localize(
- "ui.panel.config.cloud.google.aliases_not_available_learn_more"
- )}
-
- `}
-
- ${!emptyFilter
- ? html`${iconButton}`
- : html`
- ${iconButton}
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.google.expose_entity"
- )}
-
-
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.google.dont_expose_entity"
- )}
-
-
-
- ${this.hass!.localize(
- "ui.panel.config.cloud.google.follow_domain"
- )}
-
-
- `}
-
- ${entity.might_2fa
- ? html`
-
-
-
-
-
- `
- : ""}
-
-
- `);
- });
-
- if (trackExposed) {
- this._isInitialExposed = showInExposed;
- }
-
- return html`
-
-
-
-
-
- ${this.hass.localize(
- "ui.panel.config.cloud.google.manage_defaults"
- )}
-
-
-
-
- ${this.hass.localize("ui.panel.config.cloud.google.sync_entities")}
-
-
-
- ${
- !emptyFilter
- ? html`
-
- ${this.hass!.localize("ui.panel.config.cloud.google.banner")}
-
- `
- : ""
- }
- ${
- exposedCards.length > 0
- ? html`
-
- ${exposedCards}
- `
- : ""
- }
- ${
- notExposedCards.length > 0
- ? html`
-
- ${notExposedCards}
- `
- : ""
- }
-
-
- `;
- }
-
- protected firstUpdated(changedProps) {
- super.firstUpdated(changedProps);
- this._fetchData();
- }
-
- protected updated(changedProps) {
- super.updated(changedProps);
- 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;
- }
- }
-
- private async _openAliasesSettings(ev) {
- ev.stopPropagation();
- const entityId = ev.target.entityId;
- const entry = this._entries![entityId];
- if (!entry) {
- return;
- }
- 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;
- },
- });
- }
-
- private _configIsDomainExposed(
- entityId: string,
- entityCategory: EntityRegistryEntry["entity_category"] | undefined
- ) {
- const domain = computeDomain(entityId);
- return this.cloudStatus.prefs.google_default_expose
- ? !entityCategory &&
- this.cloudStatus.prefs.google_default_expose.includes(domain)
- : DEFAULT_CONFIG_EXPOSE;
- }
-
- private _configIsExposed(
- entityId: string,
- config: GoogleEntityConfig,
- entityCategory: EntityRegistryEntry["entity_category"] | undefined
- ) {
- return (
- config.should_expose ??
- this._configIsDomainExposed(entityId, entityCategory)
- );
- }
-
- private async _fetchData() {
- const entities = await fetchCloudGoogleEntities(this.hass);
- this._entries = await getExtendedEntityRegistryEntries(
- this.hass,
- entities
- .filter((ent) => this.hass.entities[ent.entity_id])
- .map((e) => e.entity_id)
- );
-
- entities.sort((a, b) => {
- const stateA = this.hass.states[a.entity_id];
- const stateB = this.hass.states[b.entity_id];
- return stringCompare(
- stateA ? computeStateName(stateA) : a.entity_id,
- stateB ? computeStateName(stateB) : b.entity_id,
- this.hass.locale.language
- );
- });
- this._entities = entities;
- }
-
- private _showMoreInfo(ev) {
- const entityId = ev.currentTarget.stateObj.entity_id;
- fireEvent(this, "hass-more-info", { entityId });
- }
-
- private _showMoreInfoSettings(ev) {
- ev.stopPropagation();
- const entityId = ev.currentTarget.stateObj.entity_id;
- fireEvent(this, "hass-more-info", { entityId, view: "settings" });
- }
-
- private async _exposeChanged(ev: CustomEvent) {
- const entityId = (ev.currentTarget as any).entityId;
- let newVal: boolean | null = null;
- switch (ev.detail.index) {
- case 0:
- newVal = true;
- break;
- case 1:
- newVal = false;
- break;
- case 2:
- newVal = null;
- break;
- }
- await this._updateExposed(entityId, newVal);
- }
-
- private async _updateExposed(entityId: string, newExposed: boolean | null) {
- await this._updateConfig(entityId, {
- should_expose: newExposed,
- });
- if (this.cloudStatus.google_registered) {
- this._ensureEntitySync();
- }
- }
-
- private async _disable2FAChanged(ev: Event) {
- const entityId = (ev.currentTarget as any).entityId;
- const newDisable2FA = (ev.target as HaSwitch).checked;
- const curDisable2FA = Boolean(
- (this._entityConfigs[entityId] || {}).disable_2fa
- );
- if (newDisable2FA === curDisable2FA) {
- return;
- }
- await this._updateConfig(entityId, {
- disable_2fa: newDisable2FA,
- });
- }
-
- private async _updateConfig(entityId: string, values: GoogleEntityConfig) {
- const updatedConfig = await updateCloudGoogleEntityConfig(
- this.hass,
- entityId,
- values
- );
- this._entityConfigs = {
- ...this._entityConfigs,
- [entityId]: updatedConfig,
- };
- this._ensureStatusReload();
- }
-
- private _openDomainToggler() {
- showDomainTogglerDialog(this, {
- title: this.hass!.localize(
- "ui.panel.config.cloud.google.manage_defaults"
- ),
- description: this.hass!.localize(
- "ui.panel.config.cloud.google.manage_defaults_dialog_description"
- ),
- domains: this._entities!.map((entity) =>
- computeDomain(entity.entity_id)
- ).filter((value, idx, self) => self.indexOf(value) === idx),
- exposedDomains: this.cloudStatus.prefs.google_default_expose,
- toggleDomain: (domain, expose) => {
- this._updateDomainExposed(domain, expose);
- },
- resetDomain: (domain) => {
- this._entities!.forEach((entity) => {
- if (computeDomain(entity.entity_id) === domain) {
- this._updateExposed(entity.entity_id, null);
- }
- });
- },
- });
- }
-
- private async _updateDomainExposed(domain: string, expose: boolean) {
- const defaultExpose =
- this.cloudStatus.prefs.google_default_expose ||
- this._entities!.map((entity) => computeDomain(entity.entity_id)).filter(
- (value, idx, self) => self.indexOf(value) === idx
- );
-
- if (
- (expose && defaultExpose.includes(domain)) ||
- (!expose && !defaultExpose.includes(domain))
- ) {
- return;
- }
-
- if (expose) {
- defaultExpose.push(domain);
- } else {
- defaultExpose.splice(defaultExpose.indexOf(domain), 1);
- }
-
- await updateCloudPref(this.hass!, {
- google_default_expose: defaultExpose,
- });
- fireEvent(this, "ha-refresh-cloud-status");
- }
-
- private _ensureStatusReload() {
- if (this._popstateReloadStatusAttached) {
- return;
- }
- this._popstateReloadStatusAttached = true;
- // Cache parent because by the time popstate happens,
- // this element is detached
- const parent = this.parentElement!;
- window.addEventListener(
- "popstate",
- () => fireEvent(parent, "ha-refresh-cloud-status"),
- { once: true }
- );
- }
-
- private async _handleSync() {
- this._syncing = true;
- try {
- await cloudSyncGoogleAssistant(this.hass!);
- } catch (err: any) {
- showAlertDialog(this, {
- title: this.hass.localize(
- `ui.panel.config.cloud.google.${
- err.status_code === 404
- ? "not_configured_title"
- : "sync_failed_title"
- }`
- ),
- text: this.hass.localize(
- `ui.panel.config.cloud.google.${
- err.status_code === 404 ? "not_configured_text" : "sync_failed_text"
- }`
- ),
- });
- fireEvent(this, "ha-refresh-cloud-status");
- } finally {
- this._syncing = false;
- }
- }
-
- private _ensureEntitySync() {
- if (this._popstateSyncAttached) {
- return;
- }
- this._popstateSyncAttached = true;
- // Cache parent because by the time popstate happens,
- // this element is detached
- const parent = this.parentElement!;
- window.addEventListener(
- "popstate",
- () => {
- showToast(parent, {
- message: this.hass!.localize(
- "ui.panel.config.cloud.google.sync_to_google"
- ),
- });
- cloudSyncGoogleAssistant(this.hass);
- },
- { once: true }
- );
- }
-
- static get styles(): CSSResultGroup {
- return [
- haStyle,
- buttonLinkStyle,
- css`
- mwc-list-item > [slot="meta"] {
- margin-left: 4px;
- }
- .banner {
- color: var(--primary-text-color);
- background-color: var(
- --ha-card-background,
- var(--card-background-color, white)
- );
- padding: 16px 8px;
- text-align: center;
- }
- .content {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
- grid-gap: 8px 8px;
- padding: 8px;
- }
- .card-content {
- padding-bottom: 12px;
- }
- state-info {
- cursor: pointer;
- }
- ha-switch {
- padding: 8px 0;
- }
- .top-line {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 16px;
- border-bottom: 1px solid var(--divider-color);
- background: var(--app-header-background-color);
- }
- .header.second {
- border-top: 1px solid var(--divider-color);
- }
- .exposed {
- color: var(--success-color);
- }
- .not-exposed {
- color: var(--error-color);
- }
- @media all and (max-width: 450px) {
- ha-card {
- max-width: 100%;
- }
- }
- `,
- ];
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "cloud-google-assistant": CloudGoogleAssistant;
- }
-}
diff --git a/src/panels/config/cloud/ha-config-cloud.ts b/src/panels/config/cloud/ha-config-cloud.ts
index 8fe5c0a085..e5ccd56148 100644
--- a/src/panels/config/cloud/ha-config-cloud.ts
+++ b/src/panels/config/cloud/ha-config-cloud.ts
@@ -56,14 +56,6 @@ class HaConfigCloud extends HassRouterPage {
account: {
tag: "cloud-account",
},
- "google-assistant": {
- tag: "cloud-google-assistant",
- load: () => import("./google-assistant/cloud-google-assistant"),
- },
- alexa: {
- tag: "cloud-alexa",
- load: () => import("./alexa/cloud-alexa"),
- },
},
};
diff --git a/src/panels/config/core/ha-config-system-navigation.ts b/src/panels/config/core/ha-config-system-navigation.ts
index 54a22a9988..9225670215 100644
--- a/src/panels/config/core/ha-config-system-navigation.ts
+++ b/src/panels/config/core/ha-config-system-navigation.ts
@@ -8,7 +8,6 @@ import { blankBeforePercent } from "../../../common/translations/blank_before_pe
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
import "../../../components/ha-navigation-list";
-import "../../../components/ha-tip";
import { BackupContent, fetchBackupInfo } from "../../../data/backup";
import { CloudStatus, fetchCloudStatus } from "../../../data/cloud";
import { BOARD_NAMES, HardwareInfo } from "../../../data/hardware";
@@ -270,9 +269,6 @@ class HaConfigSystemNavigation extends LitElement {
ha-navigation-list {
--navigation-list-item-title-font-size: 16px;
}
- ha-tip {
- margin-bottom: max(env(safe-area-inset-bottom), 8px);
- }
`,
];
}
diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts
index 817819b7b5..1ab9238576 100644
--- a/src/panels/config/entities/entity-registry-settings.ts
+++ b/src/panels/config/entities/entity-registry-settings.ts
@@ -1,15 +1,14 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-formfield/mwc-formfield";
import "@material/mwc-list/mwc-list-item";
-import { mdiPencil } from "@mdi/js";
import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
import {
css,
CSSResultGroup,
html,
LitElement,
- PropertyValues,
nothing,
+ PropertyValues,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
@@ -17,7 +16,6 @@ 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 { formatNumber } from "../../../common/number/format_number";
@@ -30,6 +28,7 @@ import "../../../components/ha-alert";
import "../../../components/ha-area-picker";
import "../../../components/ha-expansion-panel";
import "../../../components/ha-icon";
+import "../../../components/ha-icon-button-next";
import "../../../components/ha-icon-picker";
import "../../../components/ha-radio";
import "../../../components/ha-select";
@@ -73,15 +72,15 @@ import { domainToName } from "../../../data/integration";
import { getNumberDeviceClassConvertibleUnits } from "../../../data/number";
import { getSensorDeviceClassConvertibleUnits } from "../../../data/sensor";
import {
- WeatherUnits,
getWeatherConvertibleUnits,
+ WeatherUnits,
} from "../../../data/weather";
-import { showAliasesDialog } from "../../../dialogs/aliases/show-dialog-aliases";
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box";
+import { showVoiceAssistantsView } from "../../../dialogs/more-info/components/voice/show-view-voice-assistants";
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles";
@@ -699,6 +698,23 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
@value-changed=${this._areaPicked}
>`
: ""}
+
+ 0} hasMeta>
+ Voice assistants
+
+ ${this.entry.aliases.length
+ ? [...this.entry.aliases]
+ .sort((a, b) =>
+ stringCompare(a, b, this.hass.locale.language)
+ )
+ .join(", ")
+ : this.hass.localize(
+ "ui.dialogs.entity_registry.editor.no_aliases"
+ )}
+
+
+
+
${this._cameraPrefs
? html`
@@ -848,34 +864,6 @@ export class EntityRegistrySettings 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]
- .sort((a, b) =>
- stringCompare(a, b, this.hass.locale.language)
- )
- .join(", ")}
-
-
-
-
${this.hass.localize(
"ui.dialogs.entity_registry.editor.aliases_description"
@@ -1070,25 +1058,8 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
});
}
- private _handleAliasesClicked(ev: CustomEvent) {
- if (ev.detail.index !== 0) return;
-
- 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,
- { aliases }
- );
- fireEvent(this, "entity-entry-updated", result.entity_entry);
- },
- });
+ private _handleVoiceAssistantsClicked() {
+ showVoiceAssistantsView(this, "Voice assistants");
}
private async _enableEntry() {
diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts
index c00faf3711..57011cf0e4 100644
--- a/src/panels/config/ha-panel-config.ts
+++ b/src/panels/config/ha-panel-config.ts
@@ -12,6 +12,7 @@ import {
mdiMapMarkerRadius,
mdiMathLog,
mdiMemory,
+ mdiMicrophone,
mdiNetwork,
mdiNfcVariant,
mdiPalette,
@@ -82,6 +83,12 @@ export const configSections: { [name: string]: PageNavigation[] } = {
iconColor: "#B1345C",
component: "lovelace",
},
+ {
+ path: "/config/voice-assistants",
+ translationKey: "voice_assistants",
+ iconPath: mdiMicrophone,
+ iconColor: "#3263C3",
+ },
{
path: "/config/tags",
translationKey: "tags",
@@ -199,6 +206,14 @@ export const configSections: { [name: string]: PageNavigation[] } = {
iconColor: "#616161",
},
],
+ voice_assistants: [
+ {
+ path: "/config/voice-assistants",
+ translationKey: "ui.panel.config.dashboard.voice_assistants.main",
+ iconPath: mdiMicrophone,
+ iconColor: "#3263C3",
+ },
+ ],
// Not used as a tab, but this way it will stay in the quick bar
energy: [
{
diff --git a/src/panels/config/lovelace/ha-config-lovelace.ts b/src/panels/config/lovelace/ha-config-lovelace.ts
index 280a951b38..727438f3b6 100644
--- a/src/panels/config/lovelace/ha-config-lovelace.ts
+++ b/src/panels/config/lovelace/ha-config-lovelace.ts
@@ -1,3 +1,4 @@
+import { mdiViewDashboard } from "@mdi/js";
import { customElement, property } from "lit/decorators";
import {
HassRouterPage,
@@ -10,7 +11,7 @@ export const lovelaceTabs = [
component: "lovelace",
path: "/config/lovelace/dashboards",
translationKey: "ui.panel.config.lovelace.dashboards.caption",
- icon: "hass:view-dashboard",
+ iconPath: mdiViewDashboard,
},
];
diff --git a/src/panels/config/voice-assistants/cloud-alexa-pref.ts b/src/panels/config/voice-assistants/cloud-alexa-pref.ts
new file mode 100644
index 0000000000..5f6bce0416
--- /dev/null
+++ b/src/panels/config/voice-assistants/cloud-alexa-pref.ts
@@ -0,0 +1,272 @@
+import "@material/mwc-button";
+import { mdiHelpCircle } from "@mdi/js";
+import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { property, state } from "lit/decorators";
+import { fireEvent } from "../../../common/dom/fire_event";
+import { isEmptyFilter } from "../../../common/entity/entity_filter";
+import "../../../components/ha-alert";
+import "../../../components/ha-card";
+import "../../../components/ha-settings-row";
+import "../../../components/ha-switch";
+import type { HaSwitch } from "../../../components/ha-switch";
+import { CloudStatusLoggedIn, updateCloudPref } from "../../../data/cloud";
+import {
+ getExposeNewEntities,
+ setExposeNewEntities,
+} from "../../../data/voice";
+import type { HomeAssistant } from "../../../types";
+import { brandsUrl } from "../../../util/brands-url";
+
+export class CloudAlexaPref extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property() public cloudStatus?: CloudStatusLoggedIn;
+
+ @state() private _exposeNew?: boolean;
+
+ protected willUpdate() {
+ if (!this.hasUpdated) {
+ getExposeNewEntities(this.hass, "cloud.alexa").then((value) => {
+ this._exposeNew = value.expose_new;
+ });
+ }
+ }
+
+ protected render() {
+ if (!this.cloudStatus) {
+ return nothing;
+ }
+
+ const alexa_registered = this.cloudStatus.alexa_registered;
+ const { alexa_enabled, alexa_report_state } = this.cloudStatus!.prefs;
+
+ const manualConfig = !isEmptyFilter(this.cloudStatus.alexa_entities);
+
+ return html`
+
+
+
+
+
+ ${this.hass!.localize("ui.panel.config.cloud.account.alexa.info")}
+
+ ${manualConfig
+ ? html`
+ ${this.hass.localize(
+ "ui.panel.config.cloud.account.alexa.manual_config"
+ )}
+ `
+ : ""}
+ ${!alexa_enabled
+ ? ""
+ : html`${!alexa_registered
+ ? html`
+ ${this.hass.localize(
+ "ui.panel.config.cloud.account.alexa.not_configured_text"
+ )}
+
+
+ `
+ : ""}
+
+ ${this.hass!.localize(
+ "ui.panel.config.cloud.account.alexa.expose_new_entities"
+ )}
+
+
+ ${this.hass!.localize(
+ "ui.panel.config.cloud.account.alexa.expose_new_entities_info"
+ )}
+
+ ${alexa_registered
+ ? html`
+
+
+ ${this.hass!.localize(
+ "ui.panel.config.cloud.account.alexa.enable_state_reporting"
+ )}
+
+
+ ${this.hass!.localize(
+ "ui.panel.config.cloud.account.alexa.info_state_reporting"
+ )}
+
+
+
+ `
+ : ""}`}
+
+
+
+ `;
+ }
+
+ private async _exposeNewToggleChanged(ev) {
+ const toggle = ev.target as HaSwitch;
+ if (this._exposeNew === undefined || this._exposeNew === toggle.checked) {
+ return;
+ }
+ try {
+ await setExposeNewEntities(this.hass, "cloud.alexa", toggle.checked);
+ } catch (err: any) {
+ toggle.checked = !toggle.checked;
+ }
+ }
+
+ private async _enabledToggleChanged(ev) {
+ const toggle = ev.target as HaSwitch;
+ try {
+ await updateCloudPref(this.hass!, { alexa_enabled: toggle.checked! });
+ fireEvent(this, "ha-refresh-cloud-status");
+ } catch (err: any) {
+ toggle.checked = !toggle.checked;
+ }
+ }
+
+ private async _reportToggleChanged(ev) {
+ const toggle = ev.target as HaSwitch;
+ try {
+ await updateCloudPref(this.hass!, {
+ alexa_report_state: toggle.checked!,
+ });
+ fireEvent(this, "ha-refresh-cloud-status");
+ } catch (err: any) {
+ alert(
+ `${this.hass!.localize(
+ "ui.panel.config.cloud.account.alexa.state_reporting_error",
+ "enable_disable",
+ this.hass!.localize(
+ toggle.checked
+ ? "ui.panel.config.cloud.account.alexa.enable"
+ : "ui.panel.config.cloud.account.alexa.disable"
+ )
+ )} ${err.message}`
+ );
+ toggle.checked = !toggle.checked;
+ }
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ a {
+ color: var(--primary-color);
+ }
+ ha-settings-row {
+ padding: 0;
+ }
+ .header-actions {
+ position: absolute;
+ right: 24px;
+ top: 24px;
+ display: flex;
+ flex-direction: row;
+ }
+ :host([dir="rtl"]) .header-actions {
+ right: auto;
+ left: 24px;
+ }
+ .header-actions .icon-link {
+ margin-top: -16px;
+ margin-inline-end: 8px;
+ margin-right: 8px;
+ direction: var(--direction);
+ color: var(--secondary-text-color);
+ }
+ .card-actions {
+ display: flex;
+ }
+ .card-actions a {
+ text-decoration: none;
+ }
+ .card-header {
+ display: flex;
+ align-items: center;
+ }
+ img {
+ height: 28px;
+ margin-right: 16px;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "cloud-alexa-pref": CloudAlexaPref;
+ }
+}
+
+customElements.define("cloud-alexa-pref", CloudAlexaPref);
diff --git a/src/panels/config/voice-assistants/cloud-google-pref.ts b/src/panels/config/voice-assistants/cloud-google-pref.ts
new file mode 100644
index 0000000000..531e05dd0b
--- /dev/null
+++ b/src/panels/config/voice-assistants/cloud-google-pref.ts
@@ -0,0 +1,352 @@
+import "@material/mwc-button";
+import { mdiHelpCircle } from "@mdi/js";
+import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { property, state } from "lit/decorators";
+import { fireEvent } from "../../../common/dom/fire_event";
+import "../../../components/ha-alert";
+import "../../../components/ha-card";
+import "../../../components/ha-settings-row";
+import type { HaSwitch } from "../../../components/ha-switch";
+import "../../../components/ha-textfield";
+import type { HaTextField } from "../../../components/ha-textfield";
+import { CloudStatusLoggedIn, updateCloudPref } from "../../../data/cloud";
+import { showSaveSuccessToast } from "../../../util/toast-saved-success";
+import { HomeAssistant } from "../../../types";
+import { brandsUrl } from "../../../util/brands-url";
+import { isEmptyFilter } from "../../../common/entity/entity_filter";
+import {
+ getExposeNewEntities,
+ setExposeNewEntities,
+} from "../../../data/voice";
+
+export class CloudGooglePref extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ attribute: false }) public cloudStatus?: CloudStatusLoggedIn;
+
+ @state() private _exposeNew?: boolean;
+
+ protected willUpdate() {
+ if (!this.hasUpdated) {
+ getExposeNewEntities(this.hass, "cloud.google_assistant").then(
+ (value) => {
+ this._exposeNew = value.expose_new;
+ }
+ );
+ }
+ }
+
+ protected render() {
+ if (!this.cloudStatus) {
+ return nothing;
+ }
+
+ const google_registered = this.cloudStatus.google_registered;
+ const { google_enabled, google_report_state, google_secure_devices_pin } =
+ this.cloudStatus.prefs;
+
+ const manualConfig = !isEmptyFilter(this.cloudStatus.google_entities);
+
+ return html`
+
+
+
+
+
+ ${this.hass.localize("ui.panel.config.cloud.account.google.info")}
+
+ ${manualConfig
+ ? html`
+ ${this.hass.localize(
+ "ui.panel.config.cloud.account.google.manual_config"
+ )}
+ `
+ : ""}
+ ${!google_enabled
+ ? ""
+ : html`${!google_registered
+ ? html`
+
+ ${this.hass.localize(
+ "ui.panel.config.cloud.account.google.not_configured_text"
+ )}
+
+
+
+ `
+ : ""}
+
+
+ ${this.hass!.localize(
+ "ui.panel.config.cloud.account.google.expose_new_entities"
+ )}
+
+
+ ${this.hass!.localize(
+ "ui.panel.config.cloud.account.google.expose_new_entities_info"
+ )}
+
+ ${google_registered
+ ? html`
+ ${this.cloudStatus.http_use_ssl
+ ? html`
+
+ ${this.hass.localize(
+ "ui.panel.config.cloud.account.google.http_use_ssl_warning_text"
+ )}
+ ${this.hass.localize(
+ "ui.panel.config.common.learn_more"
+ )}
+
+ `
+ : ""}
+
+
+
+ ${this.hass!.localize(
+ "ui.panel.config.cloud.account.google.enable_state_reporting"
+ )}
+
+
+ ${this.hass!.localize(
+ "ui.panel.config.cloud.account.google.info_state_reporting"
+ )}
+
+
+
+
+
+
+ ${this.hass.localize(
+ "ui.panel.config.cloud.account.google.security_devices"
+ )}
+
+
+ ${this.hass.localize(
+ "ui.panel.config.cloud.account.google.enter_pin_info"
+ )}
+
+
+
+
+ `
+ : ""}`}
+
+
+
+ `;
+ }
+
+ private async _exposeNewToggleChanged(ev) {
+ const toggle = ev.target as HaSwitch;
+ if (this._exposeNew === undefined || this._exposeNew === toggle.checked) {
+ return;
+ }
+ try {
+ await setExposeNewEntities(
+ this.hass,
+ "cloud.google_assistant",
+ toggle.checked
+ );
+ } catch (err: any) {
+ toggle.checked = !toggle.checked;
+ }
+ }
+
+ private async _enabledToggleChanged(ev) {
+ const toggle = ev.target as HaSwitch;
+ try {
+ await updateCloudPref(this.hass, { google_enabled: toggle.checked! });
+ fireEvent(this, "ha-refresh-cloud-status");
+ } catch (err: any) {
+ toggle.checked = !toggle.checked;
+ }
+ }
+
+ private async _reportToggleChanged(ev) {
+ const toggle = ev.target as HaSwitch;
+ try {
+ await updateCloudPref(this.hass, {
+ google_report_state: toggle.checked!,
+ });
+ fireEvent(this, "ha-refresh-cloud-status");
+ } catch (err: any) {
+ alert(
+ `Unable to ${toggle.checked ? "enable" : "disable"} report state. ${
+ err.message
+ }`
+ );
+ toggle.checked = !toggle.checked;
+ }
+ }
+
+ private async _pinChanged(ev) {
+ const input = ev.target as HaTextField;
+ try {
+ await updateCloudPref(this.hass, {
+ [input.id]: input.value || null,
+ });
+ showSaveSuccessToast(this, this.hass);
+ fireEvent(this, "ha-refresh-cloud-status");
+ } catch (err: any) {
+ alert(
+ `${this.hass.localize(
+ "ui.panel.config.cloud.account.google.enter_pin_error"
+ )} ${err.message}`
+ );
+ input.value = this.cloudStatus!.prefs.google_secure_devices_pin || "";
+ }
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ a {
+ color: var(--primary-color);
+ }
+ .header-actions {
+ position: absolute;
+ right: 24px;
+ top: 24px;
+ display: flex;
+ flex-direction: row;
+ }
+ :host([dir="rtl"]) .header-actions {
+ right: auto;
+ left: 24px;
+ }
+ .header-actions .icon-link {
+ margin-top: -16px;
+ margin-inline-end: 8px;
+ margin-right: 8px;
+ direction: var(--direction);
+ color: var(--secondary-text-color);
+ }
+ ha-settings-row {
+ padding: 0;
+ }
+ ha-textfield {
+ width: 250px;
+ display: block;
+ margin-top: 8px;
+ }
+ .card-actions {
+ display: flex;
+ }
+ .card-actions a {
+ text-decoration: none;
+ }
+ .warning {
+ color: var(--error-color);
+ }
+ .card-header {
+ display: flex;
+ align-items: center;
+ }
+ img {
+ height: 28px;
+ margin-right: 16px;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "cloud-google-pref": CloudGooglePref;
+ }
+}
+
+customElements.define("cloud-google-pref", CloudGooglePref);
diff --git a/src/panels/config/voice-assistants/dialog-expose-entity.ts b/src/panels/config/voice-assistants/dialog-expose-entity.ts
new file mode 100644
index 0000000000..36f3409e82
--- /dev/null
+++ b/src/panels/config/voice-assistants/dialog-expose-entity.ts
@@ -0,0 +1,218 @@
+import "@material/mwc-button";
+import "@material/mwc-list";
+import { mdiClose } from "@mdi/js";
+import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { customElement, property, state } from "lit/decorators";
+import { ifDefined } from "lit/directives/if-defined";
+import memoizeOne from "memoize-one";
+import { fireEvent } from "../../../common/dom/fire_event";
+import "../../../components/ha-check-list-item";
+import "../../../components/search-input";
+import {
+ computeEntityRegistryName,
+ ExtEntityRegistryEntry,
+} from "../../../data/entity_registry";
+import { haStyle, haStyleDialog } from "../../../resources/styles";
+import { HomeAssistant } from "../../../types";
+import "./entity-voice-settings";
+import { ExposeEntityDialogParams } from "./show-dialog-expose-entity";
+
+@customElement("dialog-expose-entity")
+class DialogExposeEntity extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @state() private _params?: ExposeEntityDialogParams;
+
+ @state() private _filter?: string;
+
+ @state() private _selected: string[] = [];
+
+ public async showDialog(params: ExposeEntityDialogParams): Promise
{
+ this._params = params;
+ }
+
+ public closeDialog(): void {
+ this._params = undefined;
+ this._selected = [];
+ this._filter = undefined;
+ fireEvent(this, "dialog-closed", { dialog: this.localName });
+ }
+
+ protected render() {
+ if (!this._params) {
+ return nothing;
+ }
+
+ return html`
+
+
+
+
+
+
+
+ ${this._filterEntities(
+ this._params.extendedEntities,
+ this._filter
+ ).map((entity) => this._renderItem(entity))}
+
+
+ ${this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.expose_dialog.expose_entities",
+ { count: this._selected.length }
+ )}
+
+
+ `;
+ }
+
+ private _handleSelected(ev) {
+ if (ev.detail.source !== "property") {
+ return;
+ }
+ const entityId = ev.target.value;
+ if (ev.detail.selected) {
+ if (this._selected.includes(entityId)) {
+ return;
+ }
+ this._selected = [...this._selected, entityId];
+ } else {
+ this._selected = this._selected.filter((item) => item !== entityId);
+ }
+ }
+
+ private _filterChanged(e) {
+ this._filter = e.detail.value;
+ }
+
+ private _filterEntities = memoizeOne(
+ (RegEntries: Record, filter?: string) =>
+ Object.values(RegEntries).filter(
+ (entity) =>
+ this._params!.filterAssistants.some(
+ (ass) => !entity.options?.[ass]?.should_expose
+ ) &&
+ (!filter ||
+ entity.entity_id.includes(filter) ||
+ computeEntityRegistryName(this.hass!, entity)?.includes(filter))
+ )
+ );
+
+ private _renderItem = (entity: ExtEntityRegistryEntry) => {
+ const entityState = this.hass.states[entity.entity_id];
+ return html`
+
+ ${computeEntityRegistryName(this.hass!, entity)}
+ `;
+ };
+
+ private _expose() {
+ this._params!.exposeEntities(this._selected);
+ this.closeDialog();
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ haStyle,
+ haStyleDialog,
+ css`
+ ha-dialog {
+ --dialog-content-padding: 0;
+ }
+ search-input {
+ width: 100%;
+ display: block;
+ padding: 24px 16px 0;
+ box-sizing: border-box;
+ }
+ .header {
+ pointer-events: auto;
+ -webkit-font-smoothing: antialiased;
+ font-family: var(
+ --mdc-typography-headline6-font-family,
+ var(--mdc-typography-font-family, Roboto, sans-serif)
+ );
+ font-size: var(--mdc-typography-headline6-font-size, 1.25rem);
+ line-height: var(--mdc-typography-headline6-line-height, 2rem);
+ font-weight: var(--mdc-typography-headline6-font-weight, 500);
+ letter-spacing: var(
+ --mdc-typography-headline6-letter-spacing,
+ 0.0125em
+ );
+ text-decoration: var(
+ --mdc-typography-headline6-text-decoration,
+ inherit
+ );
+ text-transform: var(
+ --mdc-typography-headline6-text-transform,
+ inherit
+ );
+ display: block;
+ position: relative;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ margin: 0 0 1px;
+ padding: 24px 24px 0 24px;
+ padding-bottom: 15px;
+ color: var(--mdc-dialog-heading-ink-color, rgba(0, 0, 0, 0.87));
+ border-bottom: 1px solid rgba(0, 0, 0, 0.12);
+ margin-bottom: 0;
+ border-color: var(
+ --mdc-dialog-scroll-divider-color,
+ rgba(0, 0, 0, 0.12)
+ );
+ }
+ .header_button {
+ position: absolute;
+ right: 16px;
+ top: 14px;
+ text-decoration: none;
+ color: inherit;
+ }
+ .header_button {
+ inset-inline-start: initial;
+ inset-inline-end: 16px;
+ direction: var(--direction);
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "dialog-expose-entity": DialogExposeEntity;
+ }
+}
diff --git a/src/panels/config/voice-assistants/dialog-voice-settings.ts b/src/panels/config/voice-assistants/dialog-voice-settings.ts
new file mode 100644
index 0000000000..77884e7e82
--- /dev/null
+++ b/src/panels/config/voice-assistants/dialog-voice-settings.ts
@@ -0,0 +1,82 @@
+import "@material/mwc-button/mwc-button";
+import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
+import { customElement, property, state } from "lit/decorators";
+import { fireEvent } from "../../../common/dom/fire_event";
+import {
+ ExtEntityRegistryEntry,
+ computeEntityRegistryName,
+ getExtendedEntityRegistryEntry,
+} from "../../../data/entity_registry";
+import { haStyle, haStyleDialog } from "../../../resources/styles";
+import { HomeAssistant } from "../../../types";
+import { VoiceSettingsDialogParams } from "./show-dialog-voice-settings";
+import "./entity-voice-settings";
+import { createCloseHeading } from "../../../components/ha-dialog";
+
+@customElement("dialog-voice-settings")
+class DialogVoiceSettings extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @state() private _extEntityReg?: ExtEntityRegistryEntry;
+
+ public async showDialog(params: VoiceSettingsDialogParams): Promise {
+ this._extEntityReg = await getExtendedEntityRegistryEntry(
+ this.hass,
+ params.entityId
+ );
+ }
+
+ public closeDialog(): void {
+ this._extEntityReg = undefined;
+ fireEvent(this, "dialog-closed", { dialog: this.localName });
+ }
+
+ protected render() {
+ if (!this._extEntityReg) {
+ return nothing;
+ }
+
+ return html`
+
+
+
+
+
+ `;
+ }
+
+ private _entityEntryUpdated(ev: CustomEvent) {
+ this._extEntityReg = ev.detail;
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ haStyle,
+ haStyleDialog,
+ css`
+ ha-dialog {
+ --dialog-content-padding: 0;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "dialog-voice-settings": DialogVoiceSettings;
+ }
+}
diff --git a/src/panels/config/voice-assistants/entity-voice-settings.ts b/src/panels/config/voice-assistants/entity-voice-settings.ts
new file mode 100644
index 0000000000..fbe5de072e
--- /dev/null
+++ b/src/panels/config/voice-assistants/entity-voice-settings.ts
@@ -0,0 +1,327 @@
+import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
+import { customElement, property, state } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { isComponentLoaded } from "../../../common/config/is_component_loaded";
+import { fireEvent } from "../../../common/dom/fire_event";
+import {
+ EntityFilter,
+ FilterFunc,
+ generateFilter,
+ isEmptyFilter,
+} from "../../../common/entity/entity_filter";
+import "../../../components/ha-aliases-editor";
+import "../../../components/ha-settings-row";
+import "../../../components/ha-switch";
+import {
+ CloudStatus,
+ CloudStatusLoggedIn,
+ fetchCloudStatus,
+ updateCloudGoogleEntityConfig,
+} from "../../../data/cloud";
+import {
+ ExtEntityRegistryEntry,
+ getExtendedEntityRegistryEntry,
+ updateEntityRegistryEntry,
+} from "../../../data/entity_registry";
+import {
+ GoogleEntity,
+ fetchCloudGoogleEntity,
+} from "../../../data/google_assistant";
+import {
+ exposeEntities,
+ voiceAssistantKeys,
+ voiceAssistants,
+} from "../../../data/voice";
+import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
+import { haStyle } from "../../../resources/styles";
+import type { HomeAssistant } from "../../../types";
+import { brandsUrl } from "../../../util/brands-url";
+import { EntityRegistrySettings } from "../entities/entity-registry-settings";
+
+@customElement("entity-voice-settings")
+export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ type: Object }) public entry!: ExtEntityRegistryEntry;
+
+ @state() private _cloudStatus?: CloudStatus;
+
+ @state() private _aliases?: string[];
+
+ @state() private _googleEntity?: GoogleEntity;
+
+ protected willUpdate(changedProps: PropertyValues) {
+ if (!isComponentLoaded(this.hass, "cloud")) {
+ return;
+ }
+ if (changedProps.has("entry") && this.entry) {
+ fetchCloudGoogleEntity(this.hass, this.entry.entity_id).then(
+ (googleEntity) => {
+ this._googleEntity = googleEntity;
+ }
+ );
+ }
+ if (!this.hasUpdated) {
+ fetchCloudStatus(this.hass).then((status) => {
+ this._cloudStatus = status;
+ });
+ }
+ }
+
+ private _getEntityFilterFuncs = memoizeOne(
+ (googleFilter: EntityFilter, alexaFilter: EntityFilter) => ({
+ google: generateFilter(
+ googleFilter.include_domains,
+ googleFilter.include_entities,
+ googleFilter.exclude_domains,
+ googleFilter.exclude_entities
+ ),
+ alexa: generateFilter(
+ alexaFilter.include_domains,
+ alexaFilter.include_entities,
+ alexaFilter.exclude_domains,
+ alexaFilter.exclude_entities
+ ),
+ })
+ );
+
+ protected render() {
+ const googleEnabled =
+ this._cloudStatus?.logged_in === true &&
+ this._cloudStatus.prefs.google_enabled === true;
+
+ const alexaEnabled =
+ this._cloudStatus?.logged_in === true &&
+ this._cloudStatus.prefs.alexa_enabled === true;
+
+ const showAssistants = [...voiceAssistantKeys];
+ const uiAssistants = [...voiceAssistantKeys];
+
+ const alexaManual =
+ alexaEnabled &&
+ !isEmptyFilter((this._cloudStatus as CloudStatusLoggedIn).alexa_entities);
+ const googleManual =
+ googleEnabled &&
+ !isEmptyFilter(
+ (this._cloudStatus as CloudStatusLoggedIn).google_entities
+ );
+
+ if (!googleEnabled) {
+ showAssistants.splice(
+ showAssistants.indexOf("cloud.google_assistant"),
+ 1
+ );
+ uiAssistants.splice(showAssistants.indexOf("cloud.google_assistant"), 1);
+ } else if (googleManual) {
+ uiAssistants.splice(uiAssistants.indexOf("cloud.google_assistant"), 1);
+ }
+
+ if (!alexaEnabled) {
+ showAssistants.splice(showAssistants.indexOf("cloud.alexa"), 1);
+ uiAssistants.splice(uiAssistants.indexOf("cloud.alexa"), 1);
+ } else if (alexaManual) {
+ uiAssistants.splice(uiAssistants.indexOf("cloud.alexa"), 1);
+ }
+
+ const uiExposed = uiAssistants.some(
+ (key) => this.entry.options?.[key]?.should_expose
+ );
+
+ let manFilterFuncs:
+ | {
+ google: FilterFunc;
+ alexa: FilterFunc;
+ }
+ | undefined;
+
+ if (alexaManual || googleManual) {
+ manFilterFuncs = this._getEntityFilterFuncs(
+ (this._cloudStatus as CloudStatusLoggedIn).google_entities,
+ (this._cloudStatus as CloudStatusLoggedIn).alexa_entities
+ );
+ }
+
+ const manExposedAlexa =
+ alexaManual && manFilterFuncs!.alexa(this.entry.entity_id);
+ const manExposedGoogle =
+ googleManual && manFilterFuncs!.google(this.entry.entity_id);
+
+ const anyExposed = uiExposed || manExposedAlexa || manExposedGoogle;
+
+ return html`
+ ${this.hass.localize(
+ "ui.dialogs.voice-settings.expose_header"
+ )}
+
+
+ ${anyExposed
+ ? showAssistants.map(
+ (key) => html`
+
+ ${voiceAssistants[key].name}
+ ${key === "cloud.google_assistant" &&
+ !googleManual &&
+ this._googleEntity?.might_2fa
+ ? html`
+
+ `
+ : (alexaManual && key === "cloud.alexa") ||
+ (googleManual && key === "cloud.google_assistant")
+ ? html`${this.hass.localize(
+ "ui.dialogs.voice-settings.manual_config"
+ )} `
+ : ""}
+
+ `
+ )
+ : ""}
+
+
+ ${this.hass.localize("ui.dialogs.voice-settings.aliasses_header")}
+
+
+ `;
+ }
+
+ private _aliasesChanged(ev) {
+ this._aliases = ev.detail.value;
+ }
+
+ private async _2faChanged(ev) {
+ try {
+ await updateCloudGoogleEntityConfig(
+ this.hass,
+ this.entry.entity_id,
+ !ev.target.checked
+ );
+ } catch (_err) {
+ ev.target.checked = !ev.target.checked;
+ }
+ }
+
+ private async _saveAliases() {
+ if (!this._aliases) {
+ return;
+ }
+ const result = await updateEntityRegistryEntry(
+ this.hass,
+ this.entry.entity_id,
+ {
+ aliases: this._aliases
+ .map((alias) => alias.trim())
+ .filter((alias) => alias),
+ }
+ );
+ fireEvent(this, "entity-entry-updated", result.entity_entry);
+ }
+
+ private async _toggleAssistant(ev) {
+ exposeEntities(
+ this.hass,
+ [ev.target.assistant],
+ [this.entry.entity_id],
+ ev.target.checked
+ );
+ const entry = await getExtendedEntityRegistryEntry(
+ this.hass,
+ this.entry.entity_id
+ );
+ fireEvent(this, "entity-entry-updated", entry);
+ }
+
+ private async _toggleAll(ev) {
+ exposeEntities(
+ this.hass,
+ voiceAssistantKeys,
+ [this.entry.entity_id],
+ ev.target.checked
+ );
+ const entry = await getExtendedEntityRegistryEntry(
+ this.hass,
+ this.entry.entity_id
+ );
+ fireEvent(this, "entity-entry-updated", entry);
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ haStyle,
+ css`
+ :host {
+ display: block;
+ margin: 32px;
+ margin-top: 0;
+ --settings-row-prefix-display: contents;
+ }
+ ha-settings-row {
+ padding: 0;
+ }
+ img {
+ height: 32px;
+ margin-right: 16px;
+ }
+ ha-aliases-editor {
+ display: block;
+ }
+ ha-alert {
+ display: block;
+ margin-top: 16px;
+ }
+ ha-formfield {
+ margin-left: -8px;
+ }
+ ha-checkbox {
+ --mdc-checkbox-state-layer-size: 40px;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "entity-registry-settings": EntityRegistrySettings;
+ }
+ interface HASSDomEvents {
+ "entity-entry-updated": ExtEntityRegistryEntry;
+ }
+}
diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants-assistants.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants-assistants.ts
new file mode 100644
index 0000000000..191fe9f8b5
--- /dev/null
+++ b/src/panels/config/voice-assistants/ha-config-voice-assistants-assistants.ts
@@ -0,0 +1,111 @@
+import { css, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { computeRTLDirection } from "../../../common/util/compute_rtl";
+import { CloudStatus } from "../../../data/cloud";
+import "../../../layouts/hass-tabs-subpage";
+import { HomeAssistant, Route } from "../../../types";
+import "./cloud-alexa-pref";
+import "./cloud-google-pref";
+import { voiceAssistantTabs } from "./ha-config-voice-assistants";
+import "@polymer/paper-item/paper-item";
+import { isComponentLoaded } from "../../../common/config/is_component_loaded";
+
+@customElement("ha-config-voice-assistants-assistants")
+export class HaConfigVoiceAssistantsAssistants extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ attribute: false }) public cloudStatus?: CloudStatus;
+
+ @property() public isWide!: boolean;
+
+ @property() public narrow!: boolean;
+
+ @property() public route!: Route;
+
+ protected render() {
+ if (!this.hass) {
+ return html` `;
+ }
+
+ return html`
+
+
+ ${this.cloudStatus?.logged_in
+ ? html`
+
`
+ : html`
+
+ With Home Assistant Cloud, you can connect your Home
+ Assistant instance in a few simple clicks to both Google
+ Assistant and Amazon Alexa. If you can connect it to Home
+ Assistant, you can now control it with your voice using the
+ Amazon Echo, Google Home or your Android phone.
+
+
+
+ ${isComponentLoaded(this.hass, "cloud")
+ ? html`
+
+
+
+ ${this.hass.localize(
+ "ui.panel.config.cloud.login.start_trial"
+ )}
+
+ ${this.hass.localize(
+ "ui.panel.config.cloud.login.trial_info"
+ )}
+
+
+
+
+
+ `
+ : ""}`}
+
+
+ `;
+ }
+
+ static styles = css`
+ .content {
+ padding: 28px 20px 0;
+ max-width: 1040px;
+ margin: 0 auto;
+ }
+ .content > * {
+ display: block;
+ margin: auto;
+ max-width: 800px;
+ margin-bottom: 24px;
+ }
+ a {
+ text-decoration: none;
+ color: inherit;
+ }
+ `;
+}
diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts
new file mode 100644
index 0000000000..74b060b03c
--- /dev/null
+++ b/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts
@@ -0,0 +1,710 @@
+import { consume } from "@lit-labs/context";
+import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
+import {
+ mdiMinusCircle,
+ mdiMinusCircleOutline,
+ mdiPlus,
+ mdiPlusCircle,
+} from "@mdi/js";
+import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
+import { customElement, property, query, state } from "lit/decorators";
+import { classMap } from "lit/directives/class-map";
+import { ifDefined } from "lit/directives/if-defined";
+import { styleMap } from "lit/directives/style-map";
+import memoize from "memoize-one";
+import { HASSDomEvent } from "../../../common/dom/fire_event";
+import {
+ EntityFilter,
+ generateFilter,
+ isEmptyFilter,
+} from "../../../common/entity/entity_filter";
+import { navigate } from "../../../common/navigate";
+import { computeRTL } from "../../../common/util/compute_rtl";
+import {
+ DataTableColumnContainer,
+ DataTableRowData,
+ RowClickedEvent,
+ SelectionChangedEvent,
+} from "../../../components/data-table/ha-data-table";
+import "../../../components/ha-fab";
+import { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud";
+import { entitiesContext } from "../../../data/context";
+import {
+ computeEntityRegistryName,
+ EntityRegistryEntry,
+ ExtEntityRegistryEntry,
+ getExtendedEntityRegistryEntries,
+} from "../../../data/entity_registry";
+import {
+ exposeEntities,
+ voiceAssistantKeys,
+ voiceAssistants,
+} from "../../../data/voice";
+import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
+import "../../../layouts/hass-loading-screen";
+import "../../../layouts/hass-tabs-subpage-data-table";
+import type { HaTabsSubpageDataTable } from "../../../layouts/hass-tabs-subpage-data-table";
+import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
+import { haStyle } from "../../../resources/styles";
+import { HomeAssistant, Route } from "../../../types";
+import { brandsUrl } from "../../../util/brands-url";
+import { voiceAssistantTabs } from "./ha-config-voice-assistants";
+import { showExposeEntityDialog } from "./show-dialog-expose-entity";
+import { showVoiceSettingsDialog } from "./show-dialog-voice-settings";
+
+@customElement("ha-config-voice-assistants-expose")
+export class VoiceAssistantsExpose extends SubscribeMixin(LitElement) {
+ @property() public hass!: HomeAssistant;
+
+ @property({ attribute: false }) public cloudStatus?: CloudStatus;
+
+ @property({ type: Boolean }) public isWide!: boolean;
+
+ @property({ type: Boolean }) public narrow!: boolean;
+
+ @property({ attribute: false }) public route!: Route;
+
+ @state()
+ @consume({ context: entitiesContext, subscribe: true })
+ _entities!: HomeAssistant["entities"];
+
+ @state() private _extEntities?: Record;
+
+ @state() private _filter: string = history.state?.filter || "";
+
+ @state() private _numHiddenEntities = 0;
+
+ @state() private _searchParms = new URLSearchParams(window.location.search);
+
+ @state() private _selectedEntities: string[] = [];
+
+ @query("hass-tabs-subpage-data-table", true)
+ private _dataTable!: HaTabsSubpageDataTable;
+
+ private _activeFilters = memoize(
+ (filters: URLSearchParams): string[] | undefined => {
+ const filterTexts: string[] = [];
+ filters.forEach((value, key) => {
+ switch (key) {
+ case "assistants": {
+ const assistants = value.split(",");
+ assistants.forEach((assistant) => {
+ filterTexts.push(voiceAssistants[assistant]?.name || assistant);
+ });
+ }
+ }
+ });
+ return filterTexts.length ? filterTexts : undefined;
+ }
+ );
+
+ private _columns = memoize(
+ (narrow, _language): DataTableColumnContainer => ({
+ icon: {
+ title: "",
+ type: "icon",
+ template: (_, entry) => html`
+
+ `,
+ },
+ name: {
+ main: true,
+ title: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.headers.name"
+ ),
+ sortable: true,
+ filterable: true,
+ direction: "asc",
+ grows: true,
+ template: narrow
+ ? (name, entry) =>
+ html`
+ ${name}
+ ${entry.entity_id}
+ `
+ : undefined,
+ },
+ area: {
+ title: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.headers.area"
+ ),
+ sortable: true,
+ hidden: narrow,
+ filterable: true,
+ width: "15%",
+ },
+ assistants: {
+ title: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.headers.assistants"
+ ),
+ sortable: true,
+ filterable: true,
+ width: "160px",
+ type: "flex",
+ template: (assistants, entry) =>
+ html`${voiceAssistantKeys.map((key) =>
+ assistants.includes(key)
+ ? html`
+
${entry.manAssistants?.includes(key)
+ ? html`
+ Configured in YAML, not editable in UI
+ `
+ : ""}
+
`
+ : html`
`
+ )}`,
+ },
+ aliases: {
+ title: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.headers.aliases"
+ ),
+ sortable: true,
+ filterable: true,
+ width: "15%",
+ template: (aliases) =>
+ aliases.length === 0
+ ? "-"
+ : aliases.length === 1
+ ? aliases[0]
+ : this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.aliases",
+ { count: aliases.length }
+ ),
+ },
+ remove: {
+ title: "",
+ type: "icon-button",
+ template: () =>
+ html` `,
+ },
+ })
+ );
+
+ private _getEntityFilterFuncs = memoize(
+ (googleFilter: EntityFilter, alexaFilter: EntityFilter) => ({
+ google: generateFilter(
+ googleFilter.include_domains,
+ googleFilter.include_entities,
+ googleFilter.exclude_domains,
+ googleFilter.exclude_entities
+ ),
+ amazon: generateFilter(
+ alexaFilter.include_domains,
+ alexaFilter.include_entities,
+ alexaFilter.exclude_domains,
+ alexaFilter.exclude_entities
+ ),
+ })
+ );
+
+ private _filteredEntities = memoize(
+ (
+ entities: HomeAssistant["entities"],
+ extEntities: Record | undefined,
+ devices: HomeAssistant["devices"],
+ areas: HomeAssistant["areas"],
+ cloudStatus: CloudStatus | undefined,
+ filters: URLSearchParams
+ ) => {
+ const googleEnabled =
+ cloudStatus?.logged_in === true &&
+ cloudStatus.prefs.google_enabled === true;
+ const alexaEnabled =
+ cloudStatus?.logged_in === true &&
+ cloudStatus.prefs.alexa_enabled === true;
+
+ const showAssistants = [...voiceAssistantKeys];
+
+ const alexaManual =
+ alexaEnabled &&
+ !isEmptyFilter(
+ (this.cloudStatus as CloudStatusLoggedIn).alexa_entities
+ );
+ const googleManual =
+ googleEnabled &&
+ !isEmptyFilter(
+ (this.cloudStatus as CloudStatusLoggedIn).google_entities
+ );
+
+ if (!googleEnabled || googleManual) {
+ showAssistants.splice(
+ showAssistants.indexOf("cloud.google_assistant"),
+ 1
+ );
+ }
+
+ if (!alexaEnabled || alexaManual) {
+ showAssistants.splice(showAssistants.indexOf("cloud.alexa"), 1);
+ }
+
+ const result: Record = {};
+
+ let filteredEntities = Object.values(entities);
+
+ filteredEntities = filteredEntities.filter((entity) =>
+ showAssistants.some(
+ (assis) =>
+ extEntities?.[entity.entity_id].options?.[assis]?.should_expose
+ )
+ );
+
+ // If nothing gets filtered, this is our correct count of entities
+ const startLength = filteredEntities.length;
+
+ let filteredAssistants: string[];
+
+ filters.forEach((value, key) => {
+ if (key === "assistants") {
+ filteredAssistants = value.split(",");
+ filteredEntities = filteredEntities.filter((entity) =>
+ filteredAssistants.some(
+ (assis) =>
+ !(assis === "cloud.alexa" && alexaManual) &&
+ extEntities?.[entity.entity_id].options?.[assis]?.should_expose
+ )
+ );
+ }
+ });
+
+ for (const entry of filteredEntities) {
+ const entity = this.hass.states[entry.entity_id];
+ const areaId = entry.area_id ?? devices[entry.device_id!]?.area_id;
+ const area = areaId ? areas[areaId] : undefined;
+
+ result[entry.entity_id] = {
+ entity_id: entry.entity_id,
+ entity,
+ name: computeEntityRegistryName(
+ this.hass!,
+ entry as EntityRegistryEntry
+ ),
+ area: area ? area.name : "—",
+ assistants: Object.keys(
+ extEntities![entry.entity_id].options!
+ ).filter(
+ (key) =>
+ showAssistants.includes(key) &&
+ extEntities![entry.entity_id].options![key]?.should_expose
+ ),
+ aliases: extEntities?.[entry.entity_id].aliases,
+ };
+ }
+
+ this._numHiddenEntities = startLength - Object.values(result).length;
+
+ if (alexaManual || googleManual) {
+ const manFilterFuncs = this._getEntityFilterFuncs(
+ (this.cloudStatus as CloudStatusLoggedIn).google_entities,
+ (this.cloudStatus as CloudStatusLoggedIn).alexa_entities
+ );
+ Object.keys(entities).forEach((entityId) => {
+ const assistants: string[] = [];
+ if (
+ alexaManual &&
+ (!filteredAssistants ||
+ filteredAssistants.includes("cloud.alexa")) &&
+ manFilterFuncs.amazon(entityId)
+ ) {
+ assistants.push("cloud.alexa");
+ }
+ if (
+ googleManual &&
+ (!filteredAssistants ||
+ filteredAssistants.includes("cloud.google_assistant")) &&
+ manFilterFuncs.google(entityId)
+ ) {
+ assistants.push("cloud.google_assistant");
+ }
+ if (!assistants.length) {
+ return;
+ }
+ if (entityId in result) {
+ result[entityId].assistants.push(...assistants);
+ result[entityId].manAssistants = assistants;
+ } else {
+ const entry = entities[entityId];
+ const areaId = entry.area_id ?? devices[entry.device_id!]?.area_id;
+ const area = areaId ? areas[areaId] : undefined;
+ result[entityId] = {
+ entity_id: entry.entity_id,
+ entity: this.hass.states[entityId],
+ name: computeEntityRegistryName(
+ this.hass!,
+ entry as EntityRegistryEntry
+ ),
+ area: area ? area.name : "—",
+ assistants: [
+ ...(extEntities
+ ? Object.keys(extEntities[entry.entity_id].options!).filter(
+ (key) =>
+ showAssistants.includes(key) &&
+ extEntities[entry.entity_id].options![key]
+ ?.should_expose
+ )
+ : []),
+ ...assistants,
+ ],
+ manAssistants: assistants,
+ aliases: extEntities?.[entityId].aliases,
+ };
+ }
+ });
+ }
+
+ return Object.values(result);
+ }
+ );
+
+ public constructor() {
+ super();
+ window.addEventListener("location-changed", () => {
+ if (
+ window.location.search.substring(1) !== this._searchParms.toString()
+ ) {
+ this._searchParms = new URLSearchParams(window.location.search);
+ }
+ });
+ window.addEventListener("popstate", () => {
+ if (
+ window.location.search.substring(1) !== this._searchParms.toString()
+ ) {
+ this._searchParms = new URLSearchParams(window.location.search);
+ }
+ });
+ }
+
+ private async _fetchExtendedEntities() {
+ this._extEntities = await getExtendedEntityRegistryEntries(
+ this.hass,
+ Object.keys(this._entities)
+ );
+ }
+
+ public willUpdate(changedProperties: PropertyValues): void {
+ if (changedProperties.has("_entities")) {
+ this._fetchExtendedEntities();
+ }
+ }
+
+ protected render() {
+ if (!this.hass || this.hass.entities === undefined) {
+ return html` `;
+ }
+ const activeFilters = this._activeFilters(this._searchParms);
+
+ const filteredEntities = this._filteredEntities(
+ this._entities,
+ this._extEntities,
+ this.hass.devices,
+ this.hass.areas,
+ this.cloudStatus,
+ this._searchParms
+ );
+
+ return html`
+ 0}
+ .searchLabel=${this.hass.localize(
+ "ui.panel.config.entities.picker.search"
+ )}
+ .hiddenLabel=${this.hass.localize(
+ "ui.panel.config.entities.picker.filter.hidden_entities",
+ "number",
+ this._numHiddenEntities
+ )}
+ .filter=${this._filter}
+ selectable
+ clickable
+ @selection-changed=${this._handleSelectionChanged}
+ @clear-filter=${this._clearFilter}
+ @search-changed=${this._handleSearchChange}
+ @row-click=${this._openEditEntry}
+ id="entity_id"
+ hasFab
+ >
+ ${this._selectedEntities.length
+ ? html`
+
+
+ ${this.hass.localize(
+ "ui.panel.config.entities.picker.selected",
+ "number",
+ this._selectedEntities.length
+ )}
+
+
+
+ `
+ : ""}
+
+
+
+
+ `;
+ }
+
+ private _addEntry() {
+ const assistants = this._searchParms.has("assistants")
+ ? this._searchParms.get("assistants")!.split(",")
+ : voiceAssistantKeys;
+ showExposeEntityDialog(this, {
+ filterAssistants: assistants,
+ extendedEntities: this._extEntities!,
+ exposeEntities: (entities) => {
+ exposeEntities(this.hass, assistants, entities, true);
+ },
+ });
+ }
+
+ private _handleSearchChange(ev: CustomEvent) {
+ this._filter = ev.detail.value;
+ history.replaceState({ filter: this._filter }, "");
+ }
+
+ private _handleSelectionChanged(
+ ev: HASSDomEvent
+ ): void {
+ this._selectedEntities = ev.detail.value;
+ }
+
+ private _removeEntity = (ev) => {
+ ev.stopPropagation();
+ const entityId = ev.currentTarget.closest(".mdc-data-table__row").rowId;
+ const assistants = this._searchParms.has("assistants")
+ ? this._searchParms.get("assistants")!.split(",")
+ : voiceAssistantKeys;
+ exposeEntities(this.hass, assistants, [entityId], false);
+ };
+
+ private _unexposeSelected() {
+ const assistants = this._searchParms.has("assistants")
+ ? this._searchParms.get("assistants")!.split(",")
+ : voiceAssistantKeys;
+ showConfirmationDialog(this, {
+ title: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.unexpose_confirm_title"
+ ),
+ text: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.unexpose_confirm_text",
+ {
+ assistants: assistants
+ .map((ass) => voiceAssistants[ass].name)
+ .join(", "),
+ entities: this._selectedEntities.length,
+ }
+ ),
+ confirmText: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.unexpose"
+ ),
+ dismissText: this.hass.localize("ui.common.cancel"),
+ confirm: () => {
+ exposeEntities(this.hass, assistants, this._selectedEntities, false);
+ this._clearSelection();
+ },
+ });
+ }
+
+ private _exposeSelected() {
+ const assistants = this._searchParms.has("assistants")
+ ? this._searchParms.get("assistants")!.split(",")
+ : voiceAssistantKeys;
+ showConfirmationDialog(this, {
+ title: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.expose_confirm_title"
+ ),
+ text: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.expose_confirm_text",
+ {
+ assistants: assistants
+ .map((ass) => voiceAssistants[ass].name)
+ .join(", "),
+ entities: this._selectedEntities.length,
+ }
+ ),
+ confirmText: this.hass.localize(
+ "ui.panel.config.voice_assistants.expose.expose"
+ ),
+ dismissText: this.hass.localize("ui.common.cancel"),
+ confirm: () => {
+ exposeEntities(this.hass, assistants, this._selectedEntities, true);
+ this._clearSelection();
+ },
+ });
+ }
+
+ private _clearSelection() {
+ this._dataTable.clearSelection();
+ }
+
+ private _openEditEntry(ev: CustomEvent): void {
+ const entityId = (ev.detail as RowClickedEvent).id;
+ showVoiceSettingsDialog(this, { entityId });
+ }
+
+ private _clearFilter() {
+ if (this._activeFilters(this._searchParms)) {
+ navigate(window.location.pathname, { replace: true });
+ }
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ haStyle,
+ css`
+ hass-loading-screen {
+ --app-header-background-color: var(--sidebar-background-color);
+ --app-header-text-color: var(--sidebar-text-color);
+ }
+ .table-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: 56px;
+ background-color: var(--mdc-text-field-fill-color, whitesmoke);
+ border-bottom: 1px solid
+ var(--mdc-text-field-idle-line-color, rgba(0, 0, 0, 0.42));
+ box-sizing: border-box;
+ }
+ .header-toolbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ color: var(--secondary-text-color);
+ position: relative;
+ top: -4px;
+ }
+ .selected-txt {
+ font-weight: bold;
+ padding-left: 16px;
+ padding-inline-start: 16px;
+ direction: var(--direction);
+ }
+ .table-header .selected-txt {
+ margin-top: 20px;
+ }
+ .header-toolbar .selected-txt {
+ font-size: 16px;
+ }
+ .header-toolbar .header-btns {
+ margin-right: -12px;
+ margin-inline-end: -12px;
+ direction: var(--direction);
+ }
+ .header-btns {
+ display: flex;
+ }
+ .header-btns > mwc-button,
+ .header-btns > ha-icon-button {
+ margin: 8px;
+ }
+ ha-button-menu {
+ margin-left: 8px;
+ }
+ .clear {
+ color: var(--primary-color);
+ padding-left: 8px;
+ padding-inline-start: 8px;
+ text-transform: uppercase;
+ direction: var(--direction);
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-config-voice-assistants-expose": VoiceAssistantsExpose;
+ }
+}
diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants.ts
index 9ebea3faad..4009b404ad 100644
--- a/src/panels/config/voice-assistants/ha-config-voice-assistants.ts
+++ b/src/panels/config/voice-assistants/ha-config-voice-assistants.ts
@@ -1,21 +1,47 @@
+import { mdiDevices, mdiMicrophone } from "@mdi/js";
import { customElement, property } from "lit/decorators";
import {
HassRouterPage,
RouterOptions,
} from "../../../layouts/hass-router-page";
import { HomeAssistant } from "../../../types";
+import { CloudStatus } from "../../../data/cloud";
+
+export const voiceAssistantTabs = [
+ {
+ path: "/config/voice-assistants/assistants",
+ translationKey: "ui.panel.config.voice_assistants.assistants.caption",
+ iconPath: mdiMicrophone,
+ },
+ {
+ path: "/config/voice-assistants/expose",
+ translationKey: "ui.panel.config.voice_assistants.expose.caption",
+ iconPath: mdiDevices,
+ },
+];
@customElement("ha-config-voice-assistants")
class HaConfigVoiceAssistants extends HassRouterPage {
@property({ attribute: false }) public hass!: HomeAssistant;
+ @property({ attribute: false }) public cloudStatus!: CloudStatus;
+
@property() public narrow!: boolean;
@property() public isWide!: boolean;
protected routerOptions: RouterOptions = {
- defaultPage: "debug",
+ defaultPage: "assistants",
routes: {
+ assistants: {
+ tag: "ha-config-voice-assistants-assistants",
+ load: () => import("./ha-config-voice-assistants-assistants"),
+ cache: true,
+ },
+ expose: {
+ tag: "ha-config-voice-assistants-expose",
+ load: () => import("./ha-config-voice-assistants-expose"),
+ },
debug: {
tag: "assist-pipeline-debug",
load: () =>
@@ -28,6 +54,7 @@ class HaConfigVoiceAssistants extends HassRouterPage {
protected updatePageEl(pageEl) {
pageEl.hass = this.hass;
+ pageEl.cloudStatus = this.cloudStatus;
pageEl.narrow = this.narrow;
pageEl.isWide = this.isWide;
pageEl.route = this.routeTail;
diff --git a/src/panels/config/voice-assistants/show-dialog-expose-entity.ts b/src/panels/config/voice-assistants/show-dialog-expose-entity.ts
new file mode 100644
index 0000000000..acb406e711
--- /dev/null
+++ b/src/panels/config/voice-assistants/show-dialog-expose-entity.ts
@@ -0,0 +1,21 @@
+import { fireEvent } from "../../../common/dom/fire_event";
+import { ExtEntityRegistryEntry } from "../../../data/entity_registry";
+
+export interface ExposeEntityDialogParams {
+ filterAssistants: string[];
+ extendedEntities: Record;
+ exposeEntities: (entities: string[]) => void;
+}
+
+export const loadExposeEntityDialog = () => import("./dialog-expose-entity");
+
+export const showExposeEntityDialog = (
+ element: HTMLElement,
+ dialogParams: ExposeEntityDialogParams
+): void => {
+ fireEvent(element, "show-dialog", {
+ dialogTag: "dialog-expose-entity",
+ dialogImport: loadExposeEntityDialog,
+ dialogParams,
+ });
+};
diff --git a/src/panels/config/voice-assistants/show-dialog-voice-settings.ts b/src/panels/config/voice-assistants/show-dialog-voice-settings.ts
new file mode 100644
index 0000000000..1acc94bb10
--- /dev/null
+++ b/src/panels/config/voice-assistants/show-dialog-voice-settings.ts
@@ -0,0 +1,18 @@
+import { fireEvent } from "../../../common/dom/fire_event";
+
+export interface VoiceSettingsDialogParams {
+ entityId: string;
+}
+
+export const loadVoiceSettingsDialog = () => import("./dialog-voice-settings");
+
+export const showVoiceSettingsDialog = (
+ element: HTMLElement,
+ aliasesParams: VoiceSettingsDialogParams
+): void => {
+ fireEvent(element, "show-dialog", {
+ dialogTag: "dialog-voice-settings",
+ dialogImport: loadVoiceSettingsDialog,
+ dialogParams: aliasesParams,
+ });
+};
diff --git a/src/panels/my/ha-panel-my.ts b/src/panels/my/ha-panel-my.ts
index 2cfc2d7e50..49285d1687 100644
--- a/src/panels/my/ha-panel-my.ts
+++ b/src/panels/my/ha-panel-my.ts
@@ -141,6 +141,9 @@ export const getMyRedirects = (hasSupervisor: boolean): Redirects => ({
component: "tag",
redirect: "/config/tags",
},
+ "voice-assistants": {
+ redirect: "/config/voice-assistants",
+ },
lovelace_dashboards: {
component: "lovelace",
redirect: "/config/lovelace/dashboards",
diff --git a/src/translations/en.json b/src/translations/en.json
index 33394b18ab..f05539e79e 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -1060,6 +1060,12 @@
"aliases_description": "Aliases are alternative names used in voice assistants to refer to this entity."
}
},
+ "voice-settings": {
+ "expose_header": "Expose",
+ "aliasses_header": "Aliasses",
+ "ask_pin": "Ask for PIN",
+ "manual_config": "Managed with filters in configuration.yaml"
+ },
"restart": {
"heading": "Restart Home Assistant",
"advanced_options": "Advanced options",
@@ -1246,10 +1252,7 @@
"device_name_placeholder": "Change device name"
}
},
- "domain_toggler": {
- "title": "Toggle Domains",
- "reset_entities": "Reset Entity overrides"
- },
+ "entity_voice_settings": {},
"mqtt_device_debug_info": {
"title": "{device} debug info",
"deserialize": "Attempt to parse MQTT messages as JSON",
@@ -1406,6 +1409,10 @@
"main": "Dashboards",
"secondary": "Organize how you interact with your home"
},
+ "voice_assistants": {
+ "main": "Voice assistants",
+ "secondary": "Manage your voice assistants"
+ },
"energy": {
"main": "Energy",
"secondary": "Monitor your energy production and consumption"
@@ -1992,6 +1999,32 @@
}
}
},
+ "voice_assistants": {
+ "assistants": {
+ "caption": "Assistants"
+ },
+ "expose": {
+ "caption": "Expose",
+ "headers": {
+ "name": "Name",
+ "area": "Area",
+ "assistants": "Assistants",
+ "aliases": "Aliases"
+ },
+ "aliases": "{count} aliases",
+ "expose": "Expose",
+ "unexpose": "Unexpose",
+ "add": "Expose entities",
+ "expose_confirm_title": "Expose selected entities?",
+ "expose_confirm_text": "Do you want to expose {entities} entities to {assistants}?",
+ "unexpose_confirm_title": "Stop exposing selected entities?",
+ "unexpose_confirm_text": "Do you want to stop exposing {entities} entities to {assistants}?",
+ "expose_dialog": {
+ "header": "Expose entity",
+ "expose_entities": "Expose {count} {count, plural,\n one {entity}\n other {entities}\n}"
+ }
+ }
+ },
"automation": {
"caption": "Automations",
"description": "Create custom behavior rules for your home",
@@ -2677,6 +2710,7 @@
"integrations_introduction": "Integrations for Home Assistant Cloud allow you to connect with services in the cloud without having to expose your Home Assistant instance publicly on the internet.",
"integrations_introduction2": "Check the website for ",
"integrations_link_all_features": " all available features",
+ "tip_moved_voice_assistants": "Looking for Google Assistant and Amazon Alexa settings? They are moved to the new voice assistants page.",
"connected": "Connected",
"connecting": "Connecting…",
"not_connected": "Not Connected",
@@ -2718,11 +2752,14 @@
"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": "[%key:ui::panel::config::cloud::account::google::manage_entities%]",
+ "manual_config": "[%key:ui::panel::config::cloud::account::google::manual_config%]",
"enable": "enable",
"disable": "disable",
- "not_configured_title": "Alexa is not activated",
+ "not_configured_title": "Continue setting up Alexa",
"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%]"
+ "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?"
},
"google": {
"title": "Google Assistant",
@@ -2738,10 +2775,13 @@
"devices_pin": "Security Devices PIN",
"enter_pin_hint": "Enter a PIN to use security devices",
"manage_entities": "Manage Entities",
+ "manual_config": "Editing which entities are exposed via the UI is disabled because you have configured entity filters in configuration.yaml.",
"enter_pin_error": "Unable to store PIN:",
- "not_configured_title": "Google Assistant is not activated",
+ "not_configured_title": "Continue setting up Google Assistant",
"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%]"
+ "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?"
},
"webhooks": {
"title": "Webhooks",
@@ -2756,23 +2796,6 @@
"disable_hook_error_msg": "Failed to disable webhook:"
}
},
- "alexa": {
- "title": "Alexa",
- "banner": "[%key:ui::panel::config::cloud::google::banner%]",
- "exposed_entities": "[%key:ui::panel::config::cloud::google::exposed_entities%]",
- "not_exposed_entities": "[%key:ui::panel::config::cloud::google::not_exposed_entities%]",
- "manage_defaults": "[%key:ui::panel::config::cloud::google::manage_defaults%]",
- "manage_defaults_dialog_description": "[%key:ui::panel::config::cloud::google::manage_defaults_dialog_description%]",
- "expose_entity": "[%key:ui::panel::config::cloud::google::expose_entity%]",
- "dont_expose_entity": "[%key:ui::panel::config::cloud::google::dont_expose_entity%]",
- "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:"
- },
"dialog_certificate": {
"certificate_information": "Certificate Information",
"certificate_expiration_date": "Certificate expiration date:",
@@ -2780,33 +2803,6 @@
"fingerprint": "Certificate fingerprint:",
"close": "Close"
},
- "google": {
- "title": "Google Assistant",
- "expose": "Expose to Google Assistant",
- "disable_2FA": "Disable two factor authentication",
- "banner": "Editing which entities are exposed via this UI is disabled because you have configured entity filters in configuration.yaml.",
- "exposed_entities": "Exposed entities",
- "not_exposed_entities": "Not exposed entities",
- "manage_defaults": "Manage defaults",
- "manage_defaults_dialog_description": "Entities can be exposed by default based on their type.",
- "expose_entity": "Expose entity",
- "dont_expose_entity": "Don't expose entity",
- "follow_domain": "Follow domain",
- "exposed": "{selected} exposed",
- "not_exposed": "{selected} not exposed",
- "manage_aliases": "Manage aliases",
- "add_aliases": "Add aliases",
- "no_aliases": "No aliases",
- "aliases_not_available": "Aliases not available",
- "aliases_not_available_learn_more": "Learn more",
- "sync_to_google": "Synchronizing changes to Google.",
- "sync_entities": "Synchronize entities",
- "sync_entities_error": "Failed to sync entities:",
- "not_configured_title": "[%key:ui::panel::config::cloud::account::google::not_configured_title%]",
- "not_configured_text": "[%key:ui::panel::config::cloud::account::google::not_configured_text%]",
- "sync_failed_title": "Syncing failed",
- "sync_failed_text": "Syncing your entities failed, try again or check the logs."
- },
"dialog_cloudhook": {
"webhook_for": "Webhook for {name}",
"managed_by_integration": "This webhook is managed by an integration and cannot be disabled.",
From 1a9b99dd72786aa0b923426c9b89f8022e53c01b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 13 Apr 2023 03:50:02 +0000
Subject: [PATCH 007/112] Update dependency glob to v10 (#16153)
* Update dependency glob to v10
* Use named export in gallery pages task
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher
---
build-scripts/gulp/gallery.cjs | 2 +-
package.json | 2 +-
yarn.lock | 64 +++++++++++++++++++++-------------
3 files changed, 41 insertions(+), 27 deletions(-)
diff --git a/build-scripts/gulp/gallery.cjs b/build-scripts/gulp/gallery.cjs
index 25b53332ce..74a752fb5d 100644
--- a/build-scripts/gulp/gallery.cjs
+++ b/build-scripts/gulp/gallery.cjs
@@ -3,7 +3,7 @@ const gulp = require("gulp");
const fs = require("fs");
const path = require("path");
const { marked } = require("marked");
-const glob = require("glob");
+const { glob } = require("glob");
const yaml = require("js-yaml");
const env = require("../env.cjs");
diff --git a/package.json b/package.json
index 2b0687469a..bb2a39d81e 100644
--- a/package.json
+++ b/package.json
@@ -207,7 +207,7 @@
"esprima": "4.0.1",
"fancy-log": "2.0.0",
"fs-extra": "11.1.1",
- "glob": "9.3.4",
+ "glob": "10.0.0",
"gulp": "4.0.2",
"gulp-flatmap": "1.0.2",
"gulp-json-transform": "0.4.8",
diff --git a/yarn.lock b/yarn.lock
index 7e677ef499..048f2f26d6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9012,6 +9012,18 @@ __metadata:
languageName: node
linkType: hard
+"glob@npm:10.0.0":
+ version: 10.0.0
+ resolution: "glob@npm:10.0.0"
+ dependencies:
+ fs.realpath: ^1.0.0
+ minimatch: ^9.0.0
+ minipass: ^5.0.0
+ path-scurry: ^1.6.4
+ checksum: 3852a6b847106c431d87fb3e8cccb6cfc4449de3ab5d0216c44d4e2da2616df220058050d16811c42f0c2148ad8981da828227ae5c5ab798091ef27c903429f6
+ languageName: node
+ linkType: hard
+
"glob@npm:7.2.0":
version: 7.2.0
resolution: "glob@npm:7.2.0"
@@ -9026,18 +9038,6 @@ __metadata:
languageName: node
linkType: hard
-"glob@npm:9.3.4":
- version: 9.3.4
- resolution: "glob@npm:9.3.4"
- dependencies:
- fs.realpath: ^1.0.0
- minimatch: ^8.0.2
- minipass: ^4.2.4
- path-scurry: ^1.6.1
- checksum: bcf49eaf475dc4ce8d4e98f896408a9f6507a2cb7d24a207c012cb318b969e04a02bcde2ff2920eadd5055ccae444a007b769e418147a56268fab2cda8694cde
- languageName: node
- linkType: hard
-
"glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6":
version: 7.2.3
resolution: "glob@npm:7.2.3"
@@ -9577,7 +9577,7 @@ __metadata:
fancy-log: 2.0.0
fs-extra: 11.1.1
fuse.js: 6.6.2
- glob: 9.3.4
+ glob: 10.0.0
google-timezones-json: 1.0.2
gulp: 4.0.2
gulp-flatmap: 1.0.2
@@ -11495,13 +11495,20 @@ __metadata:
languageName: node
linkType: hard
-"lru-cache@npm:^7.14.1, lru-cache@npm:^7.7.1":
+"lru-cache@npm:^7.7.1":
version: 7.18.3
resolution: "lru-cache@npm:7.18.3"
checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356
languageName: node
linkType: hard
+"lru-cache@npm:^9.0.0":
+ version: 9.0.1
+ resolution: "lru-cache@npm:9.0.1"
+ checksum: 48e31a2a059730174d4b9c77c679ff922ee90ed8762376fd7a3ff5a1fae992bca26b9010dd985aff763d8444c3822c0d9ebeaba7d0552c764c200c40dedeaebd
+ languageName: node
+ linkType: hard
+
"magic-string@npm:0.30.0":
version: 0.30.0
resolution: "magic-string@npm:0.30.0"
@@ -11802,12 +11809,12 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:^8.0.2":
- version: 8.0.3
- resolution: "minimatch@npm:8.0.3"
+"minimatch@npm:^9.0.0":
+ version: 9.0.0
+ resolution: "minimatch@npm:9.0.0"
dependencies:
brace-expansion: ^2.0.1
- checksum: 8957d8105be6729bf1d3af9c410b2a38ffcf3cd17d4ffaf715b2aa4841490aaa82f1ebff785e71b5b97747199ccc61027db597495941cf46243d9a64382e1560
+ checksum: 7bd57899edd1d1b0560f50b5b2d1ea4ad2a366c5a2c8e0a943372cf2f200b64c256bae45a87a80915adbce27fa36526264296ace0da57b600481fe5ea3e372e5
languageName: node
linkType: hard
@@ -11878,13 +11885,20 @@ __metadata:
languageName: node
linkType: hard
-"minipass@npm:^4.0.0, minipass@npm:^4.0.2, minipass@npm:^4.2.4":
+"minipass@npm:^4.0.0":
version: 4.2.5
resolution: "minipass@npm:4.2.5"
checksum: 4f9c19af23a5d4a9e7156feefc9110634b178a8cff8f8271af16ec5ebf7e221725a97429952c856f5b17b30c2065ebd24c81722d90c93d2122611d75b952b48f
languageName: node
linkType: hard
+"minipass@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "minipass@npm:5.0.0"
+ checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea
+ languageName: node
+ linkType: hard
+
"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2":
version: 2.1.2
resolution: "minizlib@npm:2.1.2"
@@ -12811,13 +12825,13 @@ __metadata:
languageName: node
linkType: hard
-"path-scurry@npm:^1.6.1":
- version: 1.6.2
- resolution: "path-scurry@npm:1.6.2"
+"path-scurry@npm:^1.6.4":
+ version: 1.6.4
+ resolution: "path-scurry@npm:1.6.4"
dependencies:
- lru-cache: ^7.14.1
- minipass: ^4.0.2
- checksum: daf863a0e5135be0741a461d36fe1cf67c3dda441d6dd9b038c94c601738e389de9a2f80ae92a5aed7c424186cce46770e785feef30939d364033247436ee5ee
+ lru-cache: ^9.0.0
+ minipass: ^5.0.0
+ checksum: bd5262b51dc35b0d6f0b1d4fa4445789839982bd649904f18fe43717ecc3021d2313a80768b56cd0428f5ca50d740a6c609e747cd6a053efaa802e07eb5b7b18
languageName: node
linkType: hard
From fbb59b1459e540032ada6e12c1cc547f1537c76a Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Thu, 13 Apr 2023 10:56:52 +0200
Subject: [PATCH 008/112] Fix context provider not updated on initializing of
hass object (#16159)
---
src/state/context-mixin.ts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/state/context-mixin.ts b/src/state/context-mixin.ts
index 9b8e2a8bb7..d3bbc3ead6 100644
--- a/src/state/context-mixin.ts
+++ b/src/state/context-mixin.ts
@@ -82,6 +82,15 @@ export const contextMixin = >(
}),
};
+ protected hassConnected() {
+ super.hassConnected();
+ for (const [key, value] of Object.entries(this.hass!)) {
+ if (key in this.__contextProviders) {
+ this.__contextProviders[key]!.setValue(value);
+ }
+ }
+ }
+
protected _updateHass(obj: Partial) {
super._updateHass(obj);
for (const [key, value] of Object.entries(obj)) {
From ddb523c133f3d67039bb174584c9f814cfadea85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joakim=20S=C3=B8rensen?=
Date: Thu, 13 Apr 2023 11:11:47 +0200
Subject: [PATCH 009/112] Use certificate status for better feedback when
initialising remote (#16147)
---
src/data/cloud.ts | 7 +++++
.../config/cloud/account/cloud-remote-pref.ts | 28 +++++++++++++++----
src/translations/en.json | 3 ++
3 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/src/data/cloud.ts b/src/data/cloud.ts
index 353a5601a7..454bbcc482 100644
--- a/src/data/cloud.ts
+++ b/src/data/cloud.ts
@@ -40,6 +40,13 @@ export interface CloudStatusLoggedIn {
remote_domain: string | undefined;
remote_connected: boolean;
remote_certificate: undefined | CertificateInformation;
+ remote_certificate_status:
+ | null
+ | "error"
+ | "generating"
+ | "loaded"
+ | "loading"
+ | "ready";
http_use_ssl: boolean;
active_subscription: boolean;
}
diff --git a/src/panels/config/cloud/account/cloud-remote-pref.ts b/src/panels/config/cloud/account/cloud-remote-pref.ts
index 114bc0cbdf..d9ac6bd89c 100644
--- a/src/panels/config/cloud/account/cloud-remote-pref.ts
+++ b/src/panels/config/cloud/account/cloud-remote-pref.ts
@@ -31,10 +31,14 @@ export class CloudRemotePref extends LitElement {
const { remote_enabled } = this.cloudStatus.prefs;
- const { remote_connected, remote_domain, remote_certificate } =
- this.cloudStatus;
+ const {
+ remote_connected,
+ remote_domain,
+ remote_certificate,
+ remote_certificate_status,
+ } = this.cloudStatus;
- if (!remote_certificate) {
+ if (!remote_certificate || remote_certificate_status !== "ready") {
return html`
- ${this.hass.localize(
- "ui.panel.config.cloud.account.remote.access_is_being_prepared"
- )}
+ ${remote_certificate_status === "error"
+ ? this.hass.localize(
+ "ui.panel.config.cloud.account.remote.cerificate_error"
+ )
+ : remote_certificate_status === "loading"
+ ? this.hass.localize(
+ "ui.panel.config.cloud.account.remote.cerificate_loading"
+ )
+ : remote_certificate_status === "loaded"
+ ? this.hass.localize(
+ "ui.panel.config.cloud.account.remote.cerificate_loaded"
+ )
+ : this.hass.localize(
+ "ui.panel.config.cloud.account.remote.access_is_being_prepared"
+ )}
`;
diff --git a/src/translations/en.json b/src/translations/en.json
index f05539e79e..e3e1bfe853 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -2736,6 +2736,9 @@
"not_connected": "Not Connected",
"reconnecting": "Not connected. Trying to reconnect.",
"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.",
"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",
From 7f4dadfc20f7ef6d053cda442104ef9f26838e3c Mon Sep 17 00:00:00 2001
From: "J. Nick Koston"
Date: Wed, 12 Apr 2023 23:48:14 -1000
Subject: [PATCH 010/112] Fix energy panel fetching all stats instead of only
sum (#16161)
---
.../lovelace/cards/energy/hui-energy-devices-graph-card.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/panels/lovelace/cards/energy/hui-energy-devices-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-devices-graph-card.ts
index 5f4b012869..2e302e01b6 100644
--- a/src/panels/lovelace/cards/energy/hui-energy-devices-graph-card.ts
+++ b/src/panels/lovelace/cards/energy/hui-energy-devices-graph-card.ts
@@ -195,7 +195,8 @@ export class HuiEnergyDevicesGraphCard
energyData.end,
devices,
period,
- units
+ units,
+ ["sum"]
);
Object.values(data).forEach((stat) => {
@@ -221,7 +222,8 @@ export class HuiEnergyDevicesGraphCard
energyData.endCompare,
devices,
period,
- units
+ units,
+ ["sum"]
);
Object.values(compareData).forEach((stat) => {
From 639c120b56a52d0bba377121acc8e83a79b2ecd4 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 13 Apr 2023 08:42:24 -0400
Subject: [PATCH 011/112] Update dependency instant-mocha to v1.5.1 (#16160)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
package.json | 2 +-
yarn.lock | 24 ++++++++++++------------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/package.json b/package.json
index bb2a39d81e..531cc9304e 100644
--- a/package.json
+++ b/package.json
@@ -216,7 +216,7 @@
"gulp-zopfli-green": "6.0.1",
"html-minifier-terser": "7.1.0",
"husky": "8.0.3",
- "instant-mocha": "1.5.0",
+ "instant-mocha": "1.5.1",
"jszip": "3.10.1",
"lint-staged": "13.2.1",
"lit-analyzer": "1.2.1",
diff --git a/yarn.lock b/yarn.lock
index 048f2f26d6..27b3396892 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8754,7 +8754,7 @@ __metadata:
languageName: node
linkType: hard
-"fs-require@npm:^1.4.0":
+"fs-require@npm:^1.6.0":
version: 1.6.0
resolution: "fs-require@npm:1.6.0"
checksum: 085145a3021e142ae8d591d955f7e1d9cab17191666294e0ad394df5cb9ee379817b89c50de63bd861138dcb6adec589289d347c23de9bfe1ac82aeba6b1a128
@@ -9590,7 +9590,7 @@ __metadata:
html-minifier-terser: 7.1.0
husky: 8.0.3
idb-keyval: 6.2.0
- instant-mocha: 1.5.0
+ instant-mocha: 1.5.1
intl-messageformat: 10.3.3
js-yaml: 4.1.0
jszip: 3.10.1
@@ -10032,12 +10032,12 @@ __metadata:
languageName: node
linkType: hard
-"instant-mocha@npm:1.5.0":
- version: 1.5.0
- resolution: "instant-mocha@npm:1.5.0"
+"instant-mocha@npm:1.5.1":
+ version: 1.5.1
+ resolution: "instant-mocha@npm:1.5.1"
dependencies:
- fs-require: ^1.4.0
- memfs: ^3.4.12
+ fs-require: ^1.6.0
+ memfs: ^3.5.0
source-map-support: ^0.5.21
yargs: ^16.2.0
peerDependencies:
@@ -10045,7 +10045,7 @@ __metadata:
webpack: 4 || 5
bin:
instant-mocha: dist/cli.js
- checksum: 77741864a0b6602e7599dc93e3bd3dfc3451c58e84881c7163b8fc9494c095528ba3cc2c8b74be41e885a659711d81777ff7fd761523c34d4eabcd9fb555156d
+ checksum: c098a792ba3bddc1d421da7067c21818ccc64e45d98ccce735ab35c29132f01cf624a2106b1ecd5f1e5d9c9d9bbb8f947d92db8bcfa7ddae01425f7fd291ee6e
languageName: node
linkType: hard
@@ -11629,12 +11629,12 @@ __metadata:
languageName: node
linkType: hard
-"memfs@npm:^3.4.12, memfs@npm:^3.4.3":
- version: 3.4.13
- resolution: "memfs@npm:3.4.13"
+"memfs@npm:^3.4.3, memfs@npm:^3.5.0":
+ version: 3.5.0
+ resolution: "memfs@npm:3.5.0"
dependencies:
fs-monkey: ^1.0.3
- checksum: 3f9717d6f060919d53f211acb6096a0ea2f566a8cbcc4ef7e1f2561e31e33dc456053fdf951c90a49c8ec55402de7f01b006b81683ab7bd4bdbbd8c9b9cdae5f
+ checksum: 8427db6c3644eeb9119b7a74b232d9a6178d018878acce6f05bd89d95e28b1073c9eeb00127131b0613b07a003e2e7b15b482f9004e548fe06a0aba7aa02515c
languageName: node
linkType: hard
From 5e352f61943a2aafcbc88daec9f7d293794d6deb Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Thu, 13 Apr 2023 14:52:10 +0200
Subject: [PATCH 012/112] Voice assistants pipeline UI (#16167)
---
src/components/ha-form/ha-form-expandable.ts | 1 +
src/data/voice_assistant.ts | 51 +++++
.../config/voice-assistants/assist-pref.ts | 188 ++++++++++++++++
.../dialog-voice-assistant-pipeline-detail.ts | 204 ++++++++++++++++++
.../ha-config-voice-assistants-assistants.ts | 6 +-
...-dialog-voice-assistant-pipeline-detail.ts | 30 +++
src/translations/en.json | 22 +-
7 files changed, 499 insertions(+), 3 deletions(-)
create mode 100644 src/panels/config/voice-assistants/assist-pref.ts
create mode 100644 src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
create mode 100644 src/panels/config/voice-assistants/show-dialog-voice-assistant-pipeline-detail.ts
diff --git a/src/components/ha-form/ha-form-expandable.ts b/src/components/ha-form/ha-form-expandable.ts
index 86c108caac..2c4892efdd 100644
--- a/src/components/ha-form/ha-form-expandable.ts
+++ b/src/components/ha-form/ha-form-expandable.ts
@@ -71,6 +71,7 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
display: block;
--expansion-panel-content-padding: 0;
border-radius: 6px;
+ --ha-card-border-radius: 6px;
}
ha-svg-icon,
ha-icon {
diff --git a/src/data/voice_assistant.ts b/src/data/voice_assistant.ts
index 5500effdf7..5092509609 100644
--- a/src/data/voice_assistant.ts
+++ b/src/data/voice_assistant.ts
@@ -3,6 +3,23 @@ import type { ConversationResult } from "./conversation";
import type { ResolvedMediaSource } from "./media_source";
import type { SpeechMetadata } from "./stt";
+export interface VoiceAssistantPipeline {
+ id: string;
+ conversation_engine: string;
+ language: string;
+ name: string;
+ stt_engine: string;
+ tts_engine: string;
+}
+
+export interface VoiceAssistantPipelineMutableParams {
+ conversation_engine: string;
+ language: string;
+ name: string;
+ stt_engine: string;
+ tts_engine: string;
+}
+
interface PipelineEventBase {
timestamp: string;
}
@@ -202,3 +219,37 @@ export const runVoiceAssistantPipeline = (
return unsubProm;
};
+
+export const fetchVoiceAssistantPipelines = (hass: HomeAssistant) =>
+ hass.callWS({
+ type: "voice_assistant/pipeline/list",
+ });
+
+export const createVoiceAssistantPipeline = (
+ hass: HomeAssistant,
+ pipeline: VoiceAssistantPipelineMutableParams
+) =>
+ hass.callWS({
+ type: "voice_assistant/pipeline/create",
+ ...pipeline,
+ });
+
+export const updateVoiceAssistantPipeline = (
+ hass: HomeAssistant,
+ pipelineId: string,
+ pipeline: Partial
+) =>
+ hass.callWS({
+ type: "voice_assistant/pipeline/update",
+ pipeline_id: pipelineId,
+ ...pipeline,
+ });
+
+export const deleteVoiceAssistantPipeline = (
+ hass: HomeAssistant,
+ pipelineId: string
+) =>
+ hass.callWS({
+ type: "voice_assistant/pipeline/delete",
+ pipeline_id: pipelineId,
+ });
diff --git a/src/panels/config/voice-assistants/assist-pref.ts b/src/panels/config/voice-assistants/assist-pref.ts
new file mode 100644
index 0000000000..e08e801def
--- /dev/null
+++ b/src/panels/config/voice-assistants/assist-pref.ts
@@ -0,0 +1,188 @@
+import "@material/mwc-list/mwc-list";
+import { mdiHelpCircle, mdiPlus } from "@mdi/js";
+import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
+import { property, state } from "lit/decorators";
+import "../../../components/ha-alert";
+import "../../../components/ha-card";
+import "../../../components/ha-icon-next";
+import "../../../components/ha-list-item";
+import "../../../components/ha-switch";
+import "../../../components/ha-button";
+import {
+ createVoiceAssistantPipeline,
+ deleteVoiceAssistantPipeline,
+ fetchVoiceAssistantPipelines,
+ updateVoiceAssistantPipeline,
+ VoiceAssistantPipeline,
+} from "../../../data/voice_assistant";
+import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
+import type { HomeAssistant } from "../../../types";
+import { showVoiceAssistantPipelineDetailDialog } from "./show-dialog-voice-assistant-pipeline-detail";
+
+export class AssistPref extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @state() private _pipelines: VoiceAssistantPipeline[] = [];
+
+ protected firstUpdated(changedProps: PropertyValues) {
+ super.firstUpdated(changedProps);
+
+ fetchVoiceAssistantPipelines(this.hass).then((pipelines) => {
+ this._pipelines = pipelines;
+ });
+ }
+
+ protected render() {
+ return html`
+
+
+
+
+
+ ${this._pipelines.map(
+ (pipeline) => html`
+
+ ${pipeline.name}
+ ${pipeline.language}
+
+
+ `
+ )}
+
+
+ ${this.hass.localize(
+ "ui.panel.config.voice_assistants.assistants.pipeline.add_assistant"
+ )}
+
+
+
+
+
+ `;
+ }
+
+ private _editPipeline(ev) {
+ const id = ev.currentTarget.id as string;
+
+ const pipeline = this._pipelines.find((res) => res.id === id);
+ this._openDialog(pipeline);
+ }
+
+ private _addPipeline() {
+ this._openDialog();
+ }
+
+ private async _openDialog(pipeline?: VoiceAssistantPipeline): Promise {
+ showVoiceAssistantPipelineDetailDialog(this, {
+ pipeline,
+ createPipeline: async (values) => {
+ const created = await createVoiceAssistantPipeline(this.hass!, values);
+ this._pipelines = this._pipelines!.concat(created);
+ },
+ updatePipeline: async (values) => {
+ const updated = await updateVoiceAssistantPipeline(
+ this.hass!,
+ pipeline!.id,
+ values
+ );
+ this._pipelines = this._pipelines!.map((res) =>
+ res === pipeline ? updated : res
+ );
+ },
+ deletePipeline: async () => {
+ if (
+ !(await showConfirmationDialog(this, {
+ title: this.hass!.localize(
+ "ui.panel.config.voice_assistants.assistants.pipeline.delete.confirm_title",
+ { name: pipeline!.name }
+ ),
+ text: this.hass!.localize(
+ "ui.panel.config.voice_assistants.assistants.pipeline.delete.confirm_text",
+ { name: pipeline!.name }
+ ),
+ confirmText: this.hass!.localize("ui.common.delete"),
+ destructive: true,
+ }))
+ ) {
+ return false;
+ }
+
+ try {
+ await deleteVoiceAssistantPipeline(this.hass!, pipeline!.id);
+ this._pipelines = this._pipelines!.filter((res) => res !== pipeline);
+ return true;
+ } catch (err: any) {
+ return false;
+ }
+ },
+ });
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ a {
+ color: var(--primary-color);
+ }
+ .header-actions {
+ position: absolute;
+ right: 0px;
+ top: 24px;
+ display: flex;
+ flex-direction: row;
+ }
+ .header-actions .icon-link {
+ margin-top: -16px;
+ margin-inline-end: 8px;
+ margin-right: 8px;
+ direction: var(--direction);
+ color: var(--secondary-text-color);
+ }
+ .card-actions {
+ display: flex;
+ }
+ .card-actions a {
+ text-decoration: none;
+ }
+ .card-header {
+ display: flex;
+ align-items: center;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "assist-pref": AssistPref;
+ }
+}
+
+customElements.define("assist-pref", AssistPref);
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
new file mode 100644
index 0000000000..c40b80f2fd
--- /dev/null
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -0,0 +1,204 @@
+import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { customElement, property, state } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { fireEvent } from "../../../common/dom/fire_event";
+import "../../../components/ha-button";
+import { createCloseHeading } from "../../../components/ha-dialog";
+import "../../../components/ha-form/ha-form";
+import { SchemaUnion } from "../../../components/ha-form/types";
+import {
+ VoiceAssistantPipeline,
+ VoiceAssistantPipelineMutableParams,
+} from "../../../data/voice_assistant";
+import { haStyleDialog } from "../../../resources/styles";
+import { HomeAssistant } from "../../../types";
+import { VoiceAssistantPipelineDetailsDialogParams } from "./show-dialog-voice-assistant-pipeline-detail";
+
+@customElement("dialog-voice-assistant-pipeline-detail")
+export class DialogVoiceAssistantPipelineDetail extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @state() private _params?: VoiceAssistantPipelineDetailsDialogParams;
+
+ @state() private _data?: Partial;
+
+ @state() private _error?: Record;
+
+ @state() private _submitting = false;
+
+ public showDialog(params: VoiceAssistantPipelineDetailsDialogParams): void {
+ this._params = params;
+ this._error = undefined;
+ if (this._params.pipeline) {
+ this._data = this._params.pipeline;
+ } else {
+ this._data = {};
+ }
+ }
+
+ public closeDialog(): void {
+ this._params = undefined;
+ this._data = undefined;
+ fireEvent(this, "dialog-closed", { dialog: this.localName });
+ }
+
+ protected render() {
+ if (!this._params || !this._data) {
+ return nothing;
+ }
+
+ return html`
+
+
+
+
+ ${this._params.pipeline?.id
+ ? html`
+
+ ${this.hass.localize("ui.common.delete")}
+
+ `
+ : nothing}
+
+ ${this._params.pipeline?.id
+ ? this.hass.localize(
+ "ui.panel.config.voice_assistants.assistants.pipeline.detail.update_assistant_action"
+ )
+ : this.hass.localize(
+ "ui.panel.config.voice_assistants.assistants.pipeline.detail.add_assistant_action"
+ )}
+
+
+ `;
+ }
+
+ private _schema = memoizeOne(
+ () =>
+ [
+ {
+ name: "name",
+ required: true,
+ selector: {
+ text: {},
+ },
+ },
+ {
+ name: "conversation_engine",
+ required: true,
+ selector: {
+ text: {},
+ },
+ },
+ {
+ name: "language",
+ required: true,
+ selector: {
+ text: {},
+ },
+ },
+ {
+ name: "stt_engine",
+ required: true,
+ selector: {
+ text: {},
+ },
+ },
+ {
+ name: "tts_engine",
+ required: true,
+ selector: {
+ text: {},
+ },
+ },
+ ] as const
+ );
+
+ private _computeLabel = (
+ schema: SchemaUnion>
+ ): string =>
+ this.hass.localize(
+ `ui.panel.config.voice_assistants.assistants.pipeline.detail.form.${schema.name}`
+ );
+
+ private _valueChanged(ev: CustomEvent) {
+ this._error = undefined;
+ const value = ev.detail.value;
+ this._data = value;
+ }
+
+ private async _updatePipeline() {
+ this._submitting = true;
+ try {
+ if (this._params!.pipeline?.id) {
+ const values: Partial = {
+ name: this._data!.name,
+ conversation_engine: this._data!.conversation_engine,
+ language: this._data!.language,
+ stt_engine: this._data!.stt_engine,
+ tts_engine: this._data!.tts_engine,
+ };
+ await this._params!.updatePipeline(values);
+ } else {
+ await this._params!.createPipeline(
+ this._data as VoiceAssistantPipelineMutableParams
+ );
+ }
+ this.closeDialog();
+ } catch (err: any) {
+ this._error = { base: err?.message || "Unknown error" };
+ } finally {
+ this._submitting = false;
+ }
+ }
+
+ private async _deletePipeline() {
+ this._submitting = true;
+ try {
+ if (await this._params!.deletePipeline()) {
+ this.closeDialog();
+ }
+ } finally {
+ this._submitting = false;
+ }
+ }
+
+ static get styles(): CSSResultGroup {
+ return [haStyleDialog, css``];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "dialog-voice-assistant-pipeline-detail": DialogVoiceAssistantPipelineDetail;
+ }
+}
diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants-assistants.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants-assistants.ts
index 191fe9f8b5..ca720066ec 100644
--- a/src/panels/config/voice-assistants/ha-config-voice-assistants-assistants.ts
+++ b/src/panels/config/voice-assistants/ha-config-voice-assistants-assistants.ts
@@ -1,14 +1,15 @@
+import "@polymer/paper-item/paper-item";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
+import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { computeRTLDirection } from "../../../common/util/compute_rtl";
import { CloudStatus } from "../../../data/cloud";
import "../../../layouts/hass-tabs-subpage";
import { HomeAssistant, Route } from "../../../types";
+import "./assist-pref";
import "./cloud-alexa-pref";
import "./cloud-google-pref";
import { voiceAssistantTabs } from "./ha-config-voice-assistants";
-import "@polymer/paper-item/paper-item";
-import { isComponentLoaded } from "../../../common/config/is_component_loaded";
@customElement("ha-config-voice-assistants-assistants")
export class HaConfigVoiceAssistantsAssistants extends LitElement {
@@ -36,6 +37,7 @@ export class HaConfigVoiceAssistantsAssistants extends LitElement {
.tabs=${voiceAssistantTabs}
>
+
${this.cloudStatus?.logged_in
? html`
Promise;
+ updatePipeline: (
+ updates: Partial
+ ) => Promise;
+ deletePipeline: () => Promise;
+}
+
+export const loadVoiceAssistantPipelineDetailDialog = () =>
+ import("./dialog-voice-assistant-pipeline-detail");
+
+export const showVoiceAssistantPipelineDetailDialog = (
+ element: HTMLElement,
+ dialogParams: VoiceAssistantPipelineDetailsDialogParams
+) => {
+ fireEvent(element, "show-dialog", {
+ dialogTag: "dialog-voice-assistant-pipeline-detail",
+ dialogImport: loadVoiceAssistantPipelineDetailDialog,
+ dialogParams,
+ });
+};
diff --git a/src/translations/en.json b/src/translations/en.json
index e3e1bfe853..0cc9035a69 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -2001,7 +2001,27 @@
},
"voice_assistants": {
"assistants": {
- "caption": "Assistants"
+ "caption": "Assistants",
+ "pipeline": {
+ "add_assistant": "Add assistant",
+ "manage_entities": "[%key:ui::panel::config::cloud::account::google::manage_entities%]",
+ "delete": {
+ "confirm_title": "Delete {name}?",
+ "confirm_text": "{name} will be permanently deleted."
+ },
+ "detail": {
+ "update_assistant_action": "Update",
+ "add_assistant_title": "Add assistant",
+ "add_assistant_action": "Create",
+ "form": {
+ "name": "Name",
+ "conversation_engine": "Conversation agent",
+ "language": "Language",
+ "stt_engine": "Speech to text",
+ "tts_engine": "Text to speech"
+ }
+ }
+ }
},
"expose": {
"caption": "Expose",
From a741faced17cc996bebad0d9401743372475b4ce Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Thu, 13 Apr 2023 15:27:17 +0200
Subject: [PATCH 013/112] Update assist config layout a bit (#16170
* Update assist config a bit
* update images
* Update assist-pref.ts
---
src/data/voice.ts | 2 +-
.../config/voice-assistants/assist-pref.ts | 68 ++++++++++++-------
2 files changed, 43 insertions(+), 27 deletions(-)
diff --git a/src/data/voice.ts b/src/data/voice.ts
index e2d12bdf49..6a2c75c943 100644
--- a/src/data/voice.ts
+++ b/src/data/voice.ts
@@ -1,7 +1,7 @@
import { HomeAssistant } from "../types";
export const voiceAssistants = {
- conversation: { domain: "conversation", name: "Assist" },
+ conversation: { domain: "voice_assistant", name: "Assist" },
"cloud.alexa": {
domain: "alexa",
name: "Amazon Alexa",
diff --git a/src/panels/config/voice-assistants/assist-pref.ts b/src/panels/config/voice-assistants/assist-pref.ts
index e08e801def..f156ead905 100644
--- a/src/panels/config/voice-assistants/assist-pref.ts
+++ b/src/panels/config/voice-assistants/assist-pref.ts
@@ -18,6 +18,7 @@ import {
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../types";
import { showVoiceAssistantPipelineDetailDialog } from "./show-dialog-voice-assistant-pipeline-detail";
+import { brandsUrl } from "../../../util/brands-url";
export class AssistPref extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -35,7 +36,17 @@ export class AssistPref extends LitElement {
protected render() {
return html`
-
+
-
-
- ${this._pipelines.map(
- (pipeline) => html`
-
- ${pipeline.name}
- ${pipeline.language}
-
-
- `
- )}
-
-
- ${this.hass.localize(
- "ui.panel.config.voice_assistants.assistants.pipeline.add_assistant"
- )}
-
-
-
+
+ ${this._pipelines.map(
+ (pipeline) => html`
+
+ ${pipeline.name}
+ ${pipeline.language}
+
+
+ `
+ )}
+
+
+ ${this.hass.localize(
+ "ui.panel.config.voice_assistants.assistants.pipeline.add_assistant"
+ )}
+
+
Date: Thu, 13 Apr 2023 21:15:01 +0200
Subject: [PATCH 014/112] Use body scroll with ha-drawer (#16137)
---
src/components/ha-drawer.ts | 10 +-
src/components/ha-top-app-bar-fixed.ts | 28 +-----
src/layouts/home-assistant-main.ts | 1 +
.../ha-panel-developer-tools.ts | 24 +++--
src/panels/lovelace/hui-root.ts | 91 +++++++++----------
src/panels/lovelace/views/hui-masonry-view.ts | 3 +-
src/panels/lovelace/views/hui-panel-view.ts | 3 +-
src/panels/lovelace/views/hui-sidebar-view.ts | 3 +-
8 files changed, 75 insertions(+), 88 deletions(-)
diff --git a/src/components/ha-drawer.ts b/src/components/ha-drawer.ts
index 62930305d3..c55b56c118 100644
--- a/src/components/ha-drawer.ts
+++ b/src/components/ha-drawer.ts
@@ -63,13 +63,21 @@ export class HaDrawer extends DrawerBase {
styles,
css`
.mdc-drawer {
+ position: fixed;
top: 0;
}
.mdc-drawer.mdc-drawer--modal.mdc-drawer--open {
z-index: 200;
}
.mdc-drawer-app-content {
- transform: translateZ(0);
+ overflow: unset;
+ flex: none;
+ padding-left: var(--mdc-drawer-width);
+ padding-inline-start: var(--mdc-drawer-width);
+ padding-inline-end: initial;
+ direction: var(--direction);
+ width: 100%;
+ box-sizing: border-box;
}
`,
];
diff --git a/src/components/ha-top-app-bar-fixed.ts b/src/components/ha-top-app-bar-fixed.ts
index d75c74f651..49501ac01b 100644
--- a/src/components/ha-top-app-bar-fixed.ts
+++ b/src/components/ha-top-app-bar-fixed.ts
@@ -1,43 +1,19 @@
import { TopAppBarFixedBase } from "@material/mwc-top-app-bar-fixed/mwc-top-app-bar-fixed-base";
import { styles } from "@material/mwc-top-app-bar/mwc-top-app-bar.css";
import { css } from "lit";
-import { customElement, property } from "lit/decorators";
-
-let drawerContent: HTMLElement | undefined;
+import { customElement } from "lit/decorators";
@customElement("ha-top-app-bar-fixed")
export class HaTopAppBarFixed extends TopAppBarFixedBase {
- private get _drawerContent() {
- if (!drawerContent) {
- drawerContent = document
- .querySelector("home-assistant")!
- .renderRoot.querySelector("home-assistant-main")!
- .renderRoot.querySelector("ha-drawer")!
- .renderRoot.querySelector(".mdc-drawer-app-content") as HTMLElement;
- }
- return drawerContent;
- }
-
- @property({ type: Object })
- get scrollTarget() {
- return this._scrollTarget || this._drawerContent || window;
- }
-
- protected updateRootPosition() {}
-
static override styles = [
styles,
css`
- .mdc-top-app-bar {
- position: sticky;
- top: 0;
- }
.mdc-top-app-bar__row {
height: var(--header-height);
border-bottom: var(--app-header-border-bottom);
}
.mdc-top-app-bar--fixed-adjust {
- padding-top: 0;
+ padding-top: var(--header-height);
}
.mdc-top-app-bar {
--mdc-typography-headline6-font-weight: 400;
diff --git a/src/layouts/home-assistant-main.ts b/src/layouts/home-assistant-main.ts
index afd153947b..dcaa2b460f 100644
--- a/src/layouts/home-assistant-main.ts
+++ b/src/layouts/home-assistant-main.ts
@@ -176,6 +176,7 @@ export class HomeAssistantMain extends LitElement {
/* remove the grey tap highlights in iOS on the fullscreen touch targets */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
--mdc-drawer-width: 56px;
+ --mdc-top-app-bar-width: calc(100% - var(--mdc-drawer-width));
}
:host([expanded]) {
--mdc-drawer-width: calc(256px + env(safe-area-inset-left));
diff --git a/src/panels/developer-tools/ha-panel-developer-tools.ts b/src/panels/developer-tools/ha-panel-developer-tools.ts
index 2dac2c0389..54c5666e9f 100644
--- a/src/panels/developer-tools/ha-panel-developer-tools.ts
+++ b/src/panels/developer-tools/ha-panel-developer-tools.ts
@@ -39,7 +39,7 @@ class PanelDeveloperTools extends LitElement {
scrollable
attr-for-selected="page-name"
.selected=${page}
- @iron-activate=${this.handlePageSelected}
+ @selected-changed=${this.handlePageSelected}
>
${this.hass.localize("ui.panel.developer-tools.tabs.yaml.title")}
@@ -76,11 +76,11 @@ class PanelDeveloperTools extends LitElement {
}
private handlePageSelected(ev) {
- const newPage = ev.detail.item.getAttribute("page-name");
+ const newPage = ev.detail.value;
if (newPage !== this._page) {
navigate(`/developer-tools/${newPage}`);
} else {
- scrollTo(0, 0);
+ scrollTo({ behavior: "smooth", top: 0 });
}
}
@@ -93,13 +93,18 @@ class PanelDeveloperTools extends LitElement {
haStyle,
css`
:host {
- display: block;
- height: 100%;
color: var(--primary-text-color);
--paper-card-header-color: var(--primary-text-color);
+ display: flex;
+ min-height: 100vh;
}
.header {
+ position: fixed;
+ top: 0;
+ z-index: 4;
background-color: var(--app-header-background-color);
+ width: var(--mdc-top-app-bar-width, 100%);
+ padding-top: env(safe-area-inset-top);
color: var(--app-header-text-color, white);
border-bottom: var(--app-header-border-bottom, none);
}
@@ -124,9 +129,12 @@ class PanelDeveloperTools extends LitElement {
}
developer-tools-router {
display: block;
- height: calc(100% - var(--header-height) - 48px);
- overflow: auto;
- overscroll-behavior: contain;
+ padding-top: calc(
+ var(--header-height) + 48px + env(safe-area-inset-top)
+ );
+ padding-bottom: calc(env(safe-area-inset-bottom));
+ flex: 1 1 100%;
+ max-width: 100%;
}
paper-tabs {
margin-left: max(env(safe-area-inset-left), 24px);
diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts
index a5fb2ded57..58825d76ab 100644
--- a/src/panels/lovelace/hui-root.ts
+++ b/src/panels/lovelace/hui-root.ts
@@ -26,13 +26,7 @@ import {
PropertyValues,
TemplateResult,
} from "lit";
-import {
- customElement,
- eventOptions,
- property,
- query,
- state,
-} from "lit/decorators";
+import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one";
@@ -93,8 +87,6 @@ class HUIRoot extends LitElement {
@state() private _curView?: number | "hass-unused-entities";
- @query("#view", true) _view!: HTMLDivElement;
-
private _viewCache?: { [viewId: string]: HUIView };
private _debouncedConfigChanged: () => void;
@@ -550,19 +542,14 @@ class HUIRoot extends LitElement {
`
: ""}
-
+
`;
}
- @eventOptions({ passive: true })
- private _viewScrolled(ev) {
- this.toggleAttribute("scrolled", ev.currentTarget.scrollTop !== 0);
- }
+ private _handleWindowScroll = () => {
+ this.toggleAttribute("scrolled", window.scrollY !== 0);
+ };
private _isVisible = (view: LovelaceViewConfig) =>
Boolean(
@@ -573,7 +560,8 @@ class HUIRoot extends LitElement {
view.visible.some((show) => show.user === this.hass!.user?.id))
);
- protected firstUpdated() {
+ protected firstUpdated(changedProps: PropertyValues) {
+ super.firstUpdated(changedProps);
// Check for requested edit mode
const searchParams = extractSearchParamsObject();
if (searchParams.edit === "1") {
@@ -586,6 +574,14 @@ class HUIRoot extends LitElement {
constructUrlCurrentPath(removeSearchParam("conversation"))
);
}
+ window.addEventListener("scroll", this._handleWindowScroll, {
+ passive: true,
+ });
+ }
+
+ public disconnectedCallback(): void {
+ super.disconnectedCallback();
+ window.removeEventListener("scroll", this._handleWindowScroll);
}
protected updated(changedProperties: PropertyValues): void {
@@ -628,6 +624,9 @@ class HUIRoot extends LitElement {
}
newSelectView = index;
}
+
+ // Will allow to override history scroll restoration when using back button
+ setTimeout(() => scrollTo({ behavior: "auto", top: 0 }), 1);
}
if (changedProperties.has("lovelace")) {
@@ -817,13 +816,14 @@ class HUIRoot extends LitElement {
}
private _navigateToView(path: string | number, replace?: boolean) {
- if (!this.lovelace!.editMode) {
- navigate(`${this.route!.prefix}/${path}${location.search}`, { replace });
- return;
+ const url = this.lovelace!.editMode
+ ? `${this.route!.prefix}/${path}?${addSearchParam({ edit: "1" })}`
+ : `${this.route!.prefix}/${path}${location.search}`;
+
+ const currentUrl = `${location.pathname}${location.search}`;
+ if (currentUrl !== url) {
+ navigate(url, { replace });
}
- navigate(`${this.route!.prefix}/${path}?${addSearchParam({ edit: "1" })}`, {
- replace,
- });
}
private _editView() {
@@ -870,12 +870,12 @@ class HUIRoot extends LitElement {
private _handleViewSelected(ev) {
ev.preventDefault();
const viewIndex = ev.detail.selected as number;
-
if (viewIndex !== this._curView) {
const path = this.config.views[viewIndex].path || viewIndex;
this._navigateToView(path);
+ } else if (!this._editMode) {
+ scrollTo({ behavior: "smooth", top: 0 });
}
- this._view.scrollTo(0, 0);
}
private _selectView(viewIndex: HUIRoot["_curView"], force: boolean): void {
@@ -1048,34 +1048,31 @@ class HUIRoot extends LitElement {
color: var(--error-color);
}
#view {
- margin-top: calc(var(--header-height) + env(safe-area-inset-top));
- height: calc(100vh - var(--header-height) - env(safe-area-inset-top));
+ position: relative;
+ display: flex;
+ background: var(
+ --lovelace-background,
+ var(--primary-background-color)
+ );
+ padding-top: calc(var(--header-height) + env(safe-area-inset-top));
+ min-height: 100vh;
+ box-sizing: border-box;
+ padding-left: env(safe-area-inset-left);
+ padding-right: env(safe-area-inset-right);
+ padding-bottom: env(safe-area-inset-bottom);
+ }
+ hui-view {
+ flex: 1 1 100%;
+ max-width: 100%;
}
/**
* In edit mode we have the tab bar on a new line *
*/
.edit-mode #view {
- height: calc(
- 100vh - var(--header-height) - 48px - env(safe-area-inset-top)
- );
- margin-top: calc(
+ padding-top: calc(
var(--header-height) + 48px + env(safe-area-inset-top)
);
}
- hui-view {
- padding-left: env(safe-area-inset-left);
- padding-right: env(safe-area-inset-right);
- background: var(
- --lovelace-background,
- var(--primary-background-color)
- );
- overflow: auto;
- overscroll-behavior: contain;
- width: 100%;
- height: 100%;
- transform: translateZ(0);
- display: block;
- }
.hide-tab {
display: none;
}
diff --git a/src/panels/lovelace/views/hui-masonry-view.ts b/src/panels/lovelace/views/hui-masonry-view.ts
index 0ee9db908c..937f924b24 100644
--- a/src/panels/lovelace/views/hui-masonry-view.ts
+++ b/src/panels/lovelace/views/hui-masonry-view.ts
@@ -298,7 +298,6 @@ export class MasonryView extends LitElement implements LovelaceViewElement {
:host {
display: block;
padding-top: 4px;
- padding-bottom: env(safe-area-inset-bottom);
}
.badges {
@@ -327,7 +326,7 @@ export class MasonryView extends LitElement implements LovelaceViewElement {
}
ha-fab {
- position: absolute;
+ position: fixed;
right: calc(16px + env(safe-area-inset-right));
bottom: calc(16px + env(safe-area-inset-bottom));
z-index: 1;
diff --git a/src/panels/lovelace/views/hui-panel-view.ts b/src/panels/lovelace/views/hui-panel-view.ts
index 7b21e2a533..33ae765228 100644
--- a/src/panels/lovelace/views/hui-panel-view.ts
+++ b/src/panels/lovelace/views/hui-panel-view.ts
@@ -134,8 +134,7 @@ export class PanelView extends LitElement implements LovelaceViewElement {
}
ha-fab {
- position: sticky;
- float: right;
+ position: fixed;
right: calc(16px + env(safe-area-inset-right));
bottom: calc(16px + env(safe-area-inset-bottom));
z-index: 1;
diff --git a/src/panels/lovelace/views/hui-sidebar-view.ts b/src/panels/lovelace/views/hui-sidebar-view.ts
index 1233c00c94..6ed7cce4b4 100644
--- a/src/panels/lovelace/views/hui-sidebar-view.ts
+++ b/src/panels/lovelace/views/hui-sidebar-view.ts
@@ -196,7 +196,6 @@ export class SideBarView extends LitElement implements LovelaceViewElement {
:host {
display: block;
padding-top: 4px;
- padding-bottom: env(safe-area-inset-bottom);
}
.container {
@@ -235,7 +234,7 @@ export class SideBarView extends LitElement implements LovelaceViewElement {
}
ha-fab {
- position: absolute;
+ position: fixed;
right: calc(16px + env(safe-area-inset-right));
bottom: calc(16px + env(safe-area-inset-bottom));
z-index: 1;
From 178ad2dffa53a9f90700113961c6d02b5c958b77 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Thu, 13 Apr 2023 21:16:59 +0200
Subject: [PATCH 015/112] Fix back button when directly opening subview
(#16145)
---
src/panels/lovelace/hui-root.ts | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts
index 58825d76ab..6fda17d966 100644
--- a/src/panels/lovelace/hui-root.ts
+++ b/src/panels/lovelace/hui-root.ts
@@ -742,12 +742,14 @@ class HUIRoot extends LitElement {
const curViewConfig =
typeof this._curView === "number" ? views[this._curView] : undefined;
- if (curViewConfig?.back_path) {
- navigate(curViewConfig.back_path);
+ if (curViewConfig?.back_path != null) {
+ navigate(curViewConfig.back_path, { replace: true });
} else if (history.length > 1) {
history.back();
+ } else if (!views[0].subview) {
+ navigate(this.route!.prefix, { replace: true });
} else {
- navigate(this.route!.prefix);
+ navigate("/");
}
}
From b21605e260fc020607e713f844b54935b7924561 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Thu, 13 Apr 2023 21:34:06 +0200
Subject: [PATCH 016/112] Fix demo deployment (#16178
Update demo_deployment.yaml
---
.github/workflows/demo_deployment.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/demo_deployment.yaml b/.github/workflows/demo_deployment.yaml
index 56bb35996d..025c461ab2 100644
--- a/.github/workflows/demo_deployment.yaml
+++ b/.github/workflows/demo_deployment.yaml
@@ -17,7 +17,7 @@ jobs:
deploy_dev:
runs-on: ubuntu-latest
name: Demo Development
- if: github.event_name != 'push' || github.ref != 'master'
+ if: github.event_name != 'push' || github.ref_name != 'master'
environment:
name: Demo Development
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
@@ -53,7 +53,7 @@ jobs:
deploy_master:
runs-on: ubuntu-latest
name: Demo Production
- if: github.event_name == 'push' && github.ref == 'master'
+ if: github.event_name == 'push' && github.ref_name == 'master'
environment:
name: Demo Production
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
From 689bc48f315cf278195202efb3f10e0a9b3bfb27 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Thu, 13 Apr 2023 23:25:32 +0200
Subject: [PATCH 017/112] Rename voice_assistant to assist_pipeline (#16177)
---
...{voice_assistant.ts => assist_pipeline.ts} | 37 +++++++++----------
src/data/voice.ts | 2 +-
.../assist/assist-pipeline-debug.ts | 6 +--
.../assist/assist-render-pipeline-run.ts | 2 +-
.../config/voice-assistants/assist-pref.ts | 27 +++++++-------
.../dialog-voice-assistant-pipeline-detail.ts | 12 +++---
...-dialog-voice-assistant-pipeline-detail.ts | 14 +++----
7 files changed, 48 insertions(+), 52 deletions(-)
rename src/data/{voice_assistant.ts => assist_pipeline.ts} (86%)
diff --git a/src/data/voice_assistant.ts b/src/data/assist_pipeline.ts
similarity index 86%
rename from src/data/voice_assistant.ts
rename to src/data/assist_pipeline.ts
index 5092509609..49cd6f76bc 100644
--- a/src/data/voice_assistant.ts
+++ b/src/data/assist_pipeline.ts
@@ -3,7 +3,7 @@ import type { ConversationResult } from "./conversation";
import type { ResolvedMediaSource } from "./media_source";
import type { SpeechMetadata } from "./stt";
-export interface VoiceAssistantPipeline {
+export interface AssistPipeline {
id: string;
conversation_engine: string;
language: string;
@@ -12,7 +12,7 @@ export interface VoiceAssistantPipeline {
tts_engine: string;
}
-export interface VoiceAssistantPipelineMutableParams {
+export interface AssistPipelineMutableParams {
conversation_engine: string;
language: string;
name: string;
@@ -131,7 +131,7 @@ export interface PipelineRun {
Partial & { done: boolean };
}
-export const runVoiceAssistantPipeline = (
+export const runAssistPipeline = (
hass: HomeAssistant,
callback: (event: PipelineRun) => void,
options: PipelineRunOptions
@@ -213,43 +213,40 @@ export const runVoiceAssistantPipeline = (
},
{
...options,
- type: "voice_assistant/run",
+ type: "assist_pipeline/run",
}
);
return unsubProm;
};
-export const fetchVoiceAssistantPipelines = (hass: HomeAssistant) =>
- hass.callWS({
- type: "voice_assistant/pipeline/list",
+export const fetchAssistPipelines = (hass: HomeAssistant) =>
+ hass.callWS({
+ type: "assist_pipeline/pipeline/list",
});
-export const createVoiceAssistantPipeline = (
+export const createAssistPipeline = (
hass: HomeAssistant,
- pipeline: VoiceAssistantPipelineMutableParams
+ pipeline: AssistPipelineMutableParams
) =>
- hass.callWS({
- type: "voice_assistant/pipeline/create",
+ hass.callWS({
+ type: "assist_pipeline/pipeline/create",
...pipeline,
});
-export const updateVoiceAssistantPipeline = (
+export const updateAssistPipeline = (
hass: HomeAssistant,
pipelineId: string,
- pipeline: Partial
+ pipeline: Partial
) =>
- hass.callWS({
- type: "voice_assistant/pipeline/update",
+ hass.callWS({
+ type: "assist_pipeline/pipeline/update",
pipeline_id: pipelineId,
...pipeline,
});
-export const deleteVoiceAssistantPipeline = (
- hass: HomeAssistant,
- pipelineId: string
-) =>
+export const deleteAssistPipeline = (hass: HomeAssistant, pipelineId: string) =>
hass.callWS({
- type: "voice_assistant/pipeline/delete",
+ type: "assist_pipeline/pipeline/delete",
pipeline_id: pipelineId,
});
diff --git a/src/data/voice.ts b/src/data/voice.ts
index 6a2c75c943..dee6333220 100644
--- a/src/data/voice.ts
+++ b/src/data/voice.ts
@@ -1,7 +1,7 @@
import { HomeAssistant } from "../types";
export const voiceAssistants = {
- conversation: { domain: "voice_assistant", name: "Assist" },
+ conversation: { domain: "assist_pipeline", name: "Assist" },
"cloud.alexa": {
domain: "alexa",
name: "Amazon Alexa",
diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
index 8defe120d5..292df3874e 100644
--- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
+++ b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
@@ -4,8 +4,8 @@ import "../../../../../../components/ha-button";
import {
PipelineRun,
PipelineRunOptions,
- runVoiceAssistantPipeline,
-} from "../../../../../../data/voice_assistant";
+ runAssistPipeline,
+} from "../../../../../../data/assist_pipeline";
import "../../../../../../layouts/hass-subpage";
import "../../../../../../components/ha-formfield";
import "../../../../../../components/ha-checkbox";
@@ -269,7 +269,7 @@ export class AssistPipelineDebug extends LitElement {
this._finished = false;
let added = false;
try {
- await runVoiceAssistantPipeline(
+ await runAssistPipeline(
this.hass,
(updatedRun) => {
if (added) {
diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts
index 0238395bbc..838f0f36b9 100644
--- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts
+++ b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts
@@ -5,7 +5,7 @@ import "../../../../../../components/ha-alert";
import "../../../../../../components/ha-button";
import "../../../../../../components/ha-circular-progress";
import "../../../../../../components/ha-expansion-panel";
-import type { PipelineRun } from "../../../../../../data/voice_assistant";
+import type { PipelineRun } from "../../../../../../data/assist_pipeline";
import type { HomeAssistant } from "../../../../../../types";
import { formatNumber } from "../../../../../../common/number/format_number";
diff --git a/src/panels/config/voice-assistants/assist-pref.ts b/src/panels/config/voice-assistants/assist-pref.ts
index f156ead905..d5165e1f06 100644
--- a/src/panels/config/voice-assistants/assist-pref.ts
+++ b/src/panels/config/voice-assistants/assist-pref.ts
@@ -9,12 +9,12 @@ import "../../../components/ha-list-item";
import "../../../components/ha-switch";
import "../../../components/ha-button";
import {
- createVoiceAssistantPipeline,
- deleteVoiceAssistantPipeline,
- fetchVoiceAssistantPipelines,
- updateVoiceAssistantPipeline,
- VoiceAssistantPipeline,
-} from "../../../data/voice_assistant";
+ createAssistPipeline,
+ deleteAssistPipeline,
+ fetchAssistPipelines,
+ updateAssistPipeline,
+ AssistPipeline,
+} from "../../../data/assist_pipeline";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../types";
import { showVoiceAssistantPipelineDetailDialog } from "./show-dialog-voice-assistant-pipeline-detail";
@@ -23,12 +23,12 @@ import { brandsUrl } from "../../../util/brands-url";
export class AssistPref extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
- @state() private _pipelines: VoiceAssistantPipeline[] = [];
+ @state() private _pipelines: AssistPipeline[] = [];
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
- fetchVoiceAssistantPipelines(this.hass).then((pipelines) => {
+ fetchAssistPipelines(this.hass).then((pipelines) => {
this._pipelines = pipelines;
});
}
@@ -40,7 +40,7 @@ export class AssistPref extends LitElement {
{
+ private async _openDialog(pipeline?: AssistPipeline): Promise {
showVoiceAssistantPipelineDetailDialog(this, {
pipeline,
createPipeline: async (values) => {
- const created = await createVoiceAssistantPipeline(this.hass!, values);
+ const created = await createAssistPipeline(this.hass!, values);
this._pipelines = this._pipelines!.concat(created);
},
updatePipeline: async (values) => {
- const updated = await updateVoiceAssistantPipeline(
+ const updated = await updateAssistPipeline(
this.hass!,
pipeline!.id,
values
@@ -145,7 +145,7 @@ export class AssistPref extends LitElement {
}
try {
- await deleteVoiceAssistantPipeline(this.hass!, pipeline!.id);
+ await deleteAssistPipeline(this.hass!, pipeline!.id);
this._pipelines = this._pipelines!.filter((res) => res !== pipeline);
return true;
} catch (err: any) {
@@ -186,6 +186,7 @@ export class AssistPref extends LitElement {
.card-header {
display: flex;
align-items: center;
+ padding-bottom: 0;
}
img {
height: 28px;
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index c40b80f2fd..d5d723854b 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -7,9 +7,9 @@ import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-form/ha-form";
import { SchemaUnion } from "../../../components/ha-form/types";
import {
- VoiceAssistantPipeline,
- VoiceAssistantPipelineMutableParams,
-} from "../../../data/voice_assistant";
+ AssistPipeline,
+ AssistPipelineMutableParams,
+} from "../../../data/assist_pipeline";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { VoiceAssistantPipelineDetailsDialogParams } from "./show-dialog-voice-assistant-pipeline-detail";
@@ -20,7 +20,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
@state() private _params?: VoiceAssistantPipelineDetailsDialogParams;
- @state() private _data?: Partial;
+ @state() private _data?: Partial;
@state() private _error?: Record;
@@ -160,7 +160,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
this._submitting = true;
try {
if (this._params!.pipeline?.id) {
- const values: Partial = {
+ const values: Partial = {
name: this._data!.name,
conversation_engine: this._data!.conversation_engine,
language: this._data!.language,
@@ -170,7 +170,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
await this._params!.updatePipeline(values);
} else {
await this._params!.createPipeline(
- this._data as VoiceAssistantPipelineMutableParams
+ this._data as AssistPipelineMutableParams
);
}
this.closeDialog();
diff --git a/src/panels/config/voice-assistants/show-dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/show-dialog-voice-assistant-pipeline-detail.ts
index ad0a588cb6..dc794cb30b 100644
--- a/src/panels/config/voice-assistants/show-dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/show-dialog-voice-assistant-pipeline-detail.ts
@@ -1,16 +1,14 @@
import { fireEvent } from "../../../common/dom/fire_event";
import {
- VoiceAssistantPipeline,
- VoiceAssistantPipelineMutableParams,
-} from "../../../data/voice_assistant";
+ AssistPipeline,
+ AssistPipelineMutableParams,
+} from "../../../data/assist_pipeline";
export interface VoiceAssistantPipelineDetailsDialogParams {
- pipeline?: VoiceAssistantPipeline;
- createPipeline: (
- values: VoiceAssistantPipelineMutableParams
- ) => Promise;
+ pipeline?: AssistPipeline;
+ createPipeline: (values: AssistPipelineMutableParams) => Promise;
updatePipeline: (
- updates: Partial
+ updates: Partial
) => Promise;
deletePipeline: () => Promise;
}
From fa4550a84869268e94fb8984196d14216266a379 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 13 Apr 2023 23:49:20 -0400
Subject: [PATCH 018/112] Update typescript-eslint monorepo to v5.58.0 (#16176)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
package.json | 4 +--
yarn.lock | 100 +++++++++++++++++++++++++--------------------------
2 files changed, 52 insertions(+), 52 deletions(-)
diff --git a/package.json b/package.json
index 531cc9304e..2631354279 100644
--- a/package.json
+++ b/package.json
@@ -185,8 +185,8 @@
"@types/sortablejs": "1.15.1",
"@types/tar": "6.1.4",
"@types/webspeechapi": "0.0.29",
- "@typescript-eslint/eslint-plugin": "5.57.1",
- "@typescript-eslint/parser": "5.57.1",
+ "@typescript-eslint/eslint-plugin": "5.58.0",
+ "@typescript-eslint/parser": "5.58.0",
"@web/dev-server": "0.1.38",
"@web/dev-server-rollup": "0.4.1",
"babel-loader": "9.1.2",
diff --git a/yarn.lock b/yarn.lock
index 27b3396892..155eea6fcd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4540,14 +4540,14 @@ __metadata:
languageName: node
linkType: hard
-"@typescript-eslint/eslint-plugin@npm:5.57.1":
- version: 5.57.1
- resolution: "@typescript-eslint/eslint-plugin@npm:5.57.1"
+"@typescript-eslint/eslint-plugin@npm:5.58.0":
+ version: 5.58.0
+ resolution: "@typescript-eslint/eslint-plugin@npm:5.58.0"
dependencies:
"@eslint-community/regexpp": ^4.4.0
- "@typescript-eslint/scope-manager": 5.57.1
- "@typescript-eslint/type-utils": 5.57.1
- "@typescript-eslint/utils": 5.57.1
+ "@typescript-eslint/scope-manager": 5.58.0
+ "@typescript-eslint/type-utils": 5.58.0
+ "@typescript-eslint/utils": 5.58.0
debug: ^4.3.4
grapheme-splitter: ^1.0.4
ignore: ^5.2.0
@@ -4560,43 +4560,43 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: 3ea842ef9615e298e28c6687c4dc285577ea0995944410553b3ca514ce9d437534b6e89114e9398c1a370324afe7a4a251c8c49540bb3bf13dcadde9ada3ecc2
+ checksum: e5d76d43c466ebd4b552e3307eff72ab5ae8a0c09a1d35fa13b62769ac3336df94d9281728ab5aafd2c14a0a644133583edcd708fce60a9a82df1db3ca3b8e14
languageName: node
linkType: hard
-"@typescript-eslint/parser@npm:5.57.1":
- version: 5.57.1
- resolution: "@typescript-eslint/parser@npm:5.57.1"
+"@typescript-eslint/parser@npm:5.58.0":
+ version: 5.58.0
+ resolution: "@typescript-eslint/parser@npm:5.58.0"
dependencies:
- "@typescript-eslint/scope-manager": 5.57.1
- "@typescript-eslint/types": 5.57.1
- "@typescript-eslint/typescript-estree": 5.57.1
+ "@typescript-eslint/scope-manager": 5.58.0
+ "@typescript-eslint/types": 5.58.0
+ "@typescript-eslint/typescript-estree": 5.58.0
debug: ^4.3.4
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
typescript:
optional: true
- checksum: db61a12a67bc45d814297e7f089768c0849f18162b330279aa15121223ec3b18d80df4c327f4ca0a40a7bddb9150ba1a9379fce00bc0e4a10cc189d04e36f0e3
+ checksum: 38681da48a40132c0538579c818ceef9ba2793ab8f79236c3f64980ba1649bb87cb367cd79d37bf2982b8bfbc28f91846b8676f9bd333e8b691c9befffd8874a
languageName: node
linkType: hard
-"@typescript-eslint/scope-manager@npm:5.57.1":
- version: 5.57.1
- resolution: "@typescript-eslint/scope-manager@npm:5.57.1"
+"@typescript-eslint/scope-manager@npm:5.58.0":
+ version: 5.58.0
+ resolution: "@typescript-eslint/scope-manager@npm:5.58.0"
dependencies:
- "@typescript-eslint/types": 5.57.1
- "@typescript-eslint/visitor-keys": 5.57.1
- checksum: 4f03d54372f0591fbc5f6e0267a6f1b73e3012e8a319c1893829e0b8e71f882e17a696995dc8b11e700162daf74444fd2d8f55dba314e1a95221a9d3eabcfb2b
+ "@typescript-eslint/types": 5.58.0
+ "@typescript-eslint/visitor-keys": 5.58.0
+ checksum: f0d3df5cc3c461fe63ef89ad886b53c239cc7c1d9061d83d8a9d9c8e087e5501eac84bebff8a954728c17ccea191f235686373d54d2b8b6370af2bcf2b18e062
languageName: node
linkType: hard
-"@typescript-eslint/type-utils@npm:5.57.1":
- version: 5.57.1
- resolution: "@typescript-eslint/type-utils@npm:5.57.1"
+"@typescript-eslint/type-utils@npm:5.58.0":
+ version: 5.58.0
+ resolution: "@typescript-eslint/type-utils@npm:5.58.0"
dependencies:
- "@typescript-eslint/typescript-estree": 5.57.1
- "@typescript-eslint/utils": 5.57.1
+ "@typescript-eslint/typescript-estree": 5.58.0
+ "@typescript-eslint/utils": 5.58.0
debug: ^4.3.4
tsutils: ^3.21.0
peerDependencies:
@@ -4604,23 +4604,23 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: 06fab95315fc1ffdaaa011e6ec1ae538826ef3d9b422e2c926dbe9b83e55d9e8bdaa07c43317a4c0a59b40a24c5c48a7c8284e6a18780475a65894b1b949fc23
+ checksum: 803f24daed185152bf86952d4acebb5ea18ff03db5f28750368edf76fdea46b4b0f8803ae0b61c0282b47181c9977113457b16e33d5d2cb33b13855f55c5e5b2
languageName: node
linkType: hard
-"@typescript-eslint/types@npm:5.57.1":
- version: 5.57.1
- resolution: "@typescript-eslint/types@npm:5.57.1"
- checksum: 21789eb697904bbb44a18df961d5918e7c5bd90c79df3a8b8b835da81d0c0f42c7eeb2d05f77cafe49a7367ae7f549a0c8281656ea44b6dc56ae1bf19a3a1eae
+"@typescript-eslint/types@npm:5.58.0":
+ version: 5.58.0
+ resolution: "@typescript-eslint/types@npm:5.58.0"
+ checksum: 8622a73d73220c4a7111537825f488c0271272032a1d4e129dc722bc6e8b3ec84f64469b2ca3b8dae7da3a9c18953ce1449af51f5f757dad60835eb579ad1d2c
languageName: node
linkType: hard
-"@typescript-eslint/typescript-estree@npm:5.57.1":
- version: 5.57.1
- resolution: "@typescript-eslint/typescript-estree@npm:5.57.1"
+"@typescript-eslint/typescript-estree@npm:5.58.0":
+ version: 5.58.0
+ resolution: "@typescript-eslint/typescript-estree@npm:5.58.0"
dependencies:
- "@typescript-eslint/types": 5.57.1
- "@typescript-eslint/visitor-keys": 5.57.1
+ "@typescript-eslint/types": 5.58.0
+ "@typescript-eslint/visitor-keys": 5.58.0
debug: ^4.3.4
globby: ^11.1.0
is-glob: ^4.0.3
@@ -4629,35 +4629,35 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: bf96520f6de562838a40c3f009fc61fbee5369621071cd0d1dba4470b2b2f746cf79afe4ffa3fbccb8913295a2fbb3d89681d5178529e8da4987c46ed4e5cbed
+ checksum: 51b668ec858db0c040a71dff526273945cee4ba5a9b240528d503d02526685882d900cf071c6636a4d9061ed3fd4a7274f7f1a23fba55c4b48b143344b4009c7
languageName: node
linkType: hard
-"@typescript-eslint/utils@npm:5.57.1":
- version: 5.57.1
- resolution: "@typescript-eslint/utils@npm:5.57.1"
+"@typescript-eslint/utils@npm:5.58.0":
+ version: 5.58.0
+ resolution: "@typescript-eslint/utils@npm:5.58.0"
dependencies:
"@eslint-community/eslint-utils": ^4.2.0
"@types/json-schema": ^7.0.9
"@types/semver": ^7.3.12
- "@typescript-eslint/scope-manager": 5.57.1
- "@typescript-eslint/types": 5.57.1
- "@typescript-eslint/typescript-estree": 5.57.1
+ "@typescript-eslint/scope-manager": 5.58.0
+ "@typescript-eslint/types": 5.58.0
+ "@typescript-eslint/typescript-estree": 5.58.0
eslint-scope: ^5.1.1
semver: ^7.3.7
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
- checksum: 12e55144c8087f4e8f0f22e5693f3901b81bb7899dec42c7bfe540ac672a802028b688884bb43bd67bcf3cd3546a7205d207afcd948c731c19f551ea61267205
+ checksum: c618ae67963ecf96b1492c09afaeb363f542f0d6780bcac4af3c26034e3b20034666b2d523aa94821df813aafb57a0b150a7d5c2224fe8257452ad1de2237a58
languageName: node
linkType: hard
-"@typescript-eslint/visitor-keys@npm:5.57.1":
- version: 5.57.1
- resolution: "@typescript-eslint/visitor-keys@npm:5.57.1"
+"@typescript-eslint/visitor-keys@npm:5.58.0":
+ version: 5.58.0
+ resolution: "@typescript-eslint/visitor-keys@npm:5.58.0"
dependencies:
- "@typescript-eslint/types": 5.57.1
+ "@typescript-eslint/types": 5.58.0
eslint-visitor-keys: ^3.3.0
- checksum: d187dfac044b7c0f24264a9ba5eebcf6651412d840b4aaba8eacabff7e771babcd67c738525b1f7c9eb8c94b7edfe7658f6de99f5fdc9745e409c538c1374674
+ checksum: ab2d1f37660559954c840429ef78bbf71834063557e3e68e435005b4987970b9356fdf217ead53f7a57f66f5488dc478062c5c44bf17053a8bf041733539b98f
languageName: node
linkType: hard
@@ -9537,8 +9537,8 @@ __metadata:
"@types/sortablejs": 1.15.1
"@types/tar": 6.1.4
"@types/webspeechapi": 0.0.29
- "@typescript-eslint/eslint-plugin": 5.57.1
- "@typescript-eslint/parser": 5.57.1
+ "@typescript-eslint/eslint-plugin": 5.58.0
+ "@typescript-eslint/parser": 5.58.0
"@vaadin/combo-box": 23.3.10
"@vaadin/vaadin-themable-mixin": 23.3.10
"@vibrant/color": 3.2.1-alpha.1
From 3a1fff81b807f4bb79e5b2187af19054c4717489 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joakim=20S=C3=B8rensen?=
Date: Fri, 14 Apr 2023 13:33:03 +0200
Subject: [PATCH 019/112] Move add-on rebuild over to WS for newer core
versions (#16180)
---
.../src/addon-view/info/hassio-addon-info.ts | 28 +++++++++++++------
src/data/hassio/addon.ts | 20 +++++++++++++
src/translations/en.json | 1 +
3 files changed, 40 insertions(+), 9 deletions(-)
diff --git a/hassio/src/addon-view/info/hassio-addon-info.ts b/hassio/src/addon-view/info/hassio-addon-info.ts
index a6e8c99217..356eb64c2b 100644
--- a/hassio/src/addon-view/info/hassio-addon-info.ts
+++ b/hassio/src/addon-view/info/hassio-addon-info.ts
@@ -29,7 +29,6 @@ import memoizeOne from "memoize-one";
import { atLeastVersion } from "../../../../src/common/config/version";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { navigate } from "../../../../src/common/navigate";
-import "../../../../src/components/buttons/ha-call-api-button";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-card";
@@ -47,6 +46,7 @@ import {
HassioAddonSetOptionParams,
HassioAddonSetSecurityParams,
installHassioAddon,
+ rebuildLocalAddon,
restartHassioAddon,
setHassioAddonOption,
setHassioAddonSecurity,
@@ -640,13 +640,12 @@ class HassioAddonInfo extends LitElement {
${this.addon.build
? html`
-
${this.supervisor.localize("addon.dashboard.rebuild")}
-
+
`
: ""}`
: ""}
@@ -966,6 +965,21 @@ class HassioAddonInfo extends LitElement {
button.progress = false;
}
+ private async _rebuildClicked(ev: CustomEvent): Promise {
+ const button = ev.currentTarget as any;
+ button.progress = true;
+
+ try {
+ await rebuildLocalAddon(this.hass, this.addon.slug);
+ } catch (err: any) {
+ showAlertDialog(this, {
+ title: this.supervisor.localize("addon.dashboard.action_error.rebuild"),
+ text: extractApiErrorMessage(err),
+ });
+ }
+ button.progress = false;
+ }
+
private async _startClicked(ev: CustomEvent): Promise {
const button = ev.currentTarget as any;
button.progress = true;
@@ -1124,10 +1138,6 @@ class HassioAddonInfo extends LitElement {
ha-svg-icon.stopped {
color: var(--error-color);
}
- ha-call-api-button {
- font-weight: 500;
- color: var(--primary-color);
- }
protection-enable mwc-button {
--mdc-theme-primary: white;
}
diff --git a/src/data/hassio/addon.ts b/src/data/hassio/addon.ts
index a1a0828dd9..9b8aa7c2c6 100644
--- a/src/data/hassio/addon.ts
+++ b/src/data/hassio/addon.ts
@@ -381,3 +381,23 @@ export const fetchAddonInfo = (
? `/store/addons/${addonSlug}` // Use /store/addons when add-on is not installed
: `/addons/${addonSlug}/info` // Use /addons when add-on is installed
);
+
+export const rebuildLocalAddon = async (
+ hass: HomeAssistant,
+ slug: string
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/rebuild`,
+ method: "post",
+ timeout: null,
+ });
+ }
+ return (
+ await hass.callApi>(
+ "POST",
+ `hassio/addons/${slug}rebuild`
+ )
+ ).data;
+};
diff --git a/src/translations/en.json b/src/translations/en.json
index 0cc9035a69..af1cfe642d 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -5373,6 +5373,7 @@
"uninstall": "Failed to uninstall add-on",
"install": "Failed to install add-on",
"stop": "Failed to stop add-on",
+ "rebuild": "Failed to rebuild add-on",
"restart": "Failed to restart add-on",
"start": "Failed to start add-on",
"go_to_config": "Edit Config",
From 0478aed28c3d76abd1e523d93ac3de5a6cb964e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joakim=20S=C3=B8rensen?=
Date: Fri, 14 Apr 2023 14:35:25 +0200
Subject: [PATCH 020/112] Remove ha-call-api-button (#16182)
---
hassio/src/resources/hassio-style.ts | 4 -
src/components/buttons/ha-call-api-button.ts | 77 -------------------
.../config/cloud/account/cloud-account.ts | 1 -
3 files changed, 82 deletions(-)
delete mode 100644 src/components/buttons/ha-call-api-button.ts
diff --git a/hassio/src/resources/hassio-style.ts b/hassio/src/resources/hassio-style.ts
index 5d52f618da..495d5d3e2e 100644
--- a/hassio/src/resources/hassio-style.ts
+++ b/hassio/src/resources/hassio-style.ts
@@ -44,10 +44,6 @@ export const hassioStyle = css`
grid-template-columns: repeat(auto-fit, minmax(300px, 0.25fr));
}
}
- ha-call-api-button {
- font-weight: 500;
- color: var(--primary-color);
- }
.error {
color: var(--error-color);
margin-top: 16px;
diff --git a/src/components/buttons/ha-call-api-button.ts b/src/components/buttons/ha-call-api-button.ts
deleted file mode 100644
index 05fc1f878d..0000000000
--- a/src/components/buttons/ha-call-api-button.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { css, CSSResultGroup, html, LitElement } from "lit";
-import { customElement, property, query } from "lit/decorators";
-import { fireEvent } from "../../common/dom/fire_event";
-import { HomeAssistant } from "../../types";
-import "./ha-progress-button";
-
-@customElement("ha-call-api-button")
-class HaCallApiButton extends LitElement {
- @property({ attribute: false }) public hass!: HomeAssistant;
-
- @property() public method: "POST" | "GET" | "PUT" | "DELETE" = "POST";
-
- @property() public data = {};
-
- @property({ type: Boolean, reflect: true }) public disabled = false;
-
- @property({ type: Boolean }) public progress = false;
-
- @property() public path?: string;
-
- @query("ha-progress-button", true) private _progressButton;
-
- render() {
- return html`
-
- `;
- }
-
- async _buttonTapped() {
- this.progress = true;
- const eventData: {
- method: string;
- path: string;
- data: any;
- success?: boolean;
- response?: any;
- } = {
- method: this.method,
- path: this.path!,
- data: this.data,
- };
-
- try {
- const resp = await this.hass.callApi(this.method, this.path!, this.data);
- this.progress = false;
- this._progressButton.actionSuccess();
- eventData.success = true;
- eventData.response = resp;
- } catch (err: any) {
- this.progress = false;
- this._progressButton.actionError();
- eventData.success = false;
- eventData.response = err;
- }
-
- fireEvent(this, "hass-api-called", eventData as any);
- }
-
- static get styles(): CSSResultGroup {
- return css`
- :host([disabled]) {
- pointer-events: none;
- }
- `;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "ha-call-api-button": HaCallApiButton;
- }
-}
diff --git a/src/panels/config/cloud/account/cloud-account.ts b/src/panels/config/cloud/account/cloud-account.ts
index d90056d731..2be0ccffbd 100644
--- a/src/panels/config/cloud/account/cloud-account.ts
+++ b/src/panels/config/cloud/account/cloud-account.ts
@@ -7,7 +7,6 @@ import { formatDateTime } from "../../../../common/datetime/format_date_time";
import { fireEvent } from "../../../../common/dom/fire_event";
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
import { debounce } from "../../../../common/util/debounce";
-import "../../../../components/buttons/ha-call-api-button";
import "../../../../components/ha-alert";
import "../../../../components/ha-card";
import "../../../../components/ha-tip";
From b1f94690021a17f725c48e2e3b12be024ce86ab5 Mon Sep 17 00:00:00 2001
From: Eric Severance
Date: Fri, 14 Apr 2023 07:33:21 -0700
Subject: [PATCH 021/112] Add webhook trigger allowed_methods/local_only
options (#11680)
Co-authored-by: Bram Kragten
---
src/data/automation.ts | 2 +
.../types/ha-automation-trigger-webhook.ts | 145 ++++++++++++++----
src/translations/en.json | 4 +-
3 files changed, 123 insertions(+), 28 deletions(-)
diff --git a/src/data/automation.ts b/src/data/automation.ts
index 653b24e289..ca288a8fa6 100644
--- a/src/data/automation.ts
+++ b/src/data/automation.ts
@@ -123,6 +123,8 @@ export interface TimePatternTrigger extends BaseTrigger {
export interface WebhookTrigger extends BaseTrigger {
platform: "webhook";
webhook_id: string;
+ allowed_methods?: string[];
+ local_only?: boolean;
}
export interface ZoneTrigger extends BaseTrigger {
diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts
index d546293fe4..300b7215c8 100644
--- a/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts
+++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts
@@ -1,21 +1,26 @@
-import "../../../../../components/ha-icon-button";
-import "../../../../../components/ha-textfield";
+import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
+import { mdiCog, mdiContentCopy } from "@mdi/js";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
-import { mdiContentCopy } from "@mdi/js";
import { css, html, LitElement, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { slugify } from "../../../../../common/string/slugify";
import { copyToClipboard } from "../../../../../common/util/copy-clipboard";
+import "../../../../../components/ha-button-menu";
+import "../../../../../components/ha-check-list-item";
+import "../../../../../components/ha-icon-button";
+import "../../../../../components/ha-textfield";
import type { HaTextField } from "../../../../../components/ha-textfield";
-import { showToast } from "../../../../../util/toast";
import {
- WebhookTrigger,
AutomationConfig,
+ WebhookTrigger,
} from "../../../../../data/automation";
import { HomeAssistant } from "../../../../../types";
+import { showToast } from "../../../../../util/toast";
import { handleChangeEvent } from "../ha-automation-trigger-row";
+const SUPPORTED_METHODS = ["GET", "HEAD", "POST", "PUT"];
+const DEFAULT_METHODS = ["POST", "PUT"];
const DEFAULT_WEBHOOK_ID = "";
@customElement("ha-automation-trigger-webhook")
@@ -32,6 +37,8 @@ export class HaWebhookTrigger extends LitElement {
public static get defaultConfig() {
return {
+ allowed_methods: [...DEFAULT_METHODS],
+ local_only: true,
webhook_id: DEFAULT_WEBHOOK_ID,
};
}
@@ -72,6 +79,12 @@ export class HaWebhookTrigger extends LitElement {
public willUpdate(changedProperties: PropertyValues) {
super.willUpdate(changedProperties);
if (changedProperties.has("trigger")) {
+ if (this.trigger.allowed_methods === undefined) {
+ this.trigger.allowed_methods = [...DEFAULT_METHODS];
+ }
+ if (this.trigger.local_only === undefined) {
+ this.trigger.local_only = true;
+ }
if (this.trigger.webhook_id === DEFAULT_WEBHOOK_ID) {
this.trigger.webhook_id = this._generateWebhookId();
}
@@ -79,31 +92,68 @@ export class HaWebhookTrigger extends LitElement {
}
protected render() {
- const { webhook_id: webhookId } = this.trigger;
+ const {
+ allowed_methods: allowedMethods,
+ local_only: localOnly,
+ webhook_id: webhookId,
+ } = this.trigger;
return html`
-
-
+
-
+ .helper=${this.hass.localize(
+ "ui.panel.config.automation.editor.triggers.type.webhook.webhook_id_helper"
+ )}
+ .disabled=${this.disabled}
+ iconTrailing
+ .value=${webhookId || ""}
+ @input=${this._valueChanged}
+ >
+
+
+
+
+ ${SUPPORTED_METHODS.map(
+ (method) => html`
+
+ ${method}
+
+ `
+ )}
+
+
+ ${this.hass!.localize(
+ "ui.panel.config.automation.editor.triggers.type.webhook.local_only"
+ )}
+
+
+
`;
}
@@ -111,6 +161,39 @@ export class HaWebhookTrigger extends LitElement {
handleChangeEvent(this, ev);
}
+ private _localOnlyChanged(ev: CustomEvent): void {
+ ev.stopPropagation();
+ if (this.trigger.local_only === ev.detail.selected) {
+ return;
+ }
+ const newTrigger = {
+ ...this.trigger,
+ local_only: ev.detail.selected,
+ };
+ fireEvent(this, "value-changed", { value: newTrigger });
+ }
+
+ private _allowedMethodsChanged(ev: CustomEvent): void {
+ ev.stopPropagation();
+ const method = (ev.target as any).value;
+ const selected = ev.detail.selected;
+
+ if (selected === this.trigger.allowed_methods?.includes(method)) {
+ return;
+ }
+
+ const methods = this.trigger.allowed_methods ?? [];
+ const newMethods = [...methods];
+
+ if (selected) {
+ newMethods.push(method);
+ } else {
+ newMethods.splice(newMethods.indexOf(method), 1);
+ }
+ const newTrigger = { ...this.trigger, allowed_methods: newMethods };
+ fireEvent(this, "value-changed", { value: newTrigger });
+ }
+
private async _copyUrl(ev): Promise {
const inputElement = ev.target.parentElement as HaTextField;
const url = this.hass.hassUrl(`/api/webhook/${inputElement.value}`);
@@ -122,14 +205,22 @@ export class HaWebhookTrigger extends LitElement {
}
static styles = css`
+ .flex {
+ display: flex;
+ }
+
ha-textfield {
- display: block;
+ flex: 1;
}
ha-textfield > ha-icon-button {
--mdc-icon-button-size: 24px;
--mdc-icon-size: 18px;
}
+
+ ha-button-menu {
+ padding-top: 4px;
+ }
`;
}
diff --git a/src/translations/en.json b/src/translations/en.json
index af1cfe642d..984d4d8f5d 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -2259,8 +2259,10 @@
"webhook": {
"copy_url": "Copy URL to Clipboard",
"label": "Webhook",
+ "local_only": "Only accessible from the local network",
"webhook_id": "Webhook ID",
- "webhook_id_helper": "Treat this ID like a password: keep it secret, and make it hard to guess."
+ "webhook_id_helper": "Treat this ID like a password: keep it secret, and make it hard to guess.",
+ "webhook_settings": "Webhook Settings"
},
"zone": {
"label": "Zone",
From e4302a0bb5b2dd2ce29dc4ee3f33aafe10c05933 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Fri, 14 Apr 2023 20:38:34 +0200
Subject: [PATCH 022/112] Fix onboarding add integration (#16163)
---
src/auth/ha-auth-flow.ts | 6 +-
src/auth/ha-authorize.ts | 3 +-
src/auth/ha-pick-auth-provider.ts | 6 +-
src/onboarding/onboarding-integrations.ts | 103 ++++++++++++----------
4 files changed, 67 insertions(+), 51 deletions(-)
diff --git a/src/auth/ha-auth-flow.ts b/src/auth/ha-auth-flow.ts
index 0577a0af7c..b5070dee73 100644
--- a/src/auth/ha-auth-flow.ts
+++ b/src/auth/ha-auth-flow.ts
@@ -9,6 +9,7 @@ import {
PropertyValues,
} from "lit";
import { customElement, property, state } from "lit/decorators";
+import { LocalizeFunc } from "../common/translations/localize";
import "../components/ha-alert";
import "../components/ha-checkbox";
import { computeInitialHaFormData } from "../components/ha-form/compute-initial-ha-form-data";
@@ -20,13 +21,12 @@ import {
DataEntryFlowStep,
DataEntryFlowStepForm,
} from "../data/data_entry_flow";
-import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
import "./ha-password-manager-polyfill";
type State = "loading" | "error" | "step";
@customElement("ha-auth-flow")
-export class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
+export class HaAuthFlow extends LitElement {
@property({ attribute: false }) public authProvider?: AuthProvider;
@property() public clientId?: string;
@@ -35,6 +35,8 @@ export class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
@property() public oauth2State?: string;
+ @property() public localize!: LocalizeFunc;
+
@state() private _state: State = "loading";
@state() private _stepData?: Record;
diff --git a/src/auth/ha-authorize.ts b/src/auth/ha-authorize.ts
index 9f780facc2..deadcf765e 100644
--- a/src/auth/ha-authorize.ts
+++ b/src/auth/ha-authorize.ts
@@ -82,12 +82,13 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
+ .localize=${this.localize}
>
${inactiveProviders.length > 0
? html`
${this.localize("ui.panel.page-authorize.pick_auth_provider")}:
diff --git a/src/onboarding/onboarding-integrations.ts b/src/onboarding/onboarding-integrations.ts
index 519499721c..f972609dfb 100644
--- a/src/onboarding/onboarding-integrations.ts
+++ b/src/onboarding/onboarding-integrations.ts
@@ -1,20 +1,21 @@
import "@material/mwc-button/mwc-button";
import { mdiCheck, mdiDotsHorizontal } from "@mdi/js";
+import { UnsubscribeFunc } from "home-assistant-js-websocket";
import {
css,
CSSResultGroup,
html,
LitElement,
+ nothing,
PropertyValues,
TemplateResult,
- nothing,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { isComponentLoaded } from "../common/config/is_component_loaded";
import { fireEvent } from "../common/dom/fire_event";
import { stringCompare } from "../common/string/compare";
import { LocalizeFunc } from "../common/translations/localize";
-import { ConfigEntry, getConfigEntries } from "../data/config_entries";
+import { ConfigEntry, subscribeConfigEntries } from "../data/config_entries";
import {
getConfigFlowInProgressCollection,
localizeConfigFlowTitle,
@@ -27,6 +28,8 @@ import {
loadConfigFlowDialog,
showConfigFlowDialog,
} from "../dialogs/config-flow/show-dialog-config-flow";
+import { SubscribeMixin } from "../mixins/subscribe-mixin";
+import { showAddIntegrationDialog } from "../panels/config/integrations/show-add-integration-dialog";
import { HomeAssistant } from "../types";
import "./action-badge";
import "./integration-badge";
@@ -40,7 +43,7 @@ const HIDDEN_DOMAINS = new Set([
]);
@customElement("onboarding-integrations")
-class OnboardingIntegrations extends LitElement {
+class OnboardingIntegrations extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public onboardingLocalize!: LocalizeFunc;
@@ -49,30 +52,56 @@ class OnboardingIntegrations extends LitElement {
@state() private _discovered?: DataEntryFlowProgress[];
- private _unsubEvents?: () => void;
-
- public connectedCallback() {
- super.connectedCallback();
- this.hass.loadBackendTranslation("title", undefined, true);
- this._unsubEvents = subscribeConfigFlowInProgress(this.hass, (flows) => {
- this._discovered = flows;
- const integrations: Set = new Set();
- for (const flow of flows) {
- // To render title placeholders
- if (flow.context.title_placeholders) {
- integrations.add(flow.handler);
+ public hassSubscribe(): Array> {
+ return [
+ subscribeConfigFlowInProgress(this.hass, (flows) => {
+ this._discovered = flows;
+ const integrations: Set = new Set();
+ for (const flow of flows) {
+ // To render title placeholders
+ if (flow.context.title_placeholders) {
+ integrations.add(flow.handler);
+ }
}
- }
- this.hass.loadBackendTranslation("config", Array.from(integrations));
- });
- }
-
- public disconnectedCallback() {
- super.disconnectedCallback();
- if (this._unsubEvents) {
- this._unsubEvents();
- this._unsubEvents = undefined;
- }
+ this.hass.loadBackendTranslation("config", Array.from(integrations));
+ }),
+ subscribeConfigEntries(
+ this.hass,
+ (messages) => {
+ let fullUpdate = false;
+ const newEntries: ConfigEntry[] = [];
+ messages.forEach((message) => {
+ if (message.type === null || message.type === "added") {
+ if (HIDDEN_DOMAINS.has(message.entry.domain)) {
+ return;
+ }
+ newEntries.push(message.entry);
+ if (message.type === null) {
+ fullUpdate = true;
+ }
+ } else if (message.type === "removed") {
+ this._entries = this._entries!.filter(
+ (entry) => entry.entry_id !== message.entry.entry_id
+ );
+ } else if (message.type === "updated") {
+ if (HIDDEN_DOMAINS.has(message.entry.domain)) {
+ return;
+ }
+ const newEntry = message.entry;
+ this._entries = this._entries!.map((entry) =>
+ entry.entry_id === newEntry.entry_id ? newEntry : entry
+ );
+ }
+ });
+ if (!newEntries.length && !fullUpdate) {
+ return;
+ }
+ const existingEntries = fullUpdate ? [] : this._entries;
+ this._entries = [...existingEntries!, ...newEntries];
+ },
+ { type: ["device", "hub", "service"] }
+ ),
+ ];
}
protected render() {
@@ -149,25 +178,19 @@ class OnboardingIntegrations extends LitElement {
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
+ this.hass.loadBackendTranslation("title", undefined, true);
this._scanUSBDevices();
loadConfigFlowDialog();
- this._loadConfigEntries();
}
private _createFlow() {
- showConfigFlowDialog(this, {
- dialogClosedCallback: () => {
- this._loadConfigEntries();
- getConfigFlowInProgressCollection(this.hass!.connection).refresh();
- },
- });
+ showAddIntegrationDialog(this);
}
private _continueFlow(ev) {
showConfigFlowDialog(this, {
continueFlowId: ev.currentTarget.flowId,
dialogClosedCallback: () => {
- this._loadConfigEntries();
getConfigFlowInProgressCollection(this.hass!.connection).refresh();
},
});
@@ -180,18 +203,6 @@ class OnboardingIntegrations extends LitElement {
await scanUSBDevices(this.hass);
}
- private async _loadConfigEntries() {
- const entries = await getConfigEntries(this.hass!, {
- type: ["device", "hub", "service"],
- });
- // We filter out the config entries that are automatically created during onboarding.
- // It is one that we create automatically and it will confuse the user
- // if it starts showing up during onboarding.
- this._entries = entries.filter(
- (entry) => !HIDDEN_DOMAINS.has(entry.domain)
- );
- }
-
private async _finish() {
fireEvent(this, "onboarding-step", {
type: "integration",
From 9d46f0cecd5b22e1d12e1363da7130d17973ebfc Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 14 Apr 2023 17:58:37 -0400
Subject: [PATCH 023/112] Update dependency @codemirror/view to v6.9.4 (#16183)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
package.json | 2 +-
yarn.lock | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index 2631354279..e5baf76f80 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
"@codemirror/legacy-modes": "6.3.2",
"@codemirror/search": "6.3.0",
"@codemirror/state": "6.2.0",
- "@codemirror/view": "6.9.3",
+ "@codemirror/view": "6.9.4",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.5.1",
"@formatjs/intl-getcanonicallocales": "2.1.0",
diff --git a/yarn.lock b/yarn.lock
index 155eea6fcd..2c1c8d37fa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1462,14 +1462,14 @@ __metadata:
languageName: node
linkType: hard
-"@codemirror/view@npm:6.9.3, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.6.0":
- version: 6.9.3
- resolution: "@codemirror/view@npm:6.9.3"
+"@codemirror/view@npm:6.9.4, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.6.0":
+ version: 6.9.4
+ resolution: "@codemirror/view@npm:6.9.4"
dependencies:
"@codemirror/state": ^6.1.4
style-mod: ^4.0.0
w3c-keyname: ^2.2.4
- checksum: 718ecbb021ca75eb89003f73c846a07d36a708dcfec8345f0f0dbcfc0d0df5ea6f114918694b2730a6d49e5e50502bcce79ce7ff94ce55748e068e5a35073755
+ checksum: 9d2e9596caa3f568cea5aeff87c9ed10b7cf1e73d198240042bddeeffaea21f70b859927b1a05f5a613a8d58a92be762c6b899ced0725cf70194057d9591f83b
languageName: node
linkType: hard
@@ -9454,7 +9454,7 @@ __metadata:
"@codemirror/legacy-modes": 6.3.2
"@codemirror/search": 6.3.0
"@codemirror/state": 6.2.0
- "@codemirror/view": 6.9.3
+ "@codemirror/view": 6.9.4
"@egjs/hammerjs": 2.0.17
"@formatjs/intl-datetimeformat": 6.5.1
"@formatjs/intl-getcanonicallocales": 2.1.0
From f9c790e0bb0e9608717cc2e0327ef555dc0b15fc Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 14 Apr 2023 18:13:39 -0400
Subject: [PATCH 024/112] Update dependency html-minifier-terser to v7.2.0
(#16181)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
package.json | 2 +-
yarn.lock | 32 ++++++++++++++++----------------
2 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/package.json b/package.json
index e5baf76f80..17a4ff937c 100644
--- a/package.json
+++ b/package.json
@@ -214,7 +214,7 @@
"gulp-merge-json": "2.1.2",
"gulp-rename": "2.0.0",
"gulp-zopfli-green": "6.0.1",
- "html-minifier-terser": "7.1.0",
+ "html-minifier-terser": "7.2.0",
"husky": "8.0.3",
"instant-mocha": "1.5.1",
"jszip": "3.10.1",
diff --git a/yarn.lock b/yarn.lock
index 2c1c8d37fa..1a92158acf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6501,15 +6501,6 @@ __metadata:
languageName: node
linkType: hard
-"clean-css@npm:5.2.0":
- version: 5.2.0
- resolution: "clean-css@npm:5.2.0"
- dependencies:
- source-map: ~0.6.0
- checksum: ccb63b244b200abf53a005429b50132845a49b994fb6a2889a7eb775d53fbde7cb0d0b13655e435b0c3a6788d5d0fbcd2f56ccf32da852ef21ae933198dcad24
- languageName: node
- linkType: hard
-
"clean-css@npm:^4.2.1, clean-css@npm:^4.2.3":
version: 4.2.4
resolution: "clean-css@npm:4.2.4"
@@ -6519,6 +6510,15 @@ __metadata:
languageName: node
linkType: hard
+"clean-css@npm:~5.3.2":
+ version: 5.3.2
+ resolution: "clean-css@npm:5.3.2"
+ dependencies:
+ source-map: ~0.6.0
+ checksum: 8787b281acc9878f309b5f835d410085deedfd4e126472666773040a6a8a72f472a1d24185947d23b87b1c419bf2c5ed429395d5c5ff8279c98b05d8011e9758
+ languageName: node
+ linkType: hard
+
"clean-stack@npm:^2.0.0":
version: 2.2.0
resolution: "clean-stack@npm:2.2.0"
@@ -9587,7 +9587,7 @@ __metadata:
gulp-zopfli-green: 6.0.1
hls.js: 1.3.5
home-assistant-js-websocket: 8.0.1
- html-minifier-terser: 7.1.0
+ html-minifier-terser: 7.2.0
husky: 8.0.3
idb-keyval: 6.2.0
instant-mocha: 1.5.1
@@ -9702,20 +9702,20 @@ __metadata:
languageName: node
linkType: hard
-"html-minifier-terser@npm:7.1.0":
- version: 7.1.0
- resolution: "html-minifier-terser@npm:7.1.0"
+"html-minifier-terser@npm:7.2.0":
+ version: 7.2.0
+ resolution: "html-minifier-terser@npm:7.2.0"
dependencies:
camel-case: ^4.1.2
- clean-css: 5.2.0
- commander: ^9.4.1
+ clean-css: ~5.3.2
+ commander: ^10.0.0
entities: ^4.4.0
param-case: ^3.0.4
relateurl: ^0.2.7
terser: ^5.15.1
bin:
html-minifier-terser: cli.js
- checksum: 351de28d85f142314a6a9b5222bdcaf068cef6bf2f521952ef55d99a6acdcecd0b4dbc42578da2d438d579c6e868b899ca19eac901ee6f9f0c69c223b5942099
+ checksum: 39feed354b5a8aafc8e910977d68cfd961d6db330a8e1a5b16a528c86b8ee7745d8945134822cf00acf7bf0d0135bf1abad650bf308bee4ea73adb003f5b8656
languageName: node
linkType: hard
From 6df02130d93bc64c2bd558b13b83b2696f56e1cd Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 15 Apr 2023 16:31:40 -0400
Subject: [PATCH 025/112] Update dependency @rollup/plugin-commonjs to v24.1.0
(#16189)
---
package.json | 2 +-
yarn.lock | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index 17a4ff937c..ed73681766 100644
--- a/package.json
+++ b/package.json
@@ -166,7 +166,7 @@
"@octokit/rest": "19.0.7",
"@open-wc/dev-server-hmr": "0.1.4",
"@rollup/plugin-babel": "6.0.3",
- "@rollup/plugin-commonjs": "24.0.1",
+ "@rollup/plugin-commonjs": "24.1.0",
"@rollup/plugin-json": "6.0.0",
"@rollup/plugin-node-resolve": "15.0.2",
"@rollup/plugin-replace": "5.0.2",
diff --git a/yarn.lock b/yarn.lock
index 1a92158acf..5af140a1ab 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3765,9 +3765,9 @@ __metadata:
languageName: node
linkType: hard
-"@rollup/plugin-commonjs@npm:24.0.1":
- version: 24.0.1
- resolution: "@rollup/plugin-commonjs@npm:24.0.1"
+"@rollup/plugin-commonjs@npm:24.1.0":
+ version: 24.1.0
+ resolution: "@rollup/plugin-commonjs@npm:24.1.0"
dependencies:
"@rollup/pluginutils": ^5.0.1
commondir: ^1.0.1
@@ -3780,7 +3780,7 @@ __metadata:
peerDependenciesMeta:
rollup:
optional: true
- checksum: ff5b09f5c350640fe6836fcc97bf5c5612bf78b26eaaad01bf1aee955f0b136135d1a8950a02f680779aec1f16f2c6b6cf89d6080e84ed09be62737abb6b3a5f
+ checksum: 42faafc9bc8e04d75c86bb50d693ebb9c5eee19bf9ab3c09780b872547d12ff5ea85cfec7da75f5176d0aa4b5233101f667f44b85b331450a7bb14c95180852e
languageName: node
linkType: hard
@@ -9517,7 +9517,7 @@ __metadata:
"@polymer/paper-toast": 3.0.1
"@polymer/polymer": 3.5.1
"@rollup/plugin-babel": 6.0.3
- "@rollup/plugin-commonjs": 24.0.1
+ "@rollup/plugin-commonjs": 24.1.0
"@rollup/plugin-json": 6.0.0
"@rollup/plugin-node-resolve": 15.0.2
"@rollup/plugin-replace": 5.0.2
From 6d0a468e09dc4222952e3aa6898ddc180968f548 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 16 Apr 2023 20:54:52 -0400
Subject: [PATCH 026/112] Update dependency @codemirror/autocomplete to v6.5.1
(#16200)
---
package.json | 2 +-
yarn.lock | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index ed73681766..0ae73fc50c 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
"type": "module",
"dependencies": {
"@braintree/sanitize-url": "6.0.2",
- "@codemirror/autocomplete": "6.4.2",
+ "@codemirror/autocomplete": "6.5.1",
"@codemirror/commands": "6.2.2",
"@codemirror/language": "6.6.0",
"@codemirror/legacy-modes": "6.3.2",
diff --git a/yarn.lock b/yarn.lock
index 5af140a1ab..c1b9e2a307 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1392,9 +1392,9 @@ __metadata:
languageName: node
linkType: hard
-"@codemirror/autocomplete@npm:6.4.2":
- version: 6.4.2
- resolution: "@codemirror/autocomplete@npm:6.4.2"
+"@codemirror/autocomplete@npm:6.5.1":
+ version: 6.5.1
+ resolution: "@codemirror/autocomplete@npm:6.5.1"
dependencies:
"@codemirror/language": ^6.0.0
"@codemirror/state": ^6.0.0
@@ -1405,7 +1405,7 @@ __metadata:
"@codemirror/state": ^6.0.0
"@codemirror/view": ^6.0.0
"@lezer/common": ^1.0.0
- checksum: c6cc4edb1c412153e6f6f27926674d7f1d386d1f30d6d4f60c5b52bfa0105870b0c70449b69891937bcf082340d8b0fa6d1f9f28f5eb60adc2974ed4c73aadc1
+ checksum: c7026af557f5e467050bea22b3e9b060adca065fc84c22f024fd59730107ea711006dd353050300acce5862cfb82643fb3edbdef80c8b275214398147395e6da
languageName: node
linkType: hard
@@ -9448,7 +9448,7 @@ __metadata:
"@babel/preset-env": 7.21.4
"@babel/preset-typescript": 7.21.4
"@braintree/sanitize-url": 6.0.2
- "@codemirror/autocomplete": 6.4.2
+ "@codemirror/autocomplete": 6.5.1
"@codemirror/commands": 6.2.2
"@codemirror/language": 6.6.0
"@codemirror/legacy-modes": 6.3.2
From 1d42821ff575375062c0411251aaca8116d83646 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 17 Apr 2023 01:13:53 +0000
Subject: [PATCH 027/112] Update dependency core-js to v3.30.1 (#16206)
---
package.json | 2 +-
yarn.lock | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index 0ae73fc50c..7db00ffae2 100644
--- a/package.json
+++ b/package.json
@@ -101,7 +101,7 @@
"app-datepicker": "5.1.1",
"chart.js": "3.3.2",
"comlink": "4.4.1",
- "core-js": "3.30.0",
+ "core-js": "3.30.1",
"cropperjs": "1.5.13",
"date-fns": "2.29.3",
"date-fns-tz": "2.0.0",
diff --git a/yarn.lock b/yarn.lock
index c1b9e2a307..17d321edd5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6972,10 +6972,10 @@ __metadata:
languageName: node
linkType: hard
-"core-js@npm:3.30.0":
- version: 3.30.0
- resolution: "core-js@npm:3.30.0"
- checksum: 276d4444a1261739ea4c350ef3f6aeab4c7ae7f36ac197f02d197a4566b42867c3a9b12c2fcda8a736aeca888d2c4131c8cb58ad17ed02294a10c9c97606df71
+"core-js@npm:3.30.1":
+ version: 3.30.1
+ resolution: "core-js@npm:3.30.1"
+ checksum: 6d4a00b488694d4c715c424e15dfef31433ac7aa395c39c518a0cfacec918ada1c716fed74682033197e0164e23bbf38bfd598ee9a239c4aaa590ab1ba862ac8
languageName: node
linkType: hard
@@ -9555,7 +9555,7 @@ __metadata:
chai: 4.3.7
chart.js: 3.3.2
comlink: 4.4.1
- core-js: 3.30.0
+ core-js: 3.30.1
cropperjs: 1.5.13
date-fns: 2.29.3
date-fns-tz: 2.0.0
From 09ff5cdb58cef18b447b3cc092f42bc9073ab875 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 17 Apr 2023 09:23:16 +0200
Subject: [PATCH 028/112] Bump actions/checkout from 3.5.0 to 3.5.2 (#16208)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/cast_deployment.yaml | 4 ++--
.github/workflows/ci.yaml | 8 ++++----
.github/workflows/codeql-analysis.yml | 2 +-
.github/workflows/demo_deployment.yaml | 4 ++--
.github/workflows/design_deployment.yaml | 2 +-
.github/workflows/design_preview.yaml | 2 +-
.github/workflows/nightly.yaml | 2 +-
.github/workflows/release.yaml | 2 +-
.github/workflows/translations.yaml | 2 +-
9 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/.github/workflows/cast_deployment.yaml b/.github/workflows/cast_deployment.yaml
index e9e41b8b4d..1d46f47cb9 100644
--- a/.github/workflows/cast_deployment.yaml
+++ b/.github/workflows/cast_deployment.yaml
@@ -22,7 +22,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
with:
ref: dev
@@ -58,7 +58,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
with:
ref: master
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index c2b8d29baa..fe16a8df7d 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0
with:
@@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0
with:
@@ -66,7 +66,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0
with:
@@ -84,7 +84,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0
with:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 94b8ee085d..b71752c7f7 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
diff --git a/.github/workflows/demo_deployment.yaml b/.github/workflows/demo_deployment.yaml
index 025c461ab2..07eb7c900d 100644
--- a/.github/workflows/demo_deployment.yaml
+++ b/.github/workflows/demo_deployment.yaml
@@ -23,7 +23,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
with:
ref: dev
@@ -59,7 +59,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
with:
ref: master
diff --git a/.github/workflows/design_deployment.yaml b/.github/workflows/design_deployment.yaml
index 22f8673603..821b6ae9a7 100644
--- a/.github/workflows/design_deployment.yaml
+++ b/.github/workflows/design_deployment.yaml
@@ -17,7 +17,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0
diff --git a/.github/workflows/design_preview.yaml b/.github/workflows/design_preview.yaml
index 335cbca79b..e8d39053c1 100644
--- a/.github/workflows/design_preview.yaml
+++ b/.github/workflows/design_preview.yaml
@@ -22,7 +22,7 @@ jobs:
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
steps:
- name: Check out files from GitHub
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0
diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml
index 224b1b49e0..455d418443 100644
--- a/.github/workflows/nightly.yaml
+++ b/.github/workflows/nightly.yaml
@@ -21,7 +21,7 @@ jobs:
contents: write
steps:
- name: Checkout the repository
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 686ca2ab02..f7e7f7f6b3 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -24,7 +24,7 @@ jobs:
contents: write # Required to upload release assets
steps:
- name: Checkout the repository
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Verify version
uses: home-assistant/actions/helpers/verify-version@master
diff --git a/.github/workflows/translations.yaml b/.github/workflows/translations.yaml
index a0eee41524..e7e7f789ca 100644
--- a/.github/workflows/translations.yaml
+++ b/.github/workflows/translations.yaml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
- uses: actions/checkout@v3.5.0
+ uses: actions/checkout@v3.5.2
- name: Upload Translations
run: |
From dae107d3e3d14f582a00cd271d6845fda836d28f Mon Sep 17 00:00:00 2001
From: karwosts <32912880+karwosts@users.noreply.github.com>
Date: Mon, 17 Apr 2023 02:16:16 -0700
Subject: [PATCH 029/112] Fix ha-selector-select filter for multiple values
case (#16093)
---
src/components/ha-selector/ha-selector-select.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/ha-selector/ha-selector-select.ts b/src/components/ha-selector/ha-selector-select.ts
index 0d9222a266..be076d6a12 100644
--- a/src/components/ha-selector/ha-selector-select.ts
+++ b/src/components/ha-selector/ha-selector-select.ts
@@ -135,7 +135,7 @@ export class HaSelectSelector extends LitElement {
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required && !value.length}
- .value=${this._filter}
+ .value=${""}
.items=${optionItems}
.allowCustomValue=${this.selector.select.custom_value ?? false}
@filter-changed=${this._filterChanged}
From 0f622589a30013c9161b4cd38775423f5c4904cf Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Mon, 17 Apr 2023 16:51:17 +0200
Subject: [PATCH 030/112] Allow to set a default pipeline (#16209)
---
src/components/ha-list-item.ts | 3 ++
src/data/assist_pipeline.ts | 18 ++++++++++--
.../config/voice-assistants/assist-pref.ts | 28 +++++++++++++++++--
.../dialog-voice-assistant-pipeline-detail.ts | 14 ++++++++++
...-dialog-voice-assistant-pipeline-detail.ts | 2 ++
5 files changed, 60 insertions(+), 5 deletions(-)
diff --git a/src/components/ha-list-item.ts b/src/components/ha-list-item.ts
index 0331381a0c..8107ae4f2a 100644
--- a/src/components/ha-list-item.ts
+++ b/src/components/ha-list-item.ts
@@ -30,6 +30,9 @@ export class HaListItem extends ListItemBase {
margin-inline-end: 0px !important;
direction: var(--direction);
}
+ .mdc-deprecated-list-item__meta {
+ display: var(--mdc-list-item-meta-display);
+ }
:host([multiline-secondary]) {
height: auto;
}
diff --git a/src/data/assist_pipeline.ts b/src/data/assist_pipeline.ts
index 49cd6f76bc..7e442bf271 100644
--- a/src/data/assist_pipeline.ts
+++ b/src/data/assist_pipeline.ts
@@ -221,7 +221,10 @@ export const runAssistPipeline = (
};
export const fetchAssistPipelines = (hass: HomeAssistant) =>
- hass.callWS({
+ hass.callWS<{
+ pipelines: AssistPipeline[];
+ preferred_pipeline: string | null;
+ }>({
type: "assist_pipeline/pipeline/list",
});
@@ -236,15 +239,24 @@ export const createAssistPipeline = (
export const updateAssistPipeline = (
hass: HomeAssistant,
- pipelineId: string,
+ pipeline_id: string,
pipeline: Partial
) =>
hass.callWS({
type: "assist_pipeline/pipeline/update",
- pipeline_id: pipelineId,
+ pipeline_id,
...pipeline,
});
+export const setAssistPipelinePreferred = (
+ hass: HomeAssistant,
+ pipeline_id: string
+) =>
+ hass.callWS({
+ type: "assist_pipeline/pipeline/set_preferred",
+ pipeline_id,
+ });
+
export const deleteAssistPipeline = (hass: HomeAssistant, pipelineId: string) =>
hass.callWS({
type: "assist_pipeline/pipeline/delete",
diff --git a/src/panels/config/voice-assistants/assist-pref.ts b/src/panels/config/voice-assistants/assist-pref.ts
index d5165e1f06..daeb92d895 100644
--- a/src/panels/config/voice-assistants/assist-pref.ts
+++ b/src/panels/config/voice-assistants/assist-pref.ts
@@ -1,10 +1,11 @@
import "@material/mwc-list/mwc-list";
-import { mdiHelpCircle, mdiPlus } from "@mdi/js";
+import { mdiHelpCircle, mdiPlus, mdiStar } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
import { property, state } from "lit/decorators";
import "../../../components/ha-alert";
import "../../../components/ha-card";
import "../../../components/ha-icon-next";
+import "../../../components/ha-svg-icon";
import "../../../components/ha-list-item";
import "../../../components/ha-switch";
import "../../../components/ha-button";
@@ -14,6 +15,7 @@ import {
fetchAssistPipelines,
updateAssistPipeline,
AssistPipeline,
+ setAssistPipelinePreferred,
} from "../../../data/assist_pipeline";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../types";
@@ -25,11 +27,14 @@ export class AssistPref extends LitElement {
@state() private _pipelines: AssistPipeline[] = [];
+ @state() private _preferred: string | null = null;
+
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
fetchAssistPipelines(this.hass).then((pipelines) => {
- this._pipelines = pipelines;
+ this._pipelines = pipelines.pipelines;
+ this._preferred = pipelines.preferred_pipeline;
});
}
@@ -72,6 +77,12 @@ export class AssistPref extends LitElement {
>
${pipeline.name}
${pipeline.language}
+ ${this._preferred === pipeline.id
+ ? html` `
+ : ""}
`
@@ -112,6 +123,7 @@ export class AssistPref extends LitElement {
private async _openDialog(pipeline?: AssistPipeline): Promise {
showVoiceAssistantPipelineDetailDialog(this, {
pipeline,
+ preferred: pipeline?.id === this._preferred,
createPipeline: async (values) => {
const created = await createAssistPipeline(this.hass!, values);
this._pipelines = this._pipelines!.concat(created);
@@ -126,6 +138,10 @@ export class AssistPref extends LitElement {
res === pipeline ? updated : res
);
},
+ setPipelinePreferred: async () => {
+ await setAssistPipelinePreferred(this.hass!, pipeline!.id);
+ this._preferred = pipeline!.id;
+ },
deletePipeline: async () => {
if (
!(await showConfirmationDialog(this, {
@@ -174,6 +190,14 @@ export class AssistPref extends LitElement {
direction: var(--direction);
color: var(--secondary-text-color);
}
+ ha-list-item {
+ --mdc-list-item-meta-size: auto;
+ --mdc-list-item-meta-display: flex;
+ }
+ ha-svg-icon,
+ ha-icon-next {
+ width: 24px;
+ }
.add {
margin: 0 16px 16px;
}
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index d5d723854b..64b4b9efb5 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -22,6 +22,8 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
@state() private _data?: Partial;
+ @state() private _preferred?: boolean;
+
@state() private _error?: Record;
@state() private _submitting = false;
@@ -31,6 +33,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
this._error = undefined;
if (this._params.pipeline) {
this._data = this._params.pipeline;
+ this._preferred = this._params.preferred;
} else {
this._data = {};
}
@@ -82,6 +85,12 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
>
${this.hass.localize("ui.common.delete")}
+ Set as default
`
: nothing}
Promise;
updatePipeline: (
updates: Partial
) => Promise;
+ setPipelinePreferred: () => Promise;
deletePipeline: () => Promise;
}
From 7fa4a7500949f1a6df090f8a741d1f4586d449cb Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Mon, 17 Apr 2023 17:35:51 +0200
Subject: [PATCH 031/112] Pipeline debug, set pipeline instead of lang (#16217)
---
src/data/assist_pipeline.ts | 1 -
.../assist/assist-pipeline-debug.ts | 20 +++++++++----------
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/src/data/assist_pipeline.ts b/src/data/assist_pipeline.ts
index 7e442bf271..234a332bb9 100644
--- a/src/data/assist_pipeline.ts
+++ b/src/data/assist_pipeline.ts
@@ -112,7 +112,6 @@ export type PipelineRunOptions = (
}
) & {
end_stage: "stt" | "intent" | "tts";
- language?: string;
pipeline?: string;
conversation_id?: string | null;
};
diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
index 292df3874e..9d48d02402 100644
--- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
+++ b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
@@ -39,7 +39,7 @@ export class AssistPipelineDebug extends LitElement {
@state() private _finished = false;
- @state() private _languageOverride?: string;
+ @state() private _pipelineId?: string;
protected render(): TemplateResult {
return html`
@@ -65,8 +65,8 @@ export class AssistPipelineDebug extends LitElement {
`
: html`
-
- Set Language
+
+ Pick pipeline
`}
@@ -282,7 +282,7 @@ export class AssistPipelineDebug extends LitElement {
},
{
...options,
- language: this._languageOverride,
+ pipeline: this._pipelineId,
conversation_id: this.conversationId,
}
);
@@ -322,15 +322,15 @@ export class AssistPipelineDebug extends LitElement {
);
}
- private async _setLanguage() {
- const language = await showPromptDialog(this, {
- title: "Language override",
- inputLabel: "Language",
+ private async _pickPipeline() {
+ const pipeline = await showPromptDialog(this, {
+ title: "Set pipeline",
+ inputLabel: "Pipeline ID",
inputType: "text",
confirmText: "Set",
});
- if (language) {
- this._languageOverride = language;
+ if (pipeline) {
+ this._pipelineId = pipeline;
}
}
From ac1e6b87ae7a6c820503aec17f0006ec6ce28578 Mon Sep 17 00:00:00 2001
From: Stefan Agner
Date: Mon, 17 Apr 2023 18:04:09 +0200
Subject: [PATCH 032/112] Change dhcp to auto in network config (#16185)
---
hassio/src/dialogs/network/dialog-hassio-network.ts | 2 +-
src/panels/config/network/supervisor-network.ts | 2 +-
src/translations/en.json | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/hassio/src/dialogs/network/dialog-hassio-network.ts b/hassio/src/dialogs/network/dialog-hassio-network.ts
index 027b8b53ab..943e92972c 100644
--- a/hassio/src/dialogs/network/dialog-hassio-network.ts
+++ b/hassio/src/dialogs/network/dialog-hassio-network.ts
@@ -316,7 +316,7 @@ export class DialogHassioNetwork
>
Date: Mon, 17 Apr 2023 20:54:30 +0200
Subject: [PATCH 033/112] Add conversation agent selector (#16212
* Add conversation agent selector
* Add default option
* Update ha-conversation-agent-picker.ts
* Update ha-conversation-agent-picker.ts
---
.../ha-conversation-agent-picker.ts | 109 ++++++++++++++++++
.../ha-selector-conversation-agent.ts | 45 ++++++++
src/components/ha-selector/ha-selector.ts | 1 +
src/components/ha-theme-picker.ts | 1 -
src/data/conversation.ts | 18 ++-
src/data/selector.ts | 6 +
.../dialog-voice-assistant-pipeline-detail.ts | 2 +-
src/translations/en.json | 4 +
8 files changed, 183 insertions(+), 3 deletions(-)
create mode 100644 src/components/ha-conversation-agent-picker.ts
create mode 100644 src/components/ha-selector/ha-selector-conversation-agent.ts
diff --git a/src/components/ha-conversation-agent-picker.ts b/src/components/ha-conversation-agent-picker.ts
new file mode 100644
index 0000000000..5175e99f35
--- /dev/null
+++ b/src/components/ha-conversation-agent-picker.ts
@@ -0,0 +1,109 @@
+import {
+ css,
+ CSSResultGroup,
+ html,
+ LitElement,
+ nothing,
+ PropertyValueMap,
+} from "lit";
+import { customElement, property, state } from "lit/decorators";
+import { fireEvent } from "../common/dom/fire_event";
+import { stopPropagation } from "../common/dom/stop_propagation";
+import { Agent, listAgents } from "../data/conversation";
+import { HomeAssistant } from "../types";
+import "./ha-list-item";
+import "./ha-select";
+import type { HaSelect } from "./ha-select";
+
+const DEFAULT = "default_agent_option";
+@customElement("ha-conversation-agent-picker")
+export class HaConversationAgentPicker extends LitElement {
+ @property() public value?: string;
+
+ @property() public label?: string;
+
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ type: Boolean, reflect: true }) public disabled = false;
+
+ @property({ type: Boolean }) public required = false;
+
+ @state() _agents?: Agent[];
+
+ @state() _defaultAgent: string | null = null;
+
+ protected render() {
+ if (!this._agents) {
+ return nothing;
+ }
+ const value = this.value ?? DEFAULT;
+ return html`
+
+
+ ${this.hass!.localize(
+ "ui.components.coversation-agent-picker.default",
+ {
+ default: this._agents.find(
+ (agent) => agent.id === this._defaultAgent
+ )?.name,
+ }
+ )}
+
+ ${this._agents.map(
+ (agent) =>
+ html`${agent.name} `
+ )}
+
+ `;
+ }
+
+ protected firstUpdated(
+ changedProperties: PropertyValueMap | Map
+ ): void {
+ super.firstUpdated(changedProperties);
+ listAgents(this.hass).then((agents) => {
+ this._agents = agents.agents;
+ this._defaultAgent = agents.default_agent;
+ });
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-select {
+ width: 100%;
+ }
+ `;
+ }
+
+ private _changed(ev): void {
+ const target = ev.target as HaSelect;
+ if (
+ !this.hass ||
+ target.value === "" ||
+ target.value === this.value ||
+ (this.value === undefined && target.value === DEFAULT)
+ ) {
+ return;
+ }
+ this.value = target.value === DEFAULT ? undefined : target.value;
+ fireEvent(this, "value-changed", { value: this.value });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-conversation-agent-picker": HaConversationAgentPicker;
+ }
+}
diff --git a/src/components/ha-selector/ha-selector-conversation-agent.ts b/src/components/ha-selector/ha-selector-conversation-agent.ts
new file mode 100644
index 0000000000..21dcfe12d7
--- /dev/null
+++ b/src/components/ha-selector/ha-selector-conversation-agent.ts
@@ -0,0 +1,45 @@
+import { css, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { ConversationAgentSelector } from "../../data/selector";
+import { HomeAssistant } from "../../types";
+import "../ha-conversation-agent-picker";
+
+@customElement("ha-selector-conversation_agent")
+export class HaConversationAgentSelector extends LitElement {
+ @property() public hass!: HomeAssistant;
+
+ @property() public selector!: ConversationAgentSelector;
+
+ @property() public value?: any;
+
+ @property() public label?: string;
+
+ @property() public helper?: string;
+
+ @property({ type: Boolean }) public disabled = false;
+
+ @property({ type: Boolean }) public required = true;
+
+ protected render() {
+ return html` `;
+ }
+
+ static styles = css`
+ ha-conversation-agent-picker {
+ width: 100%;
+ }
+ `;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-selector-conversation_agent": HaConversationAgentSelector;
+ }
+}
diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts
index f387867025..7d4e456e60 100644
--- a/src/components/ha-selector/ha-selector.ts
+++ b/src/components/ha-selector/ha-selector.ts
@@ -17,6 +17,7 @@ const LOAD_ELEMENTS = {
boolean: () => import("./ha-selector-boolean"),
color_rgb: () => import("./ha-selector-color-rgb"),
config_entry: () => import("./ha-selector-config-entry"),
+ conversation_agent: () => import("./ha-selector-conversation-agent"),
constant: () => import("./ha-selector-constant"),
date: () => import("./ha-selector-date"),
datetime: () => import("./ha-selector-datetime"),
diff --git a/src/components/ha-theme-picker.ts b/src/components/ha-theme-picker.ts
index 95c568f592..47aadd7e62 100644
--- a/src/components/ha-theme-picker.ts
+++ b/src/components/ha-theme-picker.ts
@@ -1,4 +1,3 @@
-import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
diff --git a/src/data/conversation.ts b/src/data/conversation.ts
index 3745271c8b..d74c64d0f6 100644
--- a/src/data/conversation.ts
+++ b/src/data/conversation.ts
@@ -56,6 +56,11 @@ export interface AgentInfo {
attribution?: { name: string; url: string };
}
+export interface Agent {
+ id: string;
+ name: string;
+}
+
export const processConversationInput = (
hass: HomeAssistant,
text: string,
@@ -70,9 +75,20 @@ export const processConversationInput = (
language,
});
-export const getAgentInfo = (hass: HomeAssistant): Promise =>
+export const listAgents = (
+ hass: HomeAssistant
+): Promise<{ agents: Agent[]; default_agent: string | null }> =>
+ hass.callWS({
+ type: "conversation/agent/list",
+ });
+
+export const getAgentInfo = (
+ hass: HomeAssistant,
+ agent_id?: string
+): Promise =>
hass.callWS({
type: "conversation/agent/info",
+ agent_id,
});
export const prepareConversation = (
diff --git a/src/data/selector.ts b/src/data/selector.ts
index 3ee0d020b7..1282323595 100644
--- a/src/data/selector.ts
+++ b/src/data/selector.ts
@@ -14,6 +14,7 @@ export type Selector =
| BooleanSelector
| ColorRGBSelector
| ColorTempSelector
+ | ConversationAgentSelector
| ConfigEntrySelector
| ConstantSelector
| DateSelector
@@ -85,6 +86,11 @@ export interface ColorTempSelector {
} | null;
}
+export interface ConversationAgentSelector {
+ // eslint-disable-next-line @typescript-eslint/ban-types
+ conversation_agent: {} | null;
+}
+
export interface ConfigEntrySelector {
config_entry: {
integration?: string;
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index 64b4b9efb5..15861616e2 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -125,7 +125,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
name: "conversation_engine",
required: true,
selector: {
- text: {},
+ conversation_agent: {},
},
},
{
diff --git a/src/translations/en.json b/src/translations/en.json
index 6ee28472e1..7f6adbabb4 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -401,6 +401,10 @@
"config-entry-picker": {
"config_entry": "Integration"
},
+ "coversation-agent-picker": {
+ "conversation_agent": "Conversation agent",
+ "default": "Default agent ({default})"
+ },
"theme-picker": {
"theme": "Theme",
"no_theme": "No theme"
From b2f66aa51c2a5d5c921a293f115e3dde2519d3f0 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Mon, 17 Apr 2023 22:09:46 +0200
Subject: [PATCH 034/112] Add stt selector (#16215
* Add stt selector
* Update ha-stt-picker.ts
* Add default
* Update ha-stt-picker.ts
* Update ha-stt-picker.ts
---
src/components/ha-selector/ha-selector-stt.ts | 50 +++++++++
src/components/ha-selector/ha-selector.ts | 1 +
src/components/ha-stt-picker.ts | 105 ++++++++++++++++++
src/data/selector.ts | 5 +
src/data/stt.ts | 16 +++
.../dialog-voice-assistant-pipeline-detail.ts | 3 +-
src/translations/en.json | 1 +
7 files changed, 180 insertions(+), 1 deletion(-)
create mode 100644 src/components/ha-selector/ha-selector-stt.ts
create mode 100644 src/components/ha-stt-picker.ts
diff --git a/src/components/ha-selector/ha-selector-stt.ts b/src/components/ha-selector/ha-selector-stt.ts
new file mode 100644
index 0000000000..75549077fd
--- /dev/null
+++ b/src/components/ha-selector/ha-selector-stt.ts
@@ -0,0 +1,50 @@
+import { css, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { STTSelector } from "../../data/selector";
+import { HomeAssistant } from "../../types";
+import "../ha-stt-picker";
+
+@customElement("ha-selector-stt")
+export class HaSTTSelector extends LitElement {
+ @property() public hass!: HomeAssistant;
+
+ @property() public selector!: STTSelector;
+
+ @property() public value?: any;
+
+ @property() public label?: string;
+
+ @property() public helper?: string;
+
+ @property({ type: Boolean }) public disabled = false;
+
+ @property({ type: Boolean }) public required = true;
+
+ @property({ attribute: false }) public context?: {
+ language?: string;
+ };
+
+ protected render() {
+ return html` `;
+ }
+
+ static styles = css`
+ ha-stt-picker {
+ width: 100%;
+ }
+ `;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-selector-stt": HaSTTSelector;
+ }
+}
diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts
index 7d4e456e60..8f4d5bb343 100644
--- a/src/components/ha-selector/ha-selector.ts
+++ b/src/components/ha-selector/ha-selector.ts
@@ -31,6 +31,7 @@ const LOAD_ELEMENTS = {
object: () => import("./ha-selector-object"),
select: () => import("./ha-selector-select"),
state: () => import("./ha-selector-state"),
+ stt: () => import("./ha-selector-stt"),
target: () => import("./ha-selector-target"),
template: () => import("./ha-selector-template"),
text: () => import("./ha-selector-text"),
diff --git a/src/components/ha-stt-picker.ts b/src/components/ha-stt-picker.ts
new file mode 100644
index 0000000000..bbaab72be4
--- /dev/null
+++ b/src/components/ha-stt-picker.ts
@@ -0,0 +1,105 @@
+import {
+ css,
+ CSSResultGroup,
+ html,
+ LitElement,
+ PropertyValueMap,
+ TemplateResult,
+} from "lit";
+import { customElement, property, state } from "lit/decorators";
+import { fireEvent } from "../common/dom/fire_event";
+import { stopPropagation } from "../common/dom/stop_propagation";
+import { computeStateName } from "../common/entity/compute_state_name";
+import { listSTTEngines, STTEngine } from "../data/stt";
+import { HomeAssistant } from "../types";
+import "./ha-list-item";
+import "./ha-select";
+import type { HaSelect } from "./ha-select";
+
+const DEFAULT = "default_engine_option";
+
+@customElement("ha-stt-picker")
+export class HaSTTPicker extends LitElement {
+ @property() public value?: string;
+
+ @property() public label?: string;
+
+ @property() public language?: string;
+
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ type: Boolean, reflect: true }) public disabled = false;
+
+ @property({ type: Boolean }) public required = false;
+
+ @state() _engines: STTEngine[] = [];
+
+ protected render(): TemplateResult {
+ const value = this.value ?? DEFAULT;
+ return html`
+
+
+ ${this.hass!.localize("ui.components.stt-picker.default")}
+
+ ${this._engines.map((engine) => {
+ const stateObj = this.hass!.states[engine.engine_id];
+ return html`
+ ${stateObj ? computeStateName(stateObj) : engine.engine_id}
+ `;
+ })}
+
+ `;
+ }
+
+ protected willUpdate(
+ changedProperties: PropertyValueMap | Map
+ ): void {
+ super.willUpdate(changedProperties);
+ if (!this.hasUpdated || changedProperties.has("language")) {
+ listSTTEngines(this.hass, this.language).then((engines) => {
+ this._engines = engines.providers;
+ });
+ }
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-select {
+ width: 100%;
+ }
+ `;
+ }
+
+ private _changed(ev): void {
+ const target = ev.target as HaSelect;
+ if (
+ !this.hass ||
+ target.value === "" ||
+ target.value === this.value ||
+ (this.value === undefined && target.value === DEFAULT)
+ ) {
+ return;
+ }
+ this.value = target.value === DEFAULT ? undefined : target.value;
+ fireEvent(this, "value-changed", { value: this.value });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-stt-picker": HaSTTPicker;
+ }
+}
diff --git a/src/data/selector.ts b/src/data/selector.ts
index 1282323595..429e40d3dd 100644
--- a/src/data/selector.ts
+++ b/src/data/selector.ts
@@ -35,6 +35,7 @@ export type Selector =
| StateSelector
| StatisticSelector
| StringSelector
+ | STTSelector
| TargetSelector
| TemplateSelector
| ThemeSelector
@@ -300,6 +301,10 @@ export interface StringSelector {
} | null;
}
+export interface STTSelector {
+ stt: { language?: string } | null;
+}
+
export interface TargetSelector {
target: {
entity?: EntitySelectorFilter | readonly EntitySelectorFilter[];
diff --git a/src/data/stt.ts b/src/data/stt.ts
index c855e77757..7a5d9da961 100644
--- a/src/data/stt.ts
+++ b/src/data/stt.ts
@@ -1,3 +1,5 @@
+import { HomeAssistant } from "../types";
+
export interface SpeechMetadata {
language: string;
format: "wav" | "ogg";
@@ -15,3 +17,17 @@ export interface SpeechMetadata {
| 48000;
channel: 1 | 2;
}
+
+export interface STTEngine {
+ engine_id: string;
+ language_supported?: boolean;
+}
+
+export const listSTTEngines = (
+ hass: HomeAssistant,
+ language?: string
+): Promise<{ providers: STTEngine[] }> =>
+ hass.callWS({
+ type: "stt/engine/list",
+ language,
+ });
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index 15861616e2..1cc48117d4 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -139,8 +139,9 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
name: "stt_engine",
required: true,
selector: {
- text: {},
+ stt: {},
},
+ context: { language: "language" },
},
{
name: "tts_engine",
diff --git a/src/translations/en.json b/src/translations/en.json
index 7f6adbabb4..2f3cbbe2bf 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -462,6 +462,7 @@
}
}
},
+ "stt-picker": { "stt": "Speech to text", "default": "Default" },
"related-filter-menu": {
"filter": "Filter",
"filter_by_entity": "Filter by entity",
From e32771fb1461cd52b4aec3069635e8fd2526db83 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Mon, 17 Apr 2023 22:52:35 +0200
Subject: [PATCH 035/112] Add tts selector (#16213
* Add tts selector
* Update selector.ts
* Update ha-selector-tts.ts
* Add default
* Update ha-tts-picker.ts
* Update ha-tts-picker.ts
* Not required
---
src/components/ha-list-item.ts | 3 +
src/components/ha-selector/ha-selector-tts.ts | 50 +++++++++
src/components/ha-selector/ha-selector.ts | 1 +
src/components/ha-tts-picker.ts | 105 ++++++++++++++++++
src/data/selector.ts | 5 +
src/data/tts.ts | 30 +++++
.../dialog-voice-assistant-pipeline-detail.ts | 6 +-
src/translations/en.json | 4 +
8 files changed, 200 insertions(+), 4 deletions(-)
create mode 100644 src/components/ha-selector/ha-selector-tts.ts
create mode 100644 src/components/ha-tts-picker.ts
diff --git a/src/components/ha-list-item.ts b/src/components/ha-list-item.ts
index 8107ae4f2a..252e80954a 100644
--- a/src/components/ha-list-item.ts
+++ b/src/components/ha-list-item.ts
@@ -57,6 +57,9 @@ export class HaListItem extends ListItemBase {
.mdc-deprecated-list-item__primary-text::before {
display: none;
}
+ :host([disabled]) {
+ color: var(--disabled-text-color);
+ }
`,
];
}
diff --git a/src/components/ha-selector/ha-selector-tts.ts b/src/components/ha-selector/ha-selector-tts.ts
new file mode 100644
index 0000000000..fbf83fb167
--- /dev/null
+++ b/src/components/ha-selector/ha-selector-tts.ts
@@ -0,0 +1,50 @@
+import { css, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { TTSSelector } from "../../data/selector";
+import { HomeAssistant } from "../../types";
+import "../ha-tts-picker";
+
+@customElement("ha-selector-tts")
+export class HaTTSSelector extends LitElement {
+ @property() public hass!: HomeAssistant;
+
+ @property() public selector!: TTSSelector;
+
+ @property() public value?: any;
+
+ @property() public label?: string;
+
+ @property() public helper?: string;
+
+ @property({ type: Boolean }) public disabled = false;
+
+ @property({ type: Boolean }) public required = true;
+
+ @property({ attribute: false }) public context?: {
+ language?: string;
+ };
+
+ protected render() {
+ return html` `;
+ }
+
+ static styles = css`
+ ha-tts-picker {
+ width: 100%;
+ }
+ `;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-selector-tts": HaTTSSelector;
+ }
+}
diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts
index 8f4d5bb343..12cd14d2b9 100644
--- a/src/components/ha-selector/ha-selector.ts
+++ b/src/components/ha-selector/ha-selector.ts
@@ -39,6 +39,7 @@ const LOAD_ELEMENTS = {
icon: () => import("./ha-selector-icon"),
media: () => import("./ha-selector-media"),
theme: () => import("./ha-selector-theme"),
+ tts: () => import("./ha-selector-tts"),
location: () => import("./ha-selector-location"),
color_temp: () => import("./ha-selector-color-temp"),
"ui-action": () => import("./ha-selector-ui-action"),
diff --git a/src/components/ha-tts-picker.ts b/src/components/ha-tts-picker.ts
new file mode 100644
index 0000000000..c0d5916a4d
--- /dev/null
+++ b/src/components/ha-tts-picker.ts
@@ -0,0 +1,105 @@
+import {
+ css,
+ CSSResultGroup,
+ html,
+ LitElement,
+ PropertyValueMap,
+ TemplateResult,
+} from "lit";
+import { customElement, property, state } from "lit/decorators";
+import { fireEvent } from "../common/dom/fire_event";
+import { stopPropagation } from "../common/dom/stop_propagation";
+import { computeStateName } from "../common/entity/compute_state_name";
+import { TTSEngine, listTTSEngines } from "../data/tts";
+import { HomeAssistant } from "../types";
+import "./ha-select";
+import "./ha-list-item";
+import type { HaSelect } from "./ha-select";
+
+const DEFAULT = "default_engine_option";
+
+@customElement("ha-tts-picker")
+export class HaTTSPicker extends LitElement {
+ @property() public value?: string;
+
+ @property() public label?: string;
+
+ @property() public language?: string;
+
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ type: Boolean, reflect: true }) public disabled = false;
+
+ @property({ type: Boolean }) public required = false;
+
+ @state() _engines: TTSEngine[] = [];
+
+ protected render(): TemplateResult {
+ const value = this.value ?? DEFAULT;
+ return html`
+
+
+ ${this.hass!.localize("ui.components.tts-picker.default")}
+
+ ${this._engines.map((engine) => {
+ const stateObj = this.hass!.states[engine.engine_id];
+ return html`
+ ${stateObj ? computeStateName(stateObj) : engine.engine_id}
+ `;
+ })}
+
+ `;
+ }
+
+ protected willUpdate(
+ changedProperties: PropertyValueMap | Map
+ ): void {
+ super.willUpdate(changedProperties);
+ if (!this.hasUpdated || changedProperties.has("language")) {
+ listTTSEngines(this.hass, this.language).then((engines) => {
+ this._engines = engines.providers;
+ });
+ }
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-select {
+ width: 100%;
+ }
+ `;
+ }
+
+ private _changed(ev): void {
+ const target = ev.target as HaSelect;
+ if (
+ !this.hass ||
+ target.value === "" ||
+ target.value === this.value ||
+ (this.value === undefined && target.value === DEFAULT)
+ ) {
+ return;
+ }
+ this.value = target.value === DEFAULT ? undefined : target.value;
+ fireEvent(this, "value-changed", { value: this.value });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-tts-picker": HaTTSPicker;
+ }
+}
diff --git a/src/data/selector.ts b/src/data/selector.ts
index 429e40d3dd..e3aec23946 100644
--- a/src/data/selector.ts
+++ b/src/data/selector.ts
@@ -40,6 +40,7 @@ export type Selector =
| TemplateSelector
| ThemeSelector
| TimeSelector
+ | TTSSelector
| UiActionSelector
| UiColorSelector;
@@ -326,6 +327,10 @@ export interface TimeSelector {
time: {} | null;
}
+export interface TTSSelector {
+ tts: { language?: string } | null;
+}
+
export interface UiActionSelector {
"ui-action": {
actions?: UiAction[];
diff --git a/src/data/tts.ts b/src/data/tts.ts
index f4d0d1346b..63a237d2b8 100644
--- a/src/data/tts.ts
+++ b/src/data/tts.ts
@@ -1,5 +1,15 @@
import { HomeAssistant } from "../types";
+export interface TTSEngine {
+ engine_id: string;
+ language_supported?: boolean;
+}
+
+export interface TTSVoice {
+ voice_id: string;
+ name: string;
+}
+
export const convertTextToSpeech = (
hass: HomeAssistant,
data: {
@@ -18,3 +28,23 @@ export const isTTSMediaSource = (mediaContentId: string) =>
export const getProviderFromTTSMediaSource = (mediaContentId: string) =>
mediaContentId.substring(TTS_MEDIA_SOURCE_PREFIX.length);
+
+export const listTTSEngines = (
+ hass: HomeAssistant,
+ language?: string
+): Promise<{ providers: TTSEngine[] }> =>
+ hass.callWS({
+ type: "tts/engine/list",
+ language,
+ });
+
+export const listTTSVoices = (
+ hass: HomeAssistant,
+ engine_id: string,
+ language: string
+): Promise<{ voices: TTSVoice[] }> =>
+ hass.callWS({
+ type: "tts/engine/voices",
+ engine_id,
+ language,
+ });
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index 1cc48117d4..b70f1c2619 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -123,7 +123,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
},
{
name: "conversation_engine",
- required: true,
selector: {
conversation_agent: {},
},
@@ -137,7 +136,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
},
{
name: "stt_engine",
- required: true,
selector: {
stt: {},
},
@@ -145,10 +143,10 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
},
{
name: "tts_engine",
- required: true,
selector: {
- text: {},
+ tts: {},
},
+ context: { language: "language" },
},
] as const
);
diff --git a/src/translations/en.json b/src/translations/en.json
index 2f3cbbe2bf..43097bd8f8 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -409,6 +409,10 @@
"theme": "Theme",
"no_theme": "No theme"
},
+ "tts-picker": {
+ "tts": "Text to Speech",
+ "default": "Default"
+ },
"user-picker": {
"no_user": "No user",
"add_user": "Add user",
From 8edb48eedc460d2011c11a6dd851357d0afb0128 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Tue, 18 Apr 2023 01:13:05 +0200
Subject: [PATCH 036/112] Fetch latest pipeline run (#16220)
* Fetch latest pipeline run
very basic debug, showing raw event data
* Update dialog-voice-assistant-pipeline-detail.ts
* last one, not first
---
src/data/assist_pipeline.ts | 24 ++++++++++++++++++
.../dialog-voice-assistant-pipeline-detail.ts | 25 +++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/src/data/assist_pipeline.ts b/src/data/assist_pipeline.ts
index 234a332bb9..6b3d356ef6 100644
--- a/src/data/assist_pipeline.ts
+++ b/src/data/assist_pipeline.ts
@@ -219,6 +219,30 @@ export const runAssistPipeline = (
return unsubProm;
};
+export const listAssistPipelineRuns = (
+ hass: HomeAssistant,
+ pipeline_id: string
+) =>
+ hass.callWS<{
+ pipeline_runs: string[];
+ }>({
+ type: "assist_pipeline/pipeline_debug/list",
+ pipeline_id,
+ });
+
+export const getAssistPipelineRun = (
+ hass: HomeAssistant,
+ pipeline_id: string,
+ pipeline_run_id: string
+) =>
+ hass.callWS<{
+ events: PipelineRunEvent[];
+ }>({
+ type: "assist_pipeline/pipeline_debug/get",
+ pipeline_id,
+ pipeline_run_id,
+ });
+
export const fetchAssistPipelines = (hass: HomeAssistant) =>
hass.callWS<{
pipelines: AssistPipeline[];
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index b70f1c2619..6410c35e2d 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -9,7 +9,10 @@ import { SchemaUnion } from "../../../components/ha-form/types";
import {
AssistPipeline,
AssistPipelineMutableParams,
+ getAssistPipelineRun,
+ listAssistPipelineRuns,
} from "../../../data/assist_pipeline";
+import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { VoiceAssistantPipelineDetailsDialogParams } from "./show-dialog-voice-assistant-pipeline-detail";
@@ -91,6 +94,9 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
@click=${this._setPreferred}
>Set as default
+ Debug
`
: nothing}
${JSON.stringify(events.events, null, 2)}`,
+ });
+ }
+
private async _deletePipeline() {
this._submitting = true;
try {
From 51157caf22d2357f86edc05c867fec52c2a8b81a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 17 Apr 2023 22:35:22 -0400
Subject: [PATCH 037/112] Update dependency glob to v10.1.0 (#16221)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
package.json | 2 +-
yarn.lock | 20 ++++++++++----------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/package.json b/package.json
index 7db00ffae2..e8dc51cbcc 100644
--- a/package.json
+++ b/package.json
@@ -207,7 +207,7 @@
"esprima": "4.0.1",
"fancy-log": "2.0.0",
"fs-extra": "11.1.1",
- "glob": "10.0.0",
+ "glob": "10.1.0",
"gulp": "4.0.2",
"gulp-flatmap": "1.0.2",
"gulp-json-transform": "0.4.8",
diff --git a/yarn.lock b/yarn.lock
index 17d321edd5..113cc3bfe7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9012,15 +9012,15 @@ __metadata:
languageName: node
linkType: hard
-"glob@npm:10.0.0":
- version: 10.0.0
- resolution: "glob@npm:10.0.0"
+"glob@npm:10.1.0":
+ version: 10.1.0
+ resolution: "glob@npm:10.1.0"
dependencies:
fs.realpath: ^1.0.0
minimatch: ^9.0.0
minipass: ^5.0.0
- path-scurry: ^1.6.4
- checksum: 3852a6b847106c431d87fb3e8cccb6cfc4449de3ab5d0216c44d4e2da2616df220058050d16811c42f0c2148ad8981da828227ae5c5ab798091ef27c903429f6
+ path-scurry: ^1.7.0
+ checksum: 93021661bfcd474dcf2866f1ce1defb2a8b323fcdfaa32197040bd15235960115fd41347222eaf704050869c2922cf7c021404b77544cec77399899b0401f663
languageName: node
linkType: hard
@@ -9577,7 +9577,7 @@ __metadata:
fancy-log: 2.0.0
fs-extra: 11.1.1
fuse.js: 6.6.2
- glob: 10.0.0
+ glob: 10.1.0
google-timezones-json: 1.0.2
gulp: 4.0.2
gulp-flatmap: 1.0.2
@@ -12825,13 +12825,13 @@ __metadata:
languageName: node
linkType: hard
-"path-scurry@npm:^1.6.4":
- version: 1.6.4
- resolution: "path-scurry@npm:1.6.4"
+"path-scurry@npm:^1.7.0":
+ version: 1.7.0
+ resolution: "path-scurry@npm:1.7.0"
dependencies:
lru-cache: ^9.0.0
minipass: ^5.0.0
- checksum: bd5262b51dc35b0d6f0b1d4fa4445789839982bd649904f18fe43717ecc3021d2313a80768b56cd0428f5ca50d740a6c609e747cd6a053efaa802e07eb5b7b18
+ checksum: 4e86df0fa6848cef1ba672d4a332b8dbd0297c42d5123bcc419d714c34b25ee6775b0d2e66dd5e698a38e9bcd808f8fc47333e3a3357307cada98e16bfae8b98
languageName: node
linkType: hard
From 52f609f742dd2f28b94ee50995c7a488bf454154 Mon Sep 17 00:00:00 2001
From: Stefan Agner
Date: Tue, 18 Apr 2023 10:45:23 +0200
Subject: [PATCH 038/112] Write data disk with space everywhere (#16223)
---
src/translations/en.json | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/translations/en.json b/src/translations/en.json
index 43097bd8f8..ffc8b1fd16 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -3889,17 +3889,17 @@
"used_space": "Used Space",
"emmc_lifetime_used": "eMMC Lifetime Used",
"datadisk": {
- "title": "Move datadisk",
- "description": "You are currently using ''{current_path}'' as datadisk. Moving data disks will reboot your device and it's estimated to take {time} minutes. Your Home Assistant installation will not be accessible during this period. Do not disconnect the power during the move!",
+ "title": "Move data disk",
+ "description": "You are currently using ''{current_path}'' as data disk. Moving the data disk will reboot your device and it's estimated to take {time} minutes. Your Home Assistant installation will not be accessible during this period. Do not disconnect the power during the move!",
"extra_information": "Size: {size}, S/N: {serial}",
- "select_device": "Select new datadisk",
+ "select_device": "Select new data disk",
"no_devices_title": "No suitable storage found",
"no_devices_text": "There is no suitable external device found. The storage capacity of the external data disk must be larger than the storage capacity of the existing disk",
- "moving_desc": "Rebooting and moving datadisk. Please have patience",
- "moving": "Moving datadisk",
+ "moving_desc": "Rebooting and moving data disk. Please have patience",
+ "moving": "Moving data disk",
"loading_devices": "Loading devices",
"cancel": "[%key:ui::common::cancel%]",
- "failed_to_move": "Failed to move datadisk",
+ "failed_to_move": "Failed to move data disk",
"move": "Move"
}
},
@@ -5542,7 +5542,7 @@
"failed_to_shutdown": "Failed to shutdown the host",
"failed_to_set_hostname": "Setting hostname failed",
"failed_to_import_from_usb": "Failed to import from USB",
- "failed_to_move": "Failed to move datadisk",
+ "failed_to_move": "Failed to move data disk",
"used_space": "Used space",
"hostname": "Hostname",
"change_hostname": "Change Hostname",
@@ -5559,7 +5559,7 @@
"shutdown_host": "Shutdown host",
"hardware": "Hardware",
"import_from_usb": "Import from USB",
- "move_datadisk": "Move datadisk"
+ "move_datadisk": "Move data disk"
},
"core": {
"cpu_usage": "Core CPU Usage",
@@ -5657,11 +5657,11 @@
},
"datadisk_move": {
"title": "[%key:supervisor::system::host::move_datadisk%]",
- "description": "You are currently using ''{current_path}'' as datadisk. Moving data disks will reboot your device and it's estimated to take {time} minutes. Your Home Assistant installation will not be accessible during this period. Do not disconnect the power during the move!",
- "select_device": "Select new datadisk",
+ "description": "You are currently using ''{current_path}'' as data disk. Moving data disks will reboot your device and it's estimated to take {time} minutes. Your Home Assistant installation will not be accessible during this period. Do not disconnect the power during the move!",
+ "select_device": "Select new data disk",
"no_devices": "No suitable attached devices found",
- "moving_desc": "Rebooting and moving datadisk. Please have patience",
- "moving": "Moving datadisk",
+ "moving_desc": "Rebooting and moving data disk. Please have patience",
+ "moving": "Moving data disk",
"loading_devices": "Loading devices",
"cancel": "[%key:ui::common::cancel%]",
"move": "Move"
From 790faa9c31c2fc8dfbc95b372819a83c1f6ff613 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Tue, 18 Apr 2023 16:45:33 +0200
Subject: [PATCH 039/112] Display historic pipeline events in
`assist-render-pipeline-run` (#16225)
* Display historic pipeline events in `assist-render-pipeline-run`
* Add debug pipeline page
* Update assist-pipeline-run-debug.ts
* dont show alert
* Update assist-pipeline-debug.ts
* simplify
* link to run debug pipeline
---
src/data/assist_pipeline.ts | 153 +++++++-------
.../voice-assistants/debug/assist-debug.ts | 35 +++
.../debug/assist-pipeline-debug.ts | 200 ++++++++++++++++++
.../debug/assist-pipeline-run-debug.ts} | 36 ++--
.../debug/assist-render-pipeline-events.ts | 57 +++++
.../debug}/assist-render-pipeline-run.ts | 36 ++--
.../debug}/recorder.worklet.js | 0
.../dialog-voice-assistant-pipeline-detail.ts | 33 +--
.../ha-config-voice-assistants.ts | 7 +-
9 files changed, 423 insertions(+), 134 deletions(-)
create mode 100644 src/panels/config/voice-assistants/debug/assist-debug.ts
create mode 100644 src/panels/config/voice-assistants/debug/assist-pipeline-debug.ts
rename src/panels/config/{integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts => voice-assistants/debug/assist-pipeline-run-debug.ts} (90%)
create mode 100644 src/panels/config/voice-assistants/debug/assist-render-pipeline-events.ts
rename src/panels/config/{integrations/integration-panels/voice_assistant/assist => voice-assistants/debug}/assist-render-pipeline-run.ts (89%)
rename src/panels/config/{integrations/integration-panels/voice_assistant/assist => voice-assistants/debug}/recorder.worklet.js (100%)
diff --git a/src/data/assist_pipeline.ts b/src/data/assist_pipeline.ts
index 6b3d356ef6..dd8eca29fb 100644
--- a/src/data/assist_pipeline.ts
+++ b/src/data/assist_pipeline.ts
@@ -20,6 +20,11 @@ export interface AssistPipelineMutableParams {
tts_engine: string;
}
+export interface assistRunListing {
+ pipeline_run_id: string;
+ timestamp: string;
+}
+
interface PipelineEventBase {
timestamp: string;
}
@@ -90,7 +95,7 @@ interface PipelineTTSEndEvent extends PipelineEventBase {
};
}
-type PipelineRunEvent =
+export type PipelineRunEvent =
| PipelineRunStartEvent
| PipelineRunEndEvent
| PipelineErrorEvent
@@ -117,7 +122,7 @@ export type PipelineRunOptions = (
};
export interface PipelineRun {
- init_options: PipelineRunOptions;
+ init_options?: PipelineRunOptions;
events: PipelineRunEvent[];
stage: "ready" | "stt" | "intent" | "tts" | "done" | "error";
run: PipelineRunStartEvent["data"];
@@ -130,6 +135,73 @@ export interface PipelineRun {
Partial & { done: boolean };
}
+export const processEvent = (
+ run: PipelineRun | undefined,
+ event: PipelineRunEvent,
+ options?: PipelineRunOptions
+): PipelineRun | undefined => {
+ if (event.type === "run-start") {
+ run = {
+ init_options: options,
+ stage: "ready",
+ run: event.data,
+ events: [event],
+ };
+ return run;
+ }
+
+ if (!run) {
+ // eslint-disable-next-line no-console
+ console.warn("Received unexpected event before receiving session", event);
+ return undefined;
+ }
+
+ if (event.type === "stt-start") {
+ run = {
+ ...run,
+ stage: "stt",
+ stt: { ...event.data, done: false },
+ };
+ } else if (event.type === "stt-end") {
+ run = {
+ ...run,
+ stt: { ...run.stt!, ...event.data, done: true },
+ };
+ } else if (event.type === "intent-start") {
+ run = {
+ ...run,
+ stage: "intent",
+ intent: { ...event.data, done: false },
+ };
+ } else if (event.type === "intent-end") {
+ run = {
+ ...run,
+ intent: { ...run.intent!, ...event.data, done: true },
+ };
+ } else if (event.type === "tts-start") {
+ run = {
+ ...run,
+ stage: "tts",
+ tts: { ...event.data, done: false },
+ };
+ } else if (event.type === "tts-end") {
+ run = {
+ ...run,
+ tts: { ...run.tts!, ...event.data, done: true },
+ };
+ } else if (event.type === "run-end") {
+ run = { ...run, stage: "done" };
+ } else if (event.type === "error") {
+ run = { ...run, stage: "error", error: event.data };
+ } else {
+ run = { ...run };
+ }
+
+ run.events = [...run.events, event];
+
+ return run;
+};
+
export const runAssistPipeline = (
hass: HomeAssistant,
callback: (event: PipelineRun) => void,
@@ -139,76 +211,15 @@ export const runAssistPipeline = (
const unsubProm = hass.connection.subscribeMessage(
(updateEvent) => {
- if (updateEvent.type === "run-start") {
- run = {
- init_options: options,
- stage: "ready",
- run: updateEvent.data,
- error: undefined,
- stt: undefined,
- intent: undefined,
- tts: undefined,
- events: [updateEvent],
- };
+ run = processEvent(run, updateEvent, options);
+
+ if (updateEvent.type === "run-end" || updateEvent.type === "error") {
+ unsubProm.then((unsub) => unsub());
+ }
+
+ if (run) {
callback(run);
- return;
}
-
- if (!run) {
- // eslint-disable-next-line no-console
- console.warn(
- "Received unexpected event before receiving session",
- updateEvent
- );
- return;
- }
-
- if (updateEvent.type === "stt-start") {
- run = {
- ...run,
- stage: "stt",
- stt: { ...updateEvent.data, done: false },
- };
- } else if (updateEvent.type === "stt-end") {
- run = {
- ...run,
- stt: { ...run.stt!, ...updateEvent.data, done: true },
- };
- } else if (updateEvent.type === "intent-start") {
- run = {
- ...run,
- stage: "intent",
- intent: { ...updateEvent.data, done: false },
- };
- } else if (updateEvent.type === "intent-end") {
- run = {
- ...run,
- intent: { ...run.intent!, ...updateEvent.data, done: true },
- };
- } else if (updateEvent.type === "tts-start") {
- run = {
- ...run,
- stage: "tts",
- tts: { ...updateEvent.data, done: false },
- };
- } else if (updateEvent.type === "tts-end") {
- run = {
- ...run,
- tts: { ...run.tts!, ...updateEvent.data, done: true },
- };
- } else if (updateEvent.type === "run-end") {
- run = { ...run, stage: "done" };
- unsubProm.then((unsub) => unsub());
- } else if (updateEvent.type === "error") {
- run = { ...run, stage: "error", error: updateEvent.data };
- unsubProm.then((unsub) => unsub());
- } else {
- run = { ...run };
- }
-
- run.events = [...run.events, updateEvent];
-
- callback(run);
},
{
...options,
@@ -224,7 +235,7 @@ export const listAssistPipelineRuns = (
pipeline_id: string
) =>
hass.callWS<{
- pipeline_runs: string[];
+ pipeline_runs: assistRunListing[];
}>({
type: "assist_pipeline/pipeline_debug/list",
pipeline_id,
diff --git a/src/panels/config/voice-assistants/debug/assist-debug.ts b/src/panels/config/voice-assistants/debug/assist-debug.ts
new file mode 100644
index 0000000000..623401231e
--- /dev/null
+++ b/src/panels/config/voice-assistants/debug/assist-debug.ts
@@ -0,0 +1,35 @@
+import { html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { HomeAssistant, Route } from "../../../../types";
+import "./assist-pipeline-debug";
+import "./assist-pipeline-run-debug";
+
+@customElement("assist-debug")
+export class AssistDebug extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ type: Boolean }) public narrow!: boolean;
+
+ @property({ attribute: false }) public route!: Route;
+
+ protected render() {
+ const pipelineId = this.route.path.substring(1);
+ if (pipelineId) {
+ return html` `;
+ }
+ return html` `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "assist-debug": AssistDebug;
+ }
+}
diff --git a/src/panels/config/voice-assistants/debug/assist-pipeline-debug.ts b/src/panels/config/voice-assistants/debug/assist-pipeline-debug.ts
new file mode 100644
index 0000000000..638fad5c3c
--- /dev/null
+++ b/src/panels/config/voice-assistants/debug/assist-pipeline-debug.ts
@@ -0,0 +1,200 @@
+import {
+ mdiMicrophoneMessage,
+ mdiRayEndArrow,
+ mdiRayStartArrow,
+} from "@mdi/js";
+import { css, html, LitElement } from "lit";
+import { customElement, property, state } from "lit/decorators";
+import { repeat } from "lit/directives/repeat";
+import { formatDateTimeWithSeconds } from "../../../../common/datetime/format_date_time";
+import {
+ listAssistPipelineRuns,
+ getAssistPipelineRun,
+ PipelineRunEvent,
+ assistRunListing,
+} from "../../../../data/assist_pipeline";
+import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
+import "../../../../layouts/hass-subpage";
+import { haStyle } from "../../../../resources/styles";
+import { HomeAssistant, Route } from "../../../../types";
+import "./assist-render-pipeline-events";
+
+@customElement("assist-pipeline-debug")
+export class AssistPipelineDebug extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ type: Boolean }) public narrow!: boolean;
+
+ @property({ attribute: false }) public route!: Route;
+
+ @property() public pipelineId!: string;
+
+ @state() private _runId?: string;
+
+ @state() private _runs?: assistRunListing[];
+
+ @state() private _events?: PipelineRunEvent[];
+
+ protected render() {
+ return html`
+
+
+ ${this._runs?.length
+ ? html`
+
+
+ ${repeat(
+ this._runs,
+ (run) => run.pipeline_run_id,
+ (run) =>
+ html`
+ ${formatDateTimeWithSeconds(
+ new Date(run.timestamp),
+ this.hass.locale
+ )}
+ `
+ )}
+
+
+ `
+ : ""}
+
+ ${this._runs?.length === 0
+ ? html`No runs found
`
+ : ""}
+
+ ${this._events
+ ? html`
`
+ : ""}
+
+ `;
+ }
+
+ protected willUpdate(changedProperties) {
+ if (changedProperties.has("pipelineId")) {
+ this._fetchRuns();
+ }
+ if (changedProperties.has("_runId")) {
+ this._fetchEvents();
+ }
+ }
+
+ private async _fetchRuns() {
+ if (!this.pipelineId) {
+ this._runs = undefined;
+ return;
+ }
+ try {
+ this._runs = (
+ await listAssistPipelineRuns(this.hass, this.pipelineId)
+ ).pipeline_runs.reverse();
+ } catch (e: any) {
+ showAlertDialog(this, {
+ title: "Failed to fetch pipeline runs",
+ text: e.message,
+ });
+ return;
+ }
+ if (!this._runs.length) {
+ return;
+ }
+ if (
+ !this._runId ||
+ !this._runs.find((run) => run.pipeline_run_id === this._runId)
+ ) {
+ this._runId = this._runs[0].pipeline_run_id;
+ this._fetchEvents();
+ }
+ }
+
+ private async _fetchEvents() {
+ if (!this._runId) {
+ this._events = undefined;
+ return;
+ }
+ try {
+ this._events = (
+ await getAssistPipelineRun(this.hass, this.pipelineId, this._runId)
+ ).events;
+ } catch (e: any) {
+ showAlertDialog(this, {
+ title: "Failed to fetch events",
+ text: e.message,
+ });
+ }
+ }
+
+ private _pickOlderRun() {
+ const curIndex = this._runs!.findIndex(
+ (run) => run.pipeline_run_id === this._runId
+ );
+ this._runId = this._runs![curIndex + 1].pipeline_run_id;
+ }
+
+ private _pickNewerRun() {
+ const curIndex = this._runs!.findIndex(
+ (run) => run.pipeline_run_id === this._runId
+ );
+ this._runId = this._runs![curIndex - 1].pipeline_run_id;
+ }
+
+ private _pickRun(ev) {
+ this._runId = ev.target.value;
+ }
+
+ static styles = [
+ haStyle,
+ css`
+ .toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: var(--header-height);
+ background-color: var(--primary-background-color);
+ color: var(--app-header-text-color, white);
+ border-bottom: var(--app-header-border-bottom, none);
+ box-sizing: border-box;
+ }
+ .content {
+ padding: 24px 0 32px;
+ max-width: 600px;
+ margin: 0 auto;
+ direction: ltr;
+ }
+ .container {
+ padding: 16px;
+ }
+ assist-render-pipeline-run {
+ padding-top: 16px;
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "assist-pipeline-debug": AssistPipelineDebug;
+ }
+}
diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts b/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts
similarity index 90%
rename from src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
rename to src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts
index 9d48d02402..2f67415dbe 100644
--- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts
+++ b/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts
@@ -1,28 +1,29 @@
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property, query, state } from "lit/decorators";
-import "../../../../../../components/ha-button";
+import "../../../../components/ha-button";
import {
PipelineRun,
PipelineRunOptions,
runAssistPipeline,
-} from "../../../../../../data/assist_pipeline";
-import "../../../../../../layouts/hass-subpage";
-import "../../../../../../components/ha-formfield";
-import "../../../../../../components/ha-checkbox";
-import { haStyle } from "../../../../../../resources/styles";
-import type { HomeAssistant } from "../../../../../../types";
+} from "../../../../data/assist_pipeline";
+import "../../../../layouts/hass-subpage";
+import "../../../../components/ha-formfield";
+import "../../../../components/ha-checkbox";
+import { haStyle } from "../../../../resources/styles";
+import type { HomeAssistant } from "../../../../types";
import {
showAlertDialog,
showPromptDialog,
-} from "../../../../../../dialogs/generic/show-dialog-box";
+} from "../../../../dialogs/generic/show-dialog-box";
import "./assist-render-pipeline-run";
-import type { HaCheckbox } from "../../../../../../components/ha-checkbox";
-import type { HaTextField } from "../../../../../../components/ha-textfield";
-import "../../../../../../components/ha-textfield";
-import { fileDownload } from "../../../../../../util/file_download";
+import type { HaCheckbox } from "../../../../components/ha-checkbox";
+import type { HaTextField } from "../../../../components/ha-textfield";
+import "../../../../components/ha-textfield";
+import { fileDownload } from "../../../../util/file_download";
+import { extractSearchParam } from "../../../../common/url/search-params";
-@customElement("assist-pipeline-debug")
-export class AssistPipelineDebug extends LitElement {
+@customElement("assist-pipeline-run-debug")
+export class AssistPipelineRunDebug extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public narrow!: boolean;
@@ -39,7 +40,8 @@ export class AssistPipelineDebug extends LitElement {
@state() private _finished = false;
- @state() private _pipelineId?: string;
+ @state() private _pipelineId?: string =
+ extractSearchParam("pipeline") || undefined;
protected render(): TemplateResult {
return html`
@@ -81,7 +83,7 @@ export class AssistPipelineDebug extends LitElement {
Run Audio Pipeline
`
- : this._pipelineRuns[0].init_options.start_stage === "intent"
+ : this._pipelineRuns[0].init_options!.start_stage === "intent"
? html`
{
+ let run: PipelineRun | undefined;
+ events.forEach((event) => {
+ run = processEvent(run, event);
+ });
+ return run;
+ }
+ );
+
+ protected render(): TemplateResult {
+ const run = this._processEvents(this.events);
+ if (!run) {
+ if (this.events.length) {
+ return html`Error showing run
+
+
+ Raw
+ ${JSON.stringify(this.events, null, 2)}
+
+ `;
+ }
+ return html`There where no events in this run. `;
+ }
+ return html`
+
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "assist-render-pipeline-events": AssistPipelineEvents;
+ }
+}
diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts b/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts
similarity index 89%
rename from src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts
rename to src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts
index 838f0f36b9..959bdc78d0 100644
--- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts
+++ b/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts
@@ -1,13 +1,13 @@
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
-import "../../../../../../components/ha-card";
-import "../../../../../../components/ha-alert";
-import "../../../../../../components/ha-button";
-import "../../../../../../components/ha-circular-progress";
-import "../../../../../../components/ha-expansion-panel";
-import type { PipelineRun } from "../../../../../../data/assist_pipeline";
-import type { HomeAssistant } from "../../../../../../types";
-import { formatNumber } from "../../../../../../common/number/format_number";
+import "../../../../components/ha-card";
+import "../../../../components/ha-alert";
+import "../../../../components/ha-button";
+import "../../../../components/ha-circular-progress";
+import "../../../../components/ha-expansion-panel";
+import type { PipelineRun } from "../../../../data/assist_pipeline";
+import type { HomeAssistant } from "../../../../types";
+import { formatNumber } from "../../../../common/number/format_number";
const RUN_DATA = {
pipeline: "Pipeline",
@@ -38,8 +38,10 @@ const STAGES: Record = {
};
const hasStage = (run: PipelineRun, stage: PipelineRun["stage"]) =>
- STAGES[run.init_options.start_stage] <= STAGES[stage] &&
- STAGES[stage] <= STAGES[run.init_options.end_stage];
+ run.init_options
+ ? STAGES[run.init_options.start_stage] <= STAGES[stage] &&
+ STAGES[stage] <= STAGES[run.init_options.end_stage]
+ : stage in run;
const maybeRenderError = (
run: PipelineRun,
@@ -123,21 +125,23 @@ const dataMinusKeysRender = (
export class AssistPipelineDebug extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
- @property() private pipelineRun!: PipelineRun;
+ @property() public pipelineRun!: PipelineRun;
protected render(): TemplateResult {
const lastRunStage: string = this.pipelineRun
- ? ["tts", "intent", "stt"].find(
- (stage) => this.pipelineRun![stage] !== undefined
- ) || "ready"
+ ? ["tts", "intent", "stt"].find((stage) => stage in this.pipelineRun) ||
+ "ready"
: "ready";
const messages: Array<{ from: string; text: string }> = [];
const userMessage =
- ("text" in this.pipelineRun.init_options.input
+ (this.pipelineRun.init_options &&
+ "text" in this.pipelineRun.init_options.input
? this.pipelineRun.init_options.input.text
- : undefined) || this.pipelineRun?.stt?.stt_output?.text;
+ : undefined) ||
+ this.pipelineRun?.stt?.stt_output?.text ||
+ this.pipelineRun?.intent?.intent_input;
if (userMessage) {
messages.push({
diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/recorder.worklet.js b/src/panels/config/voice-assistants/debug/recorder.worklet.js
similarity index 100%
rename from src/panels/config/integrations/integration-panels/voice_assistant/assist/recorder.worklet.js
rename to src/panels/config/voice-assistants/debug/recorder.worklet.js
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index 6410c35e2d..79897ec5c4 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -9,12 +9,10 @@ import { SchemaUnion } from "../../../components/ha-form/types";
import {
AssistPipeline,
AssistPipelineMutableParams,
- getAssistPipelineRun,
- listAssistPipelineRuns,
} from "../../../data/assist_pipeline";
-import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
+import "./debug/assist-render-pipeline-events";
import { VoiceAssistantPipelineDetailsDialogParams } from "./show-dialog-voice-assistant-pipeline-detail";
@customElement("dialog-voice-assistant-pipeline-detail")
@@ -94,9 +92,13 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
@click=${this._setPreferred}
>Set as default
- Debug
+ Debug
+
`
: nothing}
${JSON.stringify(events.events, null, 2)}`,
- });
- }
-
private async _deletePipeline() {
this._submitting = true;
try {
diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants.ts
index 4009b404ad..fe35b6dd78 100644
--- a/src/panels/config/voice-assistants/ha-config-voice-assistants.ts
+++ b/src/panels/config/voice-assistants/ha-config-voice-assistants.ts
@@ -43,11 +43,8 @@ class HaConfigVoiceAssistants extends HassRouterPage {
load: () => import("./ha-config-voice-assistants-expose"),
},
debug: {
- tag: "assist-pipeline-debug",
- load: () =>
- import(
- "../integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug"
- ),
+ tag: "assist-debug",
+ load: () => import("./debug/assist-debug"),
},
},
};
From 4ff450c5c36c4357991c73e0761f01e1fca93b25 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 18 Apr 2023 20:22:42 -0400
Subject: [PATCH 040/112] Update dependency webpack-dev-server to v4.13.3
(#16228)
---
package.json | 2 +-
yarn.lock | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index e8dc51cbcc..5c9e6adf6b 100644
--- a/package.json
+++ b/package.json
@@ -245,7 +245,7 @@
"vinyl-source-stream": "2.0.0",
"webpack": "=5.72.1",
"webpack-cli": "5.0.1",
- "webpack-dev-server": "4.13.2",
+ "webpack-dev-server": "4.13.3",
"webpack-manifest-plugin": "5.0.0",
"webpackbar": "5.0.2",
"workbox-build": "6.5.4"
diff --git a/yarn.lock b/yarn.lock
index 113cc3bfe7..5c1df324e3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9645,7 +9645,7 @@ __metadata:
vue2-daterange-picker: 0.6.8
webpack: =5.72.1
webpack-cli: 5.0.1
- webpack-dev-server: 4.13.2
+ webpack-dev-server: 4.13.3
webpack-manifest-plugin: 5.0.0
webpackbar: 5.0.2
weekstart: 2.0.0
@@ -15903,9 +15903,9 @@ __metadata:
languageName: node
linkType: hard
-"webpack-dev-server@npm:4.13.2":
- version: 4.13.2
- resolution: "webpack-dev-server@npm:4.13.2"
+"webpack-dev-server@npm:4.13.3":
+ version: 4.13.3
+ resolution: "webpack-dev-server@npm:4.13.3"
dependencies:
"@types/bonjour": ^3.5.9
"@types/connect-history-api-fallback": ^1.3.5
@@ -15946,7 +15946,7 @@ __metadata:
optional: true
bin:
webpack-dev-server: bin/webpack-dev-server.js
- checksum: 9bf573abf05b0e0f1e8219820f6264e25a0f8ee6aebed3c0d0449c24a37f88b575972e0a2bec426112ee37d48c8f5090e7754aa1873206d3c9b6344a54718232
+ checksum: d019844d3bc384676921afadfbd0a95fd06e475f2d43604789a4a8f42f79a8fb37e745f15f47f352630046dd6c6c9694051a7552b34a056c59d3a601e74d6320
languageName: node
linkType: hard
From afa071465c21c43849cca2c42bad7b6a7161b723 Mon Sep 17 00:00:00 2001
From: karwosts <32912880+karwosts@users.noreply.github.com>
Date: Tue, 18 Apr 2023 23:58:18 -0700
Subject: [PATCH 041/112] ha-selector-select fires spurious valueChanged on
initialization (#16216)
---
src/components/ha-selector/ha-selector-select.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/ha-selector/ha-selector-select.ts b/src/components/ha-selector/ha-selector-select.ts
index be076d6a12..f4b07b55aa 100644
--- a/src/components/ha-selector/ha-selector-select.ts
+++ b/src/components/ha-selector/ha-selector-select.ts
@@ -213,7 +213,7 @@ export class HaSelectSelector extends LitElement {
private _valueChanged(ev) {
ev.stopPropagation();
const value = ev.detail?.value || ev.target.value;
- if (this.disabled || value === undefined) {
+ if (this.disabled || value === undefined || value === this.value) {
return;
}
fireEvent(this, "value-changed", {
From d8cb5a6a4213db3cad84b013d0e54973b00d1aa4 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Wed, 19 Apr 2023 12:12:47 +0200
Subject: [PATCH 042/112] Prevent delete pipeline if preferred (#16237)
---
.../config/voice-assistants/assist-pref.ts | 10 +++-------
.../dialog-voice-assistant-pipeline-detail.ts | 17 +++++++++++++----
2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/src/panels/config/voice-assistants/assist-pref.ts b/src/panels/config/voice-assistants/assist-pref.ts
index daeb92d895..79aa1c5a45 100644
--- a/src/panels/config/voice-assistants/assist-pref.ts
+++ b/src/panels/config/voice-assistants/assist-pref.ts
@@ -160,13 +160,9 @@ export class AssistPref extends LitElement {
return false;
}
- try {
- await deleteAssistPipeline(this.hass!, pipeline!.id);
- this._pipelines = this._pipelines!.filter((res) => res !== pipeline);
- return true;
- } catch (err: any) {
- return false;
- }
+ await deleteAssistPipeline(this.hass!, pipeline!.id);
+ this._pipelines = this._pipelines!.filter((res) => res !== pipeline);
+ return true;
},
});
}
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index 79897ec5c4..66e5cefa56 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -81,8 +81,8 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
${this.hass.localize("ui.common.delete")}
@@ -104,7 +104,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
${this._params.pipeline?.id
@@ -198,8 +198,15 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
}
private async _setPreferred() {
- await this._params!.setPipelinePreferred();
- this._preferred = true;
+ this._submitting = true;
+ try {
+ await this._params!.setPipelinePreferred();
+ this._preferred = true;
+ } catch (err: any) {
+ this._error = { base: err?.message || "Unknown error" };
+ } finally {
+ this._submitting = false;
+ }
}
private async _deletePipeline() {
@@ -208,6 +215,8 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
if (await this._params!.deletePipeline()) {
this.closeDialog();
}
+ } catch (err: any) {
+ this._error = { base: err?.message || "Unknown error" };
} finally {
this._submitting = false;
}
From c470ced3083d0d9802a17fb746260631f698d64e Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Wed, 19 Apr 2023 12:13:19 +0200
Subject: [PATCH 043/112] Use right naming convention for ui_action and
ui_color selector (#16235)
---
.../ha-selector/ha-selector-ui-action.ts | 4 ++--
.../ha-selector/ha-selector-ui-color.ts | 2 +-
src/components/ha-selector/ha-selector.ts | 16 +++++++++++++---
src/data/selector.ts | 4 ++--
.../config-elements/hui-button-card-editor.ts | 4 ++--
.../config-elements/hui-light-card-editor.ts | 4 ++--
.../hui-picture-entity-card-editor.ts | 4 ++--
.../hui-picture-glance-card-editor.ts | 4 ++--
.../config-elements/hui-tile-card-editor.ts | 6 +++---
9 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/src/components/ha-selector/ha-selector-ui-action.ts b/src/components/ha-selector/ha-selector-ui-action.ts
index b2adde969d..a221021225 100644
--- a/src/components/ha-selector/ha-selector-ui-action.ts
+++ b/src/components/ha-selector/ha-selector-ui-action.ts
@@ -6,7 +6,7 @@ import { HomeAssistant } from "../../types";
import "../../panels/lovelace/components/hui-action-editor";
import { ActionConfig } from "../../data/lovelace";
-@customElement("ha-selector-ui-action")
+@customElement("ha-selector-ui_action")
export class HaSelectorUiAction extends LitElement {
@property() public hass!: HomeAssistant;
@@ -24,7 +24,7 @@ export class HaSelectorUiAction extends LitElement {
.label=${this.label}
.hass=${this.hass}
.config=${this.value}
- .actions=${this.selector["ui-action"]?.actions}
+ .actions=${this.selector.ui_action?.actions}
.tooltipText=${this.helper}
@value-changed=${this._valueChanged}
>
diff --git a/src/components/ha-selector/ha-selector-ui-color.ts b/src/components/ha-selector/ha-selector-ui-color.ts
index 98dbf3c1fb..149ad61550 100644
--- a/src/components/ha-selector/ha-selector-ui-color.ts
+++ b/src/components/ha-selector/ha-selector-ui-color.ts
@@ -6,7 +6,7 @@ import { UiColorSelector } from "../../data/selector";
import "../../panels/lovelace/components/hui-color-picker";
import { HomeAssistant } from "../../types";
-@customElement("ha-selector-ui-color")
+@customElement("ha-selector-ui_color")
export class HaSelectorUiColor extends LitElement {
@property() public hass!: HomeAssistant;
diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts
index 12cd14d2b9..46ee4b30ef 100644
--- a/src/components/ha-selector/ha-selector.ts
+++ b/src/components/ha-selector/ha-selector.ts
@@ -42,10 +42,12 @@ const LOAD_ELEMENTS = {
tts: () => import("./ha-selector-tts"),
location: () => import("./ha-selector-location"),
color_temp: () => import("./ha-selector-color-temp"),
- "ui-action": () => import("./ha-selector-ui-action"),
- "ui-color": () => import("./ha-selector-ui-color"),
+ ui_action: () => import("./ha-selector-ui-action"),
+ ui_color: () => import("./ha-selector-ui-color"),
};
+const LEGACY_UI_SELECTORS = new Set(["ui-action", "ui-color"]);
+
@customElement("ha-selector")
export class HaSelector extends LitElement {
@property() public hass!: HomeAssistant;
@@ -75,7 +77,11 @@ export class HaSelector extends LitElement {
}
private get _type() {
- return Object.keys(this.selector)[0];
+ const type = Object.keys(this.selector)[0];
+ if (LEGACY_UI_SELECTORS.has(type)) {
+ return type.replace("-", "_");
+ }
+ return type;
}
protected willUpdate(changedProps: PropertyValues) {
@@ -91,6 +97,10 @@ export class HaSelector extends LitElement {
if ("device" in selector) {
return handleLegacyDeviceSelector(selector);
}
+ const type = Object.keys(this.selector)[0];
+ if (LEGACY_UI_SELECTORS.has(type)) {
+ return { [type.replace("-", "_")]: selector[type] };
+ }
return selector;
});
diff --git a/src/data/selector.ts b/src/data/selector.ts
index e3aec23946..21ba8c0e5a 100644
--- a/src/data/selector.ts
+++ b/src/data/selector.ts
@@ -332,14 +332,14 @@ export interface TTSSelector {
}
export interface UiActionSelector {
- "ui-action": {
+ ui_action: {
actions?: UiAction[];
} | null;
}
export interface UiColorSelector {
// eslint-disable-next-line @typescript-eslint/ban-types
- "ui-color": {} | null;
+ ui_color: {} | null;
}
export const filterSelectorDevices = (
diff --git a/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts
index 7466a4cdcd..5f06792c46 100644
--- a/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts
@@ -65,11 +65,11 @@ const SCHEMA = [
},
{
name: "tap_action",
- selector: { "ui-action": {} },
+ selector: { ui_action: {} },
},
{
name: "hold_action",
- selector: { "ui-action": {} },
+ selector: { ui_action: {} },
},
] as const;
diff --git a/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts
index 7f9e657765..b32aa485d0 100644
--- a/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts
@@ -48,11 +48,11 @@ const SCHEMA = [
{ name: "theme", selector: { theme: {} } },
{
name: "hold_action",
- selector: { "ui-action": {} },
+ selector: { ui_action: {} },
},
{
name: "double_tap_action",
- selector: { "ui-action": {} },
+ selector: { ui_action: {} },
},
] as const;
diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts
index 6ead63f55c..8150d99968 100644
--- a/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts
@@ -61,11 +61,11 @@ const SCHEMA = [
{ name: "theme", selector: { theme: {} } },
{
name: "tap_action",
- selector: { "ui-action": {} },
+ selector: { ui_action: {} },
},
{
name: "hold_action",
- selector: { "ui-action": {} },
+ selector: { ui_action: {} },
},
] as const;
diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-glance-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-glance-card-editor.ts
index a1c988fb26..76c0634698 100644
--- a/src/panels/lovelace/editor/config-elements/hui-picture-glance-card-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-picture-glance-card-editor.ts
@@ -51,11 +51,11 @@ const SCHEMA = [
{ name: "theme", selector: { theme: {} } },
{
name: "tap_action",
- selector: { "ui-action": {} },
+ selector: { ui_action: {} },
},
{
name: "hold_action",
- selector: { "ui-action": {} },
+ selector: { ui_action: {} },
},
] as const;
diff --git a/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts
index 0241615be7..b3ccc5a692 100644
--- a/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts
@@ -87,7 +87,7 @@ export class HuiTileCardEditor
{
name: "color",
selector: {
- "ui-color": {},
+ ui_color: {},
},
},
{
@@ -115,13 +115,13 @@ export class HuiTileCardEditor
{
name: "tap_action",
selector: {
- "ui-action": {},
+ ui_action: {},
},
},
{
name: "icon_tap_action",
selector: {
- "ui-action": {},
+ ui_action: {},
},
},
] as const,
From 0ce3757b80b74363ccc4d30b831f804639706df1 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Wed, 19 Apr 2023 14:05:25 +0200
Subject: [PATCH 044/112] Remove default options from tts/stt/conversation
agent (#16236)
---
.../ha-conversation-agent-picker.ts | 25 ++++-----
src/components/ha-stt-picker.ts | 51 ++++++++++++-----
src/components/ha-tts-picker.ts | 55 +++++++++++++------
.../dialog-voice-assistant-pipeline-detail.ts | 1 +
src/translations/en.json | 6 +-
5 files changed, 89 insertions(+), 49 deletions(-)
diff --git a/src/components/ha-conversation-agent-picker.ts b/src/components/ha-conversation-agent-picker.ts
index 5175e99f35..b87f75f151 100644
--- a/src/components/ha-conversation-agent-picker.ts
+++ b/src/components/ha-conversation-agent-picker.ts
@@ -15,7 +15,7 @@ import "./ha-list-item";
import "./ha-select";
import type { HaSelect } from "./ha-select";
-const DEFAULT = "default_agent_option";
+const NONE = "__NONE_OPTION__";
@customElement("ha-conversation-agent-picker")
export class HaConversationAgentPicker extends LitElement {
@property() public value?: string;
@@ -36,7 +36,7 @@ export class HaConversationAgentPicker extends LitElement {
if (!this._agents) {
return nothing;
}
- const value = this.value ?? DEFAULT;
+ const value = this.value ?? (this.required ? this._defaultAgent : NONE);
return html`
-
- ${this.hass!.localize(
- "ui.components.coversation-agent-picker.default",
- {
- default: this._agents.find(
- (agent) => agent.id === this._defaultAgent
- )?.name,
- }
- )}
-
+ ${!this.required
+ ? html`
+ ${this.hass!.localize(
+ "ui.components.coversation-agent-picker.none"
+ )}
+ `
+ : nothing}
${this._agents.map(
(agent) =>
html`${agent.name} `
@@ -93,11 +90,11 @@ export class HaConversationAgentPicker extends LitElement {
!this.hass ||
target.value === "" ||
target.value === this.value ||
- (this.value === undefined && target.value === DEFAULT)
+ (this.value === undefined && target.value === NONE)
) {
return;
}
- this.value = target.value === DEFAULT ? undefined : target.value;
+ this.value = target.value === NONE ? undefined : target.value;
fireEvent(this, "value-changed", { value: this.value });
}
}
diff --git a/src/components/ha-stt-picker.ts b/src/components/ha-stt-picker.ts
index bbaab72be4..b7e998fb92 100644
--- a/src/components/ha-stt-picker.ts
+++ b/src/components/ha-stt-picker.ts
@@ -3,20 +3,22 @@ import {
CSSResultGroup,
html,
LitElement,
- PropertyValueMap,
+ nothing,
+ PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { stopPropagation } from "../common/dom/stop_propagation";
import { computeStateName } from "../common/entity/compute_state_name";
+import { debounce } from "../common/util/debounce";
import { listSTTEngines, STTEngine } from "../data/stt";
import { HomeAssistant } from "../types";
import "./ha-list-item";
import "./ha-select";
import type { HaSelect } from "./ha-select";
-const DEFAULT = "default_engine_option";
+const NONE = "__NONE_OPTION__";
@customElement("ha-stt-picker")
export class HaSTTPicker extends LitElement {
@@ -35,7 +37,11 @@ export class HaSTTPicker extends LitElement {
@state() _engines: STTEngine[] = [];
protected render(): TemplateResult {
- const value = this.value ?? DEFAULT;
+ const value =
+ this.value ??
+ (this.required
+ ? this._engines.find((engine) => engine.language_supported)
+ : NONE);
return html`
-
- ${this.hass!.localize("ui.components.stt-picker.default")}
-
+ ${!this.required
+ ? html`
+ ${this.hass!.localize("ui.components.stt-picker.none")}
+ `
+ : nothing}
${this._engines.map((engine) => {
const stateObj = this.hass!.states[engine.engine_id];
return html` | Map
- ): void {
+ protected willUpdate(changedProperties: PropertyValues): void {
super.willUpdate(changedProperties);
- if (!this.hasUpdated || changedProperties.has("language")) {
- listSTTEngines(this.hass, this.language).then((engines) => {
- this._engines = engines.providers;
- });
+ if (!this.hasUpdated) {
+ this._updateEngines();
+ } else if (changedProperties.has("language")) {
+ this._debouncedUpdateEngines();
+ }
+ }
+
+ private _debouncedUpdateEngines = debounce(() => this._updateEngines(), 500);
+
+ private async _updateEngines() {
+ this._engines = (await listSTTEngines(this.hass, this.language)).providers;
+
+ if (
+ this.value &&
+ !this._engines.find((engine) => engine.engine_id === this.value)
+ ?.language_supported
+ ) {
+ this.value = undefined;
+ fireEvent(this, "value-changed", { value: this.value });
}
}
@@ -89,11 +110,11 @@ export class HaSTTPicker extends LitElement {
!this.hass ||
target.value === "" ||
target.value === this.value ||
- (this.value === undefined && target.value === DEFAULT)
+ (this.value === undefined && target.value === NONE)
) {
return;
}
- this.value = target.value === DEFAULT ? undefined : target.value;
+ this.value = target.value === NONE ? undefined : target.value;
fireEvent(this, "value-changed", { value: this.value });
}
}
diff --git a/src/components/ha-tts-picker.ts b/src/components/ha-tts-picker.ts
index c0d5916a4d..fe671b3bea 100644
--- a/src/components/ha-tts-picker.ts
+++ b/src/components/ha-tts-picker.ts
@@ -1,22 +1,24 @@
+import { debounce } from "chart.js/helpers";
import {
css,
CSSResultGroup,
html,
LitElement,
- PropertyValueMap,
+ nothing,
+ PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { stopPropagation } from "../common/dom/stop_propagation";
import { computeStateName } from "../common/entity/compute_state_name";
-import { TTSEngine, listTTSEngines } from "../data/tts";
+import { listTTSEngines, TTSEngine } from "../data/tts";
import { HomeAssistant } from "../types";
-import "./ha-select";
import "./ha-list-item";
+import "./ha-select";
import type { HaSelect } from "./ha-select";
-const DEFAULT = "default_engine_option";
+const NONE = "__NONE_OPTION__";
@customElement("ha-tts-picker")
export class HaTTSPicker extends LitElement {
@@ -35,7 +37,11 @@ export class HaTTSPicker extends LitElement {
@state() _engines: TTSEngine[] = [];
protected render(): TemplateResult {
- const value = this.value ?? DEFAULT;
+ const value =
+ this.value ??
+ (this.required
+ ? this._engines.find((engine) => engine.language_supported)
+ : NONE);
return html`
-
- ${this.hass!.localize("ui.components.tts-picker.default")}
-
+ ${!this.required
+ ? html`
+ ${this.hass!.localize("ui.components.tts-picker.none")}
+ `
+ : nothing}
${this._engines.map((engine) => {
const stateObj = this.hass!.states[engine.engine_id];
return html` | Map
- ): void {
+ protected willUpdate(changedProperties: PropertyValues): void {
super.willUpdate(changedProperties);
- if (!this.hasUpdated || changedProperties.has("language")) {
- listTTSEngines(this.hass, this.language).then((engines) => {
- this._engines = engines.providers;
- });
+ if (!this.hasUpdated) {
+ this._updateEngines();
+ } else if (changedProperties.has("language")) {
+ this._debouncedUpdateEngines();
+ }
+ }
+
+ private _debouncedUpdateEngines = debounce(() => this._updateEngines(), 500);
+
+ private async _updateEngines() {
+ this._engines = (await listTTSEngines(this.hass, this.language)).providers;
+
+ if (
+ this.value &&
+ !this._engines.find((engine) => engine.engine_id === this.value)
+ ?.language_supported
+ ) {
+ this.value = undefined;
+ fireEvent(this, "value-changed", { value: this.value });
}
}
@@ -89,11 +110,11 @@ export class HaTTSPicker extends LitElement {
!this.hass ||
target.value === "" ||
target.value === this.value ||
- (this.value === undefined && target.value === DEFAULT)
+ (this.value === undefined && target.value === NONE)
) {
return;
}
- this.value = target.value === DEFAULT ? undefined : target.value;
+ this.value = target.value === NONE ? undefined : target.value;
fireEvent(this, "value-changed", { value: this.value });
}
}
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index 66e5cefa56..3bd1bd00c4 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -131,6 +131,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
},
{
name: "conversation_engine",
+ required: true,
selector: {
conversation_agent: {},
},
diff --git a/src/translations/en.json b/src/translations/en.json
index ffc8b1fd16..6034c59a02 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -403,7 +403,7 @@
},
"coversation-agent-picker": {
"conversation_agent": "Conversation agent",
- "default": "Default agent ({default})"
+ "none": "None"
},
"theme-picker": {
"theme": "Theme",
@@ -411,7 +411,7 @@
},
"tts-picker": {
"tts": "Text to Speech",
- "default": "Default"
+ "none": "None"
},
"user-picker": {
"no_user": "No user",
@@ -466,7 +466,7 @@
}
}
},
- "stt-picker": { "stt": "Speech to text", "default": "Default" },
+ "stt-picker": { "stt": "Speech to text", "none": "None" },
"related-filter-menu": {
"filter": "Filter",
"filter_by_entity": "Filter by entity",
From 910244f75179edaa35c10783acd7c1759c80c258 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Wed, 19 Apr 2023 14:23:04 +0200
Subject: [PATCH 045/112] Fix sidebar tooltip (#16238)
---
src/components/ha-sidebar.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts
index 7036ab6d71..f443ca9eee 100644
--- a/src/components/ha-sidebar.ts
+++ b/src/components/ha-sidebar.ts
@@ -810,6 +810,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
}
tooltip.innerHTML = item.querySelector(".item-text")!.innerHTML;
tooltip.style.display = "block";
+ tooltip.style.position = "fixed";
tooltip.style.top = `${top}px`;
tooltip.style.left = `${item.offsetLeft + item.clientWidth + 4}px`;
}
@@ -840,6 +841,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
haStyleScrollbar,
css`
:host {
+ overflow: visible;
height: 100%;
display: block;
overflow: hidden;
From f507a7b8b375569675c49da1441d14f202430e98 Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Wed, 19 Apr 2023 15:27:01 +0200
Subject: [PATCH 046/112] Use yaml to show raw pipeline debug data (#16234)
---
src/components/ha-yaml-editor.ts | 17 +++++++++++++++--
.../debug/assist-render-pipeline-run.ts | 18 +++++++++++++-----
2 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/src/components/ha-yaml-editor.ts b/src/components/ha-yaml-editor.ts
index f3cac3b1ea..97d06ec2ae 100644
--- a/src/components/ha-yaml-editor.ts
+++ b/src/components/ha-yaml-editor.ts
@@ -1,5 +1,5 @@
import { DEFAULT_SCHEMA, dump, load, Schema } from "js-yaml";
-import { html, LitElement, nothing } from "lit";
+import { html, LitElement, nothing, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import type { HomeAssistant } from "../types";
@@ -31,6 +31,8 @@ export class HaYamlEditor extends LitElement {
@property() public label?: string;
+ @property({ type: Boolean }) public autoUpdate = false;
+
@property({ type: Boolean }) public readOnly = false;
@property({ type: Boolean }) public required = false;
@@ -41,7 +43,11 @@ export class HaYamlEditor extends LitElement {
try {
this._yaml =
value && !isEmpty(value)
- ? dump(value, { schema: this.yamlSchema, quotingType: '"' })
+ ? dump(value, {
+ schema: this.yamlSchema,
+ quotingType: '"',
+ noRefs: true,
+ })
: "";
} catch (err: any) {
// eslint-disable-next-line no-console
@@ -56,6 +62,13 @@ export class HaYamlEditor extends LitElement {
}
}
+ protected willUpdate(changedProperties: PropertyValues): void {
+ super.willUpdate(changedProperties);
+ if (this.autoUpdate && changedProperties.has("value")) {
+ this.setValue(this.value);
+ }
+ }
+
protected render() {
if (this._yaml === undefined) {
return nothing;
diff --git a/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts b/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts
index 959bdc78d0..c6d16957f8 100644
--- a/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts
+++ b/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts
@@ -8,6 +8,7 @@ import "../../../../components/ha-expansion-panel";
import type { PipelineRun } from "../../../../data/assist_pipeline";
import type { HomeAssistant } from "../../../../types";
import { formatNumber } from "../../../../common/number/format_number";
+import "../../../../components/ha-yaml-editor";
const RUN_DATA = {
pipeline: "Pipeline",
@@ -118,7 +119,13 @@ const dataMinusKeysRender = (
render = true;
result[key] = data[key];
}
- return render ? html`${JSON.stringify(result, null, 2)} ` : "";
+ return render
+ ? html` `
+ : "";
};
@customElement("assist-render-pipeline-run")
@@ -262,7 +269,11 @@ export class AssistPipelineDebug extends LitElement {
Raw
- ${JSON.stringify(this.pipelineRun, null, 2)}
+
`;
@@ -287,9 +298,6 @@ export class AssistPipelineDebug extends LitElement {
display: flex;
justify-content: space-between;
}
- pre {
- margin: 0;
- }
ha-expansion-panel {
padding-left: 8px;
}
From 3cb3f8d3523e91d40cbddf3336795d63c2273e02 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Wed, 19 Apr 2023 15:52:55 +0200
Subject: [PATCH 047/112] Add aliases description in voice dialog (#16233)
* Add aliases description in voice dialog
* Update style
* Remove duplicate margin
---
.../voice-assistants/entity-voice-settings.ts | 149 +++++++++++-------
src/translations/en.json | 3 +-
2 files changed, 94 insertions(+), 58 deletions(-)
diff --git a/src/panels/config/voice-assistants/entity-voice-settings.ts b/src/panels/config/voice-assistants/entity-voice-settings.ts
index fbe5de072e..8d614fc1eb 100644
--- a/src/panels/config/voice-assistants/entity-voice-settings.ts
+++ b/src/panels/config/voice-assistants/entity-voice-settings.ts
@@ -1,4 +1,11 @@
-import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
+import {
+ css,
+ CSSResultGroup,
+ html,
+ LitElement,
+ nothing,
+ PropertyValues,
+} from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
@@ -148,12 +155,11 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
const anyExposed = uiExposed || manExposedAlexa || manExposedGoogle;
- return html`
- ${this.hass.localize(
- "ui.dialogs.voice-settings.expose_header"
- )}
+ return html`
+
+
+ ${this.hass.localize("ui.dialogs.voice-settings.expose_header")}
+
${anyExposed
? showAssistants.map(
- (key) => html`
-
- ${voiceAssistants[key].name}
- ${key === "cloud.google_assistant" &&
- !googleManual &&
- this._googleEntity?.might_2fa
- ? html`
-
- `
- : (alexaManual && key === "cloud.alexa") ||
- (googleManual && key === "cloud.google_assistant")
- ? html`${this.hass.localize(
- "ui.dialogs.voice-settings.manual_config"
- )} `
- : ""}
-
- `
+ (key) => html`
+
+
+ ${voiceAssistants[key].name}
+ ${key === "cloud.google_assistant" &&
+ !googleManual &&
+ this._googleEntity?.might_2fa
+ ? html`
+
+
+
+ `
+ : (alexaManual && key === "cloud.alexa") ||
+ (googleManual && key === "cloud.google_assistant")
+ ? html`
+
+ ${this.hass.localize(
+ "ui.dialogs.voice-settings.manual_config"
+ )}
+
+ `
+ : nothing}
+
+
+ `
)
- : ""}
+ : nothing}
-
- ${this.hass.localize("ui.dialogs.voice-settings.aliasses_header")}
+
+
+ ${this.hass.localize("ui.dialogs.voice-settings.aliases_description")}
+
+
`;
+ >
+ `;
}
private _aliasesChanged(ev) {
@@ -297,6 +314,7 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
}
img {
height: 32px;
+ width: 32px;
margin-right: 16px;
}
ha-aliases-editor {
@@ -312,6 +330,17 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
ha-checkbox {
--mdc-checkbox-state-layer-size: 40px;
}
+ .header {
+ margin-top: 8px;
+ margin-bottom: 4px;
+ }
+ .description {
+ color: var(--secondary-text-color);
+ font-size: 14px;
+ line-height: 20px;
+ margin-top: 0;
+ margin-bottom: 16px;
+ }
`,
];
}
@@ -325,3 +354,9 @@ declare global {
"entity-entry-updated": ExtEntityRegistryEntry;
}
}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "entity-voice-settings": EntityVoiceSettings;
+ }
+}
diff --git a/src/translations/en.json b/src/translations/en.json
index 6034c59a02..ef8afe17e2 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -1071,7 +1071,8 @@
},
"voice-settings": {
"expose_header": "Expose",
- "aliasses_header": "Aliasses",
+ "aliases_header": "Aliases",
+ "aliases_description": "Aliases are supported by Assist and Google Assistant.",
"ask_pin": "Ask for PIN",
"manual_config": "Managed with filters in configuration.yaml"
},
From d89ac0f30ddb349f553d788c22077c958b31f645 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Wed, 19 Apr 2023 21:21:27 +0200
Subject: [PATCH 048/112] Add language selector (#16242)
---
src/components/ha-language-picker.ts | 132 ++++++++++++++++++
.../ha-selector/ha-selector-language.ts | 48 +++++++
src/components/ha-selector/ha-selector.ts | 1 +
src/data/assist_pipeline.ts | 5 +
src/data/selector.ts | 5 +
.../config/core/ha-config-section-general.ts | 49 ++-----
.../dialog-voice-assistant-pipeline-detail.ts | 32 +++--
src/panels/profile/ha-pick-language-row.ts | 46 ++----
8 files changed, 237 insertions(+), 81 deletions(-)
create mode 100644 src/components/ha-language-picker.ts
create mode 100644 src/components/ha-selector/ha-selector-language.ts
diff --git a/src/components/ha-language-picker.ts b/src/components/ha-language-picker.ts
new file mode 100644
index 0000000000..55a18777dd
--- /dev/null
+++ b/src/components/ha-language-picker.ts
@@ -0,0 +1,132 @@
+import {
+ css,
+ CSSResultGroup,
+ html,
+ LitElement,
+ PropertyValues,
+ TemplateResult,
+} from "lit";
+import { customElement, property, state } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { fireEvent } from "../common/dom/fire_event";
+import { stopPropagation } from "../common/dom/stop_propagation";
+import { caseInsensitiveStringCompare } from "../common/string/compare";
+import { HomeAssistant } from "../types";
+import "./ha-list-item";
+import "./ha-select";
+import type { HaSelect } from "./ha-select";
+
+@customElement("ha-language-picker")
+export class HaLanguagePicker extends LitElement {
+ @property() public value?: string;
+
+ @property() public label?: string;
+
+ @property() public supportedLanguages?: string[];
+
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ type: Boolean, reflect: true }) public disabled = false;
+
+ @property({ type: Boolean }) public required = false;
+
+ @property({ type: Boolean }) public nativeName = false;
+
+ @state() _defaultLanguages: string[] = [];
+
+ protected firstUpdated(changedProps: PropertyValues) {
+ super.firstUpdated(changedProps);
+ this._computeDefaultLanguageOptions();
+ }
+
+ private _getLanguagesOptions = memoizeOne(
+ (languages: string[], language: string, nativeName: boolean) => {
+ let options: { label: string; value: string }[] = [];
+
+ if (nativeName) {
+ const translations = this.hass.translationMetadata.translations;
+ options = languages.map((lang) => ({
+ value: lang,
+ label: translations[lang]?.nativeName ?? lang,
+ }));
+ } else {
+ const languageDisplayNames =
+ Intl && "DisplayNames" in Intl
+ ? new Intl.DisplayNames(language, {
+ type: "language",
+ fallback: "code",
+ })
+ : undefined;
+
+ options = languages.map((lang) => ({
+ value: lang,
+ label: languageDisplayNames ? languageDisplayNames.of(lang)! : lang,
+ }));
+ }
+
+ options.sort((a, b) =>
+ caseInsensitiveStringCompare(a.label, b.label, language)
+ );
+ return options;
+ }
+ );
+
+ private _computeDefaultLanguageOptions() {
+ if (!this.hass.translationMetadata?.translations) {
+ return;
+ }
+
+ this._defaultLanguages = Object.keys(
+ this.hass.translationMetadata.translations
+ );
+ }
+
+ protected render(): TemplateResult {
+ const value = this.value;
+
+ const languageOptions = this._getLanguagesOptions(
+ this.supportedLanguages ?? this._defaultLanguages,
+ this.hass.locale.language,
+ this.nativeName
+ );
+
+ return html`
+
+ ${languageOptions.map(
+ (option) => html`
+ ${option.label}
+ `
+ )}
+
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-select {
+ width: 100%;
+ }
+ `;
+ }
+
+ private _changed(ev): void {
+ const target = ev.target as HaSelect;
+ this.value = target.value;
+ fireEvent(this, "value-changed", { value: this.value });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-language-picker": HaLanguagePicker;
+ }
+}
diff --git a/src/components/ha-selector/ha-selector-language.ts b/src/components/ha-selector/ha-selector-language.ts
new file mode 100644
index 0000000000..7a6e4fc355
--- /dev/null
+++ b/src/components/ha-selector/ha-selector-language.ts
@@ -0,0 +1,48 @@
+import { css, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { LanguageSelector } from "../../data/selector";
+import { HomeAssistant } from "../../types";
+import "../ha-language-picker";
+
+@customElement("ha-selector-language")
+export class HaLanguageSelector extends LitElement {
+ @property() public hass!: HomeAssistant;
+
+ @property() public selector!: LanguageSelector;
+
+ @property() public value?: any;
+
+ @property() public label?: string;
+
+ @property() public helper?: string;
+
+ @property({ type: Boolean }) public disabled = false;
+
+ @property({ type: Boolean }) public required = true;
+
+ protected render() {
+ return html`
+
+ `;
+ }
+
+ static styles = css`
+ ha-language-picker {
+ width: 100%;
+ }
+ `;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-selector-language": HaLanguageSelector;
+ }
+}
diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts
index 46ee4b30ef..85193753c9 100644
--- a/src/components/ha-selector/ha-selector.ts
+++ b/src/components/ha-selector/ha-selector.ts
@@ -26,6 +26,7 @@ const LOAD_ELEMENTS = {
entity: () => import("./ha-selector-entity"),
statistic: () => import("./ha-selector-statistic"),
file: () => import("./ha-selector-file"),
+ language: () => import("./ha-selector-language"),
navigation: () => import("./ha-selector-navigation"),
number: () => import("./ha-selector-number"),
object: () => import("./ha-selector-object"),
diff --git a/src/data/assist_pipeline.ts b/src/data/assist_pipeline.ts
index dd8eca29fb..abf370681f 100644
--- a/src/data/assist_pipeline.ts
+++ b/src/data/assist_pipeline.ts
@@ -296,3 +296,8 @@ export const deleteAssistPipeline = (hass: HomeAssistant, pipelineId: string) =>
type: "assist_pipeline/pipeline/delete",
pipeline_id: pipelineId,
});
+
+export const fetchAssistPipelineLanguages = (hass: HomeAssistant) =>
+ hass.callWS<{ languages: string[] }>({
+ type: "assist_pipeline/language/list",
+ });
diff --git a/src/data/selector.ts b/src/data/selector.ts
index 21ba8c0e5a..c8b1781cf1 100644
--- a/src/data/selector.ts
+++ b/src/data/selector.ts
@@ -26,6 +26,7 @@ export type Selector =
| LegacyEntitySelector
| FileSelector
| IconSelector
+ | LanguageSelector
| LocationSelector
| MediaSelector
| NavigationSelector
@@ -209,6 +210,10 @@ export interface IconSelector {
} | null;
}
+export interface LanguageSelector {
+ language: { supported_languages?: string[] } | null;
+}
+
export interface LocationSelector {
location: { radius?: boolean; icon?: string } | null;
}
diff --git a/src/panels/config/core/ha-config-section-general.ts b/src/panels/config/core/ha-config-section-general.ts
index 31abfd8346..0d6e95dbc7 100644
--- a/src/panels/config/core/ha-config-section-general.ts
+++ b/src/panels/config/core/ha-config-section-general.ts
@@ -6,13 +6,16 @@ import memoizeOne from "memoize-one";
import { UNIT_C } from "../../../common/const";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import { navigate } from "../../../common/navigate";
-import { caseInsensitiveStringCompare } from "../../../common/string/compare";
import "../../../components/buttons/ha-progress-button";
import type { HaProgressButton } from "../../../components/buttons/ha-progress-button";
import { getCountryOptions } from "../../../components/country-datalist";
import { getCurrencyOptions } from "../../../components/currency-datalist";
+import "../../../components/ha-alert";
import "../../../components/ha-card";
+import "../../../components/ha-checkbox";
+import type { HaCheckbox } from "../../../components/ha-checkbox";
import "../../../components/ha-formfield";
+import "../../../components/ha-language-picker";
import "../../../components/ha-radio";
import type { HaRadio } from "../../../components/ha-radio";
import "../../../components/ha-select";
@@ -22,13 +25,10 @@ import "../../../components/map/ha-locations-editor";
import type { MarkerLocation } from "../../../components/map/ha-locations-editor";
import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core";
import { SYMBOL_TO_ISO } from "../../../data/currency";
+import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-subpage";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
-import "../../../components/ha-alert";
-import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
-import type { HaCheckbox } from "../../../components/ha-checkbox";
-import "../../../components/ha-checkbox";
@customElement("ha-config-section-general")
class HaConfigSectionGeneral extends LitElement {
@@ -54,8 +54,6 @@ class HaConfigSectionGeneral extends LitElement {
@state() private _location?: [number, number];
- @state() private _languages?: { value: string; label: string }[];
-
@state() private _error?: string;
@state() private _updateUnits?: boolean;
@@ -255,25 +253,19 @@ class HaConfigSectionGeneral extends LitElement {
`
)}
-
- ${this._languages?.map(
- ({ value, label }) =>
- html`${label} `
- )}
+
${this.narrow
? html`
@@ -330,25 +322,10 @@ class HaConfigSectionGeneral extends LitElement {
this._timeZone = this.hass.config.time_zone || "Etc/GMT";
this._name = this.hass.config.location_name;
this._updateUnits = true;
- this._computeLanguages();
}
- private _computeLanguages() {
- if (!this.hass.translationMetadata?.translations) {
- return;
- }
- this._languages = Object.entries(this.hass.translationMetadata.translations)
- .sort((a, b) =>
- caseInsensitiveStringCompare(
- a[1].nativeName,
- b[1].nativeName,
- this.hass.locale.language
- )
- )
- .map(([value, metaData]) => ({
- value,
- label: metaData.nativeName,
- }));
+ private _handleLanguageChange(ev) {
+ this._language = ev.detail.value;
}
private _handleChange(ev) {
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index 3bd1bd00c4..0738dfd0c9 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -9,6 +9,7 @@ import { SchemaUnion } from "../../../components/ha-form/types";
import {
AssistPipeline,
AssistPipelineMutableParams,
+ fetchAssistPipelineLanguages,
} from "../../../data/assist_pipeline";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
@@ -29,6 +30,8 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
@state() private _submitting = false;
+ @state() private _supportedLanguages: string[] = [];
+
public showDialog(params: VoiceAssistantPipelineDetailsDialogParams): void {
this._params = params;
this._error = undefined;
@@ -46,6 +49,15 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
+ protected firstUpdated() {
+ this._getSupportedLanguages();
+ }
+
+ private async _getSupportedLanguages() {
+ const { languages } = await fetchAssistPipelineLanguages(this.hass);
+ this._supportedLanguages = languages;
+ }
+
protected render() {
if (!this._params || !this._data) {
return nothing;
@@ -68,7 +80,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
>
+ (languages: string[]) =>
[
{
name: "name",
@@ -129,6 +141,15 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
text: {},
},
},
+ {
+ name: "language",
+ required: true,
+ selector: {
+ language: {
+ supported_languages: languages,
+ },
+ },
+ },
{
name: "conversation_engine",
required: true,
@@ -136,13 +157,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
conversation_agent: {},
},
},
- {
- name: "language",
- required: true,
- selector: {
- text: {},
- },
- },
{
name: "stt_engine",
selector: {
diff --git a/src/panels/profile/ha-pick-language-row.ts b/src/panels/profile/ha-pick-language-row.ts
index 7bab38abdc..d33eb48941 100644
--- a/src/panels/profile/ha-pick-language-row.ts
+++ b/src/panels/profile/ha-pick-language-row.ts
@@ -1,10 +1,9 @@
-import "@material/mwc-list/mwc-list-item";
-import { css, html, LitElement, PropertyValues } from "lit";
-import { customElement, property, state } from "lit/decorators";
+import { css, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
-import "../../components/ha-select";
+import "../../components/ha-language-picker";
import "../../components/ha-settings-row";
-import { HomeAssistant, Translation } from "../../types";
+import { HomeAssistant } from "../../types";
@customElement("ha-pick-language-row")
export class HaPickLanguageRow extends LitElement {
@@ -12,13 +11,6 @@ export class HaPickLanguageRow extends LitElement {
@property() public narrow!: boolean;
- @state() private _languages: (Translation & { key: string })[] = [];
-
- protected firstUpdated(changedProps: PropertyValues) {
- super.firstUpdated(changedProps);
- this._computeLanguages();
- }
-
protected render() {
return html`
@@ -33,43 +25,25 @@ export class HaPickLanguageRow extends LitElement {
>${this.hass.localize("ui.panel.profile.language.link_promo")}
-
- ${this._languages.map(
- (language) => html`
- ${language.nativeName}
- `
- )}
-
+
`;
}
- private _computeLanguages() {
- if (!this.hass.translationMetadata?.translations) {
- return;
- }
- this._languages = Object.keys(
- this.hass.translationMetadata.translations
- ).map((key) => ({
- key,
- ...this.hass.translationMetadata.translations[key],
- }));
- }
-
private _languageSelectionChanged(ev) {
// Only fire event if language was changed. This prevents select updates when
// responding to hass changes.
- if (ev.target.value !== this.hass.language) {
+ if (ev.detail.value !== this.hass.language) {
fireEvent(this, "hass-language-select", ev.target.value);
}
}
From d48a4ab00a812d918fd36078d48c896ae3dacbd9 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 19 Apr 2023 21:08:48 +0000
Subject: [PATCH 049/112] Lock file maintenance (#16231)
* Lock file maintenance
* bump @codemirror/view and eslint-plugin-lit to remove duplicates
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher
---
package.json | 4 +-
yarn.lock | 363 +++++++++++++++++++++++++--------------------------
2 files changed, 182 insertions(+), 185 deletions(-)
diff --git a/package.json b/package.json
index 5c9e6adf6b..990608725d 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
"@codemirror/legacy-modes": "6.3.2",
"@codemirror/search": "6.3.0",
"@codemirror/state": "6.2.0",
- "@codemirror/view": "6.9.4",
+ "@codemirror/view": "6.9.5",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.5.1",
"@formatjs/intl-getcanonicallocales": "2.1.0",
@@ -200,7 +200,7 @@
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-disable": "2.0.3",
"eslint-plugin-import": "2.27.5",
- "eslint-plugin-lit": "1.8.2",
+ "eslint-plugin-lit": "1.8.3",
"eslint-plugin-lit-a11y": "2.4.1",
"eslint-plugin-unused-imports": "2.0.0",
"eslint-plugin-wc": "1.4.0",
diff --git a/yarn.lock b/yarn.lock
index 5c1df324e3..5060e5c140 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -16,12 +16,12 @@ __metadata:
linkType: hard
"@ampproject/remapping@npm:^2.2.0":
- version: 2.2.0
- resolution: "@ampproject/remapping@npm:2.2.0"
+ version: 2.2.1
+ resolution: "@ampproject/remapping@npm:2.2.1"
dependencies:
- "@jridgewell/gen-mapping": ^0.1.0
+ "@jridgewell/gen-mapping": ^0.3.0
"@jridgewell/trace-mapping": ^0.3.9
- checksum: d74d170d06468913921d72430259424b7e4c826b5a7d39ff839a29d547efb97dc577caa8ba3fb5cf023624e9af9d09651afc3d4112a45e2050328abc9b3a2292
+ checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079
languageName: node
linkType: hard
@@ -124,8 +124,8 @@ __metadata:
linkType: hard
"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0":
- version: 7.21.0
- resolution: "@babel/helper-create-class-features-plugin@npm:7.21.0"
+ version: 7.21.4
+ resolution: "@babel/helper-create-class-features-plugin@npm:7.21.4"
dependencies:
"@babel/helper-annotate-as-pure": ^7.18.6
"@babel/helper-environment-visitor": ^7.18.9
@@ -137,19 +137,19 @@ __metadata:
"@babel/helper-split-export-declaration": ^7.18.6
peerDependencies:
"@babel/core": ^7.0.0
- checksum: 3e781d91d1056ea9b3a0395f3017492594a8b86899119b4a1645227c31727b8bec9bc8f6b72e86b1c5cf2dd6690893d2e8c5baff4974c429e616ead089552a21
+ checksum: 9123ca80a4894aafdb1f0bc08e44f6be7b12ed1fbbe99c501b484f9b1a17ff296b6c90c18c222047d53c276f07f17b4de857946fa9d0aa207023b03e4cc716f2
languageName: node
linkType: hard
"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.20.5":
- version: 7.21.0
- resolution: "@babel/helper-create-regexp-features-plugin@npm:7.21.0"
+ version: 7.21.4
+ resolution: "@babel/helper-create-regexp-features-plugin@npm:7.21.4"
dependencies:
"@babel/helper-annotate-as-pure": ^7.18.6
regexpu-core: ^5.3.1
peerDependencies:
"@babel/core": ^7.0.0
- checksum: 63a6396a4e9444edc7e97617845583ea5cf059573d0b4cc566869f38576d543e37fde0edfcc21d6dfb7962ed241e909561714dc41c5213198bac04e0983b04f2
+ checksum: 78334865db2cd1d64d103bd0d96dee2818b0387d10aa973c084e245e829df32652bca530803e397b7158af4c02b9b21d5a9601c29bdfbb8d54a3d4ad894e067b
languageName: node
linkType: hard
@@ -214,11 +214,11 @@ __metadata:
linkType: hard
"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/helper-module-imports@npm:7.18.6"
+ version: 7.21.4
+ resolution: "@babel/helper-module-imports@npm:7.21.4"
dependencies:
- "@babel/types": ^7.18.6
- checksum: f393f8a3b3304b1b7a288a38c10989de754f01d29caf62ce7c4e5835daf0a27b81f3ac687d9d2780d39685aae7b55267324b512150e7b2be967b0c493b6a1def
+ "@babel/types": ^7.21.4
+ checksum: bd330a2edaafeb281fbcd9357652f8d2666502567c0aad71db926e8499c773c9ea9c10dfaae30122452940326d90c8caff5c649ed8e1bf15b23f858758d3abc6
languageName: node
linkType: hard
@@ -811,13 +811,13 @@ __metadata:
linkType: hard
"@babel/plugin-syntax-typescript@npm:^7.20.0":
- version: 7.20.0
- resolution: "@babel/plugin-syntax-typescript@npm:7.20.0"
+ version: 7.21.4
+ resolution: "@babel/plugin-syntax-typescript@npm:7.21.4"
dependencies:
- "@babel/helper-plugin-utils": ^7.19.0
+ "@babel/helper-plugin-utils": ^7.20.2
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 6189c0b5c32ba3c9a80a42338bd50719d783b20ef29b853d4f03929e971913d3cefd80184e924ae98ad6db09080be8fe6f1ffde9a6db8972523234f0274d36f7
+ checksum: a59ce2477b7ae8c8945dc37dda292fef9ce46a6507b3d76b03ce7f3a6c9451a6567438b20a78ebcb3955d04095fd1ccd767075a863f79fcc30aa34dcfa441fe0
languageName: node
linkType: hard
@@ -1462,14 +1462,14 @@ __metadata:
languageName: node
linkType: hard
-"@codemirror/view@npm:6.9.4, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.6.0":
- version: 6.9.4
- resolution: "@codemirror/view@npm:6.9.4"
+"@codemirror/view@npm:6.9.5, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.6.0":
+ version: 6.9.5
+ resolution: "@codemirror/view@npm:6.9.5"
dependencies:
"@codemirror/state": ^6.1.4
style-mod: ^4.0.0
w3c-keyname: ^2.2.4
- checksum: 9d2e9596caa3f568cea5aeff87c9ed10b7cf1e73d198240042bddeeffaea21f70b859927b1a05f5a613a8d58a92be762c6b899ced0725cf70194057d9591f83b
+ checksum: 38039ae5d1cf4ec54c5d0252790a942b5788b9e8670dcf58e63c1f2befe11e852581c88f4e044ca664a7b11c634b1c152099da1a4ac9f454939b20d7c649b808
languageName: node
linkType: hard
@@ -1490,20 +1490,20 @@ __metadata:
linkType: hard
"@eslint-community/eslint-utils@npm:^4.2.0":
- version: 4.3.0
- resolution: "@eslint-community/eslint-utils@npm:4.3.0"
+ version: 4.4.0
+ resolution: "@eslint-community/eslint-utils@npm:4.4.0"
dependencies:
eslint-visitor-keys: ^3.3.0
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
- checksum: f487760a692f0f1fef76e248ad72976919576ba57edc2b1b1dc1d182553bae6b5bf7b078e654da85d04f0af8a485d20bd26280002768f4fbcd2e330078340cb0
+ checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22
languageName: node
linkType: hard
"@eslint-community/regexpp@npm:^4.4.0":
- version: 4.4.0
- resolution: "@eslint-community/regexpp@npm:4.4.0"
- checksum: 2d127af0c752b80e8a782eacfe996a86925d21de92da3ffc6f9e615e701145e44a62e26bdd88bfac2cd76779c39ba8d9875a91046ec5e7e5f23cb647c247ea6a
+ version: 4.5.0
+ resolution: "@eslint-community/regexpp@npm:4.5.0"
+ checksum: 99c01335947dbd7f2129e954413067e217ccaa4e219fe0917b7d2bd96135789384b8fedbfb8eb09584d5130b27a7b876a7150ab7376f51b3a0c377d5ce026a10
languageName: node
linkType: hard
@@ -1875,24 +1875,14 @@ __metadata:
languageName: node
linkType: hard
-"@jridgewell/gen-mapping@npm:^0.1.0":
- version: 0.1.1
- resolution: "@jridgewell/gen-mapping@npm:0.1.1"
- dependencies:
- "@jridgewell/set-array": ^1.0.0
- "@jridgewell/sourcemap-codec": ^1.4.10
- checksum: 3bcc21fe786de6ffbf35c399a174faab05eb23ce6a03e8769569de28abbf4facc2db36a9ddb0150545ae23a8d35a7cf7237b2aa9e9356a7c626fb4698287d5cc
- languageName: node
- linkType: hard
-
"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2":
- version: 0.3.2
- resolution: "@jridgewell/gen-mapping@npm:0.3.2"
+ version: 0.3.3
+ resolution: "@jridgewell/gen-mapping@npm:0.3.3"
dependencies:
"@jridgewell/set-array": ^1.0.1
"@jridgewell/sourcemap-codec": ^1.4.10
"@jridgewell/trace-mapping": ^0.3.9
- checksum: 1832707a1c476afebe4d0fbbd4b9434fdb51a4c3e009ab1e9938648e21b7a97049fa6009393bdf05cab7504108413441df26d8a3c12193996e65493a4efb6882
+ checksum: 4a74944bd31f22354fc01c3da32e83c19e519e3bbadafa114f6da4522ea77dd0c2842607e923a591d60a76699d819a2fbb6f3552e277efdb9b58b081390b60ab
languageName: node
linkType: hard
@@ -1903,7 +1893,7 @@ __metadata:
languageName: node
linkType: hard
-"@jridgewell/set-array@npm:^1.0.0, @jridgewell/set-array@npm:^1.0.1":
+"@jridgewell/set-array@npm:^1.0.1":
version: 1.1.2
resolution: "@jridgewell/set-array@npm:1.1.2"
checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e
@@ -1911,29 +1901,36 @@ __metadata:
linkType: hard
"@jridgewell/source-map@npm:^0.3.2":
- version: 0.3.2
- resolution: "@jridgewell/source-map@npm:0.3.2"
+ version: 0.3.3
+ resolution: "@jridgewell/source-map@npm:0.3.3"
dependencies:
"@jridgewell/gen-mapping": ^0.3.0
"@jridgewell/trace-mapping": ^0.3.9
- checksum: 1b83f0eb944e77b70559a394d5d3b3f98a81fcc186946aceb3ef42d036762b52ef71493c6c0a3b7c1d2f08785f53ba2df1277fe629a06e6109588ff4cdcf7482
+ checksum: ae1302146339667da5cd6541260ecbef46ae06819a60f88da8f58b3e64682f787c09359933d050dea5d2173ea7fa40f40dd4d4e7a8d325c5892cccd99aaf8959
languageName: node
linkType: hard
-"@jridgewell/sourcemap-codec@npm:1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13":
+"@jridgewell/sourcemap-codec@npm:1.4.14":
version: 1.4.14
resolution: "@jridgewell/sourcemap-codec@npm:1.4.14"
checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97
languageName: node
linkType: hard
+"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13":
+ version: 1.4.15
+ resolution: "@jridgewell/sourcemap-codec@npm:1.4.15"
+ checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8
+ languageName: node
+ linkType: hard
+
"@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9":
- version: 0.3.17
- resolution: "@jridgewell/trace-mapping@npm:0.3.17"
+ version: 0.3.18
+ resolution: "@jridgewell/trace-mapping@npm:0.3.18"
dependencies:
"@jridgewell/resolve-uri": 3.1.0
"@jridgewell/sourcemap-codec": 1.4.14
- checksum: 9d703b859cff5cd83b7308fd457a431387db5db96bd781a63bf48e183418dd9d3d44e76b9e4ae13237f6abeeb25d739ec9215c1d5bfdd08f66f750a50074a339
+ checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02
languageName: node
linkType: hard
@@ -4015,12 +4012,12 @@ __metadata:
linkType: hard
"@types/chrome@npm:*":
- version: 0.0.224
- resolution: "@types/chrome@npm:0.0.224"
+ version: 0.0.232
+ resolution: "@types/chrome@npm:0.0.232"
dependencies:
"@types/filesystem": "*"
"@types/har-format": "*"
- checksum: 2dd2291a81a351d3639bb241647f89ece6d27d13206db73e8eac813bd7bfc7e101deaf16c34203f7db32554412f8a776da5b8bfdf8857619d96b0cc68effc196
+ checksum: ebd8ff2a4c9e1504088f73d82d22f0ebd283ae4043e079c1a5bc76ec23491a5d366fcf9c9edd7c81cfa1f10391929cdf7951333bba137110a87b9feff377b88e
languageName: node
linkType: hard
@@ -4096,12 +4093,12 @@ __metadata:
linkType: hard
"@types/eslint@npm:*":
- version: 8.21.3
- resolution: "@types/eslint@npm:8.21.3"
+ version: 8.37.0
+ resolution: "@types/eslint@npm:8.37.0"
dependencies:
"@types/estree": "*"
"@types/json-schema": "*"
- checksum: 80e0b5ca9ffb77bff19d01df08b93a99a6b44cad4c40e6450733ead6f1bc44b5514e7d28c3b0ad6304aeb01d690ee7ca89250729a9373551b7e587c6dbb41d7f
+ checksum: 06d3b3fba12004294591b5c7a52e3cec439472195da54e096076b1f2ddfbb8a445973b9681046dd530a6ac31eca502f635abc1e3ce37d03513089358e6f822ee
languageName: node
linkType: hard
@@ -4273,8 +4270,8 @@ __metadata:
linkType: hard
"@types/koa@npm:*, @types/koa@npm:^2.11.6":
- version: 2.13.5
- resolution: "@types/koa@npm:2.13.5"
+ version: 2.13.6
+ resolution: "@types/koa@npm:2.13.6"
dependencies:
"@types/accepts": "*"
"@types/content-disposition": "*"
@@ -4284,7 +4281,7 @@ __metadata:
"@types/keygrip": "*"
"@types/koa-compose": "*"
"@types/node": "*"
- checksum: e3b634d934b79ce8f394bf4130511596081f9c073dbfb4309aa32e4c421c47049a002b65111f8d9687eabec55d5a27b1b9ae0699afa83894cb7032c3536bfa17
+ checksum: a4061c2e29cd4ccb65a704fe3ef6868eac82558856c7c00a5bcc0f9fdf18c595e0156c52508eb8ba926a9108d9cf5c9a1a1b73cccf50e29b37ea1154323d0b26
languageName: node
linkType: hard
@@ -4316,9 +4313,9 @@ __metadata:
linkType: hard
"@types/lodash@npm:*":
- version: 4.14.191
- resolution: "@types/lodash@npm:4.14.191"
- checksum: ba0d5434e10690869f32d5ea49095250157cae502f10d57de0a723fd72229ce6c6a4979576f0f13e0aa9fbe3ce2457bfb9fa7d4ec3d6daba56730a51906d1491
+ version: 4.14.194
+ resolution: "@types/lodash@npm:4.14.194"
+ checksum: 113f34831c461469d91feca2dde737f88487732898b4d25e9eb23b087bb193985f864d1e1e0f3b777edc5022e460443588b6000a3b2348c966f72d17eedc35ea
languageName: node
linkType: hard
@@ -4351,9 +4348,9 @@ __metadata:
linkType: hard
"@types/node@npm:*":
- version: 18.15.5
- resolution: "@types/node@npm:18.15.5"
- checksum: 5fbf3453bd5ce1402bb2964e55d928fc8a8a7de5451b1b0fe66587fecb8a3eb86854ca9cefa5076a5971e2cff00e1773ceeb5d872a54f6c6ddfbbc1064b4e91a
+ version: 18.15.11
+ resolution: "@types/node@npm:18.15.11"
+ checksum: 977b4ad04708897ff0eb049ecf82246d210939c82461922d20f7d2dcfd81bbc661582ba3af28869210f7e8b1934529dcd46bff7d448551400f9d48b9d3bddec3
languageName: node
linkType: hard
@@ -4981,11 +4978,11 @@ __metadata:
linkType: hard
"@web/dev-server-hmr@npm:^0.1.11":
- version: 0.1.11
- resolution: "@web/dev-server-hmr@npm:0.1.11"
+ version: 0.1.12
+ resolution: "@web/dev-server-hmr@npm:0.1.12"
dependencies:
- "@web/dev-server-core": ^0.4.0
- checksum: a0c156c7c46f3463607a7ed87a6d149d372a2b1abd8ef2ce5a4d7ce3d7b0cd7e1375d93e28e87735e25617c322dd5c3d74c354a971712eb001e69adc6406698b
+ "@web/dev-server-core": ^0.4.1
+ checksum: 67255fd4a7ee4d44f6feeeb798e67c4dbb9d2e351ef404a33424fcfce7d28bea2ed165d9ff28506b44a4ac2e6ca2e3bb812c70954d04fbfdb08b8df4d47efefa
languageName: node
linkType: hard
@@ -5197,9 +5194,9 @@ __metadata:
linkType: hard
"@webcomponents/shadycss@npm:^1.9.1":
- version: 1.11.1
- resolution: "@webcomponents/shadycss@npm:1.11.1"
- checksum: e57b186190e5c4f871adef7dfd31110efca9e04cde686fd0f7651868a9420da7ec418bf060fa5aa664964b149cd69cccf2c2367cb5d06d1656eda0022834c155
+ version: 1.11.2
+ resolution: "@webcomponents/shadycss@npm:1.11.2"
+ checksum: 8349d837a7d7520b3c9fa42fc00401c0dae9c9e5dff12489fc284d773b8fad32283ea123a3073b937ef5992082ec31e84cf45f9bf0cb28dfd010a0c945bf2a94
languageName: node
linkType: hard
@@ -5364,7 +5361,7 @@ __metadata:
languageName: node
linkType: hard
-"ajv-keywords@npm:^5.0.0":
+"ajv-keywords@npm:^5.1.0":
version: 5.1.0
resolution: "ajv-keywords@npm:5.1.0"
dependencies:
@@ -5387,7 +5384,7 @@ __metadata:
languageName: node
linkType: hard
-"ajv@npm:^8.0.0, ajv@npm:^8.6.0, ajv@npm:^8.8.0":
+"ajv@npm:^8.0.0, ajv@npm:^8.6.0, ajv@npm:^8.9.0":
version: 8.12.0
resolution: "ajv@npm:8.12.0"
dependencies:
@@ -5907,9 +5904,9 @@ __metadata:
linkType: hard
"axe-core@npm:^4.3.3":
- version: 4.6.3
- resolution: "axe-core@npm:4.6.3"
- checksum: d0c46be92b9707c48b88a53cd5f471b155a2bfc8bf6beffb514ecd14e30b4863e340b5fc4f496d82a3c562048088c1f3ff5b93b9b3b026cb9c3bfacfd535da10
+ version: 4.7.0
+ resolution: "axe-core@npm:4.7.0"
+ checksum: f086bcab42be1761ba2b0b127dec350087f4c3a853bba8dd58f69d898cefaac31a1561da23146f6f3c07954c76171d1f2ce460e555e052d2b02cd79af628fa4a
languageName: node
linkType: hard
@@ -6361,9 +6358,9 @@ __metadata:
linkType: hard
"caniuse-lite@npm:^1.0.30001449":
- version: 1.0.30001469
- resolution: "caniuse-lite@npm:1.0.30001469"
- checksum: 8e496509d7e9ff189c72205675b5db0c5f1b6a09917027441e835efae0848a468a8c4e7d2b409ffc202438fcd23ae53e017f976a03c22c04d12d3c0e1e33e5de
+ version: 1.0.30001480
+ resolution: "caniuse-lite@npm:1.0.30001480"
+ checksum: c0b40f02f45ee99c73f732a3118028b2ab1544962d473d84f2afcb898a5e3099bd4c45f316ebc466fb1dbda904e86b72695578ca531a0bfa9d6337e7aad1ee2a
languageName: node
linkType: hard
@@ -6735,9 +6732,9 @@ __metadata:
linkType: hard
"colorette@npm:^2.0.10, colorette@npm:^2.0.14, colorette@npm:^2.0.19":
- version: 2.0.19
- resolution: "colorette@npm:2.0.19"
- checksum: 888cf5493f781e5fcf54ce4d49e9d7d698f96ea2b2ef67906834bb319a392c667f9ec69f4a10e268d2946d13a9503d2d19b3abaaaf174e3451bfe91fb9d82427
+ version: 2.0.20
+ resolution: "colorette@npm:2.0.20"
+ checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d
languageName: node
linkType: hard
@@ -6773,9 +6770,9 @@ __metadata:
linkType: hard
"commander@npm:^10.0.0":
- version: 10.0.0
- resolution: "commander@npm:10.0.0"
- checksum: 9f6495651f878213005ac744dd87a85fa3d9f2b8b90d1c19d0866d666bda7f735adfd7c2f10dfff345782e2f80ea258f98bb4efcef58e4e502f25f883940acfd
+ version: 10.0.1
+ resolution: "commander@npm:10.0.1"
+ checksum: 436901d64a818295803c1996cd856621a74f30b9f9e28a588e726b2b1670665bccd7c1a77007ebf328729f0139838a88a19265858a0fa7a8728c4656796db948
languageName: node
linkType: hard
@@ -6964,11 +6961,11 @@ __metadata:
linkType: hard
"core-js-compat@npm:^3.25.1":
- version: 3.29.1
- resolution: "core-js-compat@npm:3.29.1"
+ version: 3.30.1
+ resolution: "core-js-compat@npm:3.30.1"
dependencies:
browserslist: ^4.21.5
- checksum: 7260f6bbaa98836cda09a3b61aa721149d3ae95040302fb3b27eb153ae9bbddc8dee5249e72004cdc9552532029de4d50a5b2b066c37414421d2929d6091b18f
+ checksum: e450a9771fc927ce982333929e1c4b32f180f641e4cfff9de6ed44b5930de19be7707cf74f45d1746ca69b8e8ac0698a555cb7244fbfbed6c38ca93844207bf7
languageName: node
linkType: hard
@@ -7026,9 +7023,9 @@ __metadata:
linkType: hard
"csstype@npm:^3.1.0":
- version: 3.1.1
- resolution: "csstype@npm:3.1.1"
- checksum: 1f7b4f5fdd955b7444b18ebdddf3f5c699159f13e9cf8ac9027ae4a60ae226aef9bbb14a6e12ca7dba3358b007cee6354b116e720262867c398de6c955ea451d
+ version: 3.1.2
+ resolution: "csstype@npm:3.1.2"
+ checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5
languageName: node
linkType: hard
@@ -7355,9 +7352,9 @@ __metadata:
linkType: hard
"dijkstrajs@npm:^1.0.1":
- version: 1.0.2
- resolution: "dijkstrajs@npm:1.0.2"
- checksum: 8cd822441a26f190da24d69bfab7b433d080b09e069e41e046ac84e152f182a1ed9478d531b34126e000adaa7b73114a0f85fcac117a7d25b3edf302d57c0d09
+ version: 1.0.3
+ resolution: "dijkstrajs@npm:1.0.3"
+ checksum: 82ff2c6633f235dd5e6bed04ec62cdfb1f327b4d7534557bd52f18991313f864ee50654543072fff4384a92b643ada4d5452f006b7098dbdfad6c8744a8c9e08
languageName: node
linkType: hard
@@ -7378,11 +7375,11 @@ __metadata:
linkType: hard
"dns-packet@npm:^5.2.2":
- version: 5.4.0
- resolution: "dns-packet@npm:5.4.0"
+ version: 5.6.0
+ resolution: "dns-packet@npm:5.6.0"
dependencies:
"@leichtgewicht/ip-codec": ^2.0.1
- checksum: a169963848e8539dfd8a19058562f9e1c15c0f82cbf76fa98942f11c46f3c74e7e7c82e3a8a5182d4c9e6ff19e21be738dbd098a876dde755d3aedd2cc730880
+ checksum: 1b643814e5947a87620f8a906287079347492282964ce1c236d52c414e3e3941126b96581376b180ba6e66899e70b86b587bc1aa23e3acd9957765be952d83fc
languageName: node
linkType: hard
@@ -7480,9 +7477,9 @@ __metadata:
linkType: hard
"electron-to-chromium@npm:^1.4.284":
- version: 1.4.335
- resolution: "electron-to-chromium@npm:1.4.335"
- checksum: a3c9ee2412427ed0853f065f1dde64db1b567abf53d5e50e8cfba1544af4bda970f59a4f4df3dad81078c948b3277dffb42042e6a859288246d68b58db81a555
+ version: 1.4.368
+ resolution: "electron-to-chromium@npm:1.4.368"
+ checksum: b8ec4128a81c86c287cb2d677504c64d50f30c3c1d6dd9700a93797c6311f9f94b1c49a3e5112f5cfb3987a9bbade0133f9ec9898dae592db981059d5c2abdbb
languageName: node
linkType: hard
@@ -7561,9 +7558,9 @@ __metadata:
linkType: hard
"entities@npm:^4.4.0":
- version: 4.4.0
- resolution: "entities@npm:4.4.0"
- checksum: 84d250329f4b56b40fa93ed067b194db21e8815e4eb9b59f43a086f0ecd342814f6bc483de8a77da5d64e0f626033192b1b4f1792232a7ea6b970ebe0f3187c2
+ version: 4.5.0
+ resolution: "entities@npm:4.5.0"
+ checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7
languageName: node
linkType: hard
@@ -7666,9 +7663,9 @@ __metadata:
linkType: hard
"es-module-lexer@npm:^1.0.0":
- version: 1.2.0
- resolution: "es-module-lexer@npm:1.2.0"
- checksum: a0b865641ae52093fa3dffc41f3c440ac97b9932156896daa7784e66f01bef40f15b5578540f91cb4a43c38adda4a8ab8afca395b3b25480007d741ff0642de3
+ version: 1.2.1
+ resolution: "es-module-lexer@npm:1.2.1"
+ checksum: c4145b853e1491eaa5d591e4580926d242978c38071ad3d09165c3b6d50314cc0ae3bf6e1dec81a9e53768b9299df2063d2e4a67d7742a5029ddeae6c4fc26f0
languageName: node
linkType: hard
@@ -7856,14 +7853,14 @@ __metadata:
linkType: hard
"eslint-module-utils@npm:^2.7.4":
- version: 2.7.4
- resolution: "eslint-module-utils@npm:2.7.4"
+ version: 2.8.0
+ resolution: "eslint-module-utils@npm:2.8.0"
dependencies:
debug: ^3.2.7
peerDependenciesMeta:
eslint:
optional: true
- checksum: 5da13645daff145a5c922896b258f8bba560722c3767254e458d894ff5fbb505d6dfd945bffa932a5b0ae06714da2379bd41011c4c20d2d59cc83e23895360f7
+ checksum: 74c6dfea7641ebcfe174be61168541a11a14aa8d72e515f5f09af55cd0d0862686104b0524aa4b8e0ce66418a44aa38a94d2588743db5fd07a6b49ffd16921d2
languageName: node
linkType: hard
@@ -7924,16 +7921,16 @@ __metadata:
languageName: node
linkType: hard
-"eslint-plugin-lit@npm:1.8.2, eslint-plugin-lit@npm:^1.6.0":
- version: 1.8.2
- resolution: "eslint-plugin-lit@npm:1.8.2"
+"eslint-plugin-lit@npm:1.8.3, eslint-plugin-lit@npm:^1.6.0":
+ version: 1.8.3
+ resolution: "eslint-plugin-lit@npm:1.8.3"
dependencies:
parse5: ^6.0.1
parse5-htmlparser2-tree-adapter: ^6.0.1
requireindex: ^1.2.0
peerDependencies:
eslint: ">= 5"
- checksum: 30c4d60d26734e6974da3b6f4998f9c10a797f63ad123368bb9d1064efcb99ccd255ba9e4efec41f7029a0eaf8196445c3d8cf424cd4ef918faee2b388d474ae
+ checksum: 67f78b92b06224b3b83f2c914f508e94072aea106f3ea5aea42de55d3e83c73c91369b07f359a6ddeda5412c46f4f300c37d80715177cbb88834a5b497d262a0
languageName: node
linkType: hard
@@ -7989,12 +7986,12 @@ __metadata:
linkType: hard
"eslint-scope@npm:^7.1.1":
- version: 7.1.1
- resolution: "eslint-scope@npm:7.1.1"
+ version: 7.2.0
+ resolution: "eslint-scope@npm:7.2.0"
dependencies:
esrecurse: ^4.3.0
estraverse: ^5.2.0
- checksum: 9f6e974ab2db641ca8ab13508c405b7b859e72afe9f254e8131ff154d2f40c99ad4545ce326fd9fde3212ff29707102562a4834f1c48617b35d98c71a97fbf3e
+ checksum: 64591a2d8b244ade9c690b59ef238a11d5c721a98bcee9e9f445454f442d03d3e04eda88e95a4daec558220a99fa384309d9faae3d459bd40e7a81b4063980ae
languageName: node
linkType: hard
@@ -9139,15 +9136,15 @@ __metadata:
linkType: hard
"globby@npm:^13.1.2":
- version: 13.1.3
- resolution: "globby@npm:13.1.3"
+ version: 13.1.4
+ resolution: "globby@npm:13.1.4"
dependencies:
dir-glob: ^3.0.1
fast-glob: ^3.2.11
ignore: ^5.2.0
merge2: ^1.4.1
slash: ^4.0.0
- checksum: 93f06e02002cdf368f7e3d55bd59e7b00784c7cc8fe92c7ee5082cc7171ff6109fda45e1c97a80bb48bc811dedaf7843c7c9186f5f84bde4883ab630e13c43df
+ checksum: e8bc13879972082d590cd1b0e27080d90d2e12fff7eeb2cee9329c29115ace14cc5b9f899e3d6beb136ba826307a727016658919a6f383e1511d698acee81741
languageName: node
linkType: hard
@@ -9454,7 +9451,7 @@ __metadata:
"@codemirror/legacy-modes": 6.3.2
"@codemirror/search": 6.3.0
"@codemirror/state": 6.2.0
- "@codemirror/view": 6.9.4
+ "@codemirror/view": 6.9.5
"@egjs/hammerjs": 2.0.17
"@formatjs/intl-datetimeformat": 6.5.1
"@formatjs/intl-getcanonicallocales": 2.1.0
@@ -9569,7 +9566,7 @@ __metadata:
eslint-import-resolver-webpack: 0.13.2
eslint-plugin-disable: 2.0.3
eslint-plugin-import: 2.27.5
- eslint-plugin-lit: 1.8.2
+ eslint-plugin-lit: 1.8.3
eslint-plugin-lit-a11y: 2.4.1
eslint-plugin-unused-imports: 2.0.0
eslint-plugin-wc: 1.4.0
@@ -10237,12 +10234,12 @@ __metadata:
languageName: node
linkType: hard
-"is-core-module@npm:^2.11.0, is-core-module@npm:^2.7.0, is-core-module@npm:^2.9.0":
- version: 2.11.0
- resolution: "is-core-module@npm:2.11.0"
+"is-core-module@npm:^2.11.0, is-core-module@npm:^2.12.0, is-core-module@npm:^2.7.0":
+ version: 2.12.0
+ resolution: "is-core-module@npm:2.12.0"
dependencies:
has: ^1.0.3
- checksum: f96fd490c6b48eb4f6d10ba815c6ef13f410b0ba6f7eb8577af51697de523e5f2cd9de1c441b51d27251bf0e4aebc936545e33a5d26d5d51f28d25698d4a8bab
+ checksum: f7f7eb2ab71fd769ee9fb2385c095d503aa4b5ce0028c04557de03f1e67a87c85e5bac1f215945fc3c955867a139a415a3ec4c4234a0bffdf715232660f440a6
languageName: node
linkType: hard
@@ -11034,8 +11031,8 @@ __metadata:
linkType: hard
"koa@npm:^2.13.0":
- version: 2.14.1
- resolution: "koa@npm:2.14.1"
+ version: 2.14.2
+ resolution: "koa@npm:2.14.2"
dependencies:
accepts: ^1.3.5
cache-content-type: ^1.0.0
@@ -11060,7 +11057,7 @@ __metadata:
statuses: ^1.5.0
type-is: ^1.6.16
vary: ^1.1.2
- checksum: 84cfce48d72cf434831bd9f4f06beb3815da030325a7e89b13ee684f5afd158221e16c2d450ca637b221aa0c4a0ab235edd129e4efea656dc5d8384801d3e90f
+ checksum: 17fe3b8f5e0b4759004a942cc6ba2a9507299943a697dff9766b85f41f45caed4077ca2645ac9ad254d3359fffedfc4c9ebdd7a70493e5df8cdfac159a8ee835
languageName: node
linkType: hard
@@ -11253,22 +11250,22 @@ __metadata:
linkType: hard
"lit-element@npm:^3.3.0":
- version: 3.3.0
- resolution: "lit-element@npm:3.3.0"
+ version: 3.3.1
+ resolution: "lit-element@npm:3.3.1"
dependencies:
"@lit-labs/ssr-dom-shim": ^1.1.0
"@lit/reactive-element": ^1.3.0
lit-html: ^2.7.0
- checksum: 5a483c34dd55412599978e02858d841a932199dedca0b86ec54639096bc36c301f57915c0ee0463d8a57ac265d57f3468c8378224816c732c73df641a2549d62
+ checksum: c5731de5126d59ca9b2e6ae6fa61042101f7c63aaa5918fc84668f193debddb930dd217fba0f5be4bba1f90d84d40155ccb25bac56d4cb42cf2e9e41096227df
languageName: node
linkType: hard
"lit-html@npm:^2.7.0":
- version: 2.7.0
- resolution: "lit-html@npm:2.7.0"
+ version: 2.7.2
+ resolution: "lit-html@npm:2.7.2"
dependencies:
"@types/trusted-types": ^2.0.2
- checksum: 8a0f83c0f6110f8d02484803c2b309c6d21011bd03681cb790c5303e4a6e4f94956cb2dcb05e67f6c4066f382193a7e5c8987ab0ca244f2fe6e85b99e2feecdd
+ checksum: 885309bd72a9b6eb6c488ae901595c44b270023e02cafebca774b3ad14c1ec34dbe35a69d7ad22362e4ba3e7c2600662c003145db412cd9d61ecea91a93227ac
languageName: node
linkType: hard
@@ -11503,9 +11500,9 @@ __metadata:
linkType: hard
"lru-cache@npm:^9.0.0":
- version: 9.0.1
- resolution: "lru-cache@npm:9.0.1"
- checksum: 48e31a2a059730174d4b9c77c679ff922ee90ed8762376fd7a3ff5a1fae992bca26b9010dd985aff763d8444c3822c0d9ebeaba7d0552c764c200c40dedeaebd
+ version: 9.1.0
+ resolution: "lru-cache@npm:9.1.0"
+ checksum: 97b46faa2e8195b75b1c48a5515f8e458b8f6a0d0933c0484a4e45b6aa67406dcc5f6c8774fef206fd918dce6a4b4a6f627541fbdf74f8e6b3c71f688f43041e
languageName: node
linkType: hard
@@ -11886,9 +11883,9 @@ __metadata:
linkType: hard
"minipass@npm:^4.0.0":
- version: 4.2.5
- resolution: "minipass@npm:4.2.5"
- checksum: 4f9c19af23a5d4a9e7156feefc9110634b178a8cff8f8271af16ec5ebf7e221725a97429952c856f5b17b30c2065ebd24c81722d90c93d2122611d75b952b48f
+ version: 4.2.8
+ resolution: "minipass@npm:4.2.8"
+ checksum: 7f4914d5295a9a30807cae5227a37a926e6d910c03f315930fde52332cf0575dfbc20295318f91f0baf0e6bb11a6f668e30cde8027dea7a11b9d159867a3c830
languageName: node
linkType: hard
@@ -12036,12 +12033,12 @@ __metadata:
languageName: node
linkType: hard
-"nanoid@npm:^3.3.4":
- version: 3.3.4
- resolution: "nanoid@npm:3.3.4"
+"nanoid@npm:^3.3.6":
+ version: 3.3.6
+ resolution: "nanoid@npm:3.3.6"
bin:
nanoid: bin/nanoid.cjs
- checksum: 2fddd6dee994b7676f008d3ffa4ab16035a754f4bb586c61df5a22cf8c8c94017aadd360368f47d653829e0569a92b129979152ff97af23a558331e47e37cd9c
+ checksum: 7d0eda657002738aa5206107bd0580aead6c95c460ef1bdd0b1a87a9c7ae6277ac2e9b945306aaa5b32c6dcb7feaf462d0f552e7f8b5718abfc6ead5c94a71b3
languageName: node
linkType: hard
@@ -13030,13 +13027,13 @@ __metadata:
linkType: hard
"postcss@npm:^8.4.14":
- version: 8.4.21
- resolution: "postcss@npm:8.4.21"
+ version: 8.4.22
+ resolution: "postcss@npm:8.4.22"
dependencies:
- nanoid: ^3.3.4
+ nanoid: ^3.3.6
picocolors: ^1.0.0
source-map-js: ^1.0.2
- checksum: e39ac60ccd1542d4f9d93d894048aac0d686b3bb38e927d8386005718e6793dbbb46930f0a523fe382f1bbd843c6d980aaea791252bf5e176180e5a4336d9679
+ checksum: 7473dfb7ac5b4cb03576c39d687d7fc02c826ab08af97df15b5d3970662532d44a18a0994f392a9c3658ee17c292e7a55990e586b90ca0afcc9f36df13e07029
languageName: node
linkType: hard
@@ -13612,28 +13609,28 @@ __metadata:
linkType: hard
"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.4.0":
- version: 1.22.1
- resolution: "resolve@npm:1.22.1"
+ version: 1.22.3
+ resolution: "resolve@npm:1.22.3"
dependencies:
- is-core-module: ^2.9.0
+ is-core-module: ^2.12.0
path-parse: ^1.0.7
supports-preserve-symlinks-flag: ^1.0.0
bin:
resolve: bin/resolve
- checksum: 07af5fc1e81aa1d866cbc9e9460fbb67318a10fa3c4deadc35c3ad8a898ee9a71a86a65e4755ac3195e0ea0cfbe201eb323ebe655ce90526fd61917313a34e4e
+ checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374
languageName: node
linkType: hard
"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.4.0#~builtin":
- version: 1.22.1
- resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&hash=c3c19d"
+ version: 1.22.3
+ resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=c3c19d"
dependencies:
- is-core-module: ^2.9.0
+ is-core-module: ^2.12.0
path-parse: ^1.0.7
supports-preserve-symlinks-flag: ^1.0.0
bin:
resolve: bin/resolve
- checksum: 5656f4d0bedcf8eb52685c1abdf8fbe73a1603bb1160a24d716e27a57f6cecbe2432ff9c89c2bd57542c3a7b9d14b1882b73bfe2e9d7849c9a4c0b8b39f02b8b
+ checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665
languageName: node
linkType: hard
@@ -13848,25 +13845,25 @@ __metadata:
linkType: hard
"schema-utils@npm:^3.1.0, schema-utils@npm:^3.1.1":
- version: 3.1.1
- resolution: "schema-utils@npm:3.1.1"
+ version: 3.1.2
+ resolution: "schema-utils@npm:3.1.2"
dependencies:
"@types/json-schema": ^7.0.8
ajv: ^6.12.5
ajv-keywords: ^3.5.2
- checksum: fb73f3d759d43ba033c877628fe9751620a26879f6301d3dbeeb48cf2a65baec5cdf99da65d1bf3b4ff5444b2e59cbe4f81c2456b5e0d2ba7d7fd4aed5da29ce
+ checksum: 39683edfe3beff018cdb1ae4fa296fc55cea13a080aa2b4d9351895cd64b22ba4d87e2e548c2a2ac1bc76e60980670adb0f413a58104479f1a0c12e5663cb8ca
languageName: node
linkType: hard
"schema-utils@npm:^4.0.0":
- version: 4.0.0
- resolution: "schema-utils@npm:4.0.0"
+ version: 4.0.1
+ resolution: "schema-utils@npm:4.0.1"
dependencies:
"@types/json-schema": ^7.0.9
- ajv: ^8.8.0
+ ajv: ^8.9.0
ajv-formats: ^2.1.1
- ajv-keywords: ^5.0.0
- checksum: c843e92fdd1a5c145dbb6ffdae33e501867f9703afac67bdf35a685e49f85b1dcc10ea250033175a64bd9d31f0555bc6785b8359da0c90bcea30cf6dfbb55a8f
+ ajv-keywords: ^5.1.0
+ checksum: 745e7293c6b6c84940de16753c207311da821aa9911b9e2d158cfd9ffc5bf1f880147abbbe775b96cb8cd3c7f48890950fe0164f54eed9a8aabb948ebf8a3fdd
languageName: node
linkType: hard
@@ -13914,13 +13911,13 @@ __metadata:
linkType: hard
"semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7":
- version: 7.3.8
- resolution: "semver@npm:7.3.8"
+ version: 7.5.0
+ resolution: "semver@npm:7.5.0"
dependencies:
lru-cache: ^6.0.0
bin:
semver: bin/semver.js
- checksum: ba9c7cbbf2b7884696523450a61fee1a09930d888b7a8d7579025ad93d459b2d1949ee5bbfeb188b2be5f4ac163544c5e98491ad6152df34154feebc2cc337c1
+ checksum: 2d266937756689a76f124ffb4c1ea3e1bbb2b263219f90ada8a11aebebe1280b13bb76cca2ca96bdee3dbc554cbc0b24752eb895b2a51577aa644427e9229f2b
languageName: node
linkType: hard
@@ -14081,9 +14078,9 @@ __metadata:
linkType: hard
"shell-quote@npm:^1.7.3":
- version: 1.8.0
- resolution: "shell-quote@npm:1.8.0"
- checksum: 6ef7c5e308b9c77eedded882653a132214fa98b4a1512bb507588cf6cd2fc78bfee73e945d0c3211af028a1eabe09c6a19b96edd8977dc149810797e93809749
+ version: 1.8.1
+ resolution: "shell-quote@npm:1.8.1"
+ checksum: 5f01201f4ef504d4c6a9d0d283fa17075f6770bfbe4c5850b074974c68062f37929ca61700d95ad2ac8822e14e8c4b990ca0e6e9272e64befd74ce5e19f0736b
languageName: node
linkType: hard
@@ -14691,9 +14688,9 @@ __metadata:
linkType: hard
"style-mod@npm:^4.0.0":
- version: 4.0.2
- resolution: "style-mod@npm:4.0.2"
- checksum: 4bac8877e039c61481fc729981378791979c3ebb2f827a54240e95ccca5bca92a6d660566cacb87a8d7cc1ffb26bcd5eafa10c697e131adb5ca9541f3a9cbff6
+ version: 4.0.3
+ resolution: "style-mod@npm:4.0.3"
+ checksum: 934556e720bd29026ff8fef43a1a35b58957813025b91f996d886e9405acf934ddb1934def4400b174bd7784c9263eb9c71f07ae83925af9271b7d921d546854
languageName: node
linkType: hard
@@ -14855,8 +14852,8 @@ __metadata:
linkType: hard
"terser@npm:^5.0.0, terser@npm:^5.15.1, terser@npm:^5.16.5":
- version: 5.16.6
- resolution: "terser@npm:5.16.6"
+ version: 5.17.1
+ resolution: "terser@npm:5.17.1"
dependencies:
"@jridgewell/source-map": ^0.3.2
acorn: ^8.5.0
@@ -14864,7 +14861,7 @@ __metadata:
source-map-support: ~0.5.20
bin:
terser: bin/terser
- checksum: f763a7bcc7b98cb2bfc41434f7b92bfe8a701a12c92ea6049377736c8e6de328240d654a20dfe15ce170fd783491b9873fad9f4cd8fee4f6c6fb8ca407859dee
+ checksum: 69b0e80e3c4084db2819de4d6ae8a2ba79f2fcd7ed6df40fe4b602ec7bfd8e889cc63c7d5268f30990ffecbf6eeda18f857adad9386fe2c2331b398d58ed855c
languageName: node
linkType: hard
@@ -15513,16 +15510,16 @@ __metadata:
linkType: hard
"update-browserslist-db@npm:^1.0.10":
- version: 1.0.10
- resolution: "update-browserslist-db@npm:1.0.10"
+ version: 1.0.11
+ resolution: "update-browserslist-db@npm:1.0.11"
dependencies:
escalade: ^3.1.1
picocolors: ^1.0.0
peerDependencies:
browserslist: ">= 4.21.0"
bin:
- browserslist-lint: cli.js
- checksum: 12db73b4f63029ac407b153732e7cd69a1ea8206c9100b482b7d12859cd3cd0bc59c602d7ae31e652706189f1acb90d42c53ab24a5ba563ed13aebdddc5561a0
+ update-browserslist-db: cli.js
+ checksum: b98327518f9a345c7cad5437afae4d2ae7d865f9779554baf2a200fdf4bac4969076b679b1115434bd6557376bdd37ca7583d0f9b8f8e302d7d4cc1e91b5f231
languageName: node
linkType: hard
@@ -15821,8 +15818,8 @@ __metadata:
linkType: hard
"web-component-analyzer@npm:~1.1.1":
- version: 1.1.6
- resolution: "web-component-analyzer@npm:1.1.6"
+ version: 1.1.7
+ resolution: "web-component-analyzer@npm:1.1.7"
dependencies:
fast-glob: ^3.2.2
ts-simple-type: ~1.0.5
@@ -15831,7 +15828,7 @@ __metadata:
bin:
wca: cli.js
web-component-analyzer: cli.js
- checksum: 8071b348ffc8e40ff024fc63490e9c7a0d9b929aa88b44548ccb559110ba926cf2063cefe864a7060c73d515a35496f6d8990bed9a743a819e6b4b26e93a9042
+ checksum: 6c36521b7b79d5547ffdbc359029651ad1d929df6e09f8adfbafb2a34c23199712b7080f08f941f056b6a989718c11eb9221171d97ad397ed8a20cf08dd78e4b
languageName: node
linkType: hard
From 0b3dff00df2ad2d44c0ed9ddbea59594bc1f221c Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Wed, 19 Apr 2023 23:58:58 +0200
Subject: [PATCH 050/112] Revert "Add language selector" (#16247)
Revert "Add language selector (#16242)"
This reverts commit d89ac0f30ddb349f553d788c22077c958b31f645.
---
src/components/ha-language-picker.ts | 132 ------------------
.../ha-selector/ha-selector-language.ts | 48 -------
src/components/ha-selector/ha-selector.ts | 1 -
src/data/assist_pipeline.ts | 5 -
src/data/selector.ts | 5 -
.../config/core/ha-config-section-general.ts | 49 +++++--
.../dialog-voice-assistant-pipeline-detail.ts | 32 ++---
src/panels/profile/ha-pick-language-row.ts | 46 ++++--
8 files changed, 81 insertions(+), 237 deletions(-)
delete mode 100644 src/components/ha-language-picker.ts
delete mode 100644 src/components/ha-selector/ha-selector-language.ts
diff --git a/src/components/ha-language-picker.ts b/src/components/ha-language-picker.ts
deleted file mode 100644
index 55a18777dd..0000000000
--- a/src/components/ha-language-picker.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import {
- css,
- CSSResultGroup,
- html,
- LitElement,
- PropertyValues,
- TemplateResult,
-} from "lit";
-import { customElement, property, state } from "lit/decorators";
-import memoizeOne from "memoize-one";
-import { fireEvent } from "../common/dom/fire_event";
-import { stopPropagation } from "../common/dom/stop_propagation";
-import { caseInsensitiveStringCompare } from "../common/string/compare";
-import { HomeAssistant } from "../types";
-import "./ha-list-item";
-import "./ha-select";
-import type { HaSelect } from "./ha-select";
-
-@customElement("ha-language-picker")
-export class HaLanguagePicker extends LitElement {
- @property() public value?: string;
-
- @property() public label?: string;
-
- @property() public supportedLanguages?: string[];
-
- @property({ attribute: false }) public hass!: HomeAssistant;
-
- @property({ type: Boolean, reflect: true }) public disabled = false;
-
- @property({ type: Boolean }) public required = false;
-
- @property({ type: Boolean }) public nativeName = false;
-
- @state() _defaultLanguages: string[] = [];
-
- protected firstUpdated(changedProps: PropertyValues) {
- super.firstUpdated(changedProps);
- this._computeDefaultLanguageOptions();
- }
-
- private _getLanguagesOptions = memoizeOne(
- (languages: string[], language: string, nativeName: boolean) => {
- let options: { label: string; value: string }[] = [];
-
- if (nativeName) {
- const translations = this.hass.translationMetadata.translations;
- options = languages.map((lang) => ({
- value: lang,
- label: translations[lang]?.nativeName ?? lang,
- }));
- } else {
- const languageDisplayNames =
- Intl && "DisplayNames" in Intl
- ? new Intl.DisplayNames(language, {
- type: "language",
- fallback: "code",
- })
- : undefined;
-
- options = languages.map((lang) => ({
- value: lang,
- label: languageDisplayNames ? languageDisplayNames.of(lang)! : lang,
- }));
- }
-
- options.sort((a, b) =>
- caseInsensitiveStringCompare(a.label, b.label, language)
- );
- return options;
- }
- );
-
- private _computeDefaultLanguageOptions() {
- if (!this.hass.translationMetadata?.translations) {
- return;
- }
-
- this._defaultLanguages = Object.keys(
- this.hass.translationMetadata.translations
- );
- }
-
- protected render(): TemplateResult {
- const value = this.value;
-
- const languageOptions = this._getLanguagesOptions(
- this.supportedLanguages ?? this._defaultLanguages,
- this.hass.locale.language,
- this.nativeName
- );
-
- return html`
-
- ${languageOptions.map(
- (option) => html`
- ${option.label}
- `
- )}
-
- `;
- }
-
- static get styles(): CSSResultGroup {
- return css`
- ha-select {
- width: 100%;
- }
- `;
- }
-
- private _changed(ev): void {
- const target = ev.target as HaSelect;
- this.value = target.value;
- fireEvent(this, "value-changed", { value: this.value });
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "ha-language-picker": HaLanguagePicker;
- }
-}
diff --git a/src/components/ha-selector/ha-selector-language.ts b/src/components/ha-selector/ha-selector-language.ts
deleted file mode 100644
index 7a6e4fc355..0000000000
--- a/src/components/ha-selector/ha-selector-language.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { css, html, LitElement } from "lit";
-import { customElement, property } from "lit/decorators";
-import { LanguageSelector } from "../../data/selector";
-import { HomeAssistant } from "../../types";
-import "../ha-language-picker";
-
-@customElement("ha-selector-language")
-export class HaLanguageSelector extends LitElement {
- @property() public hass!: HomeAssistant;
-
- @property() public selector!: LanguageSelector;
-
- @property() public value?: any;
-
- @property() public label?: string;
-
- @property() public helper?: string;
-
- @property({ type: Boolean }) public disabled = false;
-
- @property({ type: Boolean }) public required = true;
-
- protected render() {
- return html`
-
- `;
- }
-
- static styles = css`
- ha-language-picker {
- width: 100%;
- }
- `;
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "ha-selector-language": HaLanguageSelector;
- }
-}
diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts
index 85193753c9..46ee4b30ef 100644
--- a/src/components/ha-selector/ha-selector.ts
+++ b/src/components/ha-selector/ha-selector.ts
@@ -26,7 +26,6 @@ const LOAD_ELEMENTS = {
entity: () => import("./ha-selector-entity"),
statistic: () => import("./ha-selector-statistic"),
file: () => import("./ha-selector-file"),
- language: () => import("./ha-selector-language"),
navigation: () => import("./ha-selector-navigation"),
number: () => import("./ha-selector-number"),
object: () => import("./ha-selector-object"),
diff --git a/src/data/assist_pipeline.ts b/src/data/assist_pipeline.ts
index abf370681f..dd8eca29fb 100644
--- a/src/data/assist_pipeline.ts
+++ b/src/data/assist_pipeline.ts
@@ -296,8 +296,3 @@ export const deleteAssistPipeline = (hass: HomeAssistant, pipelineId: string) =>
type: "assist_pipeline/pipeline/delete",
pipeline_id: pipelineId,
});
-
-export const fetchAssistPipelineLanguages = (hass: HomeAssistant) =>
- hass.callWS<{ languages: string[] }>({
- type: "assist_pipeline/language/list",
- });
diff --git a/src/data/selector.ts b/src/data/selector.ts
index c8b1781cf1..21ba8c0e5a 100644
--- a/src/data/selector.ts
+++ b/src/data/selector.ts
@@ -26,7 +26,6 @@ export type Selector =
| LegacyEntitySelector
| FileSelector
| IconSelector
- | LanguageSelector
| LocationSelector
| MediaSelector
| NavigationSelector
@@ -210,10 +209,6 @@ export interface IconSelector {
} | null;
}
-export interface LanguageSelector {
- language: { supported_languages?: string[] } | null;
-}
-
export interface LocationSelector {
location: { radius?: boolean; icon?: string } | null;
}
diff --git a/src/panels/config/core/ha-config-section-general.ts b/src/panels/config/core/ha-config-section-general.ts
index 0d6e95dbc7..31abfd8346 100644
--- a/src/panels/config/core/ha-config-section-general.ts
+++ b/src/panels/config/core/ha-config-section-general.ts
@@ -6,16 +6,13 @@ import memoizeOne from "memoize-one";
import { UNIT_C } from "../../../common/const";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import { navigate } from "../../../common/navigate";
+import { caseInsensitiveStringCompare } from "../../../common/string/compare";
import "../../../components/buttons/ha-progress-button";
import type { HaProgressButton } from "../../../components/buttons/ha-progress-button";
import { getCountryOptions } from "../../../components/country-datalist";
import { getCurrencyOptions } from "../../../components/currency-datalist";
-import "../../../components/ha-alert";
import "../../../components/ha-card";
-import "../../../components/ha-checkbox";
-import type { HaCheckbox } from "../../../components/ha-checkbox";
import "../../../components/ha-formfield";
-import "../../../components/ha-language-picker";
import "../../../components/ha-radio";
import type { HaRadio } from "../../../components/ha-radio";
import "../../../components/ha-select";
@@ -25,10 +22,13 @@ import "../../../components/map/ha-locations-editor";
import type { MarkerLocation } from "../../../components/map/ha-locations-editor";
import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core";
import { SYMBOL_TO_ISO } from "../../../data/currency";
-import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-subpage";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
+import "../../../components/ha-alert";
+import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
+import type { HaCheckbox } from "../../../components/ha-checkbox";
+import "../../../components/ha-checkbox";
@customElement("ha-config-section-general")
class HaConfigSectionGeneral extends LitElement {
@@ -54,6 +54,8 @@ class HaConfigSectionGeneral extends LitElement {
@state() private _location?: [number, number];
+ @state() private _languages?: { value: string; label: string }[];
+
@state() private _error?: string;
@state() private _updateUnits?: boolean;
@@ -253,19 +255,25 @@ class HaConfigSectionGeneral extends LitElement {
`
)}
-
+ ${this._languages?.map(
+ ({ value, label }) =>
+ html`${label} `
+ )}
-
${this.narrow
? html`
@@ -322,10 +330,25 @@ class HaConfigSectionGeneral extends LitElement {
this._timeZone = this.hass.config.time_zone || "Etc/GMT";
this._name = this.hass.config.location_name;
this._updateUnits = true;
+ this._computeLanguages();
}
- private _handleLanguageChange(ev) {
- this._language = ev.detail.value;
+ private _computeLanguages() {
+ if (!this.hass.translationMetadata?.translations) {
+ return;
+ }
+ this._languages = Object.entries(this.hass.translationMetadata.translations)
+ .sort((a, b) =>
+ caseInsensitiveStringCompare(
+ a[1].nativeName,
+ b[1].nativeName,
+ this.hass.locale.language
+ )
+ )
+ .map(([value, metaData]) => ({
+ value,
+ label: metaData.nativeName,
+ }));
}
private _handleChange(ev) {
diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
index 0738dfd0c9..3bd1bd00c4 100644
--- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
+++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts
@@ -9,7 +9,6 @@ import { SchemaUnion } from "../../../components/ha-form/types";
import {
AssistPipeline,
AssistPipelineMutableParams,
- fetchAssistPipelineLanguages,
} from "../../../data/assist_pipeline";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
@@ -30,8 +29,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
@state() private _submitting = false;
- @state() private _supportedLanguages: string[] = [];
-
public showDialog(params: VoiceAssistantPipelineDetailsDialogParams): void {
this._params = params;
this._error = undefined;
@@ -49,15 +46,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
- protected firstUpdated() {
- this._getSupportedLanguages();
- }
-
- private async _getSupportedLanguages() {
- const { languages } = await fetchAssistPipelineLanguages(this.hass);
- this._supportedLanguages = languages;
- }
-
protected render() {
if (!this._params || !this._data) {
return nothing;
@@ -80,7 +68,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
>
+ () =>
[
{
name: "name",
@@ -141,15 +129,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
text: {},
},
},
- {
- name: "language",
- required: true,
- selector: {
- language: {
- supported_languages: languages,
- },
- },
- },
{
name: "conversation_engine",
required: true,
@@ -157,6 +136,13 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
conversation_agent: {},
},
},
+ {
+ name: "language",
+ required: true,
+ selector: {
+ text: {},
+ },
+ },
{
name: "stt_engine",
selector: {
diff --git a/src/panels/profile/ha-pick-language-row.ts b/src/panels/profile/ha-pick-language-row.ts
index d33eb48941..7bab38abdc 100644
--- a/src/panels/profile/ha-pick-language-row.ts
+++ b/src/panels/profile/ha-pick-language-row.ts
@@ -1,9 +1,10 @@
-import { css, html, LitElement } from "lit";
-import { customElement, property } from "lit/decorators";
+import "@material/mwc-list/mwc-list-item";
+import { css, html, LitElement, PropertyValues } from "lit";
+import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
-import "../../components/ha-language-picker";
+import "../../components/ha-select";
import "../../components/ha-settings-row";
-import { HomeAssistant } from "../../types";
+import { HomeAssistant, Translation } from "../../types";
@customElement("ha-pick-language-row")
export class HaPickLanguageRow extends LitElement {
@@ -11,6 +12,13 @@ export class HaPickLanguageRow extends LitElement {
@property() public narrow!: boolean;
+ @state() private _languages: (Translation & { key: string })[] = [];
+
+ protected firstUpdated(changedProps: PropertyValues) {
+ super.firstUpdated(changedProps);
+ this._computeLanguages();
+ }
+
protected render() {
return html`
@@ -25,25 +33,43 @@ export class HaPickLanguageRow extends LitElement {
>${this.hass.localize("ui.panel.profile.language.link_promo")}
-
-
+ ${this._languages.map(
+ (language) => html`
+ ${language.nativeName}
+ `
+ )}
+
`;
}
+ private _computeLanguages() {
+ if (!this.hass.translationMetadata?.translations) {
+ return;
+ }
+ this._languages = Object.keys(
+ this.hass.translationMetadata.translations
+ ).map((key) => ({
+ key,
+ ...this.hass.translationMetadata.translations[key],
+ }));
+ }
+
private _languageSelectionChanged(ev) {
// Only fire event if language was changed. This prevents select updates when
// responding to hass changes.
- if (ev.detail.value !== this.hass.language) {
+ if (ev.target.value !== this.hass.language) {
fireEvent(this, "hass-language-select", ev.target.value);
}
}
From f9f87d1147702ccb5132e03517134eb847d9f13a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 19 Apr 2023 19:00:16 -0400
Subject: [PATCH 051/112] Lock file maintenance (#16246)
---
yarn.lock | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 5060e5c140..c8419116da 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4012,12 +4012,12 @@ __metadata:
linkType: hard
"@types/chrome@npm:*":
- version: 0.0.232
- resolution: "@types/chrome@npm:0.0.232"
+ version: 0.0.233
+ resolution: "@types/chrome@npm:0.0.233"
dependencies:
"@types/filesystem": "*"
"@types/har-format": "*"
- checksum: ebd8ff2a4c9e1504088f73d82d22f0ebd283ae4043e079c1a5bc76ec23491a5d366fcf9c9edd7c81cfa1f10391929cdf7951333bba137110a87b9feff377b88e
+ checksum: c4eede5c0f27ccda12a0c22588027a19e0e2f18931f8df7bb62928ec1de586bb0f42d660cc5217bd3a587dc5eb2dfa8d83c92bb646b3e3104d6fbc086d1cb9b4
languageName: node
linkType: hard
@@ -4112,9 +4112,9 @@ __metadata:
linkType: hard
"@types/estree@npm:*, @types/estree@npm:^1.0.0":
- version: 1.0.0
- resolution: "@types/estree@npm:1.0.0"
- checksum: 910d97fb7092c6738d30a7430ae4786a38542023c6302b95d46f49420b797f21619cdde11fa92b338366268795884111c2eb10356e4bd2c8ad5b92941e9e6443
+ version: 1.0.1
+ resolution: "@types/estree@npm:1.0.1"
+ checksum: e9aa175eacb797216fafce4d41e8202c7a75555bc55232dee0f9903d7171f8f19f0ae7d5191bb1a88cb90e65468be508c0df850a9fb81b4433b293a5a749899d
languageName: node
linkType: hard
@@ -7223,7 +7223,7 @@ __metadata:
languageName: node
linkType: hard
-"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4":
+"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.0":
version: 1.2.0
resolution: "define-properties@npm:1.2.0"
dependencies:
@@ -7548,12 +7548,12 @@ __metadata:
linkType: hard
"enhanced-resolve@npm:^5.9.3":
- version: 5.12.0
- resolution: "enhanced-resolve@npm:5.12.0"
+ version: 5.13.0
+ resolution: "enhanced-resolve@npm:5.13.0"
dependencies:
graceful-fs: ^4.2.4
tapable: ^2.2.0
- checksum: bf3f787facaf4ce3439bef59d148646344e372bef5557f0d37ea8aa02c51f50a925cd1f07b8d338f18992c29f544ec235a8c64bcdb56030196c48832a5494174
+ checksum: 76d6844c4393d76beed5b3ce6cf5a98dee3ad5c84a9887f49ccde1224e3b7af201dfbd5a57ebf2b49f623b74883df262d50ff480d3cc02fc2881fc58b84e1bbe
languageName: node
linkType: hard
@@ -8824,7 +8824,7 @@ __metadata:
languageName: node
linkType: hard
-"functions-have-names@npm:^1.2.2":
+"functions-have-names@npm:^1.2.2, functions-have-names@npm:^1.2.3":
version: 1.2.3
resolution: "functions-have-names@npm:1.2.3"
checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5
@@ -13027,13 +13027,13 @@ __metadata:
linkType: hard
"postcss@npm:^8.4.14":
- version: 8.4.22
- resolution: "postcss@npm:8.4.22"
+ version: 8.4.23
+ resolution: "postcss@npm:8.4.23"
dependencies:
nanoid: ^3.3.6
picocolors: ^1.0.0
source-map-js: ^1.0.2
- checksum: 7473dfb7ac5b4cb03576c39d687d7fc02c826ab08af97df15b5d3970662532d44a18a0994f392a9c3658ee17c292e7a55990e586b90ca0afcc9f36df13e07029
+ checksum: 8bb9d1b2ea6e694f8987d4f18c94617971b2b8d141602725fedcc2222fdc413b776a6e1b969a25d627d7b2681ca5aabb56f59e727ef94072e1b6ac8412105a2f
languageName: node
linkType: hard
@@ -13398,13 +13398,13 @@ __metadata:
linkType: hard
"regexp.prototype.flags@npm:^1.4.3":
- version: 1.4.3
- resolution: "regexp.prototype.flags@npm:1.4.3"
+ version: 1.5.0
+ resolution: "regexp.prototype.flags@npm:1.5.0"
dependencies:
call-bind: ^1.0.2
- define-properties: ^1.1.3
- functions-have-names: ^1.2.2
- checksum: 51228bae732592adb3ededd5e15426be25f289e9c4ef15212f4da73f4ec3919b6140806374b8894036a86020d054a8d2657d3fee6bb9b4d35d8939c20030b7a6
+ define-properties: ^1.2.0
+ functions-have-names: ^1.2.3
+ checksum: c541687cdbdfff1b9a07f6e44879f82c66bbf07665f9a7544c5fd16acdb3ec8d1436caab01662d2fbcad403f3499d49ab0b77fbc7ef29ef961d98cc4bc9755b4
languageName: node
linkType: hard
@@ -15745,9 +15745,9 @@ __metadata:
linkType: hard
"vscode-languageserver-textdocument@npm:^1.0.1":
- version: 1.0.9
- resolution: "vscode-languageserver-textdocument@npm:1.0.9"
- checksum: 36b76f725098d3e0d97885c05c51fca47388d9b62e936f6c8824c44a4fac7a96e1406538538a0f46ef1fdb9f1053ddc1cacb5e7b168cecb36d3c018942ec6f52
+ version: 1.0.10
+ resolution: "vscode-languageserver-textdocument@npm:1.0.10"
+ checksum: 605ff0662535088567a145b48d28f0c41844d28269fa0b3fca3a1e179dd14baf7181150b274bf3840ef2a043ed8474a9227aaf169a6fae574516349a1b371a18
languageName: node
linkType: hard
From 52a7b410967ba00ee393786829738906f1e7cf03 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 20 Apr 2023 03:18:13 +0000
Subject: [PATCH 052/112] Lock file maintenance (#16248)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
yarn.lock | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index c8419116da..ec121220a8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3221,10 +3221,10 @@ __metadata:
languageName: node
linkType: hard
-"@octokit/openapi-types@npm:^16.0.0":
- version: 16.0.0
- resolution: "@octokit/openapi-types@npm:16.0.0"
- checksum: 844f30a545da380d63c712e0eb733366bc567d1aab34529c79fdfbec3d73810e81d83f06fdab13058a5cbc7dae786db1a9b90b5b61b1e606854ee45d5ec5f194
+"@octokit/openapi-types@npm:^16.1.0":
+ version: 16.1.0
+ resolution: "@octokit/openapi-types@npm:16.1.0"
+ checksum: 071458deee4fbd357a664ead9f1bf9a44cfc5c4fb0ef92e63fdbce2777c81d45a1d00d929093e5524c0aaa69d26d88cf412f5972ce3a61e1296b86808a188797
languageName: node
linkType: hard
@@ -3310,11 +3310,11 @@ __metadata:
linkType: hard
"@octokit/types@npm:^9.0.0":
- version: 9.0.0
- resolution: "@octokit/types@npm:9.0.0"
+ version: 9.1.0
+ resolution: "@octokit/types@npm:9.1.0"
dependencies:
- "@octokit/openapi-types": ^16.0.0
- checksum: 5c7f5cca8f00f7c4daa0d00f4fe991c1598ec47cd6ced50b1c5fbe9721bb9dee0adc2acdee265a3a715bb984e53ef3dc7f1cfb7326f712c6d809d59fc5c6648d
+ "@octokit/openapi-types": ^16.1.0
+ checksum: 6d9de8efb5a1ec8d5da9076407ddaaeabdcac5d21f0a5c7c43c0485515321187b520235e4d90e322b37c6c32167a419e33a44015347a65c2ef9f8d739525f417
languageName: node
linkType: hard
@@ -4348,9 +4348,9 @@ __metadata:
linkType: hard
"@types/node@npm:*":
- version: 18.15.11
- resolution: "@types/node@npm:18.15.11"
- checksum: 977b4ad04708897ff0eb049ecf82246d210939c82461922d20f7d2dcfd81bbc661582ba3af28869210f7e8b1934529dcd46bff7d448551400f9d48b9d3bddec3
+ version: 18.15.12
+ resolution: "@types/node@npm:18.15.12"
+ checksum: dff7596db8d0a18bcd8da542dc62ed4377cba39546ff53baaa06d106f1482bc3e4e5e03644f5d1e3cef0904ffbe8ebbc244b2b0851f8025ab2a3959ee0ace58f
languageName: node
linkType: hard
From 22f5d6cacbc6ba07c64273614ded837185af01ec Mon Sep 17 00:00:00 2001
From: Steve Repsher
Date: Thu, 20 Apr 2023 04:59:08 -0400
Subject: [PATCH 053/112] Migrate Babel loose options to assumptions (#16245)
---
build-scripts/bundle.cjs | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/build-scripts/bundle.cjs b/build-scripts/bundle.cjs
index a5077badad..393fbce92c 100644
--- a/build-scripts/bundle.cjs
+++ b/build-scripts/bundle.cjs
@@ -84,6 +84,12 @@ module.exports.terserOptions = ({ latestBuild, isTestBuild }) => ({
module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
babelrc: false,
compact: false,
+ assumptions: {
+ privateFieldsAsProperties: true,
+ setPublicClassFields: true,
+ setSpreadProperties: true,
+ },
+
presets: [
!latestBuild && [
"@babel/preset-env",
@@ -109,7 +115,7 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
!latestBuild && [
"@babel/plugin-proposal-object-rest-spread",
- { loose: true, useBuiltIns: true },
+ { useBuiltIns: true },
],
// Only support the syntax, Webpack will handle it.
"@babel/plugin-syntax-import-meta",
@@ -119,9 +125,9 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-nullish-coalescing-operator",
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
- ["@babel/plugin-proposal-private-methods", { loose: true }],
- ["@babel/plugin-proposal-private-property-in-object", { loose: true }],
- ["@babel/plugin-proposal-class-properties", { loose: true }],
+ "@babel/plugin-proposal-private-methods",
+ "@babel/plugin-proposal-private-property-in-object",
+ "@babel/plugin-proposal-class-properties",
// Minify template literals for production
isProdBuild && [
"template-html-minifier",
From eeb84f65b99f8054d8fd27c64ec15a3619c068e8 Mon Sep 17 00:00:00 2001
From: Steve Repsher
Date: Thu, 20 Apr 2023 05:00:04 -0400
Subject: [PATCH 054/112] Remove unnecessary Babel plugins from dependencies
(#16251)
---
package.json | 6 ------
yarn.lock | 18 ++++++------------
2 files changed, 6 insertions(+), 18 deletions(-)
diff --git a/package.json b/package.json
index 990608725d..0598c649c7 100644
--- a/package.json
+++ b/package.json
@@ -150,14 +150,8 @@
"devDependencies": {
"@babel/core": "7.21.4",
"@babel/plugin-external-helpers": "7.18.6",
- "@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-proposal-decorators": "7.21.0",
- "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
- "@babel/plugin-proposal-object-rest-spread": "7.20.7",
- "@babel/plugin-proposal-optional-chaining": "7.21.0",
- "@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/plugin-syntax-import-meta": "7.10.4",
- "@babel/plugin-syntax-top-level-await": "7.14.5",
"@babel/preset-env": "7.21.4",
"@babel/preset-typescript": "7.21.4",
"@koa/cors": "4.0.0",
diff --git a/yarn.lock b/yarn.lock
index ec121220a8..4c9a8ac08f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -422,7 +422,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-proposal-class-properties@npm:7.18.6, @babel/plugin-proposal-class-properties@npm:^7.18.6":
+"@babel/plugin-proposal-class-properties@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6"
dependencies:
@@ -510,7 +510,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6, @babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6":
+"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6"
dependencies:
@@ -534,7 +534,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-proposal-object-rest-spread@npm:7.20.7, @babel/plugin-proposal-object-rest-spread@npm:^7.20.7":
+"@babel/plugin-proposal-object-rest-spread@npm:^7.20.7":
version: 7.20.7
resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.20.7"
dependencies:
@@ -561,7 +561,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-proposal-optional-chaining@npm:7.21.0, @babel/plugin-proposal-optional-chaining@npm:^7.20.7, @babel/plugin-proposal-optional-chaining@npm:^7.21.0":
+"@babel/plugin-proposal-optional-chaining@npm:^7.20.7, @babel/plugin-proposal-optional-chaining@npm:^7.21.0":
version: 7.21.0
resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0"
dependencies:
@@ -656,7 +656,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-syntax-dynamic-import@npm:7.8.3, @babel/plugin-syntax-dynamic-import@npm:^7.8.3":
+"@babel/plugin-syntax-dynamic-import@npm:^7.8.3":
version: 7.8.3
resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3"
dependencies:
@@ -799,7 +799,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-syntax-top-level-await@npm:7.14.5, @babel/plugin-syntax-top-level-await@npm:^7.12.1, @babel/plugin-syntax-top-level-await@npm:^7.14.5":
+"@babel/plugin-syntax-top-level-await@npm:^7.12.1, @babel/plugin-syntax-top-level-await@npm:^7.14.5":
version: 7.14.5
resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5"
dependencies:
@@ -9434,14 +9434,8 @@ __metadata:
dependencies:
"@babel/core": 7.21.4
"@babel/plugin-external-helpers": 7.18.6
- "@babel/plugin-proposal-class-properties": 7.18.6
"@babel/plugin-proposal-decorators": 7.21.0
- "@babel/plugin-proposal-nullish-coalescing-operator": 7.18.6
- "@babel/plugin-proposal-object-rest-spread": 7.20.7
- "@babel/plugin-proposal-optional-chaining": 7.21.0
- "@babel/plugin-syntax-dynamic-import": 7.8.3
"@babel/plugin-syntax-import-meta": 7.10.4
- "@babel/plugin-syntax-top-level-await": 7.14.5
"@babel/preset-env": 7.21.4
"@babel/preset-typescript": 7.21.4
"@braintree/sanitize-url": 6.0.2
From 0d020e0300b34f464f1f9f060a5d79e7089d558a Mon Sep 17 00:00:00 2001
From: Bram Kragten
Date: Thu, 20 Apr 2023 11:03:47 +0200
Subject: [PATCH 055/112] Fix stt/tts pickers (#16241)
---
src/components/ha-stt-picker.ts | 8 +++++---
src/components/ha-tts-picker.ts | 8 +++++---
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/components/ha-stt-picker.ts b/src/components/ha-stt-picker.ts
index b7e998fb92..26e799f2e3 100644
--- a/src/components/ha-stt-picker.ts
+++ b/src/components/ha-stt-picker.ts
@@ -5,7 +5,6 @@ import {
LitElement,
nothing,
PropertyValues,
- TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
@@ -34,9 +33,12 @@ export class HaSTTPicker extends LitElement {
@property({ type: Boolean }) public required = false;
- @state() _engines: STTEngine[] = [];
+ @state() _engines?: STTEngine[];
- protected render(): TemplateResult {
+ protected render() {
+ if (!this._engines) {
+ return nothing;
+ }
const value =
this.value ??
(this.required
diff --git a/src/components/ha-tts-picker.ts b/src/components/ha-tts-picker.ts
index fe671b3bea..f71d69d030 100644
--- a/src/components/ha-tts-picker.ts
+++ b/src/components/ha-tts-picker.ts
@@ -6,7 +6,6 @@ import {
LitElement,
nothing,
PropertyValues,
- TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
@@ -34,9 +33,12 @@ export class HaTTSPicker extends LitElement {
@property({ type: Boolean }) public required = false;
- @state() _engines: TTSEngine[] = [];
+ @state() _engines?: TTSEngine[];
- protected render(): TemplateResult {
+ protected render() {
+ if (!this._engines) {
+ return nothing;
+ }
const value =
this.value ??
(this.required
From aac28efd3251a31fc341f35fa6cec83179d7b26a Mon Sep 17 00:00:00 2001
From: Steve Repsher
Date: Thu, 20 Apr 2023 05:10:12 -0400
Subject: [PATCH 056/112] Streamline HTML generation and consolidate templates
(#16117)
---
build-scripts/gulp/app.cjs | 9 +-
build-scripts/gulp/cast.cjs | 4 +-
build-scripts/gulp/demo.cjs | 4 +-
build-scripts/gulp/entry-html.cjs | 487 +++++++-----------
build-scripts/gulp/gallery.cjs | 4 +-
build-scripts/gulp/hassio.cjs | 4 +-
cast/src/html/_social_meta.html.template | 24 +
...er-faq.html.template => faq.html.template} | 23 +-
cast/src/html/index.html.template | 35 ++
cast/src/html/launcher.html.template | 57 --
cast/src/html/media.html.template | 21 +-
cast/src/html/receiver.html.template | 6 +-
demo/src/html/_social_meta.html.template | 26 +
demo/src/html/index.html.template | 58 +--
gallery/src/html/index.html.template | 5 +-
hassio/src/entrypoint.js.template | 22 +
src/html/_header.html.template | 13 +-
src/html/_script_load_es5.html.template | 17 +
src/html/authorize.html.template | 28 +-
src/html/index.html.template | 30 +-
src/html/onboarding.html.template | 33 +-
21 files changed, 383 insertions(+), 527 deletions(-)
create mode 100644 cast/src/html/_social_meta.html.template
rename cast/src/html/{launcher-faq.html.template => faq.html.template} (95%)
create mode 100644 cast/src/html/index.html.template
delete mode 100644 cast/src/html/launcher.html.template
create mode 100644 demo/src/html/_social_meta.html.template
create mode 100644 hassio/src/entrypoint.js.template
create mode 100644 src/html/_script_load_es5.html.template
diff --git a/build-scripts/gulp/app.cjs b/build-scripts/gulp/app.cjs
index 0b6c49354c..4e77e26326 100644
--- a/build-scripts/gulp/app.cjs
+++ b/build-scripts/gulp/app.cjs
@@ -24,8 +24,7 @@ gulp.task(
gulp.parallel(
"gen-service-worker-app-dev",
"gen-icons-json",
- "gen-pages-dev",
- "gen-index-app-dev",
+ "gen-pages-app-dev",
"build-translations",
"build-locale-data"
),
@@ -50,10 +49,6 @@ gulp.task(
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
// Don't compress running tests
...(env.isTestBuild() ? [] : ["compress-app"]),
- gulp.parallel(
- "gen-pages-prod",
- "gen-index-app-prod",
- "gen-service-worker-app-prod"
- )
+ gulp.parallel("gen-pages-app-prod", "gen-service-worker-app-prod")
)
);
diff --git a/build-scripts/gulp/cast.cjs b/build-scripts/gulp/cast.cjs
index 4dbc9b1eff..ae1a961139 100644
--- a/build-scripts/gulp/cast.cjs
+++ b/build-scripts/gulp/cast.cjs
@@ -19,7 +19,7 @@ gulp.task(
"translations-enable-merge-backend",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
"copy-static-cast",
- "gen-index-cast-dev",
+ "gen-pages-cast-dev",
env.useRollup() ? "rollup-dev-server-cast" : "webpack-dev-server-cast"
)
);
@@ -35,6 +35,6 @@ gulp.task(
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
"copy-static-cast",
env.useRollup() ? "rollup-prod-cast" : "webpack-prod-cast",
- "gen-index-cast-prod"
+ "gen-pages-cast-prod"
)
);
diff --git a/build-scripts/gulp/demo.cjs b/build-scripts/gulp/demo.cjs
index 65d8035c66..657dd35634 100644
--- a/build-scripts/gulp/demo.cjs
+++ b/build-scripts/gulp/demo.cjs
@@ -21,7 +21,7 @@ gulp.task(
"translations-enable-merge-backend",
gulp.parallel(
"gen-icons-json",
- "gen-index-demo-dev",
+ "gen-pages-demo-dev",
"build-translations",
"build-locale-data"
),
@@ -42,6 +42,6 @@ gulp.task(
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
"copy-static-demo",
env.useRollup() ? "rollup-prod-demo" : "webpack-prod-demo",
- "gen-index-demo-prod"
+ "gen-pages-demo-prod"
)
);
diff --git a/build-scripts/gulp/entry-html.cjs b/build-scripts/gulp/entry-html.cjs
index ffb569f7ed..53d7b24f1f 100644
--- a/build-scripts/gulp/entry-html.cjs
+++ b/build-scripts/gulp/entry-html.cjs
@@ -8,344 +8,223 @@ const paths = require("../paths.cjs");
const env = require("../env.cjs");
const { htmlMinifierOptions, terserOptions } = require("../bundle.cjs");
-const templatePath = (tpl) =>
- path.resolve(paths.polymer_dir, "src/html/", `${tpl}.html.template`);
-
-const readFile = (pth) => fs.readFileSync(pth).toString();
-
-const renderTemplate = (pth, data = {}, pathFunc = templatePath) => {
- const compiled = template(readFile(pathFunc(pth)));
+const renderTemplate = (templateFile, data = {}) => {
+ const compiled = template(
+ fs.readFileSync(templateFile, { encoding: "utf-8" })
+ );
return compiled({
...data,
useRollup: env.useRollup(),
useWDS: env.useWDS(),
- renderTemplate,
+ // Resolve any child/nested templates relative to the parent and pass the same data
+ renderTemplate: (childTemplate) =>
+ renderTemplate(
+ path.resolve(path.dirname(templateFile), childTemplate),
+ data
+ ),
});
};
-const renderDemoTemplate = (pth, data = {}) =>
- renderTemplate(pth, data, (tpl) =>
- path.resolve(paths.demo_dir, "src/html/", `${tpl}.html.template`)
- );
+const WRAP_TAGS = { ".js": "script", ".css": "style" };
-const renderCastTemplate = (pth, data = {}) =>
- renderTemplate(pth, data, (tpl) =>
- path.resolve(paths.cast_dir, "src/html/", `${tpl}.html.template`)
- );
-
-const renderGalleryTemplate = (pth, data = {}) =>
- renderTemplate(pth, data, (tpl) =>
- path.resolve(paths.gallery_dir, "src/html/", `${tpl}.html.template`)
- );
-
-const minifyHtml = (content) =>
- minify(content, {
+const minifyHtml = (content, ext) => {
+ const wrapTag = WRAP_TAGS[ext] || "";
+ const begTag = wrapTag && `<${wrapTag}>`;
+ const endTag = wrapTag && `${wrapTag}>`;
+ return minify(begTag + content + endTag, {
...htmlMinifierOptions,
conservativeCollapse: false,
minifyJS: terserOptions({
latestBuild: false, // Shared scripts should be ES5
isTestBuild: true, // Don't need source maps
}),
- });
+ }).then((wrapped) =>
+ wrapTag ? wrapped.slice(begTag.length, -endTag.length) : wrapped
+ );
+};
-const PAGES = ["onboarding", "authorize"];
+// Function to generate a dev task for each project's configuration
+// Note Currently WDS paths are hard-coded to only work for app
+const genPagesDevTask =
+ (
+ pageEntries,
+ inputRoot,
+ outputRoot,
+ useWDS = false,
+ inputSub = "src/html",
+ publicRoot = ""
+ ) =>
+ async () => {
+ for (const [page, entries] of Object.entries(pageEntries)) {
+ const content = renderTemplate(
+ path.resolve(inputRoot, inputSub, `${page}.template`),
+ {
+ latestEntryJS: entries.map((entry) =>
+ useWDS
+ ? `http://localhost:8000/src/entrypoints/${entry}.ts`
+ : `${publicRoot}/frontend_latest/${entry}.js`
+ ),
+ es5EntryJS: entries.map(
+ (entry) => `${publicRoot}/frontend_es5/${entry}.js`
+ ),
+ latestCustomPanelJS: useWDS
+ ? "http://localhost:8000/src/entrypoints/custom-panel.ts"
+ : `${publicRoot}/frontend_latest/custom-panel.js`,
+ es5CustomPanelJS: `${publicRoot}/frontend_es5/custom-panel.js`,
+ }
+ );
+ fs.outputFileSync(path.resolve(outputRoot, page), content);
+ }
+ };
-gulp.task("gen-pages-dev", (done) => {
- for (const page of PAGES) {
- const content = renderTemplate(page, {
- latestPageJS: `/frontend_latest/${page}.js`,
-
- es5PageJS: `/frontend_es5/${page}.js`,
- });
-
- fs.outputFileSync(
- path.resolve(paths.app_output_root, `${page}.html`),
- content
- );
- }
- done();
-});
-
-gulp.task("gen-pages-prod", async () => {
- const latestManifest = require(path.resolve(
- paths.app_output_latest,
- "manifest.json"
- ));
- const es5Manifest = require(path.resolve(
- paths.app_output_es5,
- "manifest.json"
- ));
-
- const minifiedHTML = [];
- for (const page of PAGES) {
- const content = renderTemplate(page, {
- latestPageJS: latestManifest[`${page}.js`],
- es5PageJS: es5Manifest[`${page}.js`],
- });
-
- minifiedHTML.push(
- minifyHtml(content).then((minified) =>
- fs.outputFileSync(
- path.resolve(paths.app_output_root, `${page}.html`),
- minified
+// Same as previous but for production builds
+// (includes minification and hashed file names from manifest)
+const genPagesProdTask =
+ (
+ pageEntries,
+ inputRoot,
+ outputRoot,
+ outputLatest,
+ outputES5,
+ inputSub = "src/html"
+ ) =>
+ async () => {
+ const latestManifest = require(path.resolve(outputLatest, "manifest.json"));
+ const es5Manifest = outputES5
+ ? require(path.resolve(outputES5, "manifest.json"))
+ : {};
+ const minifiedHTML = [];
+ for (const [page, entries] of Object.entries(pageEntries)) {
+ const content = renderTemplate(
+ path.resolve(inputRoot, inputSub, `${page}.template`),
+ {
+ latestEntryJS: entries.map((entry) => latestManifest[`${entry}.js`]),
+ es5EntryJS: entries.map((entry) => es5Manifest[`${entry}.js`]),
+ latestCustomPanelJS: latestManifest["custom-panel.js"],
+ es5CustomPanelJS: es5Manifest["custom-panel.js"],
+ }
+ );
+ minifiedHTML.push(
+ minifyHtml(content, path.extname(page)).then((minified) =>
+ fs.outputFileSync(path.resolve(outputRoot, page), minified)
)
- )
- );
- }
- await Promise.all(minifiedHTML);
-});
+ );
+ }
+ await Promise.all(minifiedHTML);
+ };
-gulp.task("gen-index-app-dev", (done) => {
- let latestAppJS;
- let latestCoreJS;
- let latestCustomPanelJS;
+// Map HTML pages to their required entrypoints
+const APP_PAGE_ENTRIES = {
+ "authorize.html": ["authorize"],
+ "onboarding.html": ["onboarding"],
+ "index.html": ["core", "app"],
+};
- if (env.useWDS()) {
- latestAppJS = "http://localhost:8000/src/entrypoints/app.ts";
- latestCoreJS = "http://localhost:8000/src/entrypoints/core.ts";
- latestCustomPanelJS =
- "http://localhost:8000/src/entrypoints/custom-panel.ts";
- } else {
- latestAppJS = "/frontend_latest/app.js";
- latestCoreJS = "/frontend_latest/core.js";
- latestCustomPanelJS = "/frontend_latest/custom-panel.js";
- }
+gulp.task(
+ "gen-pages-app-dev",
+ genPagesDevTask(
+ APP_PAGE_ENTRIES,
+ paths.polymer_dir,
+ paths.app_output_root,
+ env.useWDS()
+ )
+);
- const content = renderTemplate("index", {
- latestAppJS,
- latestCoreJS,
- latestCustomPanelJS,
-
- es5AppJS: "/frontend_es5/app.js",
- es5CoreJS: "/frontend_es5/core.js",
- es5CustomPanelJS: "/frontend_es5/custom-panel.js",
- }).replace(/#THEMEC/g, "{{ theme_color }}");
-
- fs.outputFileSync(path.resolve(paths.app_output_root, "index.html"), content);
- done();
-});
-
-gulp.task("gen-index-app-prod", async () => {
- const latestManifest = require(path.resolve(
+gulp.task(
+ "gen-pages-app-prod",
+ genPagesProdTask(
+ APP_PAGE_ENTRIES,
+ paths.polymer_dir,
+ paths.app_output_root,
paths.app_output_latest,
- "manifest.json"
- ));
- const es5Manifest = require(path.resolve(
- paths.app_output_es5,
- "manifest.json"
- ));
- const content = renderTemplate("index", {
- latestAppJS: latestManifest["app.js"],
- latestCoreJS: latestManifest["core.js"],
- latestCustomPanelJS: latestManifest["custom-panel.js"],
+ paths.app_output_es5
+ )
+);
- es5AppJS: es5Manifest["app.js"],
- es5CoreJS: es5Manifest["core.js"],
- es5CustomPanelJS: es5Manifest["custom-panel.js"],
- });
- const minified = (await minifyHtml(content)).replace(
- /#THEMEC/g,
- "{{ theme_color }}"
- );
+const CAST_PAGE_ENTRIES = {
+ "faq.html": ["launcher"],
+ "index.html": ["launcher"],
+ "media.html": ["media"],
+ "receiver.html": ["receiver"],
+};
- fs.outputFileSync(
- path.resolve(paths.app_output_root, "index.html"),
- minified
- );
-});
+gulp.task(
+ "gen-pages-cast-dev",
+ genPagesDevTask(CAST_PAGE_ENTRIES, paths.cast_dir, paths.cast_output_root)
+);
-gulp.task("gen-index-cast-dev", (done) => {
- const contentReceiver = renderCastTemplate("receiver", {
- latestReceiverJS: "/frontend_latest/receiver.js",
- });
- fs.outputFileSync(
- path.resolve(paths.cast_output_root, "receiver.html"),
- contentReceiver
- );
-
- const contentMedia = renderCastTemplate("media", {
- latestMediaJS: "/frontend_latest/media.js",
- es5MediaJS: "/frontend_es5/media.js",
- });
- fs.outputFileSync(
- path.resolve(paths.cast_output_root, "media.html"),
- contentMedia
- );
-
- const contentFAQ = renderCastTemplate("launcher-faq", {
- latestLauncherJS: "/frontend_latest/launcher.js",
- es5LauncherJS: "/frontend_es5/launcher.js",
- });
- fs.outputFileSync(
- path.resolve(paths.cast_output_root, "faq.html"),
- contentFAQ
- );
-
- const contentLauncher = renderCastTemplate("launcher", {
- latestLauncherJS: "/frontend_latest/launcher.js",
- es5LauncherJS: "/frontend_es5/launcher.js",
- });
- fs.outputFileSync(
- path.resolve(paths.cast_output_root, "index.html"),
- contentLauncher
- );
- done();
-});
-
-gulp.task("gen-index-cast-prod", (done) => {
- const latestManifest = require(path.resolve(
+gulp.task(
+ "gen-pages-cast-prod",
+ genPagesProdTask(
+ CAST_PAGE_ENTRIES,
+ paths.cast_dir,
+ paths.cast_output_root,
paths.cast_output_latest,
- "manifest.json"
- ));
- const es5Manifest = require(path.resolve(
- paths.cast_output_es5,
- "manifest.json"
- ));
+ paths.cast_output_es5
+ )
+);
- const contentReceiver = renderCastTemplate("receiver", {
- latestReceiverJS: latestManifest["receiver.js"],
- });
- fs.outputFileSync(
- path.resolve(paths.cast_output_root, "receiver.html"),
- contentReceiver
- );
+const DEMO_PAGE_ENTRIES = { "index.html": ["main"] };
- const contentMedia = renderCastTemplate("media", {
- latestMediaJS: latestManifest["media.js"],
- es5MediaJS: es5Manifest["media.js"],
- });
- fs.outputFileSync(
- path.resolve(paths.cast_output_root, "media.html"),
- contentMedia
- );
+gulp.task(
+ "gen-pages-demo-dev",
+ genPagesDevTask(DEMO_PAGE_ENTRIES, paths.demo_dir, paths.demo_output_root)
+);
- const contentFAQ = renderCastTemplate("launcher-faq", {
- latestLauncherJS: latestManifest["launcher.js"],
- es5LauncherJS: es5Manifest["launcher.js"],
- });
- fs.outputFileSync(
- path.resolve(paths.cast_output_root, "faq.html"),
- contentFAQ
- );
-
- const contentLauncher = renderCastTemplate("launcher", {
- latestLauncherJS: latestManifest["launcher.js"],
- es5LauncherJS: es5Manifest["launcher.js"],
- });
- fs.outputFileSync(
- path.resolve(paths.cast_output_root, "index.html"),
- contentLauncher
- );
- done();
-});
-
-gulp.task("gen-index-demo-dev", (done) => {
- const content = renderDemoTemplate("index", {
- latestDemoJS: "/frontend_latest/main.js",
-
- es5DemoJS: "/frontend_es5/main.js",
- });
-
- fs.outputFileSync(
- path.resolve(paths.demo_output_root, "index.html"),
- content
- );
- done();
-});
-
-gulp.task("gen-index-demo-prod", async () => {
- const latestManifest = require(path.resolve(
+gulp.task(
+ "gen-pages-demo-prod",
+ genPagesProdTask(
+ DEMO_PAGE_ENTRIES,
+ paths.demo_dir,
+ paths.demo_output_root,
paths.demo_output_latest,
- "manifest.json"
- ));
- const es5Manifest = require(path.resolve(
- paths.demo_output_es5,
- "manifest.json"
- ));
- const content = renderDemoTemplate("index", {
- latestDemoJS: latestManifest["main.js"],
+ paths.demo_output_es5
+ )
+);
- es5DemoJS: es5Manifest["main.js"],
- });
- const minified = await minifyHtml(content);
+const GALLERY_PAGE_ENTRIES = { "index.html": ["entrypoint"] };
- fs.outputFileSync(
- path.resolve(paths.demo_output_root, "index.html"),
- minified
- );
-});
+gulp.task(
+ "gen-pages-gallery-dev",
+ genPagesDevTask(
+ GALLERY_PAGE_ENTRIES,
+ paths.gallery_dir,
+ paths.gallery_output_root
+ )
+);
-gulp.task("gen-index-gallery-dev", (done) => {
- const content = renderGalleryTemplate("index", {
- latestGalleryJS: "./frontend_latest/entrypoint.js",
- });
+gulp.task(
+ "gen-pages-gallery-prod",
+ genPagesProdTask(
+ GALLERY_PAGE_ENTRIES,
+ paths.gallery_dir,
+ paths.gallery_output_root,
+ paths.gallery_output_latest
+ )
+);
- fs.outputFileSync(
- path.resolve(paths.gallery_output_root, "index.html"),
- content
- );
- done();
-});
+const HASSIO_PAGE_ENTRIES = { "entrypoint.js": ["entrypoint"] };
-gulp.task("gen-index-gallery-prod", async () => {
- const latestManifest = require(path.resolve(
- paths.gallery_output_latest,
- "manifest.json"
- ));
- const content = renderGalleryTemplate("index", {
- latestGalleryJS: latestManifest["entrypoint.js"],
- });
- const minified = await minifyHtml(content);
+gulp.task(
+ "gen-pages-hassio-dev",
+ genPagesDevTask(
+ HASSIO_PAGE_ENTRIES,
+ paths.hassio_dir,
+ paths.hassio_output_root,
+ undefined,
+ "src",
+ paths.hassio_publicPath
+ )
+);
- fs.outputFileSync(
- path.resolve(paths.gallery_output_root, "index.html"),
- minified
- );
-});
-
-gulp.task("gen-index-hassio-dev", async () => {
- writeHassioEntrypoint(
- `${paths.hassio_publicPath}/frontend_latest/entrypoint.js`,
- `${paths.hassio_publicPath}/frontend_es5/entrypoint.js`
- );
-});
-
-gulp.task("gen-index-hassio-prod", async () => {
- const latestManifest = require(path.resolve(
+gulp.task(
+ "gen-pages-hassio-prod",
+ genPagesProdTask(
+ HASSIO_PAGE_ENTRIES,
+ paths.hassio_dir,
+ paths.hassio_output_root,
paths.hassio_output_latest,
- "manifest.json"
- ));
- const es5Manifest = require(path.resolve(
paths.hassio_output_es5,
- "manifest.json"
- ));
- writeHassioEntrypoint(
- latestManifest["entrypoint.js"],
- es5Manifest["entrypoint.js"]
- );
-});
-
-function writeHassioEntrypoint(latestEntrypoint, es5Entrypoint) {
- fs.mkdirSync(paths.hassio_output_root, { recursive: true });
- // Safari 12 and below does not have a compliant ES2015 implementation of template literals, so we ship ES5
- fs.writeFileSync(
- path.resolve(paths.hassio_output_root, "entrypoint.js"),
- `
-function loadES5() {
- var el = document.createElement('script');
- el.src = '${es5Entrypoint}';
- document.body.appendChild(el);
-}
-if (/.*Version\\/(?:11|12)(?:\\.\\d+)*.*Safari\\//.test(navigator.userAgent)) {
- loadES5();
-} else {
- try {
- new Function("import('${latestEntrypoint}')")();
- } catch (err) {
- loadES5();
- }
-}
- `,
- { encoding: "utf-8" }
- );
-}
+ "src"
+ )
+);
diff --git a/build-scripts/gulp/gallery.cjs b/build-scripts/gulp/gallery.cjs
index 74a752fb5d..3670eb18e3 100644
--- a/build-scripts/gulp/gallery.cjs
+++ b/build-scripts/gulp/gallery.cjs
@@ -159,7 +159,7 @@ gulp.task(
"gather-gallery-pages"
),
"copy-static-gallery",
- "gen-index-gallery-dev",
+ "gen-pages-gallery-dev",
gulp.parallel(
env.useRollup()
? "rollup-dev-server-gallery"
@@ -193,6 +193,6 @@ gulp.task(
),
"copy-static-gallery",
env.useRollup() ? "rollup-prod-gallery" : "webpack-prod-gallery",
- "gen-index-gallery-prod"
+ "gen-pages-gallery-prod"
)
);
diff --git a/build-scripts/gulp/hassio.cjs b/build-scripts/gulp/hassio.cjs
index 562ed3b646..a958cb0365 100644
--- a/build-scripts/gulp/hassio.cjs
+++ b/build-scripts/gulp/hassio.cjs
@@ -17,7 +17,7 @@ gulp.task(
},
"clean-hassio",
"gen-dummy-icons-json",
- "gen-index-hassio-dev",
+ "gen-pages-hassio-dev",
"build-supervisor-translations",
"copy-translations-supervisor",
"build-locale-data",
@@ -39,7 +39,7 @@ gulp.task(
"build-locale-data",
"copy-locale-data-supervisor",
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
- "gen-index-hassio-prod",
+ "gen-pages-hassio-prod",
...// Don't compress running tests
(env.isTestBuild() ? [] : ["compress-hassio"])
)
diff --git a/cast/src/html/_social_meta.html.template b/cast/src/html/_social_meta.html.template
new file mode 100644
index 0000000000..d3ee681ed3
--- /dev/null
+++ b/cast/src/html/_social_meta.html.template
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cast/src/html/launcher-faq.html.template b/cast/src/html/faq.html.template
similarity index 95%
rename from cast/src/html/launcher-faq.html.template
rename to cast/src/html/faq.html.template
index 7ba706c16c..c67a5b477a 100644
--- a/cast/src/html/launcher-faq.html.template
+++ b/cast/src/html/faq.html.template
@@ -3,7 +3,7 @@
Home Assistant Cast - FAQ
- <%= renderTemplate('_style_base') %>
+ <%= renderTemplate("../../../src/html/_style_base.html.template") %>
+ <%= renderTemplate("_social_meta.html.template") %>
+
+
+ <%= renderTemplate("../../../src/html/_js_base.html.template") %>
+
+
+ <%= renderTemplate("../../../src/html/_script_load_es5.html.template") %>
+
+
+