Don't set hass to undefined in lovelace cards. (#21189)

* Wait for hass and config before building the card

* Don't use setter

* Improve code readability

* Use hasupdated

* Rename build to load
This commit is contained in:
Paul Bottein 2024-06-27 16:49:10 +02:00 committed by GitHub
parent 7aa005e0ce
commit 7603fa3aa8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 55 additions and 43 deletions

View File

@ -1,4 +1,4 @@
import { PropertyValueMap, PropertyValues, ReactiveElement } from "lit"; import { PropertyValues, ReactiveElement } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event"; import { fireEvent } from "../../../common/dom/fire_event";
import { MediaQueriesListener } from "../../../common/dom/media_query"; import { MediaQueriesListener } from "../../../common/dom/media_query";
@ -23,30 +23,21 @@ declare global {
@customElement("hui-card") @customElement("hui-card")
export class HuiCard extends ReactiveElement { export class HuiCard extends ReactiveElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@property({ type: Boolean }) public preview = false; @property({ type: Boolean }) public preview = false;
@property({ type: Boolean }) public isPanel = false; @property({ type: Boolean }) public isPanel = false;
set config(config: LovelaceCardConfig | undefined) { @property({ attribute: false }) public config?: LovelaceCardConfig;
if (!config) return;
if (config.type !== this._config?.type) { @property({ attribute: false }) public hass?: HomeAssistant;
this._buildElement(config);
} else if (config !== this.config) { public load() {
this._element?.setConfig(config); if (!this.config) {
fireEvent(this, "card-updated"); throw new Error("Cannot build card without config");
} }
this._config = config; this._loadElement(this.config);
} }
@property({ attribute: false })
public get config() {
return this._config;
}
private _config?: LovelaceCardConfig;
private _element?: LovelaceCard; private _element?: LovelaceCard;
private _listeners: MediaQueriesListener[] = []; private _listeners: MediaQueriesListener[] = [];
@ -90,57 +81,76 @@ export class HuiCard extends ReactiveElement {
return this._element?.getLayoutOptions?.() ?? {}; return this._element?.getLayoutOptions?.() ?? {};
} }
private _createElement(config: LovelaceCardConfig) { private _loadElement(config: LovelaceCardConfig) {
const element = createCardElement(config); this._element = createCardElement(config);
element.hass = this.hass; if (this.hass) {
element.preview = this.preview; this._element.hass = this.hass;
}
this._element.preview = this.preview;
// For backwards compatibility // For backwards compatibility
(element as any).editMode = this.preview; (this._element as any).editMode = this.preview;
// Update element when the visibility of the card changes (e.g. conditional card or filter card) // Update element when the visibility of the card changes (e.g. conditional card or filter card)
element.addEventListener("card-visibility-changed", (ev: Event) => { this._element.addEventListener("card-visibility-changed", (ev: Event) => {
ev.stopPropagation(); ev.stopPropagation();
this._updateVisibility(); this._updateVisibility();
}); });
element.addEventListener( this._element.addEventListener(
"ll-upgrade", "ll-upgrade",
(ev: Event) => { (ev: Event) => {
ev.stopPropagation(); ev.stopPropagation();
element.hass = this.hass; if (this.hass) {
element.preview = this.preview; this._element!.hass = this.hass;
}
fireEvent(this, "card-updated"); fireEvent(this, "card-updated");
}, },
{ once: true } { once: true }
); );
element.addEventListener( this._element.addEventListener(
"ll-rebuild", "ll-rebuild",
(ev: Event) => { (ev: Event) => {
ev.stopPropagation(); ev.stopPropagation();
this._buildElement(config); this._loadElement(config);
fireEvent(this, "card-updated"); fireEvent(this, "card-updated");
}, },
{ once: true } { once: true }
); );
return element;
}
private _buildElement(config: LovelaceCardConfig) {
this._element = this._createElement(config);
while (this.lastChild) { while (this.lastChild) {
this.removeChild(this.lastChild); this.removeChild(this.lastChild);
} }
this._updateVisibility(); this._updateVisibility();
} }
protected willUpdate(changedProps: PropertyValues<typeof this>): void {
super.willUpdate(changedProps);
if (!this._element) {
this.load();
}
}
protected update(changedProps: PropertyValues<typeof this>) { protected update(changedProps: PropertyValues<typeof this>) {
super.update(changedProps); super.update(changedProps);
if (this._element) { if (this._element) {
if (changedProps.has("config") && this.hasUpdated) {
const oldConfig = changedProps.get("config");
if (this.config !== oldConfig && this.config) {
const typeChanged = this.config?.type !== oldConfig?.type;
if (typeChanged) {
this._loadElement(this.config);
} else {
this._element?.setConfig(this.config);
fireEvent(this, "card-updated");
}
}
}
if (changedProps.has("hass")) { if (changedProps.has("hass")) {
try { try {
this._element.hass = this.hass; if (this.hass) {
this._element.hass = this.hass;
}
} catch (e: any) { } catch (e: any) {
this._buildElement(createErrorCardConfig(e.message, null)); this._loadElement(createErrorCardConfig(e.message, null));
} }
} }
if (changedProps.has("preview")) { if (changedProps.has("preview")) {
@ -149,18 +159,14 @@ export class HuiCard extends ReactiveElement {
// For backwards compatibility // For backwards compatibility
(this._element as any).editMode = this.preview; (this._element as any).editMode = this.preview;
} catch (e: any) { } catch (e: any) {
this._buildElement(createErrorCardConfig(e.message, null)); this._loadElement(createErrorCardConfig(e.message, null));
} }
} }
if (changedProps.has("isPanel")) { if (changedProps.has("isPanel")) {
this._element.isPanel = this.isPanel; this._element.isPanel = this.isPanel;
} }
} }
}
protected willUpdate(
changedProps: PropertyValueMap<any> | Map<PropertyKey, unknown>
): void {
if (changedProps.has("hass") || changedProps.has("preview")) { if (changedProps.has("hass") || changedProps.has("preview")) {
this._updateVisibility(); this._updateVisibility();
} }

View File

@ -41,6 +41,7 @@ class HuiConditionalCard extends HuiConditionalBase implements LovelaceCard {
element.hass = this.hass; element.hass = this.hass;
element.preview = this.preview; element.preview = this.preview;
element.config = cardConfig; element.config = cardConfig;
element.load();
return element; return element;
} }

View File

@ -249,6 +249,7 @@ export class HuiEntityFilterCard
element.hass = this.hass; element.hass = this.hass;
element.preview = this.preview; element.preview = this.preview;
element.config = cardConfig; element.config = cardConfig;
element.load();
return element; return element;
} }
} }

View File

@ -56,7 +56,7 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
card.hass = this.hass; card.hass = this.hass;
}); });
} }
if (changedProperties.has("editMode")) { if (changedProperties.has("preview")) {
this._cards.forEach((card) => { this._cards.forEach((card) => {
card.preview = this.preview; card.preview = this.preview;
}); });
@ -69,6 +69,7 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
element.hass = this.hass; element.hass = this.hass;
element.preview = this.preview; element.preview = this.preview;
element.config = cardConfig; element.config = cardConfig;
element.load();
return element; return element;
} }

View File

@ -146,6 +146,7 @@ export class HuiCardLayoutEditor extends LitElement {
this._defaultLayoutOptions = this._defaultLayoutOptions =
this._cardElement?.getElementLayoutOptions(); this._cardElement?.getElementLayoutOptions();
}); });
this._cardElement.load();
this._defaultLayoutOptions = this._cardElement.getElementLayoutOptions(); this._defaultLayoutOptions = this._cardElement.getElementLayoutOptions();
} catch (err) { } catch (err) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console

View File

@ -64,6 +64,7 @@ export class HuiSection extends ReactiveElement {
ev.stopPropagation(); ev.stopPropagation();
this._cards = [...this._cards]; this._cards = [...this._cards];
}); });
element.load();
return element; return element;
} }

View File

@ -82,6 +82,7 @@ export class HUIView extends ReactiveElement {
ev.stopPropagation(); ev.stopPropagation();
this._cards = [...this._cards]; this._cards = [...this._cards];
}); });
element.load();
return element; return element;
} }