diff --git a/src/panels/lovelace/editor/conditions/ha-card-condition-editor.ts b/src/panels/lovelace/editor/conditions/ha-card-condition-editor.ts index a56b0c1101cd..d97264de1598 100644 --- a/src/panels/lovelace/editor/conditions/ha-card-condition-editor.ts +++ b/src/panels/lovelace/editor/conditions/ha-card-condition-editor.ts @@ -6,6 +6,7 @@ import { customElement, property, state } from "lit/decorators"; import { dynamicElement } from "../../../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../../../common/dom/fire_event"; import { stopPropagation } from "../../../../common/dom/stop_propagation"; +import { handleStructError } from "../../../../common/structs/handle-errors"; import "../../../../components/ha-button-menu"; import "../../../../components/ha-icon-button"; import "../../../../components/ha-list-item"; @@ -14,15 +15,14 @@ import "../../../../components/ha-yaml-editor"; import { haStyle } from "../../../../resources/styles"; import type { HomeAssistant } from "../../../../types"; import { ICON_CONDITION } from "../../common/icon-condition"; -import { Condition } from "../../common/validate-condition"; +import { Condition, LegacyCondition } from "../../common/validate-condition"; import type { LovelaceConditionEditorConstructor } from "./types"; -import { handleStructError } from "../../../../common/structs/handle-errors"; @customElement("ha-card-condition-editor") export default class HaCardConditionEditor extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property({ attribute: false }) condition!: Condition; + @property({ attribute: false }) condition!: Condition | LegacyCondition; @state() public _yamlMode = false; @@ -30,20 +30,25 @@ export default class HaCardConditionEditor extends LitElement { @state() public _uiWarnings: string[] = []; + @state() _condition?: Condition; + private get _editor() { - const element = customElements.get( - `ha-card-condition-${this.condition.condition}` + if (!this._condition) return undefined; + return customElements.get( + `ha-card-condition-${this._condition.condition}` ) as LovelaceConditionEditorConstructor | undefined; - - return element; } protected willUpdate(changedProperties: PropertyValues): void { if (changedProperties.has("condition")) { + this._condition = { + condition: "state", + ...this.condition, + }; const validator = this._editor?.validateUIConfig; if (validator) { try { - validator(this.condition, this.hass); + validator(this._condition, this.hass); this._uiAvailable = true; this._uiWarnings = []; } catch (err) { @@ -65,7 +70,9 @@ export default class HaCardConditionEditor extends LitElement { } protected render() { - const condition = this.condition; + const condition = this._condition; + + if (!condition) return nothing; return html`
@@ -75,7 +82,7 @@ export default class HaCardConditionEditor extends LitElement { > ${this.hass.localize( - `ui.panel.lovelace.editor.card.conditional.condition.${condition.condition}.label` + `ui.panel.lovelace.editor.condition-editor.condition.${condition.condition}.label` ) || condition.condition} + ${this.hass!.localize( + "ui.panel.lovelace.editor.condition-editor.explanation" + )} + ${this.conditions.map( + (cond, idx) => html` +
+ +
+ ` + )} +
+ + + + + ${UI_CONDITION.map( + (condition) => html` + + ${this.hass!.localize( + `ui.panel.lovelace.editor.condition-editor.condition.${condition}.label` + ) || condition} + + + ` + )} + +
+
+ `; + } + + private _addCondition(ev: CustomEvent): void { + const condition = (ev.currentTarget as HaSelect).items[ev.detail.index] + .value as Condition["condition"]; + const conditions = [...this.conditions]; + + const elClass = customElements.get(`ha-card-condition-${condition}`) as + | LovelaceConditionEditorConstructor + | undefined; + + conditions.push( + elClass?.defaultConfig + ? { ...elClass.defaultConfig } + : { condition: condition } + ); + fireEvent(this, "value-changed", { value: conditions }); + } + + private _conditionChanged(ev: CustomEvent) { + ev.stopPropagation(); + const conditions = [...this.conditions]; + const newValue = ev.detail.value; + const index = (ev.target as any).index; + + if (newValue === null) { + conditions.splice(index, 1); + } else { + conditions[index] = newValue; + } + + fireEvent(this, "value-changed", { value: conditions }); + } + + static get styles(): CSSResultGroup { + return [ + css` + mwc-tab-bar { + border-bottom: 1px solid var(--divider-color); + } + .conditions { + margin-top: 8px; + } + .condition { + margin-top: 8px; + border: 1px solid var(--divider-color); + } + .condition .content { + padding: 12px; + } + ha-button-menu { + margin-top: 12px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-card-conditions-editor": HaCardConditionsEditor; + } +} diff --git a/src/panels/lovelace/editor/conditions/types/ha-card-condition-screen.ts b/src/panels/lovelace/editor/conditions/types/ha-card-condition-screen.ts index 3ccaba738a65..cd341562e238 100644 --- a/src/panels/lovelace/editor/conditions/types/ha-card-condition-screen.ts +++ b/src/panels/lovelace/editor/conditions/types/ha-card-condition-screen.ts @@ -129,11 +129,11 @@ export class HaCardConditionScreen extends LitElement { return { value: b, label: `${localize( - `ui.panel.lovelace.editor.card.conditional.condition.screen.breakpoints_list.${b}` + `ui.panel.lovelace.editor.condition-editor.condition.screen.breakpoints_list.${b}` )}${ value ? ` (${localize( - `ui.panel.lovelace.editor.card.conditional.condition.screen.min`, + `ui.panel.lovelace.editor.condition-editor.condition.screen.min`, { size: value } )})` : "" @@ -188,7 +188,7 @@ export class HaCardConditionScreen extends LitElement { switch (schema.name) { case "breakpoints": return this.hass.localize( - `ui.panel.lovelace.editor.card.conditional.condition.screen.${schema.name}` + `ui.panel.lovelace.editor.condition-editor.condition.screen.${schema.name}` ); default: return ""; diff --git a/src/panels/lovelace/editor/conditions/types/ha-card-condition-state.ts b/src/panels/lovelace/editor/conditions/types/ha-card-condition-state.ts index 972d62988ffe..ed4d4718ec93 100644 --- a/src/panels/lovelace/editor/conditions/types/ha-card-condition-state.ts +++ b/src/panels/lovelace/editor/conditions/types/ha-card-condition-state.ts @@ -61,19 +61,20 @@ export class HaCardConditionState extends LitElement { schema: [ { name: "invert", + required: true, selector: { select: { mode: "dropdown", options: [ { label: localize( - "ui.panel.lovelace.editor.card.conditional.state_equal" + "ui.panel.lovelace.editor.condition-editor.condition.state.state_equal" ), value: "false", }, { label: localize( - "ui.panel.lovelace.editor.card.conditional.state_not_equal" + "ui.panel.lovelace.editor.condition-editor.condition.state.state_not_equal" ), value: "true", }, @@ -148,7 +149,7 @@ export class HaCardConditionState extends LitElement { return `${this.hass.localize( "ui.components.entity.entity-state-picker.state" )} (${this.hass.localize( - "ui.panel.lovelace.editor.card.conditional.current_state" + "ui.panel.lovelace.editor.condition-editor.condition.state.current_state" )}: ${this.hass.formatEntityState(entity)})`; } return `${this.hass.localize( diff --git a/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts index f266607140ae..a7a4b6b61c88 100644 --- a/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts @@ -1,23 +1,15 @@ import "@material/mwc-tab-bar/mwc-tab-bar"; import "@material/mwc-tab/mwc-tab"; import type { MDCTabBarActivatedEvent } from "@material/tab-bar"; -import { - mdiCodeBraces, - mdiContentCopy, - mdiListBoxOutline, - mdiPlus, -} from "@mdi/js"; +import { mdiCodeBraces, mdiContentCopy, mdiListBoxOutline } from "@mdi/js"; import deepClone from "deep-clone-simple"; import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import { any, array, assert, assign, object, optional } from "superstruct"; import { storage } from "../../../../common/decorators/storage"; import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event"; -import { stopPropagation } from "../../../../common/dom/stop_propagation"; import "../../../../components/ha-button"; import "../../../../components/ha-list-item"; -import "../../../../components/ha-menu-button"; -import type { HaSelect } from "../../../../components/ha-select"; import "../../../../components/ha-svg-icon"; import type { LovelaceCardConfig, @@ -25,27 +17,17 @@ import type { } from "../../../../data/lovelace"; import type { HomeAssistant } from "../../../../types"; import type { ConditionalCardConfig } from "../../cards/types"; -import { ICON_CONDITION } from "../../common/icon-condition"; -import { Condition } from "../../common/validate-condition"; import type { LovelaceCardEditor } from "../../types"; import "../card-editor/hui-card-element-editor"; import type { HuiCardElementEditor } from "../card-editor/hui-card-element-editor"; import "../card-editor/hui-card-picker"; -import "../conditions/ha-card-condition-editor"; -import { LovelaceConditionEditorConstructor } from "../conditions/types"; -import "../conditions/types/ha-card-condition-screen"; -import "../conditions/types/ha-card-condition-state"; +import "../conditions/ha-card-conditions-editor"; import "../hui-element-editor"; import type { ConfigChangedEvent } from "../hui-element-editor"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import type { GUIModeChangedEvent } from "../types"; import { configElementStyle } from "./config-elements-style"; -const UI_CONDITION = [ - "state", - "screen", -] as const satisfies readonly Condition["condition"][]; - const cardConfigStruct = assign( baseLovelaceCardConfig, object({ @@ -162,59 +144,12 @@ export class HuiConditionalCardEditor ` : html` -
- - ${this.hass!.localize( - "ui.panel.lovelace.editor.card.conditional.condition_explanation" - )} - - ${this._config.conditions.map((cond, idx) => { - const condition: Condition = { - condition: "state", - ...cond, - }; - return html` -
- -
- `; - })} -
- - - - - ${UI_CONDITION.map( - (condition) => html` - - ${this.hass!.localize( - `ui.panel.lovelace.editor.card.conditional.condition.${condition}.label` - ) || condition} - - - ` - )} - -
-
+ + `} `; } @@ -281,43 +216,16 @@ export class HuiConditionalCardEditor fireEvent(this, "config-changed", { config: this._config }); } - private _addCondition(ev: CustomEvent): void { - const condition = (ev.currentTarget as HaSelect).items[ev.detail.index] - .value as Condition["condition"]; + private _conditionChanged(ev: CustomEvent) { + ev.stopPropagation(); if (!this._config) { return; } - const conditions = [...this._config.conditions]; - - const elClass = customElements.get(`ha-card-condition-${condition}`) as - | LovelaceConditionEditorConstructor - | undefined; - - conditions.push( - elClass?.defaultConfig - ? { ...elClass.defaultConfig } - : { condition: condition } - ); + const conditions = ev.detail.value; this._config = { ...this._config, conditions }; fireEvent(this, "config-changed", { config: this._config }); } - private _conditionChanged(ev: CustomEvent) { - ev.stopPropagation(); - const conditions = [...this._config!.conditions]; - const newValue = ev.detail.value; - const index = (ev.target as any).index; - - if (newValue === null) { - conditions.splice(index, 1); - } else { - conditions[index] = newValue; - } - - this._config = { ...this._config!, conditions }; - fireEvent(this, "config-changed", { config: this._config }); - } - static get styles(): CSSResultGroup { return [ configElementStyle, @@ -325,19 +233,6 @@ export class HuiConditionalCardEditor mwc-tab-bar { border-bottom: 1px solid var(--divider-color); } - .conditions { - margin-top: 8px; - } - .condition { - margin-top: 8px; - border: 1px solid var(--divider-color); - } - .condition .content { - padding: 12px; - } - ha-button-menu { - margin-top: 12px; - } .card { margin-top: 8px; border: 1px solid var(--divider-color); diff --git a/src/translations/en.json b/src/translations/en.json index a0958ce22ba4..513cc4e8d8df 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -4754,6 +4754,29 @@ "none": "No action" } }, + "condition-editor": { + "explanation": "The card will be shown when ALL conditions below are fulfilled.", + "add": "Add condition", + "condition": { + "screen": { + "label": "Screen", + "breakpoints": "Screen sizes", + "breakpoints_list": { + "mobile": "Mobile", + "tablet": "Tablet", + "desktop": "Desktop", + "wide": "Wide" + }, + "min": "min: {size}px" + }, + "state": { + "label": "Entity state", + "state_equal": "State is equal to", + "state_not_equal": "State is not equal to", + "current_state": "current" + } + } + }, "card": { "alarm-panel": { "name": "Alarm panel", @@ -4782,28 +4805,7 @@ "description": "The Conditional card displays another card based on entity states.", "conditions": "Conditions", "card": "Card", - "state_equal": "State is equal to", - "state_not_equal": "State is not equal to", - "current_state": "current", - "condition_explanation": "The card will be shown when ALL conditions below are fulfilled.", - "change_type": "Change type", - "add_condition": "Add condition", - "condition": { - "screen": { - "label": "Screen", - "breakpoints": "Screen sizes", - "breakpoints_list": { - "mobile": "Mobile", - "tablet": "Tablet", - "desktop": "Desktop", - "wide": "Wide" - }, - "min": "min: {size}px" - }, - "state": { - "label": "Entity state" - } - } + "change_type": "Change type" }, "config": { "required": "required",