mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-15 21:36:36 +00:00
Add rebuild support to editor preview (#4932)
* Add rebuild support to editor preview * getLovelaceCardClass function added * Use error class * Tiny cleanup * Misplaced comment
This commit is contained in:
parent
6d54496187
commit
52609dded9
@ -1,7 +0,0 @@
|
||||
const CUSTOM_TYPE_PREFIX = "custom:";
|
||||
|
||||
export function getCardElementTag(type: string): string {
|
||||
return type.startsWith(CUSTOM_TYPE_PREFIX)
|
||||
? type.substr(CUSTOM_TYPE_PREFIX.length)
|
||||
: `hui-${type}-card`;
|
||||
}
|
@ -11,7 +11,10 @@ import "../cards/hui-thermostat-card";
|
||||
import "../cards/hui-vertical-stack-card";
|
||||
import "../cards/hui-weather-forecast-card";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { createLovelaceElement } from "./create-element-base";
|
||||
import {
|
||||
createLovelaceElement,
|
||||
getLovelaceElementClass,
|
||||
} from "./create-element-base";
|
||||
|
||||
const ALWAYS_LOADED_TYPES = new Set([
|
||||
"entities",
|
||||
@ -56,3 +59,6 @@ export const createCardElement = (config: LovelaceCardConfig) =>
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
|
||||
export const getCardElementClass = (type: string) =>
|
||||
getLovelaceElementClass(type, "card", ALWAYS_LOADED_TYPES, LAZY_LOAD_TYPES);
|
||||
|
@ -7,7 +7,12 @@ import {
|
||||
createErrorCardElement,
|
||||
createErrorCardConfig,
|
||||
} from "../cards/hui-error-card";
|
||||
import { LovelaceCard, LovelaceBadge, LovelaceHeaderFooter } from "../types";
|
||||
import {
|
||||
LovelaceCard,
|
||||
LovelaceBadge,
|
||||
LovelaceHeaderFooter,
|
||||
LovelaceCardConstructor,
|
||||
} from "../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceElementConfig, LovelaceElement } from "../elements/types";
|
||||
import { LovelaceRow, LovelaceRowConfig } from "../entity-rows/types";
|
||||
@ -17,13 +22,30 @@ const CUSTOM_TYPE_PREFIX = "custom:";
|
||||
const TIMEOUT = 2000;
|
||||
|
||||
interface CreateElementConfigTypes {
|
||||
card: { config: LovelaceCardConfig; element: LovelaceCard };
|
||||
badge: { config: LovelaceBadgeConfig; element: LovelaceBadge };
|
||||
element: { config: LovelaceElementConfig; element: LovelaceElement };
|
||||
row: { config: LovelaceRowConfig; element: LovelaceRow };
|
||||
card: {
|
||||
config: LovelaceCardConfig;
|
||||
element: LovelaceCard;
|
||||
constructor: LovelaceCardConstructor;
|
||||
};
|
||||
badge: {
|
||||
config: LovelaceBadgeConfig;
|
||||
element: LovelaceBadge;
|
||||
constructor: unknown;
|
||||
};
|
||||
element: {
|
||||
config: LovelaceElementConfig;
|
||||
element: LovelaceElement;
|
||||
constructor: unknown;
|
||||
};
|
||||
row: {
|
||||
config: LovelaceRowConfig;
|
||||
element: LovelaceRow;
|
||||
constructor: unknown;
|
||||
};
|
||||
"header-footer": {
|
||||
config: LovelaceHeaderFooterConfig;
|
||||
element: LovelaceHeaderFooter;
|
||||
constructor: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
@ -75,11 +97,16 @@ const _maybeCreate = <T extends keyof CreateElementConfigTypes>(
|
||||
return element;
|
||||
};
|
||||
|
||||
const _getCustomTag = (type: string) =>
|
||||
type.startsWith(CUSTOM_TYPE_PREFIX)
|
||||
? type.substr(CUSTOM_TYPE_PREFIX.length)
|
||||
: undefined;
|
||||
|
||||
export const createLovelaceElement = <T extends keyof CreateElementConfigTypes>(
|
||||
tagSuffix: T,
|
||||
config: CreateElementConfigTypes[T]["config"],
|
||||
alwaysLoadTypes?: Set<string>,
|
||||
lazyLoadTypes?: { [domain: string]: () => unknown },
|
||||
lazyLoadTypes?: { [domain: string]: () => Promise<unknown> },
|
||||
// Allow looking at "entity" in config and mapping that to a type
|
||||
domainTypes?: { _domain_not_found: string; [domain: string]: string },
|
||||
// Default type if no type given. If given, entity types will not work.
|
||||
@ -98,8 +125,10 @@ export const createLovelaceElement = <T extends keyof CreateElementConfigTypes>(
|
||||
return _createErrorElement("No card type configured.", config);
|
||||
}
|
||||
|
||||
if (config.type && config.type.startsWith(CUSTOM_TYPE_PREFIX)) {
|
||||
return _maybeCreate(config.type.substr(CUSTOM_TYPE_PREFIX.length), config);
|
||||
const customTag = config.type ? _getCustomTag(config.type) : undefined;
|
||||
|
||||
if (customTag) {
|
||||
return _maybeCreate(customTag, config);
|
||||
}
|
||||
|
||||
let type: string | undefined;
|
||||
@ -131,3 +160,44 @@ export const createLovelaceElement = <T extends keyof CreateElementConfigTypes>(
|
||||
|
||||
return _createErrorElement(`Unknown type encountered: ${type}.`, config);
|
||||
};
|
||||
|
||||
export const getLovelaceElementClass = async <
|
||||
T extends keyof CreateElementConfigTypes
|
||||
>(
|
||||
type: string,
|
||||
tagSuffix: T,
|
||||
alwaysLoadTypes?: Set<string>,
|
||||
lazyLoadTypes?: { [domain: string]: () => Promise<unknown> }
|
||||
): Promise<CreateElementConfigTypes[T]["constructor"]> => {
|
||||
const customTag = _getCustomTag(type);
|
||||
|
||||
if (customTag) {
|
||||
const customCls = customElements.get(customTag);
|
||||
return customCls
|
||||
? customCls
|
||||
: new Promise((resolve, reject) => {
|
||||
// We will give custom components up to TIMEOUT seconds to get defined
|
||||
setTimeout(
|
||||
() => reject(new Error(`Custom element not found: ${customTag}`)),
|
||||
TIMEOUT
|
||||
);
|
||||
|
||||
customElements
|
||||
.whenDefined(customTag)
|
||||
.then(() => resolve(customElements.get(customTag)));
|
||||
});
|
||||
}
|
||||
|
||||
const tag = `hui-${type}-${tagSuffix}`;
|
||||
const cls = customElements.get(tag);
|
||||
|
||||
if (alwaysLoadTypes && type in alwaysLoadTypes) {
|
||||
return cls;
|
||||
}
|
||||
|
||||
if (lazyLoadTypes && type in lazyLoadTypes) {
|
||||
return cls || lazyLoadTypes[type]().then(() => customElements.get(tag));
|
||||
}
|
||||
|
||||
throw new Error(`Unknown type: ${type}`);
|
||||
};
|
||||
|
@ -14,7 +14,6 @@ import "@material/mwc-button";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { getCardElementTag } from "../../common/get-card-element-tag";
|
||||
import { computeRTL } from "../../../../common/util/compute_rtl";
|
||||
|
||||
import "../../../../components/ha-code-editor";
|
||||
@ -23,6 +22,7 @@ import "../../../../components/ha-code-editor";
|
||||
import { HaCodeEditor } from "../../../../components/ha-code-editor";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { EntityConfig } from "../../entity-rows/types";
|
||||
import { getCardElementClass } from "../../create-element/create-card-element";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@ -215,13 +215,7 @@ export class HuiCardEditor extends LitElement {
|
||||
throw new Error("No card type defined");
|
||||
}
|
||||
|
||||
const tag = getCardElementTag(cardType);
|
||||
|
||||
// Check if the card type exists
|
||||
const elClass = customElements.get(tag);
|
||||
if (!elClass) {
|
||||
throw new Error(`Unknown card type encountered: ${cardType}.`);
|
||||
}
|
||||
const elClass = await getCardElementClass(cardType);
|
||||
|
||||
this._loading = true;
|
||||
// Check if a GUI editor exists
|
||||
|
@ -10,9 +10,9 @@ import "@material/mwc-button";
|
||||
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { getCardElementTag } from "../../common/get-card-element-tag";
|
||||
import { CardPickTarget } from "../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { getCardElementClass } from "../../create-element/create-card-element";
|
||||
|
||||
const cards: string[] = [
|
||||
"alarm-panel",
|
||||
@ -94,15 +94,14 @@ export class HuiCardPicker extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _cardPicked(ev: Event): void {
|
||||
private async _cardPicked(ev: Event): Promise<void> {
|
||||
const type = (ev.currentTarget! as CardPickTarget).type;
|
||||
const tag = getCardElementTag(type);
|
||||
|
||||
const elClass = customElements.get(tag);
|
||||
const elClass = await getCardElementClass(type);
|
||||
let config: LovelaceCardConfig = { type };
|
||||
|
||||
if (elClass && elClass.getStubConfig) {
|
||||
const cardConfig = elClass.getStubConfig(this.hass);
|
||||
const cardConfig = elClass.getStubConfig(this.hass!);
|
||||
config = { ...config, ...cardConfig };
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,23 @@ import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { LovelaceCard } from "../../types";
|
||||
import { ConfigError } from "../types";
|
||||
import { getCardElementTag } from "../../common/get-card-element-tag";
|
||||
import { createErrorCardConfig } from "../../cards/hui-error-card";
|
||||
import { computeRTL } from "../../../../common/util/compute_rtl";
|
||||
|
||||
export class HuiCardPreview extends HTMLElement {
|
||||
private _hass?: HomeAssistant;
|
||||
private _element?: LovelaceCard;
|
||||
private _config?: LovelaceCardConfig;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.addEventListener("ll-rebuild", () => {
|
||||
this._cleanup();
|
||||
if (this._config) {
|
||||
this.config = this._config;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
set hass(hass: HomeAssistant) {
|
||||
if (!this._hass || this._hass.language !== hass.language) {
|
||||
@ -36,6 +46,9 @@ export class HuiCardPreview extends HTMLElement {
|
||||
}
|
||||
|
||||
set config(configValue: LovelaceCardConfig) {
|
||||
const curConfig = this._config;
|
||||
this._config = configValue;
|
||||
|
||||
if (!configValue) {
|
||||
this._cleanup();
|
||||
return;
|
||||
@ -53,9 +66,7 @@ export class HuiCardPreview extends HTMLElement {
|
||||
return;
|
||||
}
|
||||
|
||||
const tag = getCardElementTag(configValue.type);
|
||||
|
||||
if (tag.toUpperCase() === this._element.tagName) {
|
||||
if (curConfig && configValue.type === curConfig.type) {
|
||||
try {
|
||||
this._element.setConfig(deepClone(configValue));
|
||||
} catch (err) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { HomeAssistant, Constructor } from "../../types";
|
||||
import {
|
||||
LovelaceCardConfig,
|
||||
LovelaceConfig,
|
||||
@ -37,6 +37,11 @@ export interface LovelaceCard extends HTMLElement {
|
||||
setConfig(config: LovelaceCardConfig): void;
|
||||
}
|
||||
|
||||
export interface LovelaceCardConstructor extends Constructor<LovelaceCard> {
|
||||
getStubConfig?: (hass: HomeAssistant) => LovelaceCardConfig;
|
||||
getConfigElement?: () => LovelaceCardEditor;
|
||||
}
|
||||
|
||||
export interface LovelaceHeaderFooter extends HTMLElement {
|
||||
hass?: HomeAssistant;
|
||||
setConfig(config: LovelaceHeaderFooterConfig): void;
|
||||
|
Loading…
x
Reference in New Issue
Block a user