diff --git a/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts index bc6efba022..ae8f79bd27 100644 --- a/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts @@ -90,11 +90,9 @@ export class HuiAlarmPanelCardEditor private _computeLabelCallback = (schema: HaFormSchema) => { if (schema.name === "entity") { - return `${this.hass!.localize( + return this.hass!.localize( "ui.panel.lovelace.editor.card.generic.entity" - )} (${this.hass!.localize( - "ui.panel.lovelace.editor.card.config.required" - )})`; + ); } if (schema.name === "name") { diff --git a/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts index 7dcf65a1bc..c246f36250 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts @@ -107,11 +107,9 @@ export class HuiEntityCardEditor private _computeLabelCallback = (schema: HaFormSchema) => { if (schema.name === "entity") { - return `${this.hass!.localize( + return this.hass!.localize( "ui.panel.lovelace.editor.card.generic.entity" - )} (${this.hass!.localize( - "ui.panel.lovelace.editor.card.config.required" - )})`; + ); } return this.hass!.localize( diff --git a/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts b/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts index 6b94e533a6..e8c524cfdf 100644 --- a/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts @@ -1,25 +1,18 @@ -import "@material/mwc-list/mwc-list-item"; -import "@polymer/paper-input/paper-input"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import "../../../../components/ha-form/ha-form"; +import type { HassEntity } from "home-assistant-js-websocket"; +import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { assert } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { stopPropagation } from "../../../../common/dom/stop_propagation"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { domainIcon } from "../../../../common/entity/domain_icon"; -import "../../../../components/ha-formfield"; -import "../../../../components/ha-icon-picker"; -import "../../../../components/ha-select"; -import "../../../../components/ha-switch"; -import { HomeAssistant } from "../../../../types"; -import { EntitiesCardEntityConfig } from "../../cards/types"; -import "../../components/hui-action-editor"; -import "../../components/hui-entity-editor"; -import "../../components/hui-theme-select-editor"; -import { LovelaceRowEditor } from "../../types"; +import type { LocalizeFunc } from "../../../../common/translations/localize"; +import type { HaFormSchema } from "../../../../components/ha-form/types"; +import type { HomeAssistant } from "../../../../types"; +import type { EntitiesCardEntityConfig } from "../../cards/types"; +import type { LovelaceRowEditor } from "../../types"; import { entitiesConfigStruct } from "../structs/entities-struct"; -import { EditorTarget, EntitiesEditorEvent } from "../types"; -import { configElementStyle } from "./config-elements-style"; const SecondaryInfoValues: { [key: string]: { domains?: string[] } } = { "entity-id": {}, @@ -45,127 +38,105 @@ export class HuiGenericEntityRowEditor this._config = config; } - get _entity(): string { - return this._config!.entity || ""; - } + private _schema = memoizeOne( + ( + entity: string, + icon: string | undefined, + entityState: HassEntity, + localize: LocalizeFunc + ): HaFormSchema[] => { + const domain = computeDomain(entity); - get _name(): string { - return this._config!.name || ""; - } - - get _icon(): string { - return this._config!.icon || ""; - } - - get _secondary_info(): string { - return this._config!.secondary_info || ""; - } + return [ + { name: "entity", required: true, selector: { entity: {} } }, + { + type: "grid", + name: "", + schema: [ + { name: "name", selector: { text: {} } }, + { + name: "icon", + selector: { + icon: { + placeholder: icon || entityState?.attributes.icon, + fallbackPath: + !icon && !entityState?.attributes.icon && entityState + ? domainIcon(domain, entityState) + : undefined, + }, + }, + }, + ], + }, + { + name: "secondary_info", + selector: { + select: { + options: Object.keys(SecondaryInfoValues) + .filter( + (info) => + !("domains" in SecondaryInfoValues[info]) || + ("domains" in SecondaryInfoValues[info] && + SecondaryInfoValues[info].domains!.includes(domain)) + ) + .map((info) => ({ + value: info, + label: localize( + `ui.panel.lovelace.editor.card.entities.secondary_info_values.${info}` + ), + })), + }, + }, + }, + ]; + } + ); protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } - const domain = computeDomain(this._entity); - const entityState = this.hass.states[this._entity]; + const entityState = this.hass.states[this._config.entity]; + + const schema = this._schema( + this._config.entity, + this._config.icon, + entityState, + this.hass.localize + ); return html` -
- -
- - -
- - ${this.hass!.localize( - "ui.panel.lovelace.editor.card.entities.secondary_info_values.none" - )} - ${Object.keys(SecondaryInfoValues).map((info) => { - if ( - !("domains" in SecondaryInfoValues[info]) || - ("domains" in SecondaryInfoValues[info] && - SecondaryInfoValues[info].domains!.includes(domain)) - ) { - return html` - - ${this.hass!.localize( - `ui.panel.lovelace.editor.card.entities.secondary_info_values.${info}` - )} - - `; - } - return ""; - })} - -
+ `; } - private _valueChanged(ev: EntitiesEditorEvent): void { - if (!this._config || !this.hass) { - return; - } - const target = ev.target! as EditorTarget; - const value = target.value || ev.detail?.item?.value; - - if (this[`_${target.configValue}`] === value) { - return; - } - - if (target.configValue) { - if (value === "" || !value) { - this._config = { ...this._config }; - delete this._config[target.configValue!]; - } else { - this._config = { - ...this._config, - [target.configValue!]: value, - }; - } - } - - fireEvent(this, "config-changed", { config: this._config }); + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); } - static get styles(): CSSResultGroup { - return configElementStyle; - } + private _computeLabelCallback = (schema: HaFormSchema) => { + if (schema.name === "entity") { + return this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.entity" + ); + } + + return ( + this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ) || + this.hass!.localize( + `ui.panel.lovelace.editor.card.entity-row.${schema.name}` + ) + ); + }; } declare global { 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 3763707aa3..7f472d39a1 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,16 +1,13 @@ -import "@polymer/paper-input/paper-input"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import "../../../../components/ha-form/ha-form"; +import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import "../../../../components/entity/ha-entity-picker"; -import { HomeAssistant } from "../../../../types"; -import { HumidifierCardConfig } from "../../cards/types"; -import "../../components/hui-theme-select-editor"; -import { LovelaceCardEditor } from "../../types"; +import type { HaFormSchema } from "../../../../components/ha-form/types"; +import type { HomeAssistant } from "../../../../types"; +import type { HumidifierCardConfig } from "../../cards/types"; +import type { LovelaceCardEditor } from "../../types"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import { EditorTarget, EntitiesEditorEvent } from "../types"; -import { configElementStyle } from "./config-elements-style"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -21,7 +18,21 @@ const cardConfigStruct = assign( }) ); -const includeDomains = ["humidifier"]; +const SCHEMA: HaFormSchema[] = [ + { + name: "entity", + required: true, + selector: { entity: { domain: "humidifer" } }, + }, + { + type: "grid", + name: "", + schema: [ + { name: "name", selector: { text: {} } }, + { name: "theme", selector: { theme: {} } }, + ], + }, +]; @customElement("hui-humidifier-card-editor") export class HuiHumidifierCardEditor @@ -37,81 +48,37 @@ export class HuiHumidifierCardEditor this._config = config; } - get _entity(): string { - return this._config!.entity || ""; - } - - get _name(): string { - return this._config!.name || ""; - } - - get _theme(): string { - return this._config!.theme || ""; - } - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } return html` -
- - - -
+ `; } - private _valueChanged(ev: EntitiesEditorEvent): void { - if (!this._config || !this.hass) { - return; - } - const target = ev.target! as EditorTarget; - - if (this[`_${target.configValue}`] === target.value) { - return; - } - if (target.configValue) { - if (target.value === "") { - this._config = { ...this._config }; - delete this._config[target.configValue!]; - } else { - this._config = { ...this._config, [target.configValue!]: target.value }; - } - } - fireEvent(this, "config-changed", { config: this._config }); + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); } - static get styles(): CSSResultGroup { - return configElementStyle; - } + private _computeLabelCallback = (schema: HaFormSchema) => { + if (schema.name === "entity") { + return this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.entity" + ); + } + + return this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ); + }; } declare global { diff --git a/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts index f88fff1f22..bef193337b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts @@ -1,14 +1,13 @@ -import "@polymer/paper-input/paper-input"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import "../../../../components/ha-form/ha-form"; +import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { HomeAssistant } from "../../../../types"; -import { IframeCardConfig } from "../../cards/types"; -import { LovelaceCardEditor } from "../../types"; +import type { HaFormSchema } from "../../../../components/ha-form/types"; +import type { HomeAssistant } from "../../../../types"; +import type { IframeCardConfig } from "../../cards/types"; +import type { LovelaceCardEditor } from "../../types"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import { EditorTarget, EntitiesEditorEvent } from "../types"; -import { configElementStyle } from "./config-elements-style"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -19,6 +18,18 @@ const cardConfigStruct = assign( }) ); +const SCHEMA: HaFormSchema[] = [ + { name: "title", selector: { text: {} } }, + { + name: "", + type: "grid", + schema: [ + { name: "url", required: true, selector: { text: {} } }, + { name: "aspect_ratio", selector: { text: {} } }, + ], + }, +]; + @customElement("hui-iframe-card-editor") export class HuiIframeCardEditor extends LitElement @@ -33,85 +44,28 @@ export class HuiIframeCardEditor this._config = config; } - get _title(): string { - return this._config!.title || ""; - } - - get _url(): string { - return this._config!.url || ""; - } - - get _aspect_ratio(): string { - return this._config!.aspect_ratio || ""; - } - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } return html` -
- -
- - -
-
+ `; } - private _valueChanged(ev: EntitiesEditorEvent): void { - if (!this._config || !this.hass) { - return; - } - const target = ev.target! as EditorTarget; - const value = target.value; - - if (this[`_${target.configValue}`] === value) { - return; - } - if (target.configValue) { - if (value === "") { - this._config = { ...this._config }; - delete this._config[target.configValue!]; - } else { - this._config = { ...this._config, [target.configValue!]: value }; - } - } - fireEvent(this, "config-changed", { config: this._config }); + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); } - static get styles(): CSSResultGroup { - return configElementStyle; - } + private _computeLabelCallback = (schema: HaFormSchema) => + this.hass!.localize(`ui.panel.lovelace.editor.card.generic.${schema.name}`); } declare global { diff --git a/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts index 7671f60b6e..8995c7a6ff 100644 --- a/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts @@ -1,22 +1,21 @@ -import "@polymer/paper-input/paper-input"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, object, optional, string, assign } from "superstruct"; +import type { HassEntity } from "home-assistant-js-websocket"; +import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; -import "../../../../components/ha-icon-picker"; -import { ActionConfig } from "../../../../data/lovelace"; -import { HomeAssistant } from "../../../../types"; -import { LightCardConfig } from "../../cards/types"; +import type { ActionConfig } from "../../../../data/lovelace"; +import type { HomeAssistant } from "../../../../types"; +import type { LightCardConfig } from "../../cards/types"; import "../../components/hui-action-editor"; -import "../../components/hui-entity-editor"; -import "../../components/hui-theme-select-editor"; -import { LovelaceCardEditor } from "../../types"; +import type { LovelaceCardEditor } from "../../types"; import { actionConfigStruct } from "../structs/action-struct"; -import { EditorTarget } from "../types"; +import type { EditorTarget } from "../types"; import { configElementStyle } from "./config-elements-style"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { domainIcon } from "../../../../common/entity/domain_icon"; import { computeDomain } from "../../../../common/entity/compute_domain"; +import type { HaFormSchema } from "../../../../components/ha-form/types"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -30,8 +29,6 @@ const cardConfigStruct = assign( }) ); -const includeDomains = ["light"]; - @customElement("hui-light-card-editor") export class HuiLightCardEditor extends LitElement @@ -46,21 +43,39 @@ export class HuiLightCardEditor this._config = config; } - get _name(): string { - return this._config!.name || ""; - } - - get _theme(): string { - return this._config!.theme || ""; - } - - get _entity(): string { - return this._config!.entity || ""; - } - - get _icon(): string { - return this._config!.icon || ""; - } + private _schema = memoizeOne( + ( + entity: string, + icon: string | undefined, + entityState: HassEntity + ): HaFormSchema[] => [ + { + name: "entity", + required: true, + selector: { entity: { domain: "light" } }, + }, + { + type: "grid", + name: "", + schema: [ + { name: "name", selector: { text: {} } }, + { + name: "icon", + selector: { + icon: { + placeholder: icon || entityState?.attributes.icon, + fallbackPath: + !icon && !entityState?.attributes.icon && entityState + ? domainIcon(computeDomain(entity), entityState) + : undefined, + }, + }, + }, + ], + }, + { name: "theme", selector: { theme: {} } }, + ] + ); get _hold_action(): ActionConfig { return this._config!.hold_action || { action: "more-info" }; @@ -84,59 +99,22 @@ export class HuiLightCardEditor "none", ]; - const entityState = this.hass.states[this._entity]; + const entityState = this.hass.states[this._config.entity]; + const schema = this._schema( + this._config.entity, + this._config.icon, + entityState + ); return html` +
- -
- - -
- - -
`; } - private _valueChanged(ev: CustomEvent): void { + private _actionChanged(ev: CustomEvent): void { if (!this._config || !this.hass) { return; } @@ -190,9 +168,33 @@ export class HuiLightCardEditor fireEvent(this, "config-changed", { config: this._config }); } - static get styles(): CSSResultGroup { - return configElementStyle; + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); } + + private _computeLabelCallback = (schema: HaFormSchema) => { + if (schema.name === "entity") { + return this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.entity" + ); + } + + return this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ); + }; + + static styles: CSSResultGroup = [ + configElementStyle, + css` + ha-form, + hui-action-editor { + display: block; + margin-bottom: 24px; + overflow: auto; + } + `, + ]; } declare global { diff --git a/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts index 13887619c7..427535e412 100644 --- a/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts @@ -1,5 +1,5 @@ -import "@polymer/paper-input/paper-input"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import "../../../../components/ha-form/ha-form"; +import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { array, @@ -12,15 +12,11 @@ import { } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/entity/ha-entities-picker"; -import "../../../../components/entity/ha-entity-picker"; -import { HomeAssistant } from "../../../../types"; -import { LogbookCardConfig } from "../../cards/types"; -import "../../components/hui-entity-editor"; -import "../../components/hui-theme-select-editor"; -import { LovelaceCardEditor } from "../../types"; +import type { HaFormSchema } from "../../../../components/ha-form/types"; +import type { HomeAssistant } from "../../../../types"; +import type { LogbookCardConfig } from "../../cards/types"; +import type { LovelaceCardEditor } from "../../types"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import { EditorTarget } from "../types"; -import { configElementStyle } from "./config-elements-style"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -32,6 +28,18 @@ const cardConfigStruct = assign( }) ); +const SCHEMA: HaFormSchema[] = [ + { name: "title", selector: { text: {} } }, + { + name: "", + type: "grid", + schema: [ + { name: "theme", selector: { theme: {} } }, + { name: "hours_to_show", selector: { number: { mode: "box", min: 1 } } }, + ], + }, +]; + @customElement("hui-logbook-card-editor") export class HuiLogbookCardEditor extends LitElement @@ -41,118 +49,58 @@ export class HuiLogbookCardEditor @state() private _config?: LogbookCardConfig; - @state() private _configEntities?: string[]; - public setConfig(config: LogbookCardConfig): void { assert(config, cardConfigStruct); this._config = config; - this._configEntities = config.entities; - } - - get _title(): string { - return this._config!.title || ""; } get _entities(): string[] { return this._config!.entities || []; } - get _hours_to_show(): number { - return this._config!.hours_to_show || 24; - } - - get _theme(): string { - return this._config!.theme || ""; - } - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } return html` -
- -
- - -
-

- ${`${this.hass!.localize( - "ui.panel.lovelace.editor.card.generic.entities" - )} (${this.hass!.localize( - "ui.panel.lovelace.editor.card.config.required" - )})`} -

- - -
+ +

+ ${`${this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.entities" + )} (${this.hass!.localize( + "ui.panel.lovelace.editor.card.config.required" + )})`} +

+ + `; } - private _valueChanged(ev: CustomEvent): void { - if (!this._config || !this.hass) { - return; - } - const target = ev.target! as EditorTarget; - - if (this[`_${target.configValue}`] === target.value) { - return; - } - if (ev.detail && ev.detail.value && Array.isArray(ev.detail.value)) { - this._config = { ...this._config, entities: ev.detail.value }; - } else if (target.configValue) { - if (target.value === "") { - this._config = { ...this._config }; - delete this._config[target.configValue!]; - } else { - let value: any = target.value; - - if (target.type === "number") { - value = Number(value); - } - - this._config = { - ...this._config, - [target.configValue!]: value, - }; - } - } + private _entitiesChanged(ev: CustomEvent): void { + this._config = { ...this._config!, entities: ev.detail.value }; fireEvent(this, "config-changed", { config: this._config }); } - static get styles(): CSSResultGroup { - return configElementStyle; + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); } + + private _computeLabelCallback = (schema: HaFormSchema) => + this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ) || + this.hass!.localize(`ui.panel.lovelace.editor.card.logbook.${schema.name}`); } declare global { diff --git a/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts index 18b54b2450..50c8fd65d3 100644 --- a/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts @@ -1,3 +1,4 @@ +import "../../../../components/ha-form/ha-form"; import "@polymer/paper-input/paper-input"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; @@ -12,7 +13,6 @@ import { assign, } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeRTLDirection } from "../../../../common/util/compute_rtl"; import "../../../../components/ha-formfield"; import "../../../../components/ha-switch"; import { PolymerChangedEvent } from "../../../../polymer-types"; @@ -27,6 +27,7 @@ import { entitiesConfigStruct } from "../structs/entities-struct"; import { EditorTarget, EntitiesEditorEvent } from "../types"; import { configElementStyle } from "./config-elements-style"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; +import { HaFormSchema } from "../../../../components/ha-form/types"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -41,6 +42,20 @@ const cardConfigStruct = assign( }) ); +const SCHEMA: HaFormSchema[] = [ + { name: "title", selector: { text: {} } }, + { + name: "", + type: "grid", + schema: [ + { name: "aspect_ratio", selector: { text: {} } }, + { name: "default_zoom", selector: { number: { mode: "box", min: 0 } } }, + { name: "dark_mode", selector: { boolean: {} } }, + { name: "hours_to_show", selector: { number: { mode: "box", min: 1 } } }, + ], + }, +]; + @customElement("hui-map-card-editor") export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor { @property({ attribute: false }) public hass?: HomeAssistant; @@ -57,99 +72,24 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor { : []; } - get _title(): string { - return this._config!.title || ""; - } - - get _aspect_ratio(): string { - return this._config!.aspect_ratio || ""; - } - - get _default_zoom(): number { - return this._config!.default_zoom || 0; - } - get _geo_location_sources(): string[] { return this._config!.geo_location_sources || []; } - get _hours_to_show(): number { - return this._config!.hours_to_show || 0; - } - - get _dark_mode(): boolean { - return this._config!.dark_mode || false; - } - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } return html` +
- -
- - -
-
- - - -
@@ -176,18 +115,15 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor { } private _entitiesValueChanged(ev: EntitiesEditorEvent): void { - if (!this._config || !this.hass) { - return; - } if (ev.detail && ev.detail.entities) { - this._config = { ...this._config, entities: ev.detail.entities }; + this._config = { ...this._config!, entities: ev.detail.entities }; this._configEntities = processEditorEntities(this._config.entities); - fireEvent(this, "config-changed", { config: this._config }); + fireEvent(this, "config-changed", { config: this._config! }); } } - private _valueChanged(ev: PolymerChangedEvent): void { + private _geoSourcesChanged(ev: PolymerChangedEvent): void { if (!this._config || !this.hass) { return; } @@ -196,26 +132,34 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor { return; } - let value = target.checked ?? ev.detail.value; + const value = ev.detail.value; - if (value && target.type === "number") { - value = Number(value); - } - if (this[`_${target.configValue}`] === value) { + if (this._geo_location_sources === value) { return; } + if (value === "") { this._config = { ...this._config }; - delete this._config[target.configValue!]; - } else if (target.configValue) { + delete this._config.geo_location_sources; + } else { this._config = { ...this._config, - [target.configValue]: value, + geo_location_sources: value, }; } fireEvent(this, "config-changed", { config: this._config }); } + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); + } + + private _computeLabelCallback = (schema: HaFormSchema) => + this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ) || + this.hass!.localize(`ui.panel.lovelace.editor.card.map.${schema.name}`); + static get styles(): CSSResultGroup { return [ configElementStyle, diff --git a/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts index d73f109fd8..fe1b3360c4 100644 --- a/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts @@ -1,16 +1,13 @@ -import "@polymer/paper-input/paper-input"; -import "@polymer/paper-input/paper-textarea"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import "../../../../components/ha-form/ha-form"; +import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { HomeAssistant } from "../../../../types"; -import { MarkdownCardConfig } from "../../cards/types"; -import "../../components/hui-theme-select-editor"; -import { LovelaceCardEditor } from "../../types"; +import type { HaFormSchema } from "../../../../components/ha-form/types"; +import type { HomeAssistant } from "../../../../types"; +import type { MarkdownCardConfig } from "../../cards/types"; +import type { LovelaceCardEditor } from "../../types"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import { EditorTarget, EntitiesEditorEvent } from "../types"; -import { configElementStyle } from "./config-elements-style"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -21,6 +18,12 @@ const cardConfigStruct = assign( }) ); +const SCHEMA: HaFormSchema[] = [ + { name: "title", selector: { text: {} } }, + { name: "content", required: true, selector: { text: { multiline: true } } }, + { name: "theme", selector: { theme: {} } }, +]; + @customElement("hui-markdown-card-editor") export class HuiMarkdownCardEditor extends LitElement @@ -35,90 +38,33 @@ export class HuiMarkdownCardEditor this._config = config; } - get _title(): string { - return this._config!.title || ""; - } - - get _content(): string { - return this._config!.content || ""; - } - - get _theme(): string { - return this._config!.theme || ""; - } - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } return html` -
- - - -
+ `; } - private _ignoreKeydown(ev: KeyboardEvent) { - // Stop keyboard events from the paper-textarea from propagating to avoid accidentally closing the dialog when the user presses Enter. - ev.stopPropagation(); + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); } - private _valueChanged(ev: EntitiesEditorEvent): void { - if (!this._config || !this.hass) { - return; - } - const target = ev.target! as EditorTarget; - - if (this[`_${target.configValue}`] === target.value) { - return; - } - if (target.configValue) { - if (target.value === "" && target.configValue !== "content") { - this._config = { ...this._config }; - delete this._config[target.configValue!]; - } else { - this._config = { - ...this._config, - [target.configValue!]: target.value, - }; - } - } - fireEvent(this, "config-changed", { config: this._config }); - } - - static get styles(): CSSResultGroup { - return configElementStyle; - } + private _computeLabelCallback = (schema: HaFormSchema) => + this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ) || + this.hass!.localize( + `ui.panel.lovelace.editor.card.markdown.${schema.name}` + ); } declare global { diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts index 1e21fe3d59..53288a843b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts @@ -1,5 +1,5 @@ import "@polymer/paper-input/paper-input"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, object, optional, string, assign } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; @@ -63,7 +63,7 @@ export class HuiPictureCardEditor return html`
- + @input=${this._valueChanged} + >
- - - - -
- - ${views.map( - (view) => - html`${view} ` - )} - - -
-
-
- - -
-
- - -
-
-
`; } - private _change(ev: Event) { - if (!this._config || !this.hass) { - return; - } - const target = ev.target! as EditorTarget; - const value = target.checked; - - if (this[`_${target.configValue}`] === value) { - return; - } - - this._config = { - ...this._config, - [target.configValue!]: value, - }; - fireEvent(this, "config-changed", { config: this._config }); + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); } - private _valueChanged(ev: CustomEvent): void { + private _changed(ev: CustomEvent): void { if (!this._config || !this.hass) { return; } @@ -279,23 +153,36 @@ export class HuiPictureEntityCardEditor return; } - if (target.configValue) { - if (value !== false && !value) { - this._config = { ...this._config }; - delete this._config[target.configValue!]; - } else { - this._config = { - ...this._config, - [target.configValue!]: value, - }; - } + if (value !== false && !value) { + this._config = { ...this._config }; + delete this._config[target.configValue!]; + } else { + this._config = { + ...this._config, + [target.configValue!]: value, + }; } fireEvent(this, "config-changed", { config: this._config }); } - static get styles(): CSSResultGroup { - return configElementStyle; - } + private _computeLabelCallback = (schema: HaFormSchema) => { + if (schema.name === "entity") { + return this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.entity" + ); + } + + return ( + this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ) || + this.hass!.localize( + `ui.panel.lovelace.editor.card.picture-entity.${schema.name}` + ) + ); + }; + + static styles: CSSResultGroup = configElementStyle; } declare global { diff --git a/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts index 2eb8827290..56e7ad503f 100644 --- a/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts @@ -1,16 +1,13 @@ -import "@polymer/paper-input/paper-input"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import "../../../../components/ha-form/ha-form"; +import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; -import "../../../../components/entity/ha-entity-picker"; -import { HomeAssistant } from "../../../../types"; -import { PlantStatusCardConfig } from "../../cards/types"; -import "../../components/hui-theme-select-editor"; -import { LovelaceCardEditor } from "../../types"; +import type { HaFormSchema } from "../../../../components/ha-form/types"; +import type { HomeAssistant } from "../../../../types"; +import type { PlantStatusCardConfig } from "../../cards/types"; +import type { LovelaceCardEditor } from "../../types"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import { EditorTarget, EntitiesEditorEvent } from "../types"; -import { configElementStyle } from "./config-elements-style"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -21,7 +18,11 @@ const cardConfigStruct = assign( }) ); -const includeDomains = ["plant"]; +const SCHEMA: HaFormSchema[] = [ + { name: "entity", required: true, selector: { entity: { domain: "plant" } } }, + { name: "name", selector: { text: {} } }, + { name: "theme", selector: { theme: {} } }, +]; @customElement("hui-plant-status-card-editor") export class HuiPlantStatusCardEditor @@ -37,83 +38,37 @@ export class HuiPlantStatusCardEditor this._config = config; } - get _entity(): string { - return this._config!.entity || ""; - } - - get _name(): string { - return this._config!.name || ""; - } - - get _theme(): string { - return this._config!.theme || ""; - } - protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } return html` -
- - - -
+ `; } - private _valueChanged(ev: EntitiesEditorEvent): void { - if (!this._config || !this.hass) { - return; - } - const target = ev.target! as EditorTarget; - if (this[`_${target.configValue}`] === target.value) { - return; - } - if (target.configValue) { - if (target.value === "") { - this._config = { ...this._config }; - delete this._config[target.configValue!]; - } else { - this._config = { - ...this._config, - [target.configValue!]: target.value, - }; - } - } - fireEvent(this, "config-changed", { config: this._config }); + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); } - static get styles(): CSSResultGroup { - return configElementStyle; - } + private _computeLabelCallback = (schema: HaFormSchema) => { + if (schema.name === "entity") { + return this.hass!.localize( + "ui.panel.lovelace.editor.card.generic.entity" + ); + } + + return this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ); + }; } declare global { diff --git a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts index 0d867e35fe..d78fb83cf8 100644 --- a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts @@ -148,11 +148,9 @@ export class HuiSensorCardEditor private _computeLabelCallback = (schema: HaFormSchema) => { if (schema.name === "entity") { - return `${this.hass!.localize( + return this.hass!.localize( "ui.panel.lovelace.editor.card.generic.entity" - )} (${this.hass!.localize( - "ui.panel.lovelace.editor.card.config.required" - )})`; + ); } if (schema.name === "detail") { 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 fbae156c62..ed4ab2a61b 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 @@ -66,11 +66,9 @@ export class HuiThermostatCardEditor private _computeLabelCallback = (schema: HaFormSchema) => { if (schema.name === "entity") { - return `${this.hass!.localize( + return this.hass!.localize( "ui.panel.lovelace.editor.card.generic.entity" - )} (${this.hass!.localize( - "ui.panel.lovelace.editor.card.config.required" - )})`; + ); } return this.hass!.localize( diff --git a/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts b/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts index 5c5e3aa4b7..5974cddd1d 100644 --- a/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts +++ b/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts @@ -16,7 +16,7 @@ export class HuiDialogEditLovelace extends LitElement { @state() private _lovelace?: Lovelace; - private _config?: LovelaceConfig; + @state() private _config?: LovelaceConfig; private _saving = false; diff --git a/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts b/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts index 6a453d51dc..cfe3627398 100644 --- a/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts +++ b/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts @@ -1,10 +1,9 @@ -import "@polymer/paper-input/paper-input"; -import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import "../../../../components/ha-textfield"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import { LovelaceConfig } from "../../../../data/lovelace"; import { HomeAssistant } from "../../../../types"; -import { configElementStyle } from "../config-elements/config-elements-style"; import { EditorTarget } from "../types"; declare global { @@ -30,16 +29,14 @@ export class HuiLovelaceEditor extends LitElement { protected render(): TemplateResult { return html` -
- -
+ `; } @@ -66,9 +63,11 @@ export class HuiLovelaceEditor extends LitElement { fireEvent(this, "lovelace-config-changed", { config: newConfig }); } - static get styles(): CSSResultGroup { - return configElementStyle; - } + static styles: CSSResultGroup = css` + ha-textfield { + display: block; + } + `; } declare global { diff --git a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts index f04f74e0dd..91c284ec73 100644 --- a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts +++ b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts @@ -1,24 +1,17 @@ -import "@material/mwc-list/mwc-list-item"; -import "@polymer/paper-input/paper-input"; -import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import "../../../../components/ha-form/ha-form"; +import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { stopPropagation } from "../../../../common/dom/stop_propagation"; import { slugify } from "../../../../common/string/slugify"; -import "../../../../components/ha-formfield"; -import "../../../../components/ha-icon-picker"; -import "../../../../components/ha-select"; -import "../../../../components/ha-switch"; -import { LovelaceViewConfig } from "../../../../data/lovelace"; -import { HomeAssistant } from "../../../../types"; -import "../../components/hui-theme-select-editor"; +import type { HaFormSchema } from "../../../../components/ha-form/types"; +import type { LovelaceViewConfig } from "../../../../data/lovelace"; +import type { HomeAssistant } from "../../../../types"; import { DEFAULT_VIEW_LAYOUT, PANEL_VIEW_LAYOUT, SIDEBAR_VIEW_LAYOUT, } from "../../views/const"; -import { configElementStyle } from "../config-elements/config-elements-style"; -import { EditorTarget } from "../types"; declare global { interface HASSDomEvents { @@ -38,32 +31,35 @@ export class HuiViewEditor extends LitElement { private _suggestedPath = false; - get _path(): string { - if (!this._config) { - return ""; - } - return this._config.path || ""; - } + private _schema = memoizeOne((localize): HaFormSchema[] => [ + { name: "title", selector: { text: {} } }, + { + name: "icon", + selector: { + icon: {}, + }, + }, + { name: "path", selector: { text: {} } }, + { name: "theme", selector: { theme: {} } }, + { + name: "type", + selector: { + select: { + options: [ + DEFAULT_VIEW_LAYOUT, + SIDEBAR_VIEW_LAYOUT, + PANEL_VIEW_LAYOUT, + ].map((type) => ({ + value: type, + label: localize(`ui.panel.lovelace.editor.edit_view.types.${type}`), + })), + }, + }, + }, + ]); - get _title(): string { - if (!this._config) { - return ""; - } - return this._config.title || ""; - } - - get _icon(): string { - if (!this._config) { - return ""; - } - return this._config.icon || ""; - } - - get _theme(): string { - if (!this._config) { - return ""; - } - return this._config.theme || "Backend-selected"; + set config(config: LovelaceViewConfig) { + this._config = config; } get _type(): string { @@ -75,142 +71,59 @@ export class HuiViewEditor extends LitElement { : this._config.type || DEFAULT_VIEW_LAYOUT; } - set config(config: LovelaceViewConfig) { - this._config = config; - } - protected render(): TemplateResult { if (!this.hass) { return html``; } + const schema = this._schema(this.hass.localize); + const data = { + theme: "Backend-selected", + ...this._config, + type: this._type, + }; + return html` -
- - - - - - ${[DEFAULT_VIEW_LAYOUT, SIDEBAR_VIEW_LAYOUT, PANEL_VIEW_LAYOUT].map( - (type) => html` - ${this.hass.localize( - `ui.panel.lovelace.editor.edit_view.types.${type}` - )} - ` - )} - -
+ `; } - private _valueChanged(ev: Event): void { - const target = ev.currentTarget! as EditorTarget; + private _valueChanged(ev: CustomEvent): void { + const config = ev.detail.value; - if (this[`_${target.configValue}`] === target.value) { - return; + if (config.type === "masonry") { + delete config.type; } - let newConfig; - - if (target.configValue) { - newConfig = { - ...this._config, - [target.configValue!]: - target.checked !== undefined ? target.checked : target.value, - }; - } - - fireEvent(this, "view-config-changed", { config: newConfig }); - } - - private _typeChanged(ev): void { - const selected = ev.target.value; - if (selected === "") { - return; - } - const newConfig = { - ...this._config, - }; - delete newConfig.panel; - if (selected === "masonry") { - delete newConfig.type; - } else { - newConfig.type = selected; - } - fireEvent(this, "view-config-changed", { config: newConfig }); - } - - private _handleTitleBlur(ev) { if ( - !this.isNew || - this._suggestedPath || - this._config.path || - !ev.currentTarget.value + this.isNew && + !this._suggestedPath && + config.title && + (!this._config.path || + config.path === slugify(this._config.title || "", "-")) ) { - return; + config.path = slugify(config.title, "-"); } - const config = { - ...this._config, - path: slugify(ev.currentTarget.value, "-"), - }; fireEvent(this, "view-config-changed", { config }); } - static get styles(): CSSResultGroup { - return [ - configElementStyle, - css` - .panel { - color: var(--secondary-text-color); - display: block; - } - `, - ]; - } + private _computeLabelCallback = (schema: HaFormSchema) => { + if (schema.name === "path") { + return this.hass!.localize(`ui.panel.lovelace.editor.card.generic.url`); + } + return ( + this.hass!.localize( + `ui.panel.lovelace.editor.card.generic.${schema.name}` + ) || this.hass.localize("ui.panel.lovelace.editor.edit_view.type") + ); + }; } declare global { diff --git a/src/translations/en.json b/src/translations/en.json index 4807070e24..d080bac456 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3520,6 +3520,9 @@ "name": "Entity Filter", "description": "The Entity Filter card allows you to define a list of entities that you want to track only when in a certain state." }, + "entity-row": { + "secondary_info": "Secondary Information" + }, "gauge": { "name": "Gauge", "needle_gauge": "Display as needle gauge?",