From 3de78cca2d5c7d98f84bca21240472ca05ad5d50 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 22 Oct 2020 11:00:36 +0200 Subject: [PATCH 01/25] Fix quickbar debounce (#7426) * Fix quicbar debounce * Clear search property when dialog is closed Co-authored-by: Donnie --- src/dialogs/quick-bar/ha-quick-bar.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/dialogs/quick-bar/ha-quick-bar.ts b/src/dialogs/quick-bar/ha-quick-bar.ts index ce8ace0a88..dc1fce0136 100644 --- a/src/dialogs/quick-bar/ha-quick-bar.ts +++ b/src/dialogs/quick-bar/ha-quick-bar.ts @@ -55,6 +55,8 @@ export class QuickBar extends LitElement { @internalProperty() private _filter = ""; + @internalProperty() private _search = ""; + @internalProperty() private _opened = false; @internalProperty() private _commandMode = false; @@ -79,6 +81,7 @@ export class QuickBar extends LitElement { this._done = false; this._focusSet = false; this._filter = ""; + this._search = ""; this._commandTriggered = -1; this._items = []; fireEvent(this, "dialog-closed", { dialog: this.localName }); @@ -116,7 +119,7 @@ export class QuickBar extends LitElement { .label=${this.hass.localize( "ui.dialogs.quick-bar.filter_placeholder" )} - .filter=${this._commandMode ? `>${this._filter}` : this._filter} + .filter=${this._commandMode ? `>${this._search}` : this._search} @keydown=${this._handleInputKeyDown} @focus=${this._setFocusFirstListItem} > @@ -237,12 +240,14 @@ export class QuickBar extends LitElement { if (newFilter.startsWith(">")) { this._commandMode = true; - this._debouncedSetFilter(newFilter.substring(1)); + this._search = newFilter.substring(1); } else { this._commandMode = false; - this._debouncedSetFilter(newFilter); + this._search = newFilter; } + this._debouncedSetFilter(this._search); + if (oldCommandMode !== this._commandMode) { this._items = undefined; this._focusSet = false; From a2d9f9b41706a95fe9ab2a6ed115c2020daf9030 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 22 Oct 2020 22:43:15 +0200 Subject: [PATCH 02/25] Fix ES5 build, fix virtualizer polyfill (#7451) --- build-scripts/bundle.js | 2 -- build-scripts/webpack.js | 12 +++++++++--- package.json | 1 - src/common/translations/localize.ts | 17 ++++++++++++----- src/fake_data/provide_hass.ts | 4 ++-- src/managers/notification-manager.ts | 2 +- src/mixins/lit-localize-lite-mixin.ts | 6 ++++-- src/resources/EventTarget-ponyfill.js | 14 ++++++++++++++ src/state/translations-mixin.ts | 8 ++++---- 9 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 src/resources/EventTarget-ponyfill.js diff --git a/build-scripts/bundle.js b/build-scripts/bundle.js index c5056cc8b6..41f60aa66d 100644 --- a/build-scripts/bundle.js +++ b/build-scripts/bundle.js @@ -55,7 +55,6 @@ module.exports.babelOptions = ({ latestBuild }) => ({ !latestBuild && [ require("@babel/preset-env").default, { - modules: false, useBuiltIns: "entry", corejs: "3.6", }, @@ -71,7 +70,6 @@ module.exports.babelOptions = ({ latestBuild }) => ({ // Only support the syntax, Webpack will handle it. "@babel/plugin-syntax-import-meta", "@babel/plugin-syntax-dynamic-import", - "@babel/plugin-syntax-top-level-await", "@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-nullish-coalescing-operator", [ diff --git a/build-scripts/webpack.js b/build-scripts/webpack.js index f82591e9e7..65d4287a34 100644 --- a/build-scripts/webpack.js +++ b/build-scripts/webpack.js @@ -51,9 +51,6 @@ const createWebpackConfig = ({ }), ], }, - experiments: { - topLevelAwait: true, - }, plugins: [ new ManifestPlugin({ // Only include the JS of entrypoints @@ -98,6 +95,15 @@ const createWebpackConfig = ({ new RegExp(bundle.emptyPackages({ latestBuild }).join("|")), path.resolve(paths.polymer_dir, "src/util/empty.js") ), + // We need to change the import of the polyfill for EventTarget, so we replace the polyfill file with our customized one + new webpack.NormalModuleReplacementPlugin( + new RegExp( + require.resolve( + "lit-virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js" + ) + ), + path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js") + ), ], resolve: { extensions: [".ts", ".js", ".json"], diff --git a/package.json b/package.json index 380e52a57d..82ba1c1336 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,6 @@ "@babel/plugin-proposal-optional-chaining": "^7.11.0", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-top-level-await": "^7.10.4", "@babel/preset-env": "^7.11.5", "@babel/preset-typescript": "^7.10.4", "@rollup/plugin-commonjs": "^11.1.0", diff --git a/src/common/translations/localize.ts b/src/common/translations/localize.ts index df7b993b1d..fa6adc1b52 100644 --- a/src/common/translations/localize.ts +++ b/src/common/translations/localize.ts @@ -13,9 +13,12 @@ export interface FormatsType { time: FormatType; } -if (shouldPolyfill()) { - await import("@formatjs/intl-pluralrules/polyfill-locales"); -} +let polyfillLoaded = !shouldPolyfill(); +const polyfillProm = polyfillLoaded + ? import("@formatjs/intl-pluralrules/polyfill-locales").then(() => { + polyfillLoaded = true; + }) + : undefined; /** * Adapted from Polymer app-localize-behavior. @@ -38,12 +41,16 @@ if (shouldPolyfill()) { * } */ -export const computeLocalize = ( +export const computeLocalize = async ( cache: any, language: string, resources: Resources, formats?: FormatsType -): LocalizeFunc => { +): Promise => { + if (!polyfillLoaded) { + await polyfillProm; + } + // Everytime any of the parameters change, invalidate the strings cache. cache._localizationCache = {}; diff --git a/src/fake_data/provide_hass.ts b/src/fake_data/provide_hass.ts index f070dc7f41..0bc58b1040 100644 --- a/src/fake_data/provide_hass.ts +++ b/src/fake_data/provide_hass.ts @@ -55,7 +55,7 @@ export const provideHass = ( function updateTranslations(fragment: null | string, language?: string) { const lang = language || getLocalLanguage(); - getTranslation(fragment, lang).then((translation) => { + getTranslation(fragment, lang).then(async (translation) => { const resources = { [lang]: { ...(hass().resources && hass().resources[lang]), @@ -64,7 +64,7 @@ export const provideHass = ( }; hass().updateHass({ resources, - localize: computeLocalize(elements[0], lang, resources), + localize: await computeLocalize(elements[0], lang, resources), }); }); } diff --git a/src/managers/notification-manager.ts b/src/managers/notification-manager.ts index 9dcadfb2b2..a2db48db89 100644 --- a/src/managers/notification-manager.ts +++ b/src/managers/notification-manager.ts @@ -33,7 +33,7 @@ class NotificationManager extends LitElement { @internalProperty() private _noCancelOnOutsideClick = false; - @query("ha-toast", true) private _toast!: HaToast; + @query("ha-toast") private _toast!: HaToast; public async showDialog({ message, diff --git a/src/mixins/lit-localize-lite-mixin.ts b/src/mixins/lit-localize-lite-mixin.ts index a43ce610a1..f1d2cf072c 100644 --- a/src/mixins/lit-localize-lite-mixin.ts +++ b/src/mixins/lit-localize-lite-mixin.ts @@ -36,11 +36,13 @@ export const litLocalizeLiteMixin = >( (changedProperties.has("language") || changedProperties.has("resources")) ) { - this.localize = computeLocalize( + computeLocalize( this.constructor.prototype, this.language, this.resources - ); + ).then((localize) => { + this.localize = localize; + }); } } diff --git a/src/resources/EventTarget-ponyfill.js b/src/resources/EventTarget-ponyfill.js new file mode 100644 index 0000000000..730e3f0ad6 --- /dev/null +++ b/src/resources/EventTarget-ponyfill.js @@ -0,0 +1,14 @@ +let ET; +export default async function EventTarget() { + return ET || init(); +} +async function init() { + ET = window.EventTarget; + try { + // eslint-disable-next-line no-new + new ET(); + } catch (_a) { + ET = (await import("event-target-shim")).default.EventTarget; + } + return ET; +} diff --git a/src/state/translations-mixin.ts b/src/state/translations-mixin.ts index 215752dfa8..16e3abb5ac 100644 --- a/src/state/translations-mixin.ts +++ b/src/state/translations-mixin.ts @@ -133,7 +133,7 @@ export default >(superClass: T) => return this.hass!.localize; } - this._updateResources(language, resources); + await this._updateResources(language, resources); return this.hass!.localize; } @@ -187,7 +187,7 @@ export default >(superClass: T) => return this.hass!.localize; } - this._updateResources(language, resources); + await this._updateResources(language, resources); return this.hass!.localize; } @@ -216,7 +216,7 @@ export default >(superClass: T) => } } - private _updateResources(language: string, data: any) { + private async _updateResources(language: string, data: any) { // Update the language in hass, and update the resources with the newly // loaded resources. This merges the new data on top of the old data for // this language, so that the full translation set can be loaded across @@ -229,7 +229,7 @@ export default >(superClass: T) => }; const changes: Partial = { resources }; if (this.hass && language === this.hass.language) { - changes.localize = computeLocalize(this, language, resources); + changes.localize = await computeLocalize(this, language, resources); } this._updateHass(changes); } From 1346156ecd2808528e3bcb327928a84b312c57ef Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 22 Oct 2020 15:47:19 -0500 Subject: [PATCH 03/25] Avoid fetching logbook data instead in addition to not displaying it (#7427) Co-authored-by: Zack Barett --- src/dialogs/more-info/ha-more-info-dialog.ts | 45 ++++++++++++++----- src/dialogs/more-info/ha-more-info-logbook.ts | 13 +----- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/dialogs/more-info/ha-more-info-dialog.ts b/src/dialogs/more-info/ha-more-info-dialog.ts index a0c3378af6..10a4b1f15b 100644 --- a/src/dialogs/more-info/ha-more-info-dialog.ts +++ b/src/dialogs/more-info/ha-more-info-dialog.ts @@ -38,6 +38,7 @@ import { showConfirmationDialog } from "../generic/show-dialog-box"; import "./ha-more-info-history"; import "./ha-more-info-logbook"; import "./controls/more-info-default"; +import { CONTINUOUS_DOMAINS } from "../../data/logbook"; const DOMAINS_NO_INFO = ["camera", "configurator"]; /** @@ -169,7 +170,8 @@ export class MoreInfoDialog extends LitElement { : ""} ${DOMAINS_WITH_MORE_INFO.includes(domain) && - this._computeShowHistoryComponent(entityId) + (this._computeShowHistoryComponent(entityId) || + this._computeShowLogBookComponent(entityId)) ? html` - `} + .hass=${this.hass} + .entityId=${this._entityId} + >`} + ${DOMAINS_WITH_MORE_INFO.includes(domain) || + !this._computeShowLogBookComponent(entityId) + ? "" + : html``} ${this._moreInfoType ? dynamicElement(this._moreInfoType, { hass: this.hass, @@ -264,12 +269,32 @@ export class MoreInfoDialog extends LitElement { private _computeShowHistoryComponent(entityId) { return ( - (isComponentLoaded(this.hass, "history") || - isComponentLoaded(this.hass, "logbook")) && + isComponentLoaded(this.hass, "history") && !DOMAINS_MORE_INFO_NO_HISTORY.includes(computeDomain(entityId)) ); } + private _computeShowLogBookComponent(entityId): boolean { + if (!isComponentLoaded(this.hass, "logbook")) { + return false; + } + + const stateObj = this.hass.states[entityId]; + if (!stateObj || stateObj.attributes.unit_of_measurement) { + return false; + } + + const domain = computeDomain(entityId); + if ( + CONTINUOUS_DOMAINS.includes(domain) || + DOMAINS_MORE_INFO_NO_HISTORY.includes(domain) + ) { + return false; + } + + return true; + } + private _removeEntity() { const entityId = this._entityId!; showConfirmationDialog(this, { diff --git a/src/dialogs/more-info/ha-more-info-logbook.ts b/src/dialogs/more-info/ha-more-info-logbook.ts index a221fae68f..107636a7c0 100644 --- a/src/dialogs/more-info/ha-more-info-logbook.ts +++ b/src/dialogs/more-info/ha-more-info-logbook.ts @@ -13,11 +13,7 @@ import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { throttle } from "../../common/util/throttle"; import "../../components/ha-circular-progress"; import "../../components/state-history-charts"; -import { - CONTINUOUS_DOMAINS, - getLogbookData, - LogbookEntry, -} from "../../data/logbook"; +import { getLogbookData, LogbookEntry } from "../../data/logbook"; import "../../panels/logbook/ha-logbook"; import { haStyle, haStyleScrollbar } from "../../resources/styles"; import { HomeAssistant } from "../../types"; @@ -44,12 +40,7 @@ export class MoreInfoLogbook extends LitElement { } const stateObj = this.hass.states[this.entityId]; - if (!stateObj || stateObj.attributes.unit_of_measurement) { - return html``; - } - - const domain = computeStateDomain(stateObj); - if (CONTINUOUS_DOMAINS.includes(domain)) { + if (!stateObj) { return html``; } From d54710f11367cc6e02761f055069471ea013c83a Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Thu, 22 Oct 2020 23:13:36 +0200 Subject: [PATCH 04/25] Fix capitalization of state attributes (#7448) --- src/components/ha-attributes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ha-attributes.ts b/src/components/ha-attributes.ts index 933ed41d19..892148e664 100644 --- a/src/components/ha-attributes.ts +++ b/src/components/ha-attributes.ts @@ -34,7 +34,7 @@ class HaAttributes extends LitElement { (attribute) => html`
- ${attribute.replace(/_/g, " ").replace("id", "ID")} + ${attribute.replace(/_/g, " ").replace(/\bid\b/g, "ID")}
${this.formatAttribute(attribute)} From 6c314982dca4853946641e7d2abb8201fc759934 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 22 Oct 2020 23:29:26 +0200 Subject: [PATCH 05/25] Pass narrow to masonry view to calc columns (#7454) --- src/data/lovelace.ts | 1 + src/panels/lovelace/hui-root.ts | 5 +++++ src/panels/lovelace/views/hui-masonry-view.ts | 9 ++++++++- src/panels/lovelace/views/hui-view.ts | 7 +++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/data/lovelace.ts b/src/data/lovelace.ts index 608dbb9fb7..090bb0dfc0 100644 --- a/src/data/lovelace.ts +++ b/src/data/lovelace.ts @@ -89,6 +89,7 @@ export interface LovelaceViewConfig { export interface LovelaceViewElement extends HTMLElement { hass?: HomeAssistant; lovelace?: Lovelace; + narrow?: boolean; index?: number; cards?: Array; badges?: LovelaceBadge[]; diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 740c5a7afb..ab652d6dcc 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -490,6 +490,10 @@ class HUIRoot extends LitElement { huiView.hass = this.hass; } + if (changedProperties.has("narrow") && huiView) { + huiView.narrow = this.narrow; + } + let newSelectView; let force = false; @@ -753,6 +757,7 @@ class HUIRoot extends LitElement { view.lovelace = this.lovelace; view.hass = this.hass; + view.narrow = this.narrow; const configBackground = viewConfig.background || this.config.background; diff --git a/src/panels/lovelace/views/hui-masonry-view.ts b/src/panels/lovelace/views/hui-masonry-view.ts index 00555cd6b1..23d9833c4c 100644 --- a/src/panels/lovelace/views/hui-masonry-view.ts +++ b/src/panels/lovelace/views/hui-masonry-view.ts @@ -49,6 +49,8 @@ export class MasonryView extends LitElement implements LovelaceViewElement { @property({ attribute: false }) public lovelace?: Lovelace; + @property({ type: Boolean }) public narrow!: boolean; + @property({ type: Number }) public index?: number; @property({ attribute: false }) public cards: Array< @@ -128,6 +130,10 @@ export class MasonryView extends LitElement implements LovelaceViewElement { } } + if (changedProperties.has("narrow")) { + this._updateColumns(); + } + const oldLovelace = changedProperties.get("lovelace") as | Lovelace | undefined; @@ -252,7 +258,8 @@ export class MasonryView extends LitElement implements LovelaceViewElement { // Do -1 column if the menu is docked and open this._columns = Math.max( 1, - matchColumns - Number(this.hass!.dockedSidebar === "docked") + matchColumns - + Number(!this.narrow && this.hass!.dockedSidebar === "docked") ); } diff --git a/src/panels/lovelace/views/hui-view.ts b/src/panels/lovelace/views/hui-view.ts index 60ee6c4760..1fd878e572 100644 --- a/src/panels/lovelace/views/hui-view.ts +++ b/src/panels/lovelace/views/hui-view.ts @@ -31,6 +31,8 @@ export class HUIView extends UpdatingElement { @property({ attribute: false }) public lovelace?: Lovelace; + @property({ type: Boolean }) public narrow!: boolean; + @property({ type: Number }) public index?: number; @internalProperty() private _cards: Array = []; @@ -111,6 +113,7 @@ export class HUIView extends UpdatingElement { this._createCards(viewConfig!); this._layoutElement!.hass = this.hass; + this._layoutElement!.narrow = this.narrow; this._layoutElement!.lovelace = lovelace; this._layoutElement!.index = this.index; } @@ -127,6 +130,10 @@ export class HUIView extends UpdatingElement { this._layoutElement!.hass = this.hass; } + if (changedProperties.has("narrow")) { + this._layoutElement!.narrow = this.narrow; + } + if (editModeChanged) { this._layoutElement!.lovelace = lovelace; } From bd7cb1c877e72c6f1332b85e37c7c41bafefb53b Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 22 Oct 2020 23:51:33 +0200 Subject: [PATCH 06/25] Template dev tools: Print the type of the response and stringify objects (#7439) --- .../template/developer-tools-template.ts | 37 ++++++++++++++----- src/translations/en.json | 1 + 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/panels/developer-tools/template/developer-tools-template.ts b/src/panels/developer-tools/template/developer-tools-template.ts index a44755deb5..564f08f984 100644 --- a/src/panels/developer-tools/template/developer-tools-template.ts +++ b/src/panels/developer-tools/template/developer-tools-template.ts @@ -82,6 +82,13 @@ class HaPanelDevTemplate extends LitElement { } protected render() { + const type = typeof this._templateResult?.result; + const resultType = + type === "object" + ? Array.isArray(this._templateResult?.result) + ? "list" + : "dict" + : type; return html`
- - + ${this._rendering + ? html`` + : ""} + ${this._templateResult + ? html`${this.hass.localize( + "ui.panel.developer-tools.tabs.templates.result_type" + )}: + ${resultType}` + : ""} +
${this._error}${this._templateResult
-            ?.result}
+ class="rendered ${classMap({ + error: Boolean(this._error), + [resultType]: resultType, + })}" + >${this._error}${type === "object" + ? JSON.stringify(this._templateResult!.result, null, 2) + : this._templateResult?.result} ${this._templateResult?.listeners.time ? html`

diff --git a/src/translations/en.json b/src/translations/en.json index 284f574513..f0e50d3d92 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2956,6 +2956,7 @@ "description": "Templates are rendered using the Jinja2 template engine with some Home Assistant specific extensions.", "editor": "Template editor", "reset": "Reset to demo template", + "result_type": "Result type", "jinja_documentation": "Jinja2 template documentation", "template_extensions": "Home Assistant template extensions", "unknown_error_template": "Unknown error rendering template", From 1064cdb79d40b2e87ec6cd31cc234ce78e63b57e Mon Sep 17 00:00:00 2001 From: Donnie Date: Thu, 22 Oct 2020 15:06:36 -0700 Subject: [PATCH 07/25] Fix quick bar dark mode contrast, filter returning all items, no primary text (#7430) Co-authored-by: Bram Kragten --- src/common/string/filter/sequence-matching.ts | 2 +- src/dialogs/quick-bar/ha-quick-bar.ts | 23 ++++++++----------- src/resources/styles.ts | 1 + 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/common/string/filter/sequence-matching.ts b/src/common/string/filter/sequence-matching.ts index f8ea1f40cf..dac81672a8 100644 --- a/src/common/string/filter/sequence-matching.ts +++ b/src/common/string/filter/sequence-matching.ts @@ -59,7 +59,7 @@ export const fuzzyFilterSort: FuzzyFilterSort = (filter, items) => { : fuzzySequentialMatch(filter, item.text); return item; }) - .filter((item) => item.score === undefined || item.score > 0) + .filter((item) => item.score !== undefined && item.score > 0) .sort(({ score: scoreA = 0 }, { score: scoreB = 0 }) => scoreA > scoreB ? -1 : scoreA < scoreB ? 1 : 0 ); diff --git a/src/dialogs/quick-bar/ha-quick-bar.ts b/src/dialogs/quick-bar/ha-quick-bar.ts index dc1fce0136..68132cad04 100644 --- a/src/dialogs/quick-bar/ha-quick-bar.ts +++ b/src/dialogs/quick-bar/ha-quick-bar.ts @@ -61,8 +61,6 @@ export class QuickBar extends LitElement { @internalProperty() private _commandMode = false; - @internalProperty() private _commandTriggered = -1; - @internalProperty() private _done = false; @query("search-input", false) private _filterInputField?: HTMLElement; @@ -82,7 +80,6 @@ export class QuickBar extends LitElement { this._focusSet = false; this._filter = ""; this._search = ""; - this._commandTriggered = -1; this._items = []; fireEvent(this, "dialog-closed", { dialog: this.localName }); } @@ -137,7 +134,6 @@ export class QuickBar extends LitElement { active >` : html`${item.altText} ` : null} - ${this._commandTriggered === index - ? html`` - : null} `; } private async processItemAndCloseDialog(item: QuickBarItem, index: number) { - this._commandTriggered = index; + this._addSpinnerToCommandItem(index); await item.action(); this.closeDialog(); @@ -234,6 +223,14 @@ export class QuickBar extends LitElement { return this.renderRoot.querySelector(`mwc-list-item[index="${index}"]`); } + private _addSpinnerToCommandItem(index: number): void { + const spinner = document.createElement("ha-circular-progress"); + spinner.size = "small"; + spinner.slot = "meta"; + spinner.active = true; + this._getItemAtIndex(index)?.appendChild(spinner); + } + private _handleSearchChange(ev: CustomEvent): void { const newFilter = ev.detail.value; const oldCommandMode = this._commandMode; @@ -303,7 +300,7 @@ export class QuickBar extends LitElement { private _generateEntityItems(): QuickBarItem[] { return Object.keys(this.hass.states) .map((entityId) => ({ - text: computeStateName(this.hass.states[entityId]), + text: computeStateName(this.hass.states[entityId]) || entityId, altText: entityId, icon: domainIcon(computeDomain(entityId), this.hass.states[entityId]), action: () => fireEvent(this, "hass-more-info", { entityId }), diff --git a/src/resources/styles.ts b/src/resources/styles.ts index 948102eb4d..56f11d6b5c 100644 --- a/src/resources/styles.ts +++ b/src/resources/styles.ts @@ -12,6 +12,7 @@ export const darkStyles = { "switch-unchecked-button-color": "#999999", "switch-unchecked-track-color": "#9b9b9b", "divider-color": "rgba(225, 225, 225, .12)", + "mdc-ripple-color": "#AAAAAA", "codemirror-keyword": "#C792EA", "codemirror-operator": "#89DDFF", "codemirror-variable": "#f07178", From 2acb6a28fe2171bb6f413fe022e093123e5aec14 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 22 Oct 2020 17:10:51 -0500 Subject: [PATCH 08/25] Update template time listener phrasing for core changes (#7450) --- .../developer-tools/template/developer-tools-template.ts | 6 ++++-- src/translations/en.json | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/panels/developer-tools/template/developer-tools-template.ts b/src/panels/developer-tools/template/developer-tools-template.ts index 564f08f984..9ec9c1c4ad 100644 --- a/src/panels/developer-tools/template/developer-tools-template.ts +++ b/src/panels/developer-tools/template/developer-tools-template.ts @@ -228,11 +228,13 @@ class HaPanelDevTemplate extends LitElement { )} ` - : html` + : !this._templateResult?.listeners.time + ? html` ${this.hass.localize( "ui.panel.developer-tools.tabs.templates.no_listeners" )} - `} + ` + : html``}

`; diff --git a/src/translations/en.json b/src/translations/en.json index f0e50d3d92..59a2fb4e04 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2960,9 +2960,9 @@ "jinja_documentation": "Jinja2 template documentation", "template_extensions": "Home Assistant template extensions", "unknown_error_template": "Unknown error rendering template", - "time": "This template updates every 60 seconds after the last state changed event.", + "time": "This template updates at the start of each minute.", "all_listeners": "This template listens for all state changed events.", - "no_listeners": "This template does not listen for any state changed events and will not update automatically.", + "no_listeners": "This template does not listen for any events and will not update automatically.", "listeners": "This template listens for the following state changed events:", "entity": "Entity", "domain": "Domain" From b22f5ae5c2f0086d4cf1f00cd4cb976e5c2a6f45 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Thu, 22 Oct 2020 16:24:12 +0200 Subject: [PATCH 09/25] Add outline color for dark buttons (#7444) --- src/resources/styles.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/resources/styles.ts b/src/resources/styles.ts index 56f11d6b5c..2313327b54 100644 --- a/src/resources/styles.ts +++ b/src/resources/styles.ts @@ -90,6 +90,7 @@ export const derivedStyles = { "mdc-radio-disabled-color": "var(--disabled-text-color)", "mdc-tab-text-label-color-default": "var(--primary-text-color)", "mdc-button-disabled-ink-color": "var(--disabled-text-color)", + "mdc-button-outline-color": "var(--divider-color)", "mdc-dialog-scroll-divider-color": "var(--divider-color)", }; From 48543a2dad6ee04b8fbbc8eef70fe1ed7a9752e4 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 23 Oct 2020 00:18:49 +0200 Subject: [PATCH 10/25] Bumped version to 20201021.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index af4d870361..4270f08ea8 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20201021.1", + version="20201021.2", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From 603b833757eb3872bc4f5f8493b95cf98e29a4d1 Mon Sep 17 00:00:00 2001 From: Ryan Meek <25127328+maykar@users.noreply.github.com> Date: Fri, 23 Oct 2020 18:53:11 -0400 Subject: [PATCH 11/25] fix edit mode mwc-button size (#7472) --- src/components/ha-sidebar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 086b0bfdba..2f1f473ca4 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -781,7 +781,7 @@ class HaSidebar extends LitElement { display: initial; } .title mwc-button { - width: 100%; + width: 90%; } #sortable, .hidden-panel { From 79927f4dc947f790cedaa4e69899ebf5847bfdda Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 26 Oct 2020 09:41:43 +0100 Subject: [PATCH 12/25] Update translation for MQTT reload (#7475) --- src/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/en.json b/src/translations/en.json index 59a2fb4e04..6891985d2c 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -999,7 +999,7 @@ "filesize": "Reload file size entities", "telegram": "Reload telegram notify services", "smtp": "Reload smtp notify services", - "mqtt": "Reload mqtt entities", + "mqtt": "Reload manually configured mqtt entities", "rpi_gpio": "Reload Raspberry Pi GPIO entities" }, "server_management": { From e4e6edd573f795d4b0b053f28f475f451d0aedb6 Mon Sep 17 00:00:00 2001 From: Ryan Meek <25127328+maykar@users.noreply.github.com> Date: Mon, 26 Oct 2020 04:42:57 -0400 Subject: [PATCH 13/25] Fix lovelace background color (#7478) --- src/panels/lovelace/hui-root.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index ab652d6dcc..ad92d4a9f8 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -789,7 +789,10 @@ class HUIRoot extends LitElement { ha-app-layout { min-height: 100%; - background: var(--lovelace-background); + background: var( + --lovelace-background, + var(--primary-background-color) + ); } ha-tabs { width: 100%; From ce414a5ca915f7c590d55dea9d80b70deb9a7f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Mon, 26 Oct 2020 20:55:47 +0100 Subject: [PATCH 14/25] Correctly replace rebuilt badges in view (#7487) --- src/panels/lovelace/views/hui-view.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/views/hui-view.ts b/src/panels/lovelace/views/hui-view.ts index 1fd878e572..39b2cb3d44 100644 --- a/src/panels/lovelace/views/hui-view.ts +++ b/src/panels/lovelace/views/hui-view.ts @@ -224,7 +224,7 @@ export class HUIView extends UpdatingElement { badgeElToReplace ); } - this._badges = this._cards!.map((curBadgeEl) => + this._badges = this._badges!.map((curBadgeEl) => curBadgeEl === badgeElToReplace ? newBadgeEl : curBadgeEl ); } From 30466ec3fe88e0e712b4677270d7e3d264d18775 Mon Sep 17 00:00:00 2001 From: Donnie Date: Tue, 27 Oct 2020 10:00:46 -0700 Subject: [PATCH 15/25] Add toggle for disabling quick bar shortcuts (#7495) * Add toggle for disabling quick bar shortcuts * Remove accidentally included code * Change copy for toggle * Rename hass property to be for generic shortcuts --- src/panels/profile/ha-enable-shortcuts-row.ts | 51 +++++++++++++++++++ src/panels/profile/ha-panel-profile.ts | 6 ++- src/state/connection-mixin.ts | 1 + src/state/quick-bar-mixin.ts | 10 +++- src/translations/en.json | 4 ++ src/types.ts | 1 + src/util/ha-pref-storage.ts | 1 + 7 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 src/panels/profile/ha-enable-shortcuts-row.ts diff --git a/src/panels/profile/ha-enable-shortcuts-row.ts b/src/panels/profile/ha-enable-shortcuts-row.ts new file mode 100644 index 0000000000..8fb362c76b --- /dev/null +++ b/src/panels/profile/ha-enable-shortcuts-row.ts @@ -0,0 +1,51 @@ +import { + customElement, + html, + LitElement, + property, + TemplateResult, +} from "lit-element"; +import { fireEvent } from "../../common/dom/fire_event"; +import "../../components/ha-switch"; +import type { HaSwitch } from "../../components/ha-switch"; +import type { HomeAssistant } from "../../types"; +import "../../components/ha-settings-row"; + +@customElement("ha-enable-shortcuts-row") +class HaEnableShortcutsRow extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public narrow!: boolean; + + protected render(): TemplateResult { + return html` + + + ${this.hass.localize("ui.panel.profile.enable_shortcuts.header")} + + + ${this.hass.localize("ui.panel.profile.enable_shortcuts.description")} + + + + `; + } + + private async _checkedChanged(ev: Event) { + const enabled = (ev.target as HaSwitch).checked; + if (enabled === this.hass.enableShortcuts) { + return; + } + + fireEvent(this, "hass-enable-shortcuts", enabled); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-enable-shortcuts-row": HaEnableShortcutsRow; + } +} diff --git a/src/panels/profile/ha-panel-profile.ts b/src/panels/profile/ha-panel-profile.ts index 3c8e6ab6a4..9ce8a0bb6e 100644 --- a/src/panels/profile/ha-panel-profile.ts +++ b/src/panels/profile/ha-panel-profile.ts @@ -38,6 +38,7 @@ import "./ha-push-notifications-row"; import "./ha-refresh-tokens-card"; import "./ha-set-suspend-row"; import "./ha-set-vibrate-row"; +import "./ha-enable-shortcuts-row"; class HaPanelProfile extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -161,7 +162,10 @@ class HaPanelProfile extends LitElement { .narrow=${this.narrow} .hass=${this.hass} > - +
${this.hass.localize("ui.panel.profile.logout")} diff --git a/src/state/connection-mixin.ts b/src/state/connection-mixin.ts index 7af421029d..9862ed3bb3 100644 --- a/src/state/connection-mixin.ts +++ b/src/state/connection-mixin.ts @@ -48,6 +48,7 @@ export const connectionMixin = >( dockedSidebar: "docked", vibrate: true, suspendWhenHidden: true, + enableShortcuts: true, moreInfoEntityId: null, hassUrl: (path = "") => new URL(path, auth.data.hassUrl).toString(), callService: async (domain, service, serviceData = {}) => { diff --git a/src/state/quick-bar-mixin.ts b/src/state/quick-bar-mixin.ts index cfefcb388c..c7a8844285 100644 --- a/src/state/quick-bar-mixin.ts +++ b/src/state/quick-bar-mixin.ts @@ -4,10 +4,13 @@ import { QuickBarParams, showQuickBar, } from "../dialogs/quick-bar/show-dialog-quick-bar"; +import { HomeAssistant } from "../types"; +import { storeState } from "../util/ha-pref-storage"; declare global { interface HASSDomEvents { "hass-quick-bar": QuickBarParams; + "hass-enable-shortcuts": HomeAssistant["enableShortcuts"]; } } @@ -18,12 +21,17 @@ export default >(superClass: T) => protected firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); + this.addEventListener("hass-enable-shortcuts", (ev) => { + this._updateHass({ enableShortcuts: ev.detail }); + storeState(this.hass!); + }); + this._registerShortcut(); } private _registerShortcut() { document.addEventListener("keydown", (e: KeyboardEvent) => { - if (!this.hass?.user?.is_admin) { + if (!this.hass?.user?.is_admin || !this.hass.enableShortcuts) { return; } if (this.isOSCtrlKey(e) && e.code === "KeyP") { diff --git a/src/translations/en.json b/src/translations/en.json index 6891985d2c..c43967cbbf 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2664,6 +2664,10 @@ "header": "Vibrate", "description": "Enable or disable vibration on this device when controlling devices." }, + "enable_shortcuts": { + "header": "Keyboard Shortcuts", + "description": "Enable or disable keyboard shortcuts for performing various actions in the UI." + }, "suspend": { "header": "Automatically close connection", "description": "Should we close the connection to the server after being hidden for 5 minutes?" diff --git a/src/types.ts b/src/types.ts index 4092ac6c6a..5f302d4895 100644 --- a/src/types.ts +++ b/src/types.ts @@ -237,6 +237,7 @@ export interface HomeAssistant { localize: LocalizeFunc; translationMetadata: TranslationMetadata; suspendWhenHidden: boolean; + enableShortcuts: boolean; vibrate: boolean; dockedSidebar: "docked" | "always_hidden" | "auto"; defaultPanel: string; diff --git a/src/util/ha-pref-storage.ts b/src/util/ha-pref-storage.ts index bb06674f35..8c21de00b7 100644 --- a/src/util/ha-pref-storage.ts +++ b/src/util/ha-pref-storage.ts @@ -6,6 +6,7 @@ const STORED_STATE = [ "selectedLanguage", "vibrate", "suspendWhenHidden", + "enableShortcuts", "defaultPanel", ]; const STORAGE = window.localStorage || {}; From 36c1d3230cdaa328fbba48bc5e977807c520f2c2 Mon Sep 17 00:00:00 2001 From: Donnie Date: Tue, 27 Oct 2020 10:34:51 -0700 Subject: [PATCH 16/25] Change Quick Bar shortcuts to "e" and "c" (#7496) * Add toggle for disabling quick bar shortcuts * Change shortcut from Ctrl+P and Ctrl+Shift+P to qe and qc (Quick Entity, Quick Command) * Remove accidentally included code * Use tinykeys for handling shortcuts * Change shortcuts to e and c. And fix small typo. * Change copy for toggle * Rename hass property to be for generic shortcuts * Minor tweaks to address review comments --- package.json | 1 + src/state/quick-bar-mixin.ts | 37 +++++++++++++++++++----------------- yarn.lock | 5 +++++ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 82ba1c1336..483b6ea952 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "roboto-fontface": "^0.10.0", "sortablejs": "^1.10.2", "superstruct": "^0.10.12", + "tinykeys": "^1.1.1", "unfetch": "^4.1.0", "vue": "^2.6.11", "vue2-daterange-picker": "^0.5.1", diff --git a/src/state/quick-bar-mixin.ts b/src/state/quick-bar-mixin.ts index c7a8844285..3940ffe831 100644 --- a/src/state/quick-bar-mixin.ts +++ b/src/state/quick-bar-mixin.ts @@ -1,3 +1,4 @@ +import tinykeys from "tinykeys"; import type { Constructor, PropertyValues } from "lit-element"; import { HassElement } from "./hass-element"; import { @@ -14,8 +15,6 @@ declare global { } } -const isMacOS = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform); - export default >(superClass: T) => class extends superClass { protected firstUpdated(changedProps: PropertyValues) { @@ -30,23 +29,27 @@ export default >(superClass: T) => } private _registerShortcut() { - document.addEventListener("keydown", (e: KeyboardEvent) => { - if (!this.hass?.user?.is_admin || !this.hass.enableShortcuts) { - return; - } - if (this.isOSCtrlKey(e) && e.code === "KeyP") { - e.preventDefault(); - const eventParams: QuickBarParams = {}; - if (e.shiftKey) { - eventParams.commandMode = true; - } - - showQuickBar(this, eventParams); - } + tinykeys(window, { + e: (ev) => this._showQuickBar(ev), + c: (ev) => this._showQuickBar(ev, true), }); } - private isOSCtrlKey(e: KeyboardEvent) { - return isMacOS ? e.metaKey : e.ctrlKey; + private _showQuickBar(e: KeyboardEvent, commandMode = false) { + if ( + !this.hass?.user?.is_admin || + !this.hass.enableShortcuts || + this._inInputField(e) + ) { + return; + } + + showQuickBar(this, { commandMode }); + } + + private _inInputField(e: KeyboardEvent) { + return ["INPUT", "TEXTAREA"].includes( + (e.composedPath()[0] as HTMLElement).tagName + ); } }; diff --git a/yarn.lock b/yarn.lock index e1439d610c..7133eda793 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12230,6 +12230,11 @@ tinycolor2@^1.4.1: resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g= +tinykeys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tinykeys/-/tinykeys-1.1.1.tgz#2535e8b24c8e2be447dd0ee1cff656ef435cd63d" + integrity sha512-YEA1TGMlkMabXI0NGddRFti+c1eMO2QP7wefwibSz0Pip8sA+d99yX5Pp7pK7wUeTKmrF4ys4XZVz44YydlTYg== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" From e6a4ab789b8a3ce49f124b2801d2ad00eaedb991 Mon Sep 17 00:00:00 2001 From: Donnie Date: Tue, 27 Oct 2020 12:14:25 -0700 Subject: [PATCH 17/25] Add server restart/stop to quick bar command list (#7488) --- src/dialogs/quick-bar/ha-quick-bar.ts | 46 +++++++++++++++++++++++++-- src/translations/en.json | 5 +++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/dialogs/quick-bar/ha-quick-bar.ts b/src/dialogs/quick-bar/ha-quick-bar.ts index 68132cad04..95c4ce18bb 100644 --- a/src/dialogs/quick-bar/ha-quick-bar.ts +++ b/src/dialogs/quick-bar/ha-quick-bar.ts @@ -36,6 +36,10 @@ import "../../components/ha-header-bar"; import { domainToName } from "../../data/integration"; import { haStyleDialog } from "../../resources/styles"; import { HomeAssistant } from "../../types"; +import { + ConfirmationDialogParams, + showConfirmationDialog, +} from "../generic/show-dialog-box"; import { QuickBarParams } from "./show-dialog-quick-bar"; interface QuickBarItem extends ScorableTextItem { @@ -276,9 +280,10 @@ export class QuickBar extends LitElement { } private _generateCommandItems(): QuickBarItem[] { - return [...this._generateReloadCommands()].sort((a, b) => - compare(a.text.toLowerCase(), b.text.toLowerCase()) - ); + return [ + ...this._generateReloadCommands(), + ...this._generateServerControlCommands(), + ].sort((a, b) => compare(a.text.toLowerCase(), b.text.toLowerCase())); } private _generateReloadCommands(): QuickBarItem[] { @@ -297,6 +302,41 @@ export class QuickBar extends LitElement { })); } + private _generateServerControlCommands(): QuickBarItem[] { + const serverActions = ["restart", "stop"]; + + return serverActions.map((action) => + this._generateConfirmationCommand( + { + text: this.hass.localize( + "ui.dialogs.quick-bar.commands.server_control.perform_action", + "action", + this.hass.localize( + `ui.dialogs.quick-bar.commands.server_control.${action}` + ) + ), + icon: "hass:server", + action: () => this.hass.callService("homeassistant", action), + }, + this.hass.localize("ui.dialogs.generic.ok") + ) + ); + } + + private _generateConfirmationCommand( + item: QuickBarItem, + confirmText: ConfirmationDialogParams["confirmText"] + ): QuickBarItem { + return { + ...item, + action: () => + showConfirmationDialog(this, { + confirmText, + confirm: item.action, + }), + }; + } + private _generateEntityItems(): QuickBarItem[] { return Object.keys(this.hass.states) .map((entityId) => ({ diff --git a/src/translations/en.json b/src/translations/en.json index c43967cbbf..0181e61104 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -485,6 +485,11 @@ "smtp": "[%key:ui::panel::config::server_control::section::reloading::smtp%]", "mqtt": "[%key:ui::panel::config::server_control::section::reloading::mqtt%]", "rpi_gpio": "[%key:ui::panel::config::server_control::section::reloading::rpi_gpio%]" + }, + "server_control": { + "perform_action": "{action} Server", + "restart": "[%key:ui::panel::config::server_control::section::server_management::restart%]", + "stop": "[%key:ui::panel::config::server_control::section::server_management::stop%]" } }, "filter_placeholder": "Entity Filter" From bec0d9b00e821c5ed00dc0f51b98e0c80f35b9b7 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 27 Oct 2020 20:18:52 +0100 Subject: [PATCH 18/25] Bumped version to 20201021.3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4270f08ea8..db4badf978 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20201021.2", + version="20201021.3", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From 0baaaefdf8e3cf88c2d1210d6bc55816b962c9e8 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Thu, 22 Oct 2020 23:57:52 +0200 Subject: [PATCH 19/25] Get rid of the unwanted tooltip copying (#7408) --- src/panels/config/info/system-health-card.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/panels/config/info/system-health-card.ts b/src/panels/config/info/system-health-card.ts index b3433a0831..13b9b80e2b 100644 --- a/src/panels/config/info/system-health-card.ts +++ b/src/panels/config/info/system-health-card.ts @@ -128,14 +128,24 @@ class SystemHealthCard extends LitElement { } private _copyInfo(): void { + // We have to copy title text and content separately, because + // copying the whole would also copy the tooltip text. const selection = window.getSelection()!; selection.removeAllRanges(); - const copyElement = this.shadowRoot?.querySelector( - "ha-card" + let copyElement = this.shadowRoot?.querySelector( + ".card-header-text" ) as HTMLElement; - const range = document.createRange(); + let range = document.createRange(); + range.selectNodeContents(copyElement); + selection.addRange(range); + + copyElement = this.shadowRoot?.querySelector( + ".card-content" + ) as HTMLElement; + + range = document.createRange(); range.selectNodeContents(copyElement); selection.addRange(range); From e37eebe4ad4580be6a0d79415106dd848683b8d0 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Tue, 27 Oct 2020 20:20:15 +0100 Subject: [PATCH 20/25] Get rid of the unwanted tooltip copying (final) (#7459) --- src/panels/config/info/system-health-card.ts | 29 +++++++++----------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/panels/config/info/system-health-card.ts b/src/panels/config/info/system-health-card.ts index 13b9b80e2b..69df18b5b5 100644 --- a/src/panels/config/info/system-health-card.ts +++ b/src/panels/config/info/system-health-card.ts @@ -72,7 +72,7 @@ class SystemHealthCard extends LitElement { } if (domain !== "homeassistant") { sections.push( - html`

${domainToName(this.hass.localize, domain)}

` + html`

${domainToName(this.hass.localize, domain)}

` ); } sections.push(html` @@ -128,30 +128,27 @@ class SystemHealthCard extends LitElement { } private _copyInfo(): void { - // We have to copy title text and content separately, because - // copying the whole would also copy the tooltip text. - const selection = window.getSelection()!; - selection.removeAllRanges(); - - let copyElement = this.shadowRoot?.querySelector( - ".card-header-text" - ) as HTMLElement; - - let range = document.createRange(); - range.selectNodeContents(copyElement); - selection.addRange(range); - - copyElement = this.shadowRoot?.querySelector( + const copyElement = this.shadowRoot?.querySelector( ".card-content" ) as HTMLElement; - range = document.createRange(); + // Add temporary heading (fixed in EN since usually executed to provide support data) + const tempTitle = document.createElement("h3"); + tempTitle.innerText = "System Health"; + copyElement.insertBefore(tempTitle, copyElement.firstElementChild); + + const selection = window.getSelection()!; + selection.removeAllRanges(); + const range = document.createRange(); range.selectNodeContents(copyElement); selection.addRange(range); document.execCommand("copy"); window.getSelection()!.removeAllRanges(); + // Remove temporary heading again + copyElement.removeChild(tempTitle); + this._toolTip!.show(); setTimeout(() => this._toolTip?.hide(), 3000); } From 35151bbac703575a3ab08c2783e8e11133a2b1cb Mon Sep 17 00:00:00 2001 From: Donnie Date: Thu, 29 Oct 2020 09:18:47 -0700 Subject: [PATCH 21/25] Fix issue with toggles blocking dialog and dialog launching on mobile (#7506) * Fix issue with some inputs blocking, or incorrectly allowing, keyboard shortcut activation * Explicitly declare all input types that we can allow alphanumeric overrides * Do not launch dialog in codemirror targets on mobile devices --- src/components/ha-code-editor.ts | 5 +++++ src/state/quick-bar-mixin.ts | 37 +++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/components/ha-code-editor.ts b/src/components/ha-code-editor.ts index b49d57c897..5dc3b7f826 100644 --- a/src/components/ha-code-editor.ts +++ b/src/components/ha-code-editor.ts @@ -81,6 +81,7 @@ export class HaCodeEditor extends UpdatingElement { protected firstUpdated(changedProps: PropertyValues): void { super.firstUpdated(changedProps); + this._blockKeyboardShortcuts(); this._load(); } @@ -232,6 +233,10 @@ export class HaCodeEditor extends UpdatingElement { this.codemirror!.on("changes", () => this._onChange()); } + private _blockKeyboardShortcuts() { + this.addEventListener("keydown", (ev) => ev.stopPropagation()); + } + private _onChange(): void { const newValue = this.value; if (newValue === this._value) { diff --git a/src/state/quick-bar-mixin.ts b/src/state/quick-bar-mixin.ts index 3940ffe831..ceac362aa1 100644 --- a/src/state/quick-bar-mixin.ts +++ b/src/state/quick-bar-mixin.ts @@ -36,20 +36,41 @@ export default >(superClass: T) => } private _showQuickBar(e: KeyboardEvent, commandMode = false) { - if ( - !this.hass?.user?.is_admin || - !this.hass.enableShortcuts || - this._inInputField(e) - ) { + if (!this._canShowQuickBar(e)) { return; } showQuickBar(this, { commandMode }); } - private _inInputField(e: KeyboardEvent) { - return ["INPUT", "TEXTAREA"].includes( - (e.composedPath()[0] as HTMLElement).tagName + private _canShowQuickBar(e: KeyboardEvent) { + return ( + this.hass?.user?.is_admin && + this.hass.enableShortcuts && + this._canOverrideAlphanumericInput(e) ); } + + private _canOverrideAlphanumericInput(e: KeyboardEvent) { + const el = e.composedPath()[0] as any; + + if (el.tagName === "TEXTAREA") { + return false; + } + + if (el.tagName !== "INPUT") { + return true; + } + + switch (el.type) { + case "button": + case "checkbox": + case "hidden": + case "radio": + case "range": + return true; + default: + return false; + } + } }; From 5b232b5d35714b9b2d4073940f0f8f3e9b9440c8 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 29 Oct 2020 18:29:20 +0100 Subject: [PATCH 22/25] Fix glance card with header if parent does not set block (#7526) --- src/panels/lovelace/cards/hui-glance-card.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index f3e9fb7f55..d446b109ec 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -197,7 +197,6 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard { display: flex; padding: 0 16px 4px; flex-wrap: wrap; - height: 100%; box-sizing: border-box; align-content: center; } From ce4ba2f6f17a74326ca6c7c7d0796957baa002a4 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 29 Oct 2020 18:29:54 +0100 Subject: [PATCH 23/25] Fix tooltip creating scrollbar history card (#7528) --- src/panels/lovelace/cards/hui-history-graph-card.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/panels/lovelace/cards/hui-history-graph-card.ts b/src/panels/lovelace/cards/hui-history-graph-card.ts index 57b932c2db..8b67582946 100644 --- a/src/panels/lovelace/cards/hui-history-graph-card.ts +++ b/src/panels/lovelace/cards/hui-history-graph-card.ts @@ -189,7 +189,6 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard { return css` ha-card { height: 100%; - overflow-y: auto; } .content { padding: 16px; From bf4a94dc484e97a0a4dfe352474e8597bf4185ab Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Thu, 29 Oct 2020 18:30:20 +0100 Subject: [PATCH 24/25] Add MQTT as ignorable discovery flow (#7527) --- src/data/config_flow.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data/config_flow.ts b/src/data/config_flow.ts index 94cce83ba8..367924e015 100644 --- a/src/data/config_flow.ts +++ b/src/data/config_flow.ts @@ -11,6 +11,7 @@ export const DISCOVERY_SOURCES = [ "ssdp", "zeroconf", "discovery", + "mqtt", ]; export const ATTENTION_SOURCES = ["reauth"]; From 744efa30f2e875d056bef38c6a2ed7a6bde3e287 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 29 Oct 2020 18:33:22 +0100 Subject: [PATCH 25/25] Bumped version to 20201021.4 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index db4badf978..e6b913852e 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20201021.3", + version="20201021.4", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors",