mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Allow cards and tile features to provide a schema to create the editor (#16142)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
7faa165558
commit
1fe5d66a68
@ -4,14 +4,15 @@ import {
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
nothing,
|
||||
PropertyValues,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeAttributeValueDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
@ -27,7 +28,6 @@ import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import { HVAC_ACTION_TO_MODE } from "../../../data/climate";
|
||||
import { isUnavailableState } from "../../../data/entity";
|
||||
import { computeAttributeValueDisplay } from "../../../common/entity/compute_attribute_display";
|
||||
import { LightEntity } from "../../../data/light";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
@ -35,21 +35,12 @@ import { findEntities } from "../common/find-entities";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import { createHeaderFooterElement } from "../create-element/create-header-footer-element";
|
||||
import {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceHeaderFooter,
|
||||
} from "../types";
|
||||
import { LovelaceCard, LovelaceHeaderFooter } from "../types";
|
||||
import { HuiErrorCard } from "./hui-error-card";
|
||||
import { EntityCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-entity-card")
|
||||
export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||
await import("../editor/config-elements/hui-entity-card-editor");
|
||||
return document.createElement("hui-entity-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
entities: string[],
|
||||
@ -70,6 +61,11 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
};
|
||||
}
|
||||
|
||||
public static async getConfigForm() {
|
||||
return (await import("../editor/config-elements/hui-entity-card-editor"))
|
||||
.default;
|
||||
}
|
||||
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@state() private _config?: EntityCardConfig;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { customElement } from "lit/decorators";
|
||||
import type { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { getCardElementClass } from "../../create-element/create-card-element";
|
||||
import type { LovelaceCardEditor } from "../../types";
|
||||
import type { LovelaceCardEditor, LovelaceConfigForm } from "../../types";
|
||||
import { HuiElementEditor } from "../hui-element-editor";
|
||||
|
||||
@customElement("hui-card-element-editor")
|
||||
@ -16,6 +16,17 @@ export class HuiCardElementEditor extends HuiElementEditor<LovelaceCardConfig> {
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected async getConfigForm(): Promise<LovelaceConfigForm | undefined> {
|
||||
const elClass = await getCardElementClass(this.configElementType!);
|
||||
|
||||
// Check if a schema exists
|
||||
if (elClass && elClass.getConfigForm) {
|
||||
return elClass.getConfigForm();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -1,16 +1,12 @@
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { assert, assign, boolean, object, optional, string } from "superstruct";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { EntityCardConfig } from "../../cards/types";
|
||||
import { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import { HaFormSchema } from "../../../../components/ha-form/types";
|
||||
import { EntityCardConfig } from "../../cards/types";
|
||||
import { headerFooterConfigStructs } from "../../header-footer/structs";
|
||||
import type { LovelaceCardEditor } from "../../types";
|
||||
import { LovelaceConfigForm } from "../../types";
|
||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||
|
||||
const cardConfigStruct = assign(
|
||||
const struct = assign(
|
||||
baseLovelaceCardConfig,
|
||||
object({
|
||||
entity: optional(string()),
|
||||
@ -54,67 +50,19 @@ const SCHEMA = [
|
||||
{ name: "state_color", selector: { boolean: {} } },
|
||||
],
|
||||
},
|
||||
] as const;
|
||||
|
||||
@customElement("hui-entity-card-editor")
|
||||
export class HuiEntityCardEditor
|
||||
extends LitElement
|
||||
implements LovelaceCardEditor
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@state() private _config?: EntityCardConfig;
|
||||
|
||||
public setConfig(config: EntityCardConfig): void {
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this.hass || !this._config) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${this._config}
|
||||
.schema=${SCHEMA}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
const config = ev.detail.value;
|
||||
Object.keys(config).forEach((k) => config[k] === "" && delete config[k]);
|
||||
fireEvent(this, "config-changed", { config });
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
|
||||
if (schema.name === "entity") {
|
||||
return this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.generic.entity"
|
||||
);
|
||||
}
|
||||
] as HaFormSchema[];
|
||||
|
||||
const entityCardConfigForm: LovelaceConfigForm = {
|
||||
schema: SCHEMA,
|
||||
assertConfig: (config: EntityCardConfig) => assert(config, struct),
|
||||
computeLabel: (schema: HaFormSchema, localize: LocalizeFunc) => {
|
||||
if (schema.name === "theme") {
|
||||
return `${this.hass!.localize(
|
||||
return `${localize(
|
||||
"ui.panel.lovelace.editor.card.generic.theme"
|
||||
)} (${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.config.optional"
|
||||
)})`;
|
||||
)} (${localize("ui.panel.lovelace.editor.card.config.optional")})`;
|
||||
}
|
||||
return localize(`ui.panel.lovelace.editor.card.generic.${schema.name}`);
|
||||
},
|
||||
};
|
||||
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-entity-card-editor": HuiEntityCardEditor;
|
||||
}
|
||||
}
|
||||
export default entityCardConfigForm;
|
||||
|
@ -0,0 +1,82 @@
|
||||
import { CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { capitalizeFirstLetter } from "../../../../common/string/capitalize-first-letter";
|
||||
import { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import type { HaFormSchema } from "../../../../components/ha-form/types";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LovelaceGenericElementEditor } from "../../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
@customElement("hui-form-editor")
|
||||
export class HuiFormEditor
|
||||
extends LitElement
|
||||
implements LovelaceGenericElementEditor
|
||||
{
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public schema!: HaFormSchema[];
|
||||
|
||||
@state() private _config?: LovelaceCardConfig;
|
||||
|
||||
public assertConfig(_config: LovelaceCardConfig): void {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public setConfig(config: LovelaceCardConfig): void {
|
||||
this.assertConfig(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._config) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${this._config}
|
||||
.schema=${this.schema}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
.computeHelper=${this._computeHelperCallback}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>
|
||||
`;
|
||||
}
|
||||
|
||||
public computeLabel = (
|
||||
_schema: HaFormSchema,
|
||||
_localize: LocalizeFunc
|
||||
): string | undefined => undefined;
|
||||
|
||||
public computeHelper = (
|
||||
_schema: HaFormSchema,
|
||||
_localize: LocalizeFunc
|
||||
): string | undefined => undefined;
|
||||
|
||||
private _computeLabelCallback = (schema: HaFormSchema) =>
|
||||
this.computeLabel(schema, this.hass.localize) ||
|
||||
this.hass.localize(
|
||||
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
||||
) ||
|
||||
capitalizeFirstLetter(schema.name.split("_").join(" "));
|
||||
|
||||
private _computeHelperCallback = (schema: HaFormSchema) =>
|
||||
this.computeHelper(schema, this.hass.localize);
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
const config = ev.detail.value;
|
||||
fireEvent(this, "config-changed", { config });
|
||||
}
|
||||
|
||||
static styles: CSSResultGroup = configElementStyle;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-form-editor": HuiFormEditor;
|
||||
}
|
||||
}
|
@ -8,13 +8,13 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { property, state, query } from "lit/decorators";
|
||||
import { property, query, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { handleStructError } from "../../../common/structs/handle-errors";
|
||||
import { deepEqual } from "../../../common/util/deep-equal";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-circular-progress";
|
||||
import "../../../components/ha-code-editor";
|
||||
import "../../../components/ha-alert";
|
||||
import type { HaCodeEditor } from "../../../components/ha-code-editor";
|
||||
import type {
|
||||
LovelaceCardConfig,
|
||||
@ -23,11 +23,15 @@ import type {
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { LovelaceRowConfig } from "../entity-rows/types";
|
||||
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
||||
import type { LovelaceGenericElementEditor } from "../types";
|
||||
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||
import type {
|
||||
LovelaceConfigForm,
|
||||
LovelaceGenericElementEditor,
|
||||
} from "../types";
|
||||
import type { HuiFormEditor } from "./config-elements/hui-form-editor";
|
||||
import "./config-elements/hui-generic-entity-row-editor";
|
||||
import { GUISupportError } from "./gui-support-error";
|
||||
import { EditSubElementEvent, GUIModeChangedEvent } from "./types";
|
||||
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||
|
||||
export interface ConfigChangedEvent {
|
||||
config:
|
||||
@ -182,6 +186,10 @@ export abstract class HuiElementEditor<T, C = any> extends LitElement {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected async getConfigForm(): Promise<LovelaceConfigForm | undefined> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected get configElementType(): string | undefined {
|
||||
return this.value ? (this.value as any).type : undefined;
|
||||
}
|
||||
@ -328,6 +336,25 @@ export abstract class HuiElementEditor<T, C = any> extends LitElement {
|
||||
this._loading = true;
|
||||
configElement = await this.getConfigElement();
|
||||
|
||||
if (!configElement) {
|
||||
const form = await this.getConfigForm();
|
||||
if (form) {
|
||||
await import("./config-elements/hui-form-editor");
|
||||
configElement = document.createElement("hui-form-editor");
|
||||
const { schema, assertConfig, computeLabel, computeHelper } = form;
|
||||
(configElement as HuiFormEditor).schema = schema;
|
||||
if (computeLabel) {
|
||||
(configElement as HuiFormEditor).computeLabel = computeLabel;
|
||||
}
|
||||
if (computeHelper) {
|
||||
(configElement as HuiFormEditor).computeHelper = computeHelper;
|
||||
}
|
||||
if (assertConfig) {
|
||||
(configElement as HuiFormEditor).assertConfig = assertConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configElement) {
|
||||
configElement.hass = this.hass;
|
||||
if ("lovelace" in configElement) {
|
||||
|
@ -4,7 +4,10 @@ import {
|
||||
LovelaceTileFeatureConfig,
|
||||
LovelaceTileFeatureContext,
|
||||
} from "../../tile-features/types";
|
||||
import type { LovelaceTileFeatureEditor } from "../../types";
|
||||
import type {
|
||||
LovelaceConfigForm,
|
||||
LovelaceTileFeatureEditor,
|
||||
} from "../../types";
|
||||
import { HuiElementEditor } from "../hui-element-editor";
|
||||
|
||||
@customElement("hui-tile-feature-element-editor")
|
||||
@ -24,6 +27,17 @@ export class HuiTileFeatureElementEditor extends HuiElementEditor<
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected async getConfigForm(): Promise<LovelaceConfigForm | undefined> {
|
||||
const elClass = await getTileFeatureElementClass(this.configElementType!);
|
||||
|
||||
// Check if a schema exists
|
||||
if (elClass && elClass.getConfigForm) {
|
||||
return elClass.getConfigForm();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { LocalizeFunc } from "../../common/translations/localize";
|
||||
import { HaFormSchema } from "../../components/ha-form/types";
|
||||
import {
|
||||
LovelaceBadgeConfig,
|
||||
LovelaceCardConfig,
|
||||
@ -45,6 +47,19 @@ export interface LovelaceCard extends HTMLElement {
|
||||
setConfig(config: LovelaceCardConfig): void;
|
||||
}
|
||||
|
||||
export interface LovelaceConfigForm {
|
||||
schema: HaFormSchema[];
|
||||
assertConfig?: (config: LovelaceCardConfig) => void;
|
||||
computeLabel?: (
|
||||
schema: HaFormSchema,
|
||||
localize: LocalizeFunc
|
||||
) => string | undefined;
|
||||
computeHelper?: (
|
||||
schema: HaFormSchema,
|
||||
localize: LocalizeFunc
|
||||
) => string | undefined;
|
||||
}
|
||||
|
||||
export interface LovelaceCardConstructor extends Constructor<LovelaceCard> {
|
||||
getStubConfig?: (
|
||||
hass: HomeAssistant,
|
||||
@ -52,6 +67,7 @@ export interface LovelaceCardConstructor extends Constructor<LovelaceCard> {
|
||||
entitiesFallback: string[]
|
||||
) => LovelaceCardConfig;
|
||||
getConfigElement?: () => LovelaceCardEditor;
|
||||
getConfigForm?: () => LovelaceConfigForm;
|
||||
}
|
||||
|
||||
export interface LovelaceHeaderFooterConstructor
|
||||
@ -104,11 +120,15 @@ export interface LovelaceTileFeature extends HTMLElement {
|
||||
|
||||
export interface LovelaceTileFeatureConstructor
|
||||
extends Constructor<LovelaceTileFeature> {
|
||||
getConfigElement?: () => LovelaceTileFeatureEditor;
|
||||
getStubConfig?: (
|
||||
hass: HomeAssistant,
|
||||
stateObj?: HassEntity
|
||||
) => LovelaceTileFeatureConfig;
|
||||
getConfigElement?: () => LovelaceTileFeatureEditor;
|
||||
getConfigForm?: () => {
|
||||
schema: HaFormSchema[];
|
||||
assertConfig?: (config: LovelaceCardConfig) => void;
|
||||
};
|
||||
isSupported?: (stateObj?: HassEntity) => boolean;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user