diff --git a/setup.cfg b/setup.cfg index 0b418da16a..fd31a6964f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = home-assistant-frontend -version = 20220503.0 +version = 20220504.0 author = The Home Assistant Authors author_email = hello@home-assistant.io license = Apache-2.0 diff --git a/src/components/media-player/ha-media-player-browse.ts b/src/components/media-player/ha-media-player-browse.ts index 5f219bf247..285ebcea54 100644 --- a/src/components/media-player/ha-media-player-browse.ts +++ b/src/components/media-player/ha-media-player-browse.ts @@ -1,10 +1,11 @@ +import "@lit-labs/virtualizer"; +import type { LitVirtualizer } from "@lit-labs/virtualizer"; +import { grid } from "@lit-labs/virtualizer/layouts/grid"; import "@material/mwc-button/mwc-button"; import "@material/mwc-list/mwc-list"; import "@material/mwc-list/mwc-list-item"; import { mdiArrowUpRight, mdiPlay, mdiPlus } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { grid } from "@lit-labs/virtualizer/layouts/grid"; -import "@lit-labs/virtualizer"; import { css, CSSResultGroup, @@ -21,10 +22,12 @@ import { state, } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; +import { styleMap } from "lit/directives/style-map"; import { until } from "lit/directives/until"; import { fireEvent } from "../../common/dom/fire_event"; import { computeRTLDirection } from "../../common/util/compute_rtl"; import { debounce } from "../../common/util/debounce"; +import { getSignedPath } from "../../data/auth"; import type { MediaPlayerItem } from "../../data/media-player"; import { browseMediaPlayer, @@ -39,6 +42,7 @@ import { showAlertDialog } from "../../dialogs/generic/show-dialog-box"; import { installResizeObserver } from "../../panels/lovelace/common/install-resize-observer"; import { haStyle } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; +import { brandsUrl, extractDomainFromBrandUrl } from "../../util/brands-url"; import { documentationUrl } from "../../util/documentation-url"; import "../entity/ha-entity-picker"; import "../ha-button-menu"; @@ -49,8 +53,6 @@ import "../ha-icon-button"; import "../ha-svg-icon"; import "./ha-browse-media-tts"; import type { TtsMediaPickedEvent } from "./ha-browse-media-tts"; -import { getSignedPath } from "../../data/auth"; -import { brandsUrl, extractDomainFromBrandUrl } from "../../util/brands-url"; declare global { interface HASSDomEvents { @@ -100,6 +102,10 @@ export class HaMediaPlayerBrowse extends LitElement { @query(".content") private _content?: HTMLDivElement; + @query("lit-virtualizer") private _virtualizer?: LitVirtualizer; + + private _observed = false; + private _headerOffsetHeight = 0; private _resizeObserver?: ResizeObserver; @@ -280,6 +286,19 @@ export class HaMediaPlayerBrowse extends LitElement { this._animateHeaderHeight(); } else if (changedProps.has("_currentItem")) { this._setHeaderHeight(); + + // This fixes a race condition for resizing of the cards using the grid layout + if (this._observed) { + return; + } + + // @ts-ignore + const virtualizer = this._virtualizer?._virtualizer; + + if (virtualizer) { + this._observed = true; + setTimeout(() => virtualizer._observeMutations(), 0); + } } } @@ -477,6 +496,9 @@ export class HaMediaPlayerBrowse extends LitElement { ${currentItem.not_shown @@ -606,7 +628,6 @@ export class HaMediaPlayerBrowse extends LitElement { ${child.title} -
  • `; }; diff --git a/src/data/update.ts b/src/data/update.ts index e76a8947a3..f888823d21 100644 --- a/src/data/update.ts +++ b/src/data/update.ts @@ -2,8 +2,10 @@ import type { HassEntities, HassEntityAttributeBase, HassEntityBase, + HassEvent, } from "home-assistant-js-websocket"; import { BINARY_STATE_ON } from "../common/const"; +import { computeDomain } from "../common/entity/compute_domain"; import { computeStateDomain } from "../common/entity/compute_state_domain"; import { supportsFeature } from "../common/entity/supports-feature"; import { caseInsensitiveStringCompare } from "../common/string/compare"; @@ -110,15 +112,32 @@ export const checkForEntityUpdates = async ( return; } + let updated = 0; + + const unsubscribeEvents = await hass.connection.subscribeEvents( + (event) => { + if (computeDomain(event.data.entity_id) === "update") { + updated++; + showToast(element, { + message: hass.localize("ui.panel.config.updates.updates_refreshed", { + count: updated, + }), + }); + } + }, + "state_changed" + ); + await hass.callService("homeassistant", "update_entity", { entity_id: entities, }); - if (filterUpdateEntitiesWithInstall(hass.states).length) { - showToast(element, { - message: hass.localize("ui.panel.config.updates.updates_refreshed"), - }); - } else { + // there is no reliable way to know if all the updates are done updating, so we just wait a bit for now... + await new Promise((r) => setTimeout(r, 10000)); + + unsubscribeEvents(); + + if (updated === 0) { showToast(element, { message: hass.localize("ui.panel.config.updates.no_new_updates"), }); diff --git a/src/panels/config/automation/action/ha-automation-action.ts b/src/panels/config/automation/action/ha-automation-action.ts index 0222b11609..3abbbd7d6e 100644 --- a/src/panels/config/automation/action/ha-automation-action.ts +++ b/src/panels/config/automation/action/ha-automation-action.ts @@ -1,3 +1,4 @@ +import deepClone from "deep-clone-simple"; import "@material/mwc-button"; import { css, CSSResultGroup, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; @@ -83,7 +84,7 @@ export default class HaAutomationAction extends LitElement { ev.stopPropagation(); const index = (ev.target as any).index; fireEvent(this, "value-changed", { - value: this.actions.concat(this.actions[index]), + value: this.actions.concat(deepClone(this.actions[index])), }); } diff --git a/src/panels/config/automation/condition/ha-automation-condition.ts b/src/panels/config/automation/condition/ha-automation-condition.ts index 4cee821b21..de5972e164 100644 --- a/src/panels/config/automation/condition/ha-automation-condition.ts +++ b/src/panels/config/automation/condition/ha-automation-condition.ts @@ -1,3 +1,4 @@ +import deepClone from "deep-clone-simple"; import "@material/mwc-button"; import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; import { customElement, property } from "lit/decorators"; @@ -96,7 +97,7 @@ export default class HaAutomationCondition extends LitElement { ev.stopPropagation(); const index = (ev.target as any).index; fireEvent(this, "value-changed", { - value: this.conditions.concat(this.conditions[index]), + value: this.conditions.concat(deepClone(this.conditions[index])), }); } diff --git a/src/panels/config/automation/trigger/ha-automation-trigger.ts b/src/panels/config/automation/trigger/ha-automation-trigger.ts index 3d058a83fb..1b359dd83e 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger.ts @@ -1,3 +1,4 @@ +import deepClone from "deep-clone-simple"; import "@material/mwc-button"; import { css, CSSResultGroup, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; @@ -67,7 +68,7 @@ export default class HaAutomationTrigger extends LitElement { ev.stopPropagation(); const index = (ev.target as any).index; fireEvent(this, "value-changed", { - value: this.triggers.concat(this.triggers[index]), + value: this.triggers.concat(deepClone(this.triggers[index])), }); } diff --git a/src/panels/config/core/ha-config-section-updates.ts b/src/panels/config/core/ha-config-section-updates.ts index a60d568b2c..e7f11d6318 100644 --- a/src/panels/config/core/ha-config-section-updates.ts +++ b/src/panels/config/core/ha-config-section-updates.ts @@ -109,7 +109,11 @@ class HaConfigSectionUpdates extends LitElement { > ` : html` - ${this.hass.localize("ui.panel.config.updates.no_updates")} +
    + ${this.hass.localize( + "ui.panel.config.updates.no_updates" + )} +
    `} @@ -198,6 +202,10 @@ class HaConfigSectionUpdates extends LitElement { flex-direction: column; padding: 0; } + + .no-updates { + padding: 16px; + } `; } diff --git a/src/panels/config/dashboard/ha-config-updates.ts b/src/panels/config/dashboard/ha-config-updates.ts index 416b0d9d8d..dcb02c4de4 100644 --- a/src/panels/config/dashboard/ha-config-updates.ts +++ b/src/panels/config/dashboard/ha-config-updates.ts @@ -9,6 +9,7 @@ import "../../../components/ha-alert"; import "../../../components/ha-icon-next"; import type { UpdateEntity } from "../../../data/update"; import type { HomeAssistant } from "../../../types"; +import "../../../components/ha-circular-progress"; @customElement("ha-config-updates") class HaConfigUpdates extends LitElement { @@ -51,7 +52,18 @@ class HaConfigUpdates extends LitElement { .title=${entity.attributes.title || entity.attributes.friendly_name} .stateObj=${entity} + class=${this.narrow && entity.attributes.in_progress + ? "updating" + : ""} > + ${this.narrow && entity.attributes.in_progress + ? html`` + : ""} ${entity.attributes.title || entity.attributes.friendly_name} ${!this.narrow - ? html`` + ? entity.attributes.in_progress + ? html`` + : html`` : ""} ` @@ -121,6 +139,12 @@ class HaConfigUpdates extends LitElement { cursor: pointer; font-size: 16px; } + ha-circular-progress.absolute { + position: absolute; + } + state-badge.updating { + opacity: 0.5; + } `, ]; } diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts index d2790ec98f..40484aa881 100644 --- a/src/panels/config/integrations/ha-integration-card.ts +++ b/src/panels/config/integrations/ha-integration-card.ts @@ -52,7 +52,6 @@ import type { ConfigEntryExtended } from "./ha-config-integrations"; import "./ha-integration-header"; const integrationsWithPanel = { - hassio: "/hassio/dashboard", mqtt: "/config/mqtt", zha: "/config/zha/dashboard", zwave_js: "/config/zwave_js/dashboard", diff --git a/src/translations/en.json b/src/translations/en.json index 4255e3aaab..649aea8f90 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1175,7 +1175,7 @@ }, "updates": { "caption": "Updates", - "description": "Manage updates of Home Assistant, Add-ons and devices", + "description": "Manage updates of Home Assistant, add-ons and devices", "no_updates": "No updates available", "no_update_entities": { "title": "Unable to check for updates", @@ -1183,7 +1183,7 @@ }, "check_updates": "Check for updates", "no_new_updates": "No new updates found", - "updates_refreshed": "Updates refreshed", + "updates_refreshed": "{count} {count, plural,\n one {update}\n other {updates}\n} refreshed", "title": "{count} {count, plural,\n one {update}\n other {updates}\n}", "unable_to_fetch": "Unable to load updates", "version_available": "Version {version_available} is available", @@ -1490,7 +1490,7 @@ }, "core": { "caption": "General", - "description": "Name, Timezone and locale settings", + "description": "Name, time zone and locale settings", "section": { "core": { "header": "General Configuration", @@ -3139,7 +3139,7 @@ }, "analytics": { "caption": "Analytics", - "description": "Learn how to share data to better the Open Home" + "description": "Learn how to share data to improve Home Assistant" }, "network": { "caption": "Network", @@ -3184,11 +3184,11 @@ }, "system_health": { "caption": "System Health", - "description": "Status, Stats and Integration startup time", + "description": "Status, metrics and integration startup time", "cpu_usage": "Processor Usage", "ram_usage": "Memory Usage", - "core_stats": "Core Stats", - "supervisor_stats": "Supervisor Stats", + "core_stats": "Core Metrics", + "supervisor_stats": "Supervisor Metrics", "integration_start_time": "Integration Startup Time" }, "system_dashboard": {