Handle starting the frontend before finished loading integrations (#6068)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Bram Kragten 2020-05-29 06:09:26 +02:00 committed by GitHub
parent 2e5ec1f0c1
commit d0a53d1760
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 352 additions and 261 deletions

View File

@ -89,7 +89,7 @@
"fuse.js": "^6.0.0",
"google-timezones-json": "^1.0.2",
"hls.js": "^0.12.4",
"home-assistant-js-websocket": "^5.1.2",
"home-assistant-js-websocket": "^5.2.1",
"idb-keyval": "^3.2.0",
"intl-messageformat": "^8.3.9",
"js-yaml": "^3.13.1",

View File

@ -1,4 +1,4 @@
import { HassConfig } from "home-assistant-js-websocket";
import { HassConfig, STATE_RUNNING } from "home-assistant-js-websocket";
export const demoConfig: HassConfig = {
location_name: "Home",
@ -18,6 +18,7 @@ export const demoConfig: HassConfig = {
whitelist_external_dirs: [],
config_source: "storage",
safe_mode: false,
state: STATE_RUNNING,
internal_url: "http://homeassistant.local:8123",
external_url: null,
};

View File

@ -8,6 +8,11 @@ import {
RouteOptions,
RouterOptions,
} from "./hass-router-page";
import {
STATE_STARTING,
STATE_NOT_RUNNING,
STATE_RUNNING,
} from "home-assistant-js-websocket";
const CACHE_URL_PATHS = ["lovelace", "developer-tools"];
const COMPONENTS = {
@ -84,6 +89,8 @@ class PartialPanelResolver extends HassRouterPage {
@property() public narrow?: boolean;
private _waitForStart = false;
protected updated(changedProps: PropertyValues) {
super.updated(changedProps);
@ -93,6 +100,15 @@ class PartialPanelResolver extends HassRouterPage {
const oldHass = changedProps.get("hass") as this["hass"];
if (
this._waitForStart &&
(this.hass.config.state === STATE_STARTING ||
this.hass.config.state === STATE_RUNNING)
) {
this._waitForStart = false;
this.rebuild();
}
if (this.hass.panels && (!oldHass || oldHass.panels !== this.hass.panels)) {
this._updateRoutes(oldHass?.panels);
}
@ -128,6 +144,21 @@ class PartialPanelResolver extends HassRouterPage {
private async _updateRoutes(oldPanels?: HomeAssistant["panels"]) {
this.routerOptions = getRoutes(this.hass.panels);
if (
!this._waitForStart &&
this._currentPage &&
!this.hass.panels[this._currentPage]
) {
if (this.hass.config.state !== STATE_NOT_RUNNING) {
this._waitForStart = true;
if (this.lastChild) {
this.removeChild(this.lastChild);
}
this.appendChild(this.createLoadingScreen());
return;
}
}
if (
!oldPanels ||
!deepEqual(

View File

@ -24,7 +24,11 @@ export const SubscribeMixin = <T extends Constructor<UpdatingElement>>(
if (this.__unsubs) {
while (this.__unsubs.length) {
const unsub = this.__unsubs.pop()!;
Promise.resolve(unsub).then((unsubFunc) => unsubFunc());
if (unsub instanceof Promise) {
unsub.then((unsubFunc) => unsubFunc());
} else {
unsub();
}
}
this.__unsubs = undefined;
}

View File

@ -14,7 +14,6 @@ import { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import "../components/hui-warning-element";
import { LovelaceBadge } from "../types";
import { StateLabelBadgeConfig } from "./types";

View File

@ -22,7 +22,7 @@ import {
} from "../../../data/alarm_control_panel";
import type { HomeAssistant } from "../../../types";
import { findEntities } from "../common/find-entites";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard } from "../types";
import { AlarmPanelCardConfig } from "./types";
@ -151,13 +151,9 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -33,7 +33,7 @@ import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entites";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { ButtonCardConfig } from "./types";
@ -145,13 +145,9 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
if (this._config.entity && !stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -20,7 +20,7 @@ import { UNAVAILABLE_STATES } from "../../../data/entity";
import { HomeAssistant } from "../../../types";
import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { createHeaderFooterElement } from "../create-element/create-header-footer-element";
import {
LovelaceCard,
@ -92,13 +92,9 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -20,7 +20,7 @@ import "../../../components/ha-card";
import type { HomeAssistant } from "../../../types";
import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
import type { GaugeCardConfig } from "./types";
import { debounce } from "../../../common/util/debounce";
@ -105,13 +105,9 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -30,6 +30,7 @@ import "../components/hui-warning-element";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import "../components/hui-timestamp-display";
import { GlanceCardConfig, GlanceConfigEntity } from "./types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@customElement("hui-glance-card")
export class HuiGlanceCard extends LitElement implements LovelaceCard {
@ -212,11 +213,7 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning-element
label=${this.hass!.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
entityConf.entity
)}
.label=${createEntityNotFoundWarning(this.hass!, entityConf.entity)}
></hui-warning-element>
`;
}

View File

@ -28,7 +28,7 @@ import { findEntities } from "../common/find-entites";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { LightCardConfig } from "./types";
@ -89,13 +89,9 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -44,7 +44,7 @@ import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-marquee";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { MediaControlCardConfig } from "./types";
import { installResizeObserver } from "../common/install-resize-observer";
@ -266,13 +266,9 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -24,7 +24,7 @@ import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-image";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { PictureEntityCardConfig } from "./types";
@ -116,13 +116,9 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -30,6 +30,7 @@ import "../components/hui-image";
import "../components/hui-warning-element";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { PictureGlanceCardConfig, PictureGlanceEntityConfig } from "./types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
const STATES_OFF = new Set(["closed", "locked", "not_home", "off"]);
@ -229,11 +230,7 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning-element
label=${this.hass!.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
entityConf.entity
)}
.label=${createEntityNotFoundWarning(this.hass!, entityConf.entity)}
></hui-warning-element>
`;
}

View File

@ -20,6 +20,7 @@ import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { PlantAttributeTarget, PlantStatusCardConfig } from "./types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
const SENSORS = {
moisture: "hass:water",
@ -105,13 +106,9 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -0,0 +1,86 @@
import "@material/mwc-button/mwc-button";
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
PropertyValues,
} from "lit-element";
import "../../../components/ha-card";
import { HomeAssistant } from "../../../types";
import { LovelaceCard } from "../types";
import { LovelaceCardConfig } from "../../../data/lovelace";
import "@polymer/paper-spinner/paper-spinner-lite";
import { fireEvent } from "../../../common/dom/fire_event";
import { STATE_STARTING, STATE_RUNNING } from "home-assistant-js-websocket";
@customElement("hui-starting-card")
export class HuiStartingCard extends LitElement implements LovelaceCard {
@property() public hass?: HomeAssistant;
public getCardSize(): number {
return 2;
}
public setConfig(_config: LovelaceCardConfig): void {
// eslint-disable-next-line
}
protected updated(changedProperties: PropertyValues) {
super.updated(changedProperties);
if (!changedProperties.has("hass") || !this.hass!.config) {
return;
}
const oldHass = changedProperties.get("hass") as HomeAssistant | undefined;
if (
(!oldHass?.config || oldHass.config.state !== this.hass!.config.state) &&
(this.hass!.config.state === STATE_STARTING ||
this.hass!.config.state === STATE_RUNNING)
) {
fireEvent(this, "config-refresh");
}
}
protected render(): TemplateResult {
if (!this.hass) {
return html``;
}
return html`
<div class="content">
<paper-spinner-lite active></paper-spinner-lite>
${this.hass.localize("ui.panel.lovelace.cards.starting.description")}
</div>
`;
}
static get styles(): CSSResult {
return css`
:host {
display: block;
height: calc(100vh - 64px);
}
paper-spinner-lite {
padding-bottom: 20px;
}
.content {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"hui-starting-card": HuiStartingCard;
}
}

View File

@ -29,7 +29,7 @@ import { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { ThermostatCardConfig } from "./types";
@ -96,13 +96,9 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -28,7 +28,7 @@ import type { HomeAssistant, WeatherEntity } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entites";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
import type { WeatherForecastCardConfig } from "./types";
import { installResizeObserver } from "../common/install-resize-observer";
@ -137,13 +137,9 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -2,6 +2,7 @@ import {
HassConfig,
HassEntities,
HassEntity,
STATE_NOT_RUNNING,
} from "home-assistant-js-websocket";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeObjectId } from "../../../common/entity/compute_object_id";
@ -468,6 +469,28 @@ export const generateLovelaceConfigFromHass = async (
hass: HomeAssistant,
localize?: LocalizeFunc
): Promise<LovelaceConfig> => {
if (hass.config.state === STATE_NOT_RUNNING) {
return {
title: hass.config.location_name,
views: [
{
cards: [{ type: "starting" }],
},
],
};
}
if (hass.config.safe_mode) {
return {
title: hass.config.location_name,
views: [
{
cards: [{ type: "safe-mode" }],
},
],
};
}
// We want to keep the registry subscriptions alive after generating the UI
// so that we don't serve up stale data after changing areas.
if (!subscribedRegistries) {

View File

@ -17,14 +17,15 @@ export function hasConfigOrEntityChanged(
if (
oldHass.themes !== element.hass!.themes ||
oldHass.language !== element.hass!.language
oldHass.language !== element.hass!.language ||
oldHass.localize !== element.hass.localize ||
oldHass.config.state !== element.hass.config.state
) {
return true;
}
return (
oldHass.states[element._config!.entity] !==
element.hass!.states[element._config!.entity] ||
oldHass.localize !== element.hass.localize
element.hass!.states[element._config!.entity]
);
}

View File

@ -23,7 +23,7 @@ import { EntitiesCardEntityConfig } from "../cards/types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import "./hui-warning";
import { createEntityNotFoundWarning } from "./hui-warning";
class HuiGenericEntityRow extends LitElement {
@property() public hass?: HomeAssistant;
@ -42,13 +42,9 @@ class HuiGenericEntityRow extends LitElement {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this.config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this.config.entity)}
</hui-warning>
`;
}

View File

@ -14,7 +14,7 @@ export class HuiWarningElement extends LitElement {
@property() public label?: string;
protected render(): TemplateResult {
return html` <ha-icon icon="hass:alert" .title="${this.label}"></ha-icon> `;
return html` <ha-icon icon="hass:alert" .title=${this.label}></ha-icon> `;
}
static get styles(): CSSResult {

View File

@ -6,6 +6,21 @@ import {
LitElement,
TemplateResult,
} from "lit-element";
import { HomeAssistant } from "../../../types";
import { STATE_NOT_RUNNING } from "home-assistant-js-websocket";
export const createEntityNotFoundWarning = (
hass: HomeAssistant,
entityId: string
) => {
return hass.config.state !== STATE_NOT_RUNNING
? hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
entityId
)
: hass.localize("ui.panel.lovelace.warning.starting");
};
@customElement("hui-warning")
export class HuiWarning extends LitElement {

View File

@ -35,6 +35,7 @@ const LAZY_LOAD_TYPES = {
"alarm-panel": () => import("../cards/hui-alarm-panel-card"),
error: () => import("../cards/hui-error-card"),
"empty-state": () => import("../cards/hui-empty-state-card"),
starting: () => import("../cards/hui-starting-card"),
"entity-filter": () => import("../cards/hui-entity-filter-card"),
"media-control": () => import("../cards/hui-media-control-card"),
"picture-elements": () => import("../cards/hui-picture-elements-card"),

View File

@ -17,6 +17,7 @@ import { hasAction } from "../common/has-action";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning-element";
import { LovelaceElement, StateBadgeElementConfig } from "./types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@customElement("hui-state-badge-element")
export class HuiStateBadgeElement extends LitElement
@ -47,11 +48,7 @@ export class HuiStateBadgeElement extends LitElement
if (!stateObj) {
return html`
<hui-warning-element
label="${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}"
.label=${createEntityNotFoundWarning(this.hass, this._config.entity)}
></hui-warning-element>
`;
}

View File

@ -19,6 +19,7 @@ import { hasAction } from "../common/has-action";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning-element";
import { LovelaceElement, StateIconElementConfig } from "./types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@customElement("hui-state-icon-element")
export class HuiStateIconElement extends LitElement implements LovelaceElement {
@ -48,11 +49,7 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement {
if (!stateObj) {
return html`
<hui-warning-element
label=${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}
.label=${createEntityNotFoundWarning(this.hass, this._config.entity)}
></hui-warning-element>
`;
}

View File

@ -19,6 +19,7 @@ import { hasAction } from "../common/has-action";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning-element";
import { LovelaceElement, StateLabelElementConfig } from "./types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@customElement("hui-state-label-element")
class HuiStateLabelElement extends LitElement implements LovelaceElement {
@ -48,11 +49,7 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
if (!stateObj) {
return html`
<hui-warning-element
label=${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}
.label=${createEntityNotFoundWarning(this.hass, this._config.entity)}
></hui-warning-element>
`;
}

View File

@ -12,7 +12,7 @@ import "../../../components/ha-climate-state";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { EntityConfig, LovelaceRow } from "./types";
@customElement("hui-climate-entity-row")
@ -42,13 +42,9 @@ class HuiClimateEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -14,7 +14,7 @@ import { HomeAssistant } from "../../../types";
import { isTiltOnly } from "../../../util/cover-model";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { EntityConfig, LovelaceRow } from "./types";
@customElement("hui-cover-entity-row")
@ -43,13 +43,9 @@ class HuiCoverEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -12,7 +12,7 @@ import "../../../components/entity/ha-entity-toggle";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { EntityConfig, LovelaceRow } from "./types";
@customElement("hui-group-entity-row")
@ -41,13 +41,9 @@ class HuiGroupEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -16,6 +16,7 @@ import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import type { EntityConfig, LovelaceRow } from "./types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@customElement("hui-input-datetime-entity-row")
class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
@ -43,13 +44,9 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -16,8 +16,8 @@ import { setValue } from "../../../data/input_text";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { EntityConfig, LovelaceRow } from "./types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@customElement("hui-input-number-entity-row")
class HuiInputNumberEntityRow extends LitElement implements LovelaceRow {
@ -63,13 +63,9 @@ class HuiInputNumberEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -28,7 +28,7 @@ import { actionHandler } from "../common/directives/action-handler-directive";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceRow } from "./types";
@customElement("hui-input-select-entity-row")
@ -60,13 +60,9 @@ class HuiInputSelectEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -12,7 +12,7 @@ import { setValue } from "../../../data/input_text";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { EntityConfig, LovelaceRow } from "./types";
@customElement("hui-input-text-entity-row")
@ -41,13 +41,9 @@ class HuiInputTextEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -13,7 +13,7 @@ import { UNAVAILABLE_STATES } from "../../../data/entity";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { EntityConfig, LovelaceRow } from "./types";
@customElement("hui-lock-entity-row")
@ -42,13 +42,9 @@ class HuiLockEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -30,7 +30,7 @@ import {
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { EntityConfig, LovelaceRow } from "./types";
import { installResizeObserver } from "../common/install-resize-observer";
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
@ -82,13 +82,9 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -15,7 +15,7 @@ import { activateScene } from "../../../data/scene";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { ActionRowConfig, LovelaceRow } from "./types";
@customElement("hui-scene-entity-row")
@ -44,13 +44,9 @@ class HuiSceneEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -14,7 +14,7 @@ import { UNAVAILABLE_STATES } from "../../../data/entity";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { ActionRowConfig, LovelaceRow } from "./types";
@customElement("hui-script-entity-row")
@ -43,13 +43,9 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -14,7 +14,7 @@ import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-timestamp-display";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceRow } from "./types";
import { EntitiesCardEntityConfig } from "../cards/types";
import { actionHandler } from "../common/directives/action-handler-directive";
@ -52,13 +52,9 @@ class HuiSensorEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -12,7 +12,7 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceRow } from "./types";
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const";
import { computeDomain } from "../../../common/entity/compute_domain";
@ -49,13 +49,9 @@ class HuiTextEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -12,7 +12,7 @@ import { timerTimeRemaining } from "../../../common/entity/timer_time_remaining"
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { EntityConfig } from "./types";
@customElement("hui-timer-entity-row")
@ -56,13 +56,9 @@ class HuiTimerEntityRow extends LitElement {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -12,7 +12,7 @@ import { UNAVAILABLE_STATES } from "../../../data/entity";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { EntityConfig, LovelaceRow } from "./types";
@customElement("hui-toggle-entity-row")
@ -41,13 +41,9 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -24,7 +24,7 @@ import type { HomeAssistant, WeatherEntity } from "../../../types";
import type { EntitiesCardEntityConfig } from "../cards/types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceRow } from "./types";
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const";
import { computeDomain } from "../../../common/entity/compute_domain";
@ -62,13 +62,9 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -26,6 +26,7 @@ import { loadLovelaceResources } from "./common/load-resources";
import { showSaveDialog } from "./editor/show-save-config-dialog";
import "./hui-root";
import { Lovelace } from "./types";
import { STATE_NOT_RUNNING } from "home-assistant-js-websocket";
(window as any).loadCardHelpers = () => import("./custom-card-helpers");
@ -169,7 +170,13 @@ class LovelacePanel extends LitElement {
}
// reload lovelace on reconnect so we are sure we have the latest config
window.addEventListener("connection-status", (ev) => {
if (ev.detail === "connected") {
if (
ev.detail === "connected" &&
!(
this.lovelace?.mode === "generated" &&
this.hass!.config.state === STATE_NOT_RUNNING
)
) {
this._fetchConfig(false);
}
});

View File

@ -11,8 +11,8 @@ import {
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import "../components/hui-warning";
import { AttributeRowConfig, LovelaceRow } from "../entity-rows/types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
@customElement("hui-attribute-row")
class HuiAttributeRow extends LitElement implements LovelaceRow {
@ -47,13 +47,9 @@ class HuiAttributeRow extends LitElement implements LovelaceRow {
if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}

View File

@ -6,6 +6,7 @@ import {
subscribeConfig,
subscribeEntities,
subscribeServices,
HassConfig,
} from "home-assistant-js-websocket";
import { fireEvent } from "../common/dom/fire_event";
import { broadcastConnectionStatus } from "../data/connection-status";
@ -156,8 +157,15 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
protected hassReconnected() {
super.hassReconnected();
this._updateHass({ connected: true });
broadcastConnectionStatus("connected");
// on reconnect always fetch config as we might miss an update while we were disconnected
// @ts-ignore
this.hass!.callWS({ type: "get_config" }).then((config: HassConfig) => {
this._updateHass({ config });
});
}
protected hassDisconnected() {

View File

@ -1,6 +1,11 @@
import { Constructor } from "../types";
import { showToast } from "../util/toast";
import { HassBaseEl } from "./hass-base-mixin";
import {
STATE_NOT_RUNNING,
STATE_STARTING,
STATE_RUNNING,
} from "home-assistant-js-websocket";
export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
class extends superClass {
@ -12,6 +17,34 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
);
}
updated(changedProperties) {
super.updated(changedProperties);
const oldHass = changedProperties.get("hass");
if (
!changedProperties.has("hass") ||
!oldHass?.config ||
oldHass.config.state === this.hass!.config.state
) {
return;
}
if (this.hass!.config.state === STATE_NOT_RUNNING) {
showToast(this, {
message: this.hass!.localize("ui.notification_toast.starting"),
duration: 0,
dismissable: false,
});
} else if (
oldHass.config.state === STATE_NOT_RUNNING &&
(this.hass!.config.state === STATE_STARTING ||
this.hass!.config.state === STATE_RUNNING)
) {
showToast(this, {
message: this.hass!.localize("ui.notification_toast.started"),
duration: 5000,
});
}
}
protected hassReconnected() {
super.hassReconnected();

View File

@ -498,6 +498,8 @@
"notification_toast": {
"service_call_failed": "Failed to call service {service}.",
"connection_lost": "Connection lost. Reconnecting…",
"started": "Home Assistant has started!",
"starting": "Home Assistant is starting, not everything will be available until it is finished.",
"triggered": "Triggered {name}"
},
"sidebar": {
@ -1644,6 +1646,10 @@
"safe-mode": {
"header": "Safe Mode Activated",
"description": "Home Assistant ran into trouble while loading your configuration and is now running in safe mode. Take a look at the error log to see what went wrong."
},
"starting": {
"header": "Home Assistant is starting...",
"description": "Home Assistant is starting up, please wait."
}
},
"unused_entities": {
@ -1936,7 +1942,8 @@
"attribute_not_found": "Attribute {attribute} not available in: {entity}",
"entity_not_found": "Entity not available: {entity}",
"entity_non_numeric": "Entity is non-numeric: {entity}",
"entity_unavailable": "{entity} is currently unavailable"
"entity_unavailable": "{entity} is currently unavailable",
"starting": "Home Assistant is starting, not everything may be available yet"
},
"changed_toast": {
"message": "The Lovelace UI configuration for this dashboard was updated, refresh to see changes?",

View File

@ -6613,10 +6613,10 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
home-assistant-js-websocket@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/home-assistant-js-websocket/-/home-assistant-js-websocket-5.1.2.tgz#418c027ccb0f0817004931fce4cf5c64241d16ed"
integrity sha512-tV6bLgvLHBev2tb0h6tujsLuLKZqO2qTrO6jTDx8oSDA5vo9zOEcc6QsuhC/AaTdtniT6l4UuTwsps9Wlk6nJw==
home-assistant-js-websocket@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/home-assistant-js-websocket/-/home-assistant-js-websocket-5.2.1.tgz#88c06738416e041dfd805f2543722458d9c3a391"
integrity sha512-azPiR+KABxaow1sMS70+Jk12KOaKSJY9KSKSGljkAArJmbWum3PEMNXXaG+XJnYmNuDnyzLAwi3/e1cwvVqocA==
homedir-polyfill@^1.0.1:
version "1.0.3"