From f8a7737eb998df1194ac07355df22be84262dea2 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 30 Sep 2022 08:38:56 +0200 Subject: [PATCH 01/16] Align with backend statistics WS API changes (#13913) Align with backend statists WS API changes --- src/components/chart/statistics-chart.ts | 4 ++-- src/components/entity/ha-statistic-picker.ts | 2 +- src/data/energy.ts | 4 ++-- src/data/recorder.ts | 6 +++--- .../config/energy/dialogs/dialog-energy-gas-settings.ts | 4 ++-- .../statistics/developer-tools-statistics.ts | 4 ++-- .../statistics/dialog-statistics-adjust-sum.ts | 6 +++--- .../config-elements/hui-statistics-graph-card-editor.ts | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/components/chart/statistics-chart.ts b/src/components/chart/statistics-chart.ts index ea566c9fc7..c96c02055a 100644 --- a/src/components/chart/statistics-chart.ts +++ b/src/components/chart/statistics-chart.ts @@ -258,8 +258,8 @@ class StatisticsChart extends LitElement { if (!this.unit) { if (unit === undefined) { - unit = meta?.display_unit_of_measurement; - } else if (unit !== meta?.display_unit_of_measurement) { + unit = meta?.state_unit_of_measurement; + } else if (unit !== meta?.state_unit_of_measurement) { unit = null; } } diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index ebf129efaa..84e071f87f 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -121,7 +121,7 @@ export class HaStatisticPicker extends LitElement { if (includeDisplayUnitOfMeasurement) { const includeUnits = ensureArray(includeDisplayUnitOfMeasurement); statisticIds = statisticIds.filter((meta) => - includeUnits.includes(meta.display_unit_of_measurement) + includeUnits.includes(meta.state_unit_of_measurement) ); } diff --git a/src/data/energy.ts b/src/data/energy.ts index 8420419978..8078166963 100644 --- a/src/data/energy.ts +++ b/src/data/energy.ts @@ -642,8 +642,8 @@ export const getEnergyGasUnit = ( continue; } const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from]; - if (statisticIdWithMeta?.display_unit_of_measurement) { - return statisticIdWithMeta.display_unit_of_measurement; + if (statisticIdWithMeta?.state_unit_of_measurement) { + return statisticIdWithMeta.state_unit_of_measurement; } } return undefined; diff --git a/src/data/recorder.ts b/src/data/recorder.ts index c13e8bc210..578b709e12 100644 --- a/src/data/recorder.ts +++ b/src/data/recorder.ts @@ -20,7 +20,7 @@ export interface StatisticValue { } export interface StatisticsMetaData { - display_unit_of_measurement: string; + state_unit_of_measurement: string; statistics_unit_of_measurement: string; statistic_id: string; source: string; @@ -254,14 +254,14 @@ export const adjustStatisticsSum = ( statistic_id: string, start_time: string, adjustment: number, - display_unit: string + adjustment_unit_of_measurement: string ): Promise => hass.callWS({ type: "recorder/adjust_sum_statistics", statistic_id, start_time, adjustment, - display_unit, + adjustment_unit_of_measurement, }); export const getStatisticLabel = ( diff --git a/src/panels/config/energy/dialogs/dialog-energy-gas-settings.ts b/src/panels/config/energy/dialogs/dialog-energy-gas-settings.ts index e98621f903..e2bacb7300 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-gas-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-gas-settings.ts @@ -49,7 +49,7 @@ export class DialogEnergyGasSettings this._source = params.source ? { ...params.source } : emptyGasEnergyPreference(); - this._pickedDisplayUnit = params.metadata?.display_unit_of_measurement; + this._pickedDisplayUnit = params.metadata?.state_unit_of_measurement; this._costs = this._source.entity_energy_price ? "entity" : this._source.number_energy_price @@ -269,7 +269,7 @@ export class DialogEnergyGasSettings } else { this._pickedDisplayUnit = ( await getStatisticMetadata(this.hass, [ev.detail.value]) - )[0]?.display_unit_of_measurement; + )[0]?.state_unit_of_measurement; } } else { this._pickedDisplayUnit = undefined; diff --git a/src/panels/developer-tools/statistics/developer-tools-statistics.ts b/src/panels/developer-tools/statistics/developer-tools-statistics.ts index 8ea66e1083..d483fc84ce 100644 --- a/src/panels/developer-tools/statistics/developer-tools-statistics.ts +++ b/src/panels/developer-tools/statistics/developer-tools-statistics.ts @@ -74,7 +74,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { hidden: this.narrow, width: "20%", }, - display_unit_of_measurement: { + state_unit_of_measurement: { title: "Display unit", sortable: true, filterable: true, @@ -220,7 +220,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { this._data.push({ statistic_id: statisticId, statistics_unit_of_measurement: "", - display_unit_of_measurement: "", + state_unit_of_measurement: "", source: "", state: this.hass.states[statisticId], issues: issues[statisticId], diff --git a/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts b/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts index 8598bf54f1..c00b5dc5fd 100644 --- a/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts +++ b/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts @@ -135,7 +135,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { } else { const data = this._stats5min.length >= 2 ? this._stats5min : this._statsHour; - const unit = this._params!.statistic.display_unit_of_measurement; + const unit = this._params!.statistic.state_unit_of_measurement; const rows: TemplateResult[] = []; for (let i = 1; i < data.length; i++) { const stat = data[i]; @@ -221,7 +221,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { label="New Value" .hass=${this.hass} .selector=${this._amountSelector( - this._params!.statistic.display_unit_of_measurement + this._params!.statistic.state_unit_of_measurement )} .value=${this._amount} .disabled=${this._busy} @@ -306,7 +306,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { this._params!.statistic.statistic_id, this._chosenStat!.start, this._amount! - this._origAmount!, - this._params!.statistic.display_unit_of_measurement + this._params!.statistic.state_unit_of_measurement ); } catch (err: any) { this._busy = false; diff --git a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts index 606b1d2166..8933560cd4 100644 --- a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts @@ -205,7 +205,7 @@ export class HuiStatisticsGraphCardEditor ...this._config, stat_types: configured_stat_types, }; - const displayUnit = this._metaDatas?.[0]?.display_unit_of_measurement; + const displayUnit = this._metaDatas?.[0]?.state_unit_of_measurement; return html` Date: Fri, 30 Sep 2022 11:27:59 +0200 Subject: [PATCH 02/16] Remove test devices from move datadisk dialog (#13927) --- src/panels/config/storage/dialog-move-datadisk.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/panels/config/storage/dialog-move-datadisk.ts b/src/panels/config/storage/dialog-move-datadisk.ts index 40a55395f0..dc253095dc 100644 --- a/src/panels/config/storage/dialog-move-datadisk.ts +++ b/src/panels/config/storage/dialog-move-datadisk.ts @@ -138,10 +138,6 @@ class MoveDatadiskDialog extends LitElement { ${device} ` )} - Test - Test - Test - Test Date: Fri, 30 Sep 2022 14:41:09 +0200 Subject: [PATCH 03/16] Remove inert property on combobox overlay when items change (#13928) --- src/components/ha-combo-box.ts | 31 +++++++++++++++++++++----- src/components/ha-icon-picker.ts | 2 +- src/components/ha-navigation-picker.ts | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/components/ha-combo-box.ts b/src/components/ha-combo-box.ts index 3b98083608..adbb06a1bd 100644 --- a/src/components/ha-combo-box.ts +++ b/src/components/ha-combo-box.ts @@ -8,7 +8,14 @@ import type { ComboBoxLightValueChangedEvent, } from "@vaadin/combo-box/vaadin-combo-box-light"; import { registerStyles } from "@vaadin/vaadin-themable-mixin/register-styles"; -import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, +} from "lit"; import { ComboBoxLitRenderer, comboBoxRenderer } from "@vaadin/combo-box/lit"; import { customElement, property, query } from "lit/decorators"; import { ifDefined } from "lit/directives/if-defined"; @@ -225,11 +232,13 @@ export class HaComboBox extends LitElement { // @ts-ignore fireEvent(this, ev.type, ev.detail); - if ( - opened && - "MutationObserver" in window && - !this._overlayMutationObserver - ) { + if (opened) { + this.removeInertOnOverlay(); + } + } + + private removeInertOnOverlay() { + if ("MutationObserver" in window && !this._overlayMutationObserver) { const overlay = document.querySelector( "vaadin-combo-box-overlay" ); @@ -268,6 +277,16 @@ export class HaComboBox extends LitElement { } } + updated(changedProps: PropertyValues) { + super.updated(changedProps); + if ( + changedProps.has("filteredItems") || + (changedProps.has("items") && this.opened) + ) { + this.removeInertOnOverlay(); + } + } + private _filterChanged(ev: ComboBoxLightFilterChangedEvent) { // @ts-ignore fireEvent(this, ev.type, ev.detail, { composed: false }); diff --git a/src/components/ha-icon-picker.ts b/src/components/ha-icon-picker.ts index 3f43d497e0..a424ffeda1 100644 --- a/src/components/ha-icon-picker.ts +++ b/src/components/ha-icon-picker.ts @@ -13,7 +13,7 @@ type IconItem = { icon: string; keywords: string[]; }; -let iconItems: IconItem[] = [{ icon: "", keywords: [] }]; +let iconItems: IconItem[] = []; let iconLoaded = false; // eslint-disable-next-line lit/prefer-static-styles diff --git a/src/components/ha-navigation-picker.ts b/src/components/ha-navigation-picker.ts index 84c1084b30..a9226d1e5e 100644 --- a/src/components/ha-navigation-picker.ts +++ b/src/components/ha-navigation-picker.ts @@ -20,7 +20,7 @@ type NavigationItem = { title: string; }; -const DEFAULT_ITEMS: NavigationItem[] = [{ path: "", icon: "", title: "" }]; +const DEFAULT_ITEMS: NavigationItem[] = []; // eslint-disable-next-line lit/prefer-static-styles const rowRenderer: ComboBoxLitRenderer = (item) => html` From b9395e1c97661402ee959b38d59c1166fa6bf200 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 30 Sep 2022 14:50:01 +0200 Subject: [PATCH 04/16] Add support for brand images (#13930) --- src/panels/config/integrations/dialog-add-integration.ts | 6 +++++- .../config/integrations/ha-integration-list-item.ts | 3 +++ src/util/brands-url.ts | 9 ++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/panels/config/integrations/dialog-add-integration.ts b/src/panels/config/integrations/dialog-add-integration.ts index 8df3b20903..4ef11ce6cb 100644 --- a/src/panels/config/integrations/dialog-add-integration.ts +++ b/src/panels/config/integrations/dialog-add-integration.ts @@ -385,7 +385,11 @@ class AddIntegrationDialog extends LitElement { return html``; } return html` - + `; }; diff --git a/src/panels/config/integrations/ha-integration-list-item.ts b/src/panels/config/integrations/ha-integration-list-item.ts index 714f15d667..b117d131a9 100644 --- a/src/panels/config/integrations/ha-integration-list-item.ts +++ b/src/panels/config/integrations/ha-integration-list-item.ts @@ -22,6 +22,8 @@ export class HaIntegrationListItem extends ListItemBase { @property({ type: Boolean }) hasMeta = true; + @property({ type: Boolean }) brand = false; + renderSingleLine() { if (!this.integration) { return html``; @@ -51,6 +53,7 @@ export class HaIntegrationListItem extends ListItemBase { type: "icon", useFallback: true, darkOptimized: this.hass.themes?.darkMode, + brand: this.brand, })} referrerpolicy="no-referrer" /> diff --git a/src/util/brands-url.ts b/src/util/brands-url.ts index 7b0405b696..e5afa95320 100644 --- a/src/util/brands-url.ts +++ b/src/util/brands-url.ts @@ -3,6 +3,7 @@ export interface BrandsOptions { type: "icon" | "logo" | "icon@2x" | "logo@2x"; useFallback?: boolean; darkOptimized?: boolean; + brand?: boolean; } export interface HardwareBrandsOptions { @@ -13,9 +14,11 @@ export interface HardwareBrandsOptions { } export const brandsUrl = (options: BrandsOptions): string => - `https://brands.home-assistant.io/${options.useFallback ? "_/" : ""}${ - options.domain - }/${options.darkOptimized ? "dark_" : ""}${options.type}.png`; + `https://brands.home-assistant.io/${options.brand ? "brands/" : ""}${ + options.useFallback ? "_/" : "" + }${options.domain}/${options.darkOptimized ? "dark_" : ""}${ + options.type + }.png`; export const hardwareBrandsUrl = (options: HardwareBrandsOptions): string => `https://brands.home-assistant.io/hardware/${options.category}/${ From 2a6ef9b95524f86eac30a8908578912834e65958 Mon Sep 17 00:00:00 2001 From: amitfin Date: Fri, 30 Sep 2022 18:21:54 +0300 Subject: [PATCH 05/16] Read correctly the minutes of a schedule (#13929) --- .../config/helpers/forms/ha-schedule-form.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/panels/config/helpers/forms/ha-schedule-form.ts b/src/panels/config/helpers/forms/ha-schedule-form.ts index c28e90f8f0..7aa682ae5c 100644 --- a/src/panels/config/helpers/forms/ha-schedule-form.ts +++ b/src/panels/config/helpers/forms/ha-schedule-form.ts @@ -219,19 +219,18 @@ class HaScheduleForm extends LitElement { const start = new Date(); start.setDate(start.getDate() + distance); + const start_tokens = item.from.split(":"); start.setHours( - parseInt(item.from.slice(0, 2)), - parseInt(item.from.slice(-2)) + parseInt(start_tokens[0]), + parseInt(start_tokens[1]), + 0, + 0 ); const end = new Date(); end.setDate(end.getDate() + distance); - end.setHours( - parseInt(item.to.slice(0, 2)), - parseInt(item.to.slice(-2)), - 0, - 0 - ); + const end_tokens = item.to.split(":"); + end.setHours(parseInt(end_tokens[0]), parseInt(end_tokens[1]), 0, 0); events.push({ id: `${day}-${index}`, From 6a3ac9116e1041b733f7e99b6104ae9bc4e87cdb Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 30 Sep 2022 17:29:29 +0200 Subject: [PATCH 06/16] Add yaml mode to view editor (#13926) --- .../view-editor/hui-dialog-edit-view.ts | 296 +++++++++++++----- src/translations/en.json | 4 +- 2 files changed, 214 insertions(+), 86 deletions(-) diff --git a/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts b/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts index 6b54de03dd..a9e4e4f45c 100644 --- a/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts +++ b/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts @@ -1,13 +1,26 @@ import "@material/mwc-button"; +import { ActionDetail } from "@material/mwc-list"; +import { mdiCheck, mdiDotsVertical } from "@mdi/js"; import "@polymer/paper-tabs/paper-tab"; import "@polymer/paper-tabs/paper-tabs"; -import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; -import { customElement, property, state } from "lit/decorators"; +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, +} from "lit"; +import { customElement, property, query, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event"; +import { stopPropagation } from "../../../../common/dom/stop_propagation"; import { navigate } from "../../../../common/navigate"; +import { deepEqual } from "../../../../common/util/deep-equal"; +import "../../../../components/ha-alert"; import "../../../../components/ha-circular-progress"; import "../../../../components/ha-dialog"; -import "../../../../components/ha-alert"; +import { HaYamlEditor } from "../../../../components/ha-yaml-editor"; import type { LovelaceBadgeConfig, LovelaceCardConfig, @@ -20,6 +33,11 @@ import { import { haStyleDialog } from "../../../../resources/styles"; import type { HomeAssistant } from "../../../../types"; import "../../components/hui-entity-editor"; +import { + DEFAULT_VIEW_LAYOUT, + PANEL_VIEW_LAYOUT, + VIEWS_NO_BADGE_SUPPORT, +} from "../../views/const"; import { addView, deleteView, replaceView } from "../config-util"; import "../hui-badge-preview"; import { processEditorEntities } from "../process-editor-entities"; @@ -31,12 +49,6 @@ import { import "./hui-view-editor"; import "./hui-view-visibility-editor"; import { EditViewDialogParams } from "./show-edit-view-dialog"; -import { - DEFAULT_VIEW_LAYOUT, - PANEL_VIEW_LAYOUT, - VIEWS_NO_BADGE_SUPPORT, -} from "../../views/const"; -import { deepEqual } from "../../../../common/util/deep-equal"; @customElement("hui-dialog-edit-view") export class HuiDialogEditView extends LitElement { @@ -56,6 +68,10 @@ export class HuiDialogEditView extends LitElement { @state() private _dirty = false; + @state() private _yamlMode = false; + + @query("ha-yaml-editor") private _editor?: HaYamlEditor; + private _curTabIndex = 0; get _type(): string { @@ -67,6 +83,16 @@ export class HuiDialogEditView extends LitElement { : this._config.type || DEFAULT_VIEW_LAYOUT; } + protected updated(changedProperties: PropertyValues) { + if (this._yamlMode && changedProperties.has("_yamlMode")) { + const viewConfig = { + ...this._config, + badges: this._badges, + }; + this._editor?.setValue(viewConfig); + } + } + public showDialog(params: EditViewDialogParams): void { this._params = params; @@ -89,6 +115,7 @@ export class HuiDialogEditView extends LitElement { this._params = undefined; this._config = {}; this._badges = []; + this._yamlMode = false; this._dirty = false; fireEvent(this, "dialog-closed", { dialog: this.localName }); } @@ -111,62 +138,74 @@ export class HuiDialogEditView extends LitElement { } let content; - switch (this._curTab) { - case "tab-settings": - content = html` - - `; - break; - case "tab-badges": - content = html` - ${this._badges?.length - ? html` - ${VIEWS_NO_BADGE_SUPPORT.includes(this._type) - ? html` - - ${this.hass!.localize( - "ui.panel.lovelace.editor.edit_badges.view_no_badges" - )} - - ` - : ""} -
- ${this._badges.map( - (badgeConfig) => html` - - ` - )} -
- ` - : ""} - - `; - break; - case "tab-visibility": - content = html` - - `; - break; - case "tab-cards": - content = html` Cards `; - break; + + if (this._yamlMode) { + content = html` + + `; + } else { + switch (this._curTab) { + case "tab-settings": + content = html` + + `; + break; + case "tab-badges": + content = html` + ${this._badges?.length + ? html` + ${VIEWS_NO_BADGE_SUPPORT.includes(this._type) + ? html` + + ${this.hass!.localize( + "ui.panel.lovelace.editor.edit_badges.view_no_badges" + )} + + ` + : ""} +
+ ${this._badges.map( + (badgeConfig) => html` + + ` + )} +
+ ` + : ""} + + `; + break; + case "tab-visibility": + content = html` + + `; + break; + case "tab-cards": + content = html` Cards `; + break; + } } + return html`

${this._viewConfigTitle}

- - ${this.hass!.localize( - "ui.panel.lovelace.editor.edit_view.tab_settings" - )} - ${this.hass!.localize( - "ui.panel.lovelace.editor.edit_view.tab_badges" - )} - ${this.hass!.localize( - "ui.panel.lovelace.editor.edit_view.tab_visibility" - )} - + + + ${this.hass!.localize( + "ui.panel.lovelace.editor.edit_view.edit_ui" + )} + ${!this._yamlMode + ? html`` + : ``} + + + + ${this.hass!.localize( + "ui.panel.lovelace.editor.edit_view.edit_yaml" + )} + ${this._yamlMode + ? html`` + : ``} + + + ${!this._yamlMode + ? html` + ${this.hass!.localize( + "ui.panel.lovelace.editor.edit_view.tab_settings" + )} + ${this.hass!.localize( + "ui.panel.lovelace.editor.edit_view.tab_badges" + )} + ${this.hass!.localize( + "ui.panel.lovelace.editor.edit_view.tab_visibility" + )} + ` + : ""}
${content} ${this._params.viewIndex !== undefined @@ -235,6 +318,19 @@ export class HuiDialogEditView extends LitElement { `; } + private async _handleAction(ev: CustomEvent) { + ev.stopPropagation(); + ev.preventDefault(); + switch (ev.detail.index) { + case 0: + this._yamlMode = false; + break; + case 1: + this._yamlMode = true; + break; + } + } + private async _delete(): Promise { if (!this._params) { return; @@ -348,6 +444,17 @@ export class HuiDialogEditView extends LitElement { this._dirty = true; } + private _viewYamlChanged(ev: CustomEvent) { + ev.stopPropagation(); + if (!ev.detail.isValid) { + return; + } + const { badges = [], ...config } = ev.detail.value; + this._config = config; + this._badges = badges; + this._dirty = true; + } + private _isConfigChanged(): boolean { return ( this._creatingView || @@ -366,6 +473,9 @@ export class HuiDialogEditView extends LitElement { return [ haStyleDialog, css` + ha-dialog.yaml-mode { + --dialog-content-padding: 0; + } h2 { display: block; color: var(--primary-text-color); @@ -421,6 +531,22 @@ export class HuiDialogEditView extends LitElement { ha-circular-progress[active] { display: block; } + ha-button-menu { + color: var(--secondary-text-color); + position: absolute; + right: 16px; + top: 14px; + inset-inline-end: 16px; + inset-inline-start: initial; + direction: var(--direction); + } + ha-button-menu, + ha-icon-button { + --mdc-theme-text-primary-on-background: var(--primary-text-color); + } + .selected_menu_item { + color: var(--primary-color); + } .hidden { display: none; } diff --git a/src/translations/en.json b/src/translations/en.json index 3aeb0dffa6..0814955467 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3805,7 +3805,9 @@ "subview": "Subview", "subview_helper": "Subviews don't appear in tabs and have a back button.", "back_path": "Back path (optional)", - "back_path_helper": "Only for subviews. If empty, clicking on back button will go to the previous page." + "back_path_helper": "Only for subviews. If empty, clicking on back button will go to the previous page.", + "edit_ui": "Edit in visual editor", + "edit_yaml": "Edit in YAML" }, "edit_badges": { "view_no_badges": "Badges are not be supported by the current view type." From 9811f2681c674f4703959ed31692640b19fe3a7e Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 30 Sep 2022 17:37:09 +0200 Subject: [PATCH 07/16] Add add device fab to devices page (#13931) --- .../devices/ha-config-devices-dashboard.ts | 71 +++++++++---------- .../integrations/dialog-add-integration.ts | 6 +- src/translations/en.json | 1 + 3 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index 4ef701aba1..078ec02f79 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -38,6 +38,7 @@ import { HomeAssistant, Route } from "../../../types"; import { configSections } from "../ha-panel-config"; import "../integrations/ha-integration-overflow-menu"; import { showZWaveJSAddNodeDialog } from "../integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node"; +import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog"; interface DeviceRowData extends DeviceRegistryEntry { device?: DeviceRowData; @@ -363,16 +364,15 @@ export class HaConfigDeviceDashboard extends LitElement { } protected render(): TemplateResult { - const { devicesOutput, filteredConfigEntry } = - this._devicesAndFilterDomains( - this.devices, - this.entries, - this.entities, - this.areas, - this._searchParms, - this._showDisabled, - this.hass.localize - ); + const { devicesOutput } = this._devicesAndFilterDomains( + this.devices, + this.entries, + this.entities, + this.areas, + this._searchParms, + this._showDisabled, + this.hass.localize + ); const activeFilters = this._activeFilters( this.entries, this._searchParms, @@ -405,39 +405,21 @@ export class HaConfigDeviceDashboard extends LitElement { @search-changed=${this._handleSearchChange} @row-click=${this._handleRowClicked} clickable - .hasFab=${filteredConfigEntry && - (filteredConfigEntry.domain === "zha" || - filteredConfigEntry.domain === "zwave_js")} + hasFab > - ${!filteredConfigEntry - ? "" - : filteredConfigEntry.domain === "zwave_js" - ? html` - - - - ` - : filteredConfigEntry.domain === "zha" - ? html` - - - - ` - : html``} + + + Date: Fri, 30 Sep 2022 20:52:20 +0200 Subject: [PATCH 08/16] Link google assistant, alexa and cloud to cloud config (#13933) --- .../integrations/dialog-add-integration.ts | 22 +++++++++++++------ .../integrations/ha-domain-integrations.ts | 18 ++++++++++++--- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/panels/config/integrations/dialog-add-integration.ts b/src/panels/config/integrations/dialog-add-integration.ts index bd96196143..f023eee2ae 100644 --- a/src/panels/config/integrations/dialog-add-integration.ts +++ b/src/panels/config/integrations/dialog-add-integration.ts @@ -296,14 +296,13 @@ class AddIntegrationDialog extends LitElement { scrimClickAction escapeKeyAction hideActions - .heading=${this._pickedBrand - ? true - : createCloseHeading( - this.hass, - this.hass.localize("ui.panel.config.integrations.new") - )} + .heading=${createCloseHeading( + this.hass, + this.hass.localize("ui.panel.config.integrations.new") + )} > - ${this._pickedBrand + ${this._pickedBrand && + (!this._integrations || this._pickedBrand in this._integrations) ? html`
Date: Fri, 30 Sep 2022 22:23:55 +0200 Subject: [PATCH 09/16] Remove back path from UI (#13936) Remove back path from UI as it can be edited with yaml editor --- .../editor/view-editor/hui-view-editor.ts | 27 ++----------------- src/translations/en.json | 2 -- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts index e25345e36f..74b017bea6 100644 --- a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts +++ b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts @@ -33,7 +33,7 @@ export class HuiViewEditor extends LitElement { private _suggestedPath = false; private _schema = memoizeOne( - (localize: LocalizeFunc, subview: boolean, showAdvanced: boolean) => + (localize: LocalizeFunc) => [ { name: "title", selector: { text: {} } }, { @@ -69,14 +69,6 @@ export class HuiViewEditor extends LitElement { boolean: {}, }, }, - ...(subview && showAdvanced - ? [ - { - name: "back_path", - selector: { navigation: {} }, - }, - ] - : []), ] as const ); @@ -98,11 +90,7 @@ export class HuiViewEditor extends LitElement { return html``; } - const schema = this._schema( - this.hass.localize, - this._config.subview ?? false, - this.hass.userData?.showAdvanced ?? false - ); + const schema = this._schema(this.hass.localize); const data = { theme: "Backend-selected", @@ -128,9 +116,6 @@ export class HuiViewEditor extends LitElement { if (config.type === "masonry") { delete config.type; } - if (!config.subview) { - delete config.back_path; - } if ( this.isNew && @@ -155,10 +140,6 @@ export class HuiViewEditor extends LitElement { return this.hass.localize("ui.panel.lovelace.editor.edit_view.type"); case "subview": return this.hass.localize("ui.panel.lovelace.editor.edit_view.subview"); - case "back_path": - return this.hass.localize( - "ui.panel.lovelace.editor.edit_view.back_path" - ); default: return this.hass!.localize( `ui.panel.lovelace.editor.card.generic.${schema.name}` @@ -174,10 +155,6 @@ export class HuiViewEditor extends LitElement { return this.hass.localize( "ui.panel.lovelace.editor.edit_view.subview_helper" ); - case "back_path": - return this.hass.localize( - "ui.panel.lovelace.editor.edit_view.back_path_helper" - ); default: return undefined; } diff --git a/src/translations/en.json b/src/translations/en.json index 186604a1b6..b4426b719e 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3805,8 +3805,6 @@ }, "subview": "Subview", "subview_helper": "Subviews don't appear in tabs and have a back button.", - "back_path": "Back path (optional)", - "back_path_helper": "Only for subviews. If empty, clicking on back button will go to the previous page.", "edit_ui": "Edit in visual editor", "edit_yaml": "Edit in YAML" }, From 6393944a1b1eebdc4bdce0609cbcbf5218923faa Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sat, 1 Oct 2022 18:55:05 +0200 Subject: [PATCH 10/16] Adapt to removal of statistics state_unit_of_measurement (#13935) * Adapt to removal of statistics state_unit_of_measurement * Tweak --- src/components/chart/statistics-chart.ts | 8 ++- src/components/entity/ha-statistic-picker.ts | 61 ++++++++----------- src/components/entity/ha-statistics-picker.ts | 19 +++--- src/data/energy.ts | 42 ++++++------- src/data/recorder.ts | 20 +++++- .../components/ha-energy-gas-settings.ts | 6 +- .../dialogs/dialog-energy-battery-settings.ts | 9 +-- .../dialogs/dialog-energy-device-settings.ts | 6 +- .../dialogs/dialog-energy-gas-settings.ts | 43 ++++++------- .../dialog-energy-grid-flow-settings.ts | 6 +- .../dialogs/dialog-energy-solar-settings.ts | 6 +- .../energy/dialogs/show-dialogs-energy.ts | 4 +- .../statistics/developer-tools-statistics.ts | 8 +-- .../dialog-statistics-adjust-sum.ts | 25 ++++++-- .../energy/hui-energy-distribution-card.ts | 7 ++- .../cards/energy/hui-energy-gas-graph-card.ts | 3 +- .../energy/hui-energy-sources-table-card.ts | 3 +- .../hui-statistics-graph-card-editor.ts | 4 +- 18 files changed, 140 insertions(+), 140 deletions(-) diff --git a/src/components/chart/statistics-chart.ts b/src/components/chart/statistics-chart.ts index c96c02055a..8a597fd56a 100644 --- a/src/components/chart/statistics-chart.ts +++ b/src/components/chart/statistics-chart.ts @@ -21,6 +21,7 @@ import { numberFormatToLocale, } from "../../common/number/format_number"; import { + getDisplayUnit, getStatisticLabel, getStatisticMetadata, Statistics, @@ -258,8 +259,11 @@ class StatisticsChart extends LitElement { if (!this.unit) { if (unit === undefined) { - unit = meta?.state_unit_of_measurement; - } else if (unit !== meta?.state_unit_of_measurement) { + unit = getDisplayUnit(this.hass, firstStat.statistic_id, meta); + } else if ( + unit !== getDisplayUnit(this.hass, firstStat.statistic_id, meta) + ) { + // Clear unit if not all statistics have same unit unit = null; } } diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index 84e071f87f..0b710f68ee 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -5,9 +5,12 @@ import { customElement, property, query, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { ensureArray } from "../../common/ensure-array"; import { fireEvent } from "../../common/dom/fire_event"; -import { computeStateName } from "../../common/entity/compute_state_name"; import { stringCompare } from "../../common/string/compare"; -import { getStatisticIds, StatisticsMetaData } from "../../data/recorder"; +import { + getStatisticIds, + getStatisticLabel, + StatisticsMetaData, +} from "../../data/recorder"; import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; import { documentationUrl } from "../../util/documentation-url"; @@ -43,18 +46,11 @@ export class HaStatisticPicker extends LitElement { public includeStatisticsUnitOfMeasurement?: string | string[]; /** - * Show only statistics displayed with these units of measurements. - * @attr include-display-unit-of-measurement + * Show only statistics with these unit classes. + * @attr include-unit-class */ - @property({ attribute: "include-display-unit-of-measurement" }) - public includeDisplayUnitOfMeasurement?: string | string[]; - - /** - * Show only statistics with these device classes. - * @attr include-device-classes - */ - @property({ attribute: "include-device-classes" }) - public includeDeviceClasses?: string[]; + @property({ attribute: "include-unit-class" }) + public includeUnitClass?: string | string[]; /** * Show only statistics on entities. @@ -97,8 +93,7 @@ export class HaStatisticPicker extends LitElement { ( statisticIds: StatisticsMetaData[], includeStatisticsUnitOfMeasurement?: string | string[], - includeDisplayUnitOfMeasurement?: string | string[], - includeDeviceClasses?: string[], + includeUnitClass?: string | string[], entitiesOnly?: boolean ): Array<{ id: string; name: string; state?: HassEntity }> => { if (!statisticIds.length) { @@ -113,15 +108,18 @@ export class HaStatisticPicker extends LitElement { } if (includeStatisticsUnitOfMeasurement) { - const includeUnits = ensureArray(includeStatisticsUnitOfMeasurement); + const includeUnits: (string | null)[] = ensureArray( + includeStatisticsUnitOfMeasurement + ); statisticIds = statisticIds.filter((meta) => includeUnits.includes(meta.statistics_unit_of_measurement) ); } - if (includeDisplayUnitOfMeasurement) { - const includeUnits = ensureArray(includeDisplayUnitOfMeasurement); + if (includeUnitClass) { + const includeUnitClasses: (string | null)[] = + ensureArray(includeUnitClass); statisticIds = statisticIds.filter((meta) => - includeUnits.includes(meta.state_unit_of_measurement) + includeUnitClasses.includes(meta.unit_class) ); } @@ -136,23 +134,16 @@ export class HaStatisticPicker extends LitElement { if (!entitiesOnly) { output.push({ id: meta.statistic_id, - name: meta.name || meta.statistic_id, + name: getStatisticLabel(this.hass, meta.statistic_id, meta), }); } return; } - if ( - !includeDeviceClasses || - includeDeviceClasses.includes( - entityState!.attributes.device_class || "" - ) - ) { - output.push({ - id: meta.statistic_id, - name: computeStateName(entityState), - state: entityState, - }); - } + output.push({ + id: meta.statistic_id, + name: getStatisticLabel(this.hass, meta.statistic_id, meta), + state: entityState, + }); }); if (!output.length) { @@ -203,8 +194,7 @@ export class HaStatisticPicker extends LitElement { (this.comboBox as any).items = this._getStatistics( this.statisticIds!, this.includeStatisticsUnitOfMeasurement, - this.includeDisplayUnitOfMeasurement, - this.includeDeviceClasses, + this.includeUnitClass, this.entitiesOnly ); } else { @@ -212,8 +202,7 @@ export class HaStatisticPicker extends LitElement { (this.comboBox as any).items = this._getStatistics( this.statisticIds!, this.includeStatisticsUnitOfMeasurement, - this.includeDisplayUnitOfMeasurement, - this.includeDeviceClasses, + this.includeUnitClass, this.entitiesOnly ); }); diff --git a/src/components/entity/ha-statistics-picker.ts b/src/components/entity/ha-statistics-picker.ts index ef450d4ae2..62d7c0d2b7 100644 --- a/src/components/entity/ha-statistics-picker.ts +++ b/src/components/entity/ha-statistics-picker.ts @@ -32,11 +32,11 @@ class HaStatisticsPicker extends LitElement { public includeStatisticsUnitOfMeasurement?: string[] | string; /** - * Show only statistics displayed with these units of measurements. - * @attr include-display-unit-of-measurement + * Show only statistics with these unit classes. + * @attr include-unit-class */ - @property({ attribute: "include-display-unit-of-measurement" }) - public includeDisplayUnitOfMeasurement?: string[] | string; + @property({ attribute: "include-unit-class" }) + public includeUnitClass?: string | string[]; /** * Ignore filtering of statistics type and units when only a single statistic is selected. @@ -58,12 +58,12 @@ class HaStatisticsPicker extends LitElement { this.ignoreRestrictionsOnFirstStatistic && this._currentStatistics.length <= 1; - const includeDisplayUnitCurrent = ignoreRestriction - ? undefined - : this.includeDisplayUnitOfMeasurement; const includeStatisticsUnitCurrent = ignoreRestriction ? undefined : this.includeStatisticsUnitOfMeasurement; + const includeUnitClassCurrent = ignoreRestriction + ? undefined + : this.includeUnitClass; const includeStatisticTypesCurrent = ignoreRestriction ? undefined : this.statisticTypes; @@ -75,8 +75,8 @@ class HaStatisticsPicker extends LitElement { type: "energy/solar_forecast", }); -export const ENERGY_GAS_VOLUME_UNITS = ["m³"]; -export const ENERGY_GAS_ENERGY_UNITS = ["kWh"]; -export const ENERGY_GAS_UNITS = [ - ...ENERGY_GAS_VOLUME_UNITS, - ...ENERGY_GAS_ENERGY_UNITS, -]; +const energyGasUnitClass = ["volume", "energy"] as const; +export type EnergyGasUnitClass = typeof energyGasUnitClass[number]; -export type EnergyGasUnit = "volume" | "energy"; - -export const getEnergyGasUnitCategory = ( +export const getEnergyGasUnitClass = ( prefs: EnergyPreferences, statisticsMetaData: Record = {}, excludeSource?: string -): EnergyGasUnit | undefined => { +): EnergyGasUnitClass | undefined => { for (const source of prefs.energy_sources) { if (source.type !== "gas") { continue; @@ -622,29 +616,29 @@ export const getEnergyGasUnitCategory = ( continue; } const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from]; - if (statisticIdWithMeta) { - return ENERGY_GAS_VOLUME_UNITS.includes( - statisticIdWithMeta.statistics_unit_of_measurement + if ( + energyGasUnitClass.includes( + statisticIdWithMeta.unit_class as EnergyGasUnitClass ) - ? "volume" - : "energy"; + ) { + return statisticIdWithMeta.unit_class as EnergyGasUnitClass; } } return undefined; }; export const getEnergyGasUnit = ( + hass: HomeAssistant, prefs: EnergyPreferences, statisticsMetaData: Record = {} ): string | undefined => { - for (const source of prefs.energy_sources) { - if (source.type !== "gas") { - continue; - } - const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from]; - if (statisticIdWithMeta?.state_unit_of_measurement) { - return statisticIdWithMeta.state_unit_of_measurement; - } + const unitClass = getEnergyGasUnitClass(prefs, statisticsMetaData); + if (unitClass === undefined) { + return undefined; } - return undefined; + return unitClass === "energy" + ? "kWh" + : hass.config.unit_system.length === "km" + ? "m³" + : "ft³"; }; diff --git a/src/data/recorder.ts b/src/data/recorder.ts index 578b709e12..5d6fd71806 100644 --- a/src/data/recorder.ts +++ b/src/data/recorder.ts @@ -20,13 +20,13 @@ export interface StatisticValue { } export interface StatisticsMetaData { - state_unit_of_measurement: string; - statistics_unit_of_measurement: string; + statistics_unit_of_measurement: string | null; statistic_id: string; source: string; name?: string | null; has_sum: boolean; has_mean: boolean; + unit_class: string | null; } export type StatisticsValidationResult = @@ -254,7 +254,7 @@ export const adjustStatisticsSum = ( statistic_id: string, start_time: string, adjustment: number, - adjustment_unit_of_measurement: string + adjustment_unit_of_measurement: string | null ): Promise => hass.callWS({ type: "recorder/adjust_sum_statistics", @@ -275,3 +275,17 @@ export const getStatisticLabel = ( } return statisticsMetaData?.name || statisticsId; }; + +export const getDisplayUnit = ( + hass: HomeAssistant, + statisticsId: string | undefined, + statisticsMetaData: StatisticsMetaData | undefined +): string | null | undefined => { + let unit: string | undefined; + if (statisticsId) { + unit = hass.states[statisticsId]?.attributes.unit_of_measurement; + } + return unit === undefined + ? statisticsMetaData?.statistics_unit_of_measurement + : unit; +}; diff --git a/src/panels/config/energy/components/ha-energy-gas-settings.ts b/src/panels/config/energy/components/ha-energy-gas-settings.ts index c50bc87de1..14f6653f05 100644 --- a/src/panels/config/energy/components/ha-energy-gas-settings.ts +++ b/src/panels/config/energy/components/ha-energy-gas-settings.ts @@ -10,7 +10,7 @@ import { EnergyPreferencesValidation, EnergyValidationIssue, GasSourceTypeEnergyPreference, - getEnergyGasUnitCategory, + getEnergyGasUnitClass, saveEnergyPreferences, } from "../../../../data/energy"; import { @@ -133,7 +133,7 @@ export class EnergyGasSettings extends LitElement { private _addSource() { showEnergySettingsGasDialog(this, { - allowedGasUnitCategory: getEnergyGasUnitCategory( + allowedGasUnitClass: getEnergyGasUnitClass( this.preferences, this.statsMetadata ), @@ -152,7 +152,7 @@ export class EnergyGasSettings extends LitElement { ev.currentTarget.closest(".row").source; showEnergySettingsGasDialog(this, { source: { ...origSource }, - allowedGasUnitCategory: getEnergyGasUnitCategory( + allowedGasUnitClass: getEnergyGasUnitClass( this.preferences, this.statsMetadata, origSource.stat_energy_from diff --git a/src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts b/src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts index 0314aefc0d..2dd5ce4e15 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts @@ -14,8 +14,7 @@ import { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy"; import "@material/mwc-button/mwc-button"; import "../../../../components/entity/ha-statistic-picker"; -const energyUnits = ["kWh"]; -const energyDeviceClasses = ["energy"]; +const energyUnitClasses = ["energy"]; @customElement("dialog-energy-battery-settings") export class DialogEnergyBatterySettings @@ -67,8 +66,7 @@ export class DialogEnergyBatterySettings ) { if (ev.detail.value) { - const entity = this.hass.states[ev.detail.value]; - if (entity?.attributes.unit_of_measurement) { - this._pickedDisplayUnit = entity.attributes.unit_of_measurement; - } else { - this._pickedDisplayUnit = ( - await getStatisticMetadata(this.hass, [ev.detail.value]) - )[0]?.state_unit_of_measurement; - } + const metadata = await getStatisticMetadata(this.hass, [ev.detail.value]); + this._pickedDisplayUnit = getDisplayUnit( + this.hass, + ev.detail.value, + metadata[0] + ); } else { this._pickedDisplayUnit = undefined; } diff --git a/src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts b/src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts index c2cab0d7b2..68e9879bf8 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts @@ -20,8 +20,7 @@ import "../../../../components/ha-formfield"; import type { HaRadio } from "../../../../components/ha-radio"; import "../../../../components/entity/ha-entity-picker"; -const energyUnits = ["kWh"]; -const energyDeviceClasses = ["energy"]; +const energyUnitClasses = ["energy"]; @customElement("dialog-energy-grid-flow-settings") export class DialogEnergyGridFlowSettings @@ -93,8 +92,7 @@ export class DialogEnergyGridFlowSettings Promise; } diff --git a/src/panels/developer-tools/statistics/developer-tools-statistics.ts b/src/panels/developer-tools/statistics/developer-tools-statistics.ts index d483fc84ce..7cd162ccfe 100644 --- a/src/panels/developer-tools/statistics/developer-tools-statistics.ts +++ b/src/panels/developer-tools/statistics/developer-tools-statistics.ts @@ -74,12 +74,6 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { hidden: this.narrow, width: "20%", }, - state_unit_of_measurement: { - title: "Display unit", - sortable: true, - filterable: true, - width: "10%", - }, statistics_unit_of_measurement: { title: "Statistics unit", sortable: true, @@ -220,12 +214,12 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { this._data.push({ statistic_id: statisticId, statistics_unit_of_measurement: "", - state_unit_of_measurement: "", source: "", state: this.hass.states[statisticId], issues: issues[statisticId], has_mean: false, has_sum: false, + unit_class: null, }); } }); diff --git a/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts b/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts index c00b5dc5fd..4c6c2998ad 100644 --- a/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts +++ b/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts @@ -23,6 +23,7 @@ import "../../../components/ha-svg-icon"; import { adjustStatisticsSum, fetchStatistics, + getDisplayUnit, StatisticValue, } from "../../../data/recorder"; import type { DateTimeSelector, NumberSelector } from "../../../data/selector"; @@ -59,7 +60,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { }; private _amountSelector = memoizeOne( - (unit_of_measurement: string): NumberSelector => ({ + (unit_of_measurement: string | undefined): NumberSelector => ({ number: { step: 0.01, unit_of_measurement, @@ -135,7 +136,11 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { } else { const data = this._stats5min.length >= 2 ? this._stats5min : this._statsHour; - const unit = this._params!.statistic.state_unit_of_measurement; + const unit = getDisplayUnit( + this.hass, + this._params!.statistic.statistic_id, + this._params!.statistic + ); const rows: TemplateResult[] = []; for (let i = 1; i < data.length; i++) { const stat = data[i]; @@ -192,6 +197,11 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { } private _renderAdjustStat() { + const unit = getDisplayUnit( + this.hass, + this._params!.statistic.statistic_id, + this._params!.statistic + ); return html`
Statistic: ${this._params!.statistic.statistic_id} @@ -220,9 +230,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { { @@ -299,6 +307,11 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { } private async _fixIssue(): Promise { + const unit = getDisplayUnit( + this.hass, + this._params!.statistic.statistic_id, + this._params!.statistic + ); this._busy = true; try { await adjustStatisticsSum( @@ -306,7 +319,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement { this._params!.statistic.statistic_id, this._chosenStat!.start, this._amount! - this._origAmount!, - this._params!.statistic.state_unit_of_measurement + unit || null ); } catch (err: any) { this._busy = false; diff --git a/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts b/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts index d204562559..cb311b7637 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts @@ -315,8 +315,11 @@ class HuiEnergyDistrubutionCard ${formatNumber(gasUsage || 0, this.hass.locale, { maximumFractionDigits: 1, })} - ${getEnergyGasUnit(prefs, this._data.statsMetadata) || - "m³"} + ${getEnergyGasUnit( + this.hass, + prefs, + this._data.statsMetadata + ) || "m³"}
diff --git a/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts index fc940d5605..2bd6855782 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts @@ -274,7 +274,8 @@ export class HuiEnergyGasGraphCard ) as GasSourceTypeEnergyPreference[]; this._unit = - getEnergyGasUnit(energyData.prefs, energyData.statsMetadata) || "m³"; + getEnergyGasUnit(this.hass, energyData.prefs, energyData.statsMetadata) || + "m³"; const datasets: ChartDataset<"bar", ScatterDataPoint[]>[] = []; diff --git a/src/panels/lovelace/cards/energy/hui-energy-sources-table-card.ts b/src/panels/lovelace/cards/energy/hui-energy-sources-table-card.ts index dc5eb4b977..3880736f53 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-sources-table-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-sources-table-card.ts @@ -130,7 +130,8 @@ export class HuiEnergySourcesTableCard ); const gasUnit = - getEnergyGasUnit(this._data.prefs, this._data.statsMetadata) || ""; + getEnergyGasUnit(this.hass, this._data.prefs, this._data.statsMetadata) || + ""; const compare = this._data.statsCompare !== undefined; diff --git a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts index 8933560cd4..e894f09411 100644 --- a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts @@ -205,7 +205,7 @@ export class HuiStatisticsGraphCardEditor ...this._config, stat_types: configured_stat_types, }; - const displayUnit = this._metaDatas?.[0]?.state_unit_of_measurement; + const unitClass = this._metaDatas?.[0]?.unit_class; return html` Date: Sun, 2 Oct 2022 00:02:24 +0200 Subject: [PATCH 11/16] Normalize automation config (#13938) * Normalize automation config * gen * Update ha-automation-action-choose.ts --- src/data/automation_i18n.ts | 6 ++++- .../types/ha-automation-action-choose.ts | 6 ++--- .../config/automation/ha-automation-editor.ts | 25 +++++++++++-------- src/panels/config/script/ha-script-editor.ts | 20 +++++++++------ 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/data/automation_i18n.ts b/src/data/automation_i18n.ts index 8b17c894ed..c84fc3b868 100644 --- a/src/data/automation_i18n.ts +++ b/src/data/automation_i18n.ts @@ -189,7 +189,11 @@ export const describeTrigger = ( // Time Trigger if (trigger.platform === "time" && trigger.at) { const at = trigger.at.includes(".") - ? `entity ${computeStateName(hass.states[trigger.at]) || trigger.at}` + ? `entity ${ + hass.states[trigger.at] + ? computeStateName(hass.states[trigger.at]) + : trigger.at + }` : trigger.at; return `When the time is equal to ${at}`; diff --git a/src/panels/config/automation/action/types/ha-automation-action-choose.ts b/src/panels/config/automation/action/types/ha-automation-action-choose.ts index b256e6ba50..9158f61106 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-choose.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-choose.ts @@ -55,7 +55,7 @@ export class HaChooseAction extends LitElement implements ActionElement { )}: (option.conditions)} .reOrderMode=${this.reOrderMode} .disabled=${this.disabled} .hass=${this.hass} @@ -68,7 +68,7 @@ export class HaChooseAction extends LitElement implements ActionElement { )}: { - this._config = c.config; + this._config = this._normalizeConfig(c.config); }); this._entityId = this.entityId; this._dirty = false; @@ -473,24 +473,27 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { this._entityId = automation?.entity_id; } + private _normalizeConfig(config: AutomationConfig): AutomationConfig { + // Normalize data: ensure trigger, action and condition are lists + // Happens when people copy paste their automations into the config + for (const key of ["trigger", "condition", "action"]) { + const value = config[key]; + if (value && !Array.isArray(value)) { + config[key] = [value]; + } + } + return config; + } + private async _loadConfig() { try { const config = await fetchAutomationFileConfig( this.hass, this.automationId as string ); - - // Normalize data: ensure trigger, action and condition are lists - // Happens when people copy paste their automations into the config - for (const key of ["trigger", "condition", "action"]) { - const value = config[key]; - if (value && !Array.isArray(value)) { - config[key] = [value]; - } - } this._dirty = false; this._readOnly = false; - this._config = config; + this._config = this._normalizeConfig(config); } catch (err: any) { const entity = Object.values(this.hass.entities).find( (ent) => diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index dd81e9dd8f..e842a9c949 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -469,15 +469,9 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { ) { fetchScriptFileConfig(this.hass, this.scriptId).then( (config) => { - // Normalize data: ensure sequence is a list - // Happens when people copy paste their scripts into the config - const value = config.sequence; - if (value && !Array.isArray(value)) { - config.sequence = [value]; - } this._dirty = false; this._readOnly = false; - this._config = config; + this._config = this._normalizeConfig(config); }, (resp) => { const entity = Object.values(this.hass.entities).find( @@ -524,7 +518,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { if (changedProps.has("entityId") && this.entityId) { getScriptStateConfig(this.hass, this.entityId).then((c) => { - this._config = c.config; + this._config = this._normalizeConfig(c.config); }); const regEntry = this.hass.entities[this.entityId]; if (regEntry?.unique_id) { @@ -536,6 +530,16 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { } } + private _normalizeConfig(config: ScriptConfig): ScriptConfig { + // Normalize data: ensure sequence is a list + // Happens when people copy paste their scripts into the config + const value = config.sequence; + if (value && !Array.isArray(value)) { + config.sequence = [value]; + } + return config; + } + private _computeLabelCallback = ( schema: SchemaUnion>, data: HaFormDataContainer From 176d8567f4b7ca12eef9b2e38a04e103320c8adc Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sun, 2 Oct 2022 17:39:15 +0200 Subject: [PATCH 12/16] Add condition description for trigger condition (#13941) --- gallery/src/pages/automation/describe-condition.ts | 1 + src/data/automation_i18n.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/gallery/src/pages/automation/describe-condition.ts b/gallery/src/pages/automation/describe-condition.ts index 2f6cef5f47..3350dce74f 100644 --- a/gallery/src/pages/automation/describe-condition.ts +++ b/gallery/src/pages/automation/describe-condition.ts @@ -36,6 +36,7 @@ const conditions = [ { condition: "sun", after: "sunset" }, { condition: "sun", after: "sunrise", offset: "-01:00" }, { condition: "zone", entity_id: "device_tracker.person", zone: "zone.home" }, + { condition: "trigger", id: "motion" }, { condition: "time" }, { condition: "template" }, ]; diff --git a/src/data/automation_i18n.ts b/src/data/automation_i18n.ts index c84fc3b868..c4a49721fe 100644 --- a/src/data/automation_i18n.ts +++ b/src/data/automation_i18n.ts @@ -572,6 +572,13 @@ export const describeCondition = ( }`; } + if (condition.condition === "trigger") { + if (!condition.id) { + return "Trigger condition"; + } + return `When triggered by ${condition.id}`; + } + return `${ condition.condition ? condition.condition.replace(/_/g, " ") : "Unknown" } condition`; From dd695545d34bb0ef78b13f8d517181c049f4cef0 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sun, 2 Oct 2022 19:10:15 +0200 Subject: [PATCH 13/16] Make duplicate script/automation work in picker for yaml (#13952) Co-authored-by: Paulus Schoutsen --- .../config/automation/ha-automation-picker.ts | 33 +++++++++++++------ src/panels/config/script/ha-script-picker.ts | 24 ++++++++------ src/translations/en.json | 3 +- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index 3d0327ff74..fbe82913e9 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -35,6 +35,8 @@ import { deleteAutomation, duplicateAutomation, fetchAutomationFileConfig, + getAutomationStateConfig, + showAutomationEditor, triggerAutomationActions, } from "../../../data/automation"; import { @@ -329,6 +331,14 @@ class HaAutomationPicker extends LitElement { } private _showTrace(automation: any) { + if (!automation.attributes.id) { + showAlertDialog(this, { + text: this.hass.localize( + "ui.panel.config.automation.picker.traces_not_available" + ), + }); + return; + } navigate(`/config/automation/trace/${automation.attributes.id}`); } @@ -382,17 +392,20 @@ class HaAutomationPicker extends LitElement { ); duplicateAutomation(config); } catch (err: any) { + if (err.status_code === 404) { + const response = await getAutomationStateConfig( + this.hass, + automation.entity_id + ); + showAutomationEditor({ ...response.config, id: undefined }); + return; + } await showAlertDialog(this, { - text: - err.status_code === 404 - ? this.hass.localize( - "ui.panel.config.automation.editor.load_error_not_duplicable" - ) - : this.hass.localize( - "ui.panel.config.automation.editor.load_error_unknown", - "err_no", - err.status_code - ), + text: this.hass.localize( + "ui.panel.config.automation.editor.load_error_unknown", + "err_no", + err.status_code + ), }); } } diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts index c9e8dbfd85..a4f4891ae3 100644 --- a/src/panels/config/script/ha-script-picker.ts +++ b/src/panels/config/script/ha-script-picker.ts @@ -28,6 +28,7 @@ import "../../../components/ha-svg-icon"; import { deleteScript, fetchScriptFileConfig, + getScriptStateConfig, showScriptEditor, triggerScript, } from "../../../data/script"; @@ -311,17 +312,20 @@ class HaScriptPicker extends LitElement { )})`, }); } catch (err: any) { + if (err.status_code === 404) { + const response = await getScriptStateConfig( + this.hass, + script.entity_id + ); + showScriptEditor(response.config); + return; + } await showAlertDialog(this, { - text: - err.status_code === 404 - ? this.hass.localize( - "ui.panel.config.script.editor.load_error_not_duplicable" - ) - : this.hass.localize( - "ui.panel.config.script.editor.load_error_unknown", - "err_no", - err.status_code - ), + text: this.hass.localize( + "ui.panel.config.script.editor.load_error_unknown", + "err_no", + err.status_code + ), }); } } diff --git a/src/translations/en.json b/src/translations/en.json index b4426b719e..237cdeb99c 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1855,8 +1855,8 @@ "show_info": "Information", "default_name": "New Automation", "missing_name": "Cannot save automation without a name", + "traces_not_available": "Automations need an ID for history to be tracked. Add an ID to your automation to make it available in traces.", "load_error_not_editable": "Only automations in automations.yaml are editable.", - "load_error_not_duplicable": "Only automations in automations.yaml can be duplicated.", "load_error_not_deletable": "Only automations in automations.yaml can be deleted.", "load_error_unknown": "Error loading automation ({err_no}).", "save": "Save", @@ -2341,7 +2341,6 @@ "parallel": "Max number of parallel runs" }, "load_error_not_editable": "Only scripts inside scripts.yaml are editable.", - "load_error_not_duplicable": "Only scripts in scripts.yaml can be duplicated.", "load_error_not_deletable": "Only scripts in scripts.yaml can be deleted.", "load_error_unknown": "Error loading script ({err_no}).", "delete_confirm_title": "Delete script?", From c14d9ab9576a4de1a43a22568f69ea9ffea2e0c5 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sun, 2 Oct 2022 19:10:41 +0200 Subject: [PATCH 14/16] Link discovered homekit devices to domain (#13950) --- .../integrations/dialog-add-integration.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/panels/config/integrations/dialog-add-integration.ts b/src/panels/config/integrations/dialog-add-integration.ts index f023eee2ae..34aea54d2b 100644 --- a/src/panels/config/integrations/dialog-add-integration.ts +++ b/src/panels/config/integrations/dialog-add-integration.ts @@ -509,7 +509,16 @@ class AddIntegrationDialog extends LitElement { if (integration.integrations) { const integrations = this._integrations![integration.domain].integrations!; - this._fetchFlowsInProgress(Object.keys(integrations)); + let domains = Object.keys(integrations); + if (integration.iot_standards?.includes("homekit")) { + // if homekit is supported, also fetch the discovered homekit devices + domains.push("homekit_controller"); + } + if (integration.domain === "apple") { + // we show discoverd homekit devices in their own brand section, dont show them at apple + domains = domains.filter((domain) => domain !== "homekit_controller"); + } + this._fetchFlowsInProgress(domains); this._pickedBrand = integration.domain; return; } @@ -603,7 +612,14 @@ class AddIntegrationDialog extends LitElement { private async _fetchFlowsInProgress(domains: string[]) { const flowsInProgress = ( await fetchConfigFlowInProgress(this.hass.connection) - ).filter((flow) => domains.includes(flow.handler)); + ).filter( + (flow) => + // filter config flows that are not for the integration we are looking for + domains.includes(flow.handler) || + // filter config flows of other domains (like homekit) that are for the domains we are looking for + ("alternative_domain" in flow.context && + domains.includes(flow.context.alternative_domain)) + ); if (flowsInProgress.length) { this._flowsInProgress = flowsInProgress; From cb0310593ca5480e84753df55773af687564f6c3 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sun, 2 Oct 2022 20:19:32 +0200 Subject: [PATCH 15/16] Change add application credential flow (#13951) * Change add application credential flow * Update step-flow-abort.ts * import * Add missing credential docs link * Load description, show only that if available * Update dialog-add-application-credential.ts * pass along manifest Co-authored-by: Paulus Schoutsen --- src/dialogs/config-flow/step-flow-abort.ts | 19 +-- .../dialog-add-application-credential.ts | 129 ++++++++++++------ .../show-dialog-add-application-credential.ts | 2 + .../integrations/ha-domain-integrations.ts | 5 +- src/translations/en.json | 6 +- 5 files changed, 98 insertions(+), 63 deletions(-) diff --git a/src/dialogs/config-flow/step-flow-abort.ts b/src/dialogs/config-flow/step-flow-abort.ts index 08b8a46df1..818c48b94f 100644 --- a/src/dialogs/config-flow/step-flow-abort.ts +++ b/src/dialogs/config-flow/step-flow-abort.ts @@ -14,8 +14,6 @@ import { showAddApplicationCredentialDialog } from "../../panels/config/applicat import { configFlowContentStyles } from "./styles"; import { DataEntryFlowDialogParams } from "./show-dialog-data-entry-flow"; import { showConfigFlowDialog } from "./show-dialog-config-flow"; -import { domainToName } from "../../data/integration"; -import { showConfirmationDialog } from "../generic/show-dialog-box"; @customElement("step-flow-abort") class StepFlowAbort extends LitElement { @@ -54,26 +52,11 @@ class StepFlowAbort extends LitElement { } private async _handleMissingCreds() { - const confirm = await showConfirmationDialog(this, { - title: this.hass.localize( - "ui.panel.config.integrations.config_flow.missing_credentials_title" - ), - text: this.hass.localize( - "ui.panel.config.integrations.config_flow.missing_credentials", - { - integration: domainToName(this.hass.localize, this.domain), - } - ), - confirmText: this.hass.localize("ui.common.yes"), - dismissText: this.hass.localize("ui.common.no"), - }); this._flowDone(); - if (!confirm) { - return; - } // Prompt to enter credentials and restart integration setup showAddApplicationCredentialDialog(this.params.dialogParentElement!, { selectedDomain: this.domain, + manifest: this.params.manifest, applicationCredentialAddedCallback: () => { showConfigFlowDialog(this.params.dialogParentElement!, { dialogClosedCallback: this.params.dialogClosedCallback, diff --git a/src/panels/config/application_credentials/dialog-add-application-credential.ts b/src/panels/config/application_credentials/dialog-add-application-credential.ts index f1fc6ecf87..f6d017a9ee 100644 --- a/src/panels/config/application_credentials/dialog-add-application-credential.ts +++ b/src/panels/config/application_credentials/dialog-add-application-credential.ts @@ -5,6 +5,7 @@ import { ComboBoxLitRenderer } from "@vaadin/combo-box/lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; +import "../../../components/ha-alert"; import "../../../components/ha-circular-progress"; import "../../../components/ha-combo-box"; import { createCloseHeading } from "../../../components/ha-dialog"; @@ -16,7 +17,7 @@ import { createApplicationCredential, fetchApplicationCredentialsConfig, } from "../../../data/application_credential"; -import { domainToName } from "../../../data/integration"; +import { domainToName, IntegrationManifest } from "../../../data/integration"; import { haStyleDialog } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; @@ -44,6 +45,8 @@ export class DialogAddApplicationCredential extends LitElement { @state() private _domain?: string; + @state() private _manifest?: IntegrationManifest | null; + @state() private _name?: string; @state() private _description?: string; @@ -58,8 +61,8 @@ export class DialogAddApplicationCredential extends LitElement { public showDialog(params: AddApplicationCredentialDialogParams) { this._params = params; - this._domain = - params.selectedDomain !== undefined ? params.selectedDomain : ""; + this._domain = params.selectedDomain; + this._manifest = params.manifest; this._name = ""; this._description = ""; this._clientId = ""; @@ -76,7 +79,7 @@ export class DialogAddApplicationCredential extends LitElement { name: domainToName(this.hass.localize, domain), })); await this.hass.loadBackendTranslation("application_credentials"); - if (this._domain !== "") { + if (this._domain) { this._updateDescription(); } } @@ -85,6 +88,9 @@ export class DialogAddApplicationCredential extends LitElement { if (!this._params || !this._domains) { return html``; } + const selectedDomainName = this._params.selectedDomain + ? domainToName(this.hass.localize, this._domain!) + : ""; return html`
- ${this._error ? html`
${this._error}
` : ""} -

- ${this.hass.localize( - "ui.panel.config.application_credentials.editor.description" - )} -
- - ${this.hass!.localize( - "ui.panel.config.application_credentials.editor.view_documentation" - )} - - -

- + ${this._error + ? html`${this._error} ` + : ""} + ${this._params.selectedDomain && !this._description + ? html`

+ ${this.hass.localize( + "ui.panel.config.application_credentials.editor.missing_credentials", + { + integration: selectedDomainName, + } + )} + ${this._manifest?.is_built_in || this._manifest?.documentation + ? html` + ${this.hass.localize( + "ui.panel.config.application_credentials.editor.missing_credentials_domain_link", + { + integration: selectedDomainName, + } + )} + + ` + : ""} +

` + : ""} + ${!this._params.selectedDomain || !this._description + ? html`

+ ${this.hass.localize( + "ui.panel.config.application_credentials.editor.description" + )} + + ${this.hass!.localize( + "ui.panel.config.application_credentials.editor.view_documentation" + )} + + +

` + : ""} + ${this._params.selectedDomain + ? "" + : html``} ${this._description ? html` void; dialogAbortedCallback?: () => void; selectedDomain?: string; + manifest?: IntegrationManifest | null; } export const loadAddApplicationCredentialDialog = () => diff --git a/src/panels/config/integrations/ha-domain-integrations.ts b/src/panels/config/integrations/ha-domain-integrations.ts index 2c0690639e..610414d77f 100644 --- a/src/panels/config/integrations/ha-domain-integrations.ts +++ b/src/panels/config/integrations/ha-domain-integrations.ts @@ -192,7 +192,10 @@ class HaDomainIntegrations extends LitElement { } if ( - (domain === this.domain && !this.integration!.config_flow) || + (domain === this.domain && + !this.integration!.config_flow && + (!this.integration!.integrations?.[domain] || + !this.integration!.integrations[domain].config_flow)) || !this.integration!.integrations?.[domain]?.config_flow ) { const manifest = await fetchIntegrationManifest(this.hass, domain); diff --git a/src/translations/en.json b/src/translations/en.json index 237cdeb99c..84c1a70332 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2985,8 +2985,6 @@ "error": "Error", "could_not_load": "Config flow could not be loaded", "not_loaded": "The integration could not be loaded, try to restart Home Assistant.", - "missing_credentials_title": "Add application credentials?", - "missing_credentials": "Setting up {integration} requires configuring application credentials. Do you want to do that now?", "supported_brand_flow": "Support for {supported_brand} devices is provided by {flow_domain_name}. Do you want to continue?", "missing_zwave_zigbee": "To add a {integration} device, you first need {supported_hardware_link} and the {integration} integration set up. If you already have the hardware then you can proceed with the setup of {integration}.", "supported_hardware": "supported hardware", @@ -3059,7 +3057,9 @@ "editor": { "caption": "Add Credential", "description": "OAuth is used to grant Home Assistant access to information on other websites without giving a passwords. This mechanism is used by companies such as Spotify, Google, Withings, Microsoft, and Twitter.", - "view_documentation": "View documentation", + "missing_credentials": "Setting up {integration} requires configuring application credentials.", + "missing_credentials_domain_link": "View {integration} documentation", + "view_documentation": "View application credentials documentation", "add": "Add", "domain": "Integration", "name": "Name", From e2a89b1157dfeaa753028a7592ab23131a1849ca Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sun, 2 Oct 2022 20:19:51 +0200 Subject: [PATCH 16/16] Bumped version to 20221002.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index cf6bcf6ef9..49715f19bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20220929.0" +version = "20221002.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md"