From 7de5c46f1443459b5f05166ce4ddea457694165a Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 19 Sep 2024 09:52:59 +0200 Subject: [PATCH] Improve card features editor (#22023) * Move expansion panel outside of feature component * Cache main form and feature form --- .../config-elements/config-elements-style.ts | 17 ++ .../hui-card-features-editor.ts | 221 ++++++++---------- .../hui-humidifier-card-editor.ts | 84 ++++--- .../hui-thermostat-card-editor.ts | 83 ++++--- .../config-elements/hui-tile-card-editor.ts | 71 +++--- src/translations/en.json | 3 +- 6 files changed, 268 insertions(+), 211 deletions(-) diff --git a/src/panels/lovelace/editor/config-elements/config-elements-style.ts b/src/panels/lovelace/editor/config-elements/config-elements-style.ts index a3bf655e52..5434de8d2e 100644 --- a/src/panels/lovelace/editor/config-elements/config-elements-style.ts +++ b/src/panels/lovelace/editor/config-elements/config-elements-style.ts @@ -34,4 +34,21 @@ export const configElementStyle = css` margin-top: 8px; display: block; } + ha-expansion-panel { + display: block; + --expansion-panel-content-padding: 0; + border-radius: 6px; + --ha-card-border-radius: 6px; + } + ha-expansion-panel .content { + padding: 12px; + } + ha-expansion-panel > * { + margin: 0; + font-size: inherit; + font-weight: inherit; + } + ha-expansion-panel ha-svg-icon { + color: var(--secondary-text-color); + } `; diff --git a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts index 288a6976b8..82d28ee169 100644 --- a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts @@ -1,11 +1,10 @@ -import { mdiDelete, mdiDrag, mdiListBox, mdiPencil, mdiPlus } from "@mdi/js"; +import { mdiDelete, mdiDrag, mdiPencil, mdiPlus } from "@mdi/js"; import { HassEntity } from "home-assistant-js-websocket"; import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property } from "lit/decorators"; import { repeat } from "lit/directives/repeat"; import { fireEvent } from "../../../../common/dom/fire_event"; import { stopPropagation } from "../../../../common/dom/stop_propagation"; -import "../../../../components/entity/ha-entity-picker"; import "../../../../components/ha-button"; import "../../../../components/ha-icon-button"; import "../../../../components/ha-list-item"; @@ -236,119 +235,108 @@ export class HuiCardFeaturesEditor extends LitElement { ); return html` - -

- - ${this.hass!.localize("ui.panel.lovelace.editor.features.name")} -

-
- ${supportedFeaturesType.length === 0 && this.features.length === 0 - ? html` - - ${this.hass!.localize( - "ui.panel.lovelace.editor.features.no_compatible_available" - )} - - ` - : nothing} - -
- ${repeat( - this.features, - (featureConf) => this._getKey(featureConf), - (featureConf, index) => { - const type = featureConf.type; - const supported = this._supportsFeatureType(type); - const editable = this._isFeatureTypeEditable(type); - return html` -
-
- -
-
-
- ${this._getFeatureTypeLabel(type)} - ${this.stateObj && !supported - ? html` - - ${this.hass!.localize( - "ui.panel.lovelace.editor.features.not_compatible" - )} - - ` - : nothing} -
-
- ${editable + ${supportedFeaturesType.length === 0 && this.features.length === 0 + ? html` + + ${this.hass!.localize( + "ui.panel.lovelace.editor.features.no_compatible_available" + )} + + ` + : nothing} + +
+ ${repeat( + this.features, + (featureConf) => this._getKey(featureConf), + (featureConf, index) => { + const type = featureConf.type; + const supported = this._supportsFeatureType(type); + const editable = this._isFeatureTypeEditable(type); + return html` +
+
+ +
+
+
+ ${this._getFeatureTypeLabel(type)} + ${this.stateObj && !supported ? html` - + ${this.hass!.localize( + "ui.panel.lovelace.editor.features.not_compatible" )} - .path=${mdiPencil} - class="edit-icon" - .index=${index} - @click=${this._editFeature} - .disabled=${!supported} - > + ` : nothing} -
- `; - } - )} -
- - ${supportedFeaturesType.length > 0 - ? html` - - - - - ${types.map( - (type) => html` - - ${this._getFeatureTypeLabel(type)} - - ` - )} - ${types.length > 0 && customTypes.length > 0 - ? html`
  • ` +
    + ${editable + ? html` + + ` : nothing} - ${customTypes.map( - (type) => html` - - ${this._getFeatureTypeLabel(type)} - - ` - )} - - ` - : nothing} + +
    + `; + } + )}
    - + + ${supportedFeaturesType.length > 0 + ? html` + + + + + ${types.map( + (type) => html` + + ${this._getFeatureTypeLabel(type)} + + ` + )} + ${types.length > 0 && customTypes.length > 0 + ? html`
  • ` + : nothing} + ${customTypes.map( + (type) => html` + + ${this._getFeatureTypeLabel(type)} + + ` + )} +
    + ` + : nothing} `; } @@ -409,23 +397,6 @@ export class HuiCardFeaturesEditor extends LitElement { display: flex !important; flex-direction: column; } - .content { - padding: 12px; - } - ha-expansion-panel { - display: block; - --expansion-panel-content-padding: 0; - border-radius: 6px; - } - h3 { - margin: 0; - font-size: inherit; - font-weight: inherit; - } - ha-svg-icon, - ha-icon { - color: var(--secondary-text-color); - } ha-button-menu { margin-top: 8px; } diff --git a/src/panels/lovelace/editor/config-elements/hui-humidifier-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-humidifier-card-editor.ts index fb8543a0c8..34e91af4ef 100644 --- a/src/panels/lovelace/editor/config-elements/hui-humidifier-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-humidifier-card-editor.ts @@ -1,5 +1,7 @@ +import { mdiListBox } from "@mdi/js"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { cache } from "lit/directives/cache"; import memoizeOne from "memoize-one"; import { any, @@ -12,11 +14,13 @@ import { string, } from "superstruct"; import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event"; +import "../../../../components/ha-expansion-panel"; import "../../../../components/ha-form/ha-form"; import type { HaFormSchema, SchemaUnion, } from "../../../../components/ha-form/types"; +import "../../../../components/ha-svg-icon"; import type { HomeAssistant } from "../../../../types"; import { LovelaceCardFeatureConfig, @@ -27,6 +31,7 @@ import type { LovelaceCardEditor } from "../../types"; import "../hui-sub-element-editor"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { EditSubElementEvent, SubElementEditorConfig } from "../types"; +import { configElementStyle } from "./config-elements-style"; import "./hui-card-features-editor"; import type { FeatureType } from "./hui-card-features-editor"; @@ -93,22 +98,30 @@ export class HuiHumidifierCardEditor return nothing; } - const stateObj = this._config.entity - ? this.hass.states[this._config.entity] - : undefined; + return cache( + this._subElementEditorConfig + ? this._renderFeatureForm() + : this._renderForm() + ); + } - if (this._subElementEditorConfig) { - return html` - - - `; - } + private _renderFeatureForm() { + const entityId = this._config!.entity; + return html` + + + `; + } + + private _renderForm() { + const entityId = this._config!.entity; + const stateObj = entityId ? this.hass!.states[entityId] : undefined; return html` - + +

    + + ${this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.features" + )} +

    +
    + +
    +
    `; } @@ -202,12 +225,15 @@ export class HuiHumidifierCardEditor }; static get styles() { - return css` - ha-form { - display: block; - margin-bottom: 24px; - } - `; + return [ + configElementStyle, + css` + ha-form { + display: block; + margin-bottom: 24px; + } + `, + ]; } } diff --git a/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts index 4d38affa8e..7f8f37935d 100644 --- a/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts @@ -1,5 +1,7 @@ +import { mdiListBox } from "@mdi/js"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { cache } from "lit/directives/cache"; import memoizeOne from "memoize-one"; import { any, @@ -12,11 +14,13 @@ import { string, } from "superstruct"; import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event"; +import "../../../../components/ha-expansion-panel"; import "../../../../components/ha-form/ha-form"; import type { HaFormSchema, SchemaUnion, } from "../../../../components/ha-form/types"; +import "../../../../components/ha-svg-icon"; import type { HomeAssistant } from "../../../../types"; import { LovelaceCardFeatureConfig, @@ -27,6 +31,7 @@ import type { LovelaceCardEditor } from "../../types"; import "../hui-sub-element-editor"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { EditSubElementEvent, SubElementEditorConfig } from "../types"; +import { configElementStyle } from "./config-elements-style"; import "./hui-card-features-editor"; import type { FeatureType } from "./hui-card-features-editor"; @@ -91,22 +96,29 @@ export class HuiThermostatCardEditor return nothing; } - const stateObj = this._config.entity - ? this.hass.states[this._config.entity] - : undefined; + return cache( + this._subElementEditorConfig + ? this._renderFeatureForm() + : this._renderForm() + ); + } - if (this._subElementEditorConfig) { - return html` - - - `; - } + private _renderFeatureForm() { + return html` + + + `; + } + + private _renderForm() { + const entityId = this._config!.entity; + const stateObj = entityId ? this.hass!.states[entityId] : undefined; return html` - + +

    + + ${this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.features" + )} +

    +
    + +
    +
    `; } @@ -200,12 +222,15 @@ export class HuiThermostatCardEditor }; static get styles() { - return css` - ha-form { - display: block; - margin-bottom: 24px; - } - `; + return [ + configElementStyle, + css` + ha-form { + display: block; + margin-bottom: 24px; + } + `, + ]; } } diff --git a/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts index cc8500eeb6..743a006aea 100644 --- a/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts @@ -1,6 +1,7 @@ -import { mdiGestureTap, mdiPalette } from "@mdi/js"; +import { mdiGestureTap, mdiListBox, mdiPalette } from "@mdi/js"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { cache } from "lit/directives/cache"; import memoizeOne from "memoize-one"; import { any, @@ -14,11 +15,13 @@ import { union, } from "superstruct"; import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event"; +import "../../../../components/ha-expansion-panel"; import "../../../../components/ha-form/ha-form"; import type { HaFormSchema, SchemaUnion, } from "../../../../components/ha-form/types"; +import "../../../../components/ha-svg-icon"; import type { HomeAssistant } from "../../../../types"; import { LovelaceCardFeatureConfig, @@ -168,27 +171,31 @@ export class HuiTileCardEditor return nothing; } - const stateObj = this._config.entity - ? this.hass.states[this._config.entity] - : undefined; - - const schema = this._schema( - this._config.entity, - this._config.hide_state ?? false + return cache( + this._subElementEditorConfig + ? this._renderFeatureForm() + : this._renderForm() ); + } - if (this._subElementEditorConfig) { - return html` - - - `; - } + private _renderFeatureForm() { + return html` + + + `; + } + + private _renderForm() { + const entityId = this._config!.entity; + const stateObj = entityId ? this.hass!.states[entityId] : undefined; + + const schema = this._schema(entityId, this._config!.hide_state ?? false); const data = this._config; @@ -200,13 +207,23 @@ export class HuiTileCardEditor .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > - + +

    + + ${this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.features" + )} +

    +
    + +
    +
    `; } diff --git a/src/translations/en.json b/src/translations/en.json index ea2252f25f..dc87af66c3 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5989,7 +5989,8 @@ "state_color": "Color icons based on state?", "suggested_cards": "Suggested cards", "other_cards": "Other cards", - "custom_cards": "Custom cards" + "custom_cards": "Custom cards", + "features": "Features" }, "map": { "name": "Map",