From 261cc6598db2e993f5c1f1a1dfe576ab3da86650 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 8 Jun 2023 16:38:07 +0200 Subject: [PATCH] Add conditional form schema --- src/components/ha-form/ha-form-conditional.ts | 74 +++++++++ src/components/ha-form/ha-form.ts | 8 +- src/components/ha-form/types.ts | 15 +- .../config-elements/hui-gauge-card-editor.ts | 153 +++++++++--------- 4 files changed, 168 insertions(+), 82 deletions(-) create mode 100644 src/components/ha-form/ha-form-conditional.ts diff --git a/src/components/ha-form/ha-form-conditional.ts b/src/components/ha-form/ha-form-conditional.ts new file mode 100644 index 0000000000..03c2305880 --- /dev/null +++ b/src/components/ha-form/ha-form-conditional.ts @@ -0,0 +1,74 @@ +import { + css, + CSSResultGroup, + html, + LitElement, + nothing, + PropertyValues, +} from "lit"; +import { customElement, property } from "lit/decorators"; +import type { HomeAssistant } from "../../types"; +import "./ha-form"; +import type { + HaFormDataContainer, + HaFormElement, + HaFormConditionalSchema, + HaFormSchema, +} from "./types"; + +@customElement("ha-form-conditional") +export class HaFormConditional extends LitElement implements HaFormElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public data!: HaFormDataContainer; + + @property({ attribute: false }) public schema!: HaFormConditionalSchema; + + @property({ type: Boolean }) public disabled = false; + + @property() public computeLabel?: ( + schema: HaFormSchema, + data?: HaFormDataContainer + ) => string; + + @property() public computeHelper?: (schema: HaFormSchema) => string; + + protected updated(changedProps: PropertyValues): void { + if (changedProps.has("schema") || changedProps.has("data")) { + this.toggleAttribute("hidden", !this.schema.condition(this.data)); + } + } + + protected render() { + if (!this.schema.condition(this.data)) { + return nothing; + } + return html` + + `; + } + + static get styles(): CSSResultGroup { + return css` + :host([hidden]) { + display: none !important; + } + :host ha-form { + display: block; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-form-conditional": HaFormConditional; + } +} diff --git a/src/components/ha-form/ha-form.ts b/src/components/ha-form/ha-form.ts index 3062c2317d..a583b4cde1 100644 --- a/src/components/ha-form/ha-form.ts +++ b/src/components/ha-form/ha-form.ts @@ -21,6 +21,7 @@ const LOAD_ELEMENTS = { float: () => import("./ha-form-float"), grid: () => import("./ha-form-grid"), expandable: () => import("./ha-form-expandable"), + conditional: () => import("./ha-form-conditional"), integer: () => import("./ha-form-integer"), multi_select: () => import("./ha-form-multi_select"), positive_time_period_dict: () => @@ -189,12 +190,13 @@ export class HaForm extends LitElement implements HaFormElement { static get styles(): CSSResultGroup { return css` + .root { + display: grid; + row-gap: 24px; + } .root > * { display: block; } - .root > *:not([own-margin]):not(:last-child) { - margin-bottom: 24px; - } ha-alert[own-margin] { margin-bottom: 4px; } diff --git a/src/components/ha-form/types.ts b/src/components/ha-form/types.ts index 287b904780..b76d5a6bb5 100644 --- a/src/components/ha-form/types.ts +++ b/src/components/ha-form/types.ts @@ -13,7 +13,8 @@ export type HaFormSchema = | HaFormTimeSchema | HaFormSelector | HaFormGridSchema - | HaFormExpandableSchema; + | HaFormExpandableSchema + | HaFormConditionalSchema; export interface HaFormBaseSchema { name: string; @@ -47,6 +48,13 @@ export interface HaFormExpandableSchema extends HaFormBaseSchema { schema: readonly HaFormSchema[]; } +export interface HaFormConditionalSchema extends HaFormBaseSchema { + type: "conditional"; + name: ""; + condition: (data: HaFormDataContainer) => boolean; + schema: readonly HaFormSchema[]; +} + export interface HaFormSelector extends HaFormBaseSchema { type?: never; selector: Selector; @@ -99,7 +107,10 @@ export interface HaFormTimeSchema extends HaFormBaseSchema { export type SchemaUnion< SchemaArray extends readonly HaFormSchema[], Schema = SchemaArray[number] -> = Schema extends HaFormGridSchema | HaFormExpandableSchema +> = Schema extends + | HaFormGridSchema + | HaFormExpandableSchema + | HaFormConditionalSchema ? SchemaUnion : Schema; diff --git a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts index 06f173b9b4..4e63a1749b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts @@ -1,6 +1,5 @@ import { html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; import { array, assert, @@ -13,7 +12,10 @@ import { } 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 { + HaFormSchema, + SchemaUnion, +} from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { GaugeCardConfig } from "../../cards/types"; import type { LovelaceCardEditor } from "../../types"; @@ -41,6 +43,75 @@ const cardConfigStruct = assign( }) ); +const SCHEMA = [ + { + name: "entity", + selector: { + entity: { + domain: ["counter", "input_number", "number", "sensor"], + }, + }, + }, + { + name: "", + type: "grid", + schema: [ + { name: "name", selector: { text: {} } }, + { name: "unit", selector: { text: {} } }, + ], + }, + { name: "theme", selector: { theme: {} } }, + { + name: "", + type: "grid", + schema: [ + { + name: "min", + default: DEFAULT_MIN, + selector: { number: { mode: "box" } }, + }, + { + name: "max", + default: DEFAULT_MAX, + selector: { number: { mode: "box" } }, + }, + ], + }, + { + name: "", + type: "grid", + schema: [ + { name: "needle", selector: { boolean: {} } }, + { name: "show_severity", selector: { boolean: {} } }, + ], + }, + { + name: "", + type: "conditional", + condition: (data) => !!data.show_severity, + schema: [ + { + name: "severity", + type: "grid", + schema: [ + { + name: "green", + selector: { number: { mode: "box" } }, + }, + { + name: "yellow", + selector: { number: { mode: "box" } }, + }, + { + name: "red", + selector: { number: { mode: "box" } }, + }, + ], + }, + ], + }, +] as const satisfies readonly HaFormSchema[]; + @customElement("hui-gauge-card-editor") export class HuiGaugeCardEditor extends LitElement @@ -55,81 +126,11 @@ export class HuiGaugeCardEditor this._config = config; } - private _schema = memoizeOne( - (showSeverity: boolean) => - [ - { - name: "entity", - selector: { - entity: { - domain: ["counter", "input_number", "number", "sensor"], - }, - }, - }, - { - name: "", - type: "grid", - schema: [ - { name: "name", selector: { text: {} } }, - { name: "unit", selector: { text: {} } }, - ], - }, - { name: "theme", selector: { theme: {} } }, - { - name: "", - type: "grid", - schema: [ - { - name: "min", - default: DEFAULT_MIN, - selector: { number: { mode: "box" } }, - }, - { - name: "max", - default: DEFAULT_MAX, - selector: { number: { mode: "box" } }, - }, - ], - }, - { - name: "", - type: "grid", - schema: [ - { name: "needle", selector: { boolean: {} } }, - { name: "show_severity", selector: { boolean: {} } }, - ], - }, - ...(showSeverity - ? ([ - { - name: "severity", - type: "grid", - schema: [ - { - name: "green", - selector: { number: { mode: "box" } }, - }, - { - name: "yellow", - selector: { number: { mode: "box" } }, - }, - { - name: "red", - selector: { number: { mode: "box" } }, - }, - ], - }, - ] as const) - : []), - ] as const - ); - protected render() { if (!this.hass || !this._config) { return nothing; } - const schema = this._schema(this._config!.severity !== undefined); const data = { show_severity: this._config!.severity !== undefined, ...this._config, @@ -139,7 +140,7 @@ export class HuiGaugeCardEditor @@ -153,7 +154,7 @@ export class HuiGaugeCardEditor config = { ...config, severity: { - green: config.green || config.severity?.green || 0, + green: config.green || config.severity?.green, yellow: config.yellow || config.severity?.yellow || 0, red: config.red || config.severity?.red || 0, }, @@ -170,9 +171,7 @@ export class HuiGaugeCardEditor fireEvent(this, "config-changed", { config }); } - private _computeLabelCallback = ( - schema: SchemaUnion> - ) => { + private _computeLabelCallback = (schema: SchemaUnion) => { switch (schema.name) { case "name": return this.hass!.localize(