From 494cc3a5698af32a3bce79d80d7e87f8dbabdde9 Mon Sep 17 00:00:00 2001 From: Zack Barett Date: Fri, 18 Feb 2022 14:48:17 -0600 Subject: [PATCH] Automation Conditions to conversion to ha-form or mwc (#11727) --- src/components/ha-form/types.ts | 2 +- .../ha-selector/ha-selector-time.ts | 1 + .../ha-automation-condition-editor.ts | 2 +- .../condition/ha-automation-condition-row.ts | 2 +- .../types/ha-automation-condition-device.ts | 11 +- .../types/ha-automation-condition-logical.ts | 11 +- .../ha-automation-condition-numeric_state.ts | 94 +++--- .../types/ha-automation-condition-state.ts | 99 +++--- .../types/ha-automation-condition-sun.ts | 165 ++++------ .../types/ha-automation-condition-template.ts | 31 +- .../types/ha-automation-condition-time.ts | 290 +++++++----------- .../types/ha-automation-condition-trigger.ts | 4 +- .../types/ha-automation-condition-zone.ts | 9 +- .../types/ha-automation-trigger-device.ts | 2 +- .../ha-automation-trigger-numeric_state.ts | 9 +- .../types/ha-automation-trigger-state.ts | 27 +- .../types/ha-automation-trigger-sun.ts | 3 +- .../types/ha-automation-trigger-template.ts | 31 +- .../types/ha-automation-trigger-time.ts | 137 +++++---- .../types/ha-automation-trigger-zone.ts | 9 +- src/translations/en.json | 12 +- 21 files changed, 452 insertions(+), 499 deletions(-) diff --git a/src/components/ha-form/types.ts b/src/components/ha-form/types.ts index d6cfc573ef..f476e759ca 100644 --- a/src/components/ha-form/types.ts +++ b/src/components/ha-form/types.ts @@ -49,7 +49,7 @@ export interface HaFormSelectSchema extends HaFormBaseSchema { export interface HaFormMultiSelectSchema extends HaFormBaseSchema { type: "multi_select"; - options: Record | string[]; + options: Record | string[] | Array<[string, string]>; } export interface HaFormFloatSchema extends HaFormBaseSchema { diff --git a/src/components/ha-selector/ha-selector-time.ts b/src/components/ha-selector/ha-selector-time.ts index fb3b4e2b8d..ff829ff12b 100644 --- a/src/components/ha-selector/ha-selector-time.ts +++ b/src/components/ha-selector/ha-selector-time.ts @@ -22,6 +22,7 @@ export class HaTimeSelector extends LitElement { .value=${this.value} .locale=${this.hass.locale} .disabled=${this.disabled} + .label=${this.label} enable-second > `; diff --git a/src/panels/config/automation/condition/ha-automation-condition-editor.ts b/src/panels/config/automation/condition/ha-automation-condition-editor.ts index 59148694cc..e6c9378c8f 100644 --- a/src/panels/config/automation/condition/ha-automation-condition-editor.ts +++ b/src/panels/config/automation/condition/ha-automation-condition-editor.ts @@ -6,7 +6,7 @@ import memoizeOne from "memoize-one"; import { dynamicElement } from "../../../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../../../common/dom/fire_event"; import { stringCompare } from "../../../../common/string/compare"; -import { LocalizeFunc } from "../../../../common/translations/localize"; +import type { LocalizeFunc } from "../../../../common/translations/localize"; import "../../../../components/ha-card"; import "../../../../components/ha-yaml-editor"; import type { Condition } from "../../../../data/automation"; diff --git a/src/panels/config/automation/condition/ha-automation-condition-row.ts b/src/panels/config/automation/condition/ha-automation-condition-row.ts index bee7358190..4bce08a441 100644 --- a/src/panels/config/automation/condition/ha-automation-condition-row.ts +++ b/src/panels/config/automation/condition/ha-automation-condition-row.ts @@ -27,7 +27,7 @@ export const handleChangeEvent = ( if (!name) { return; } - const newVal = ev.detail.value; + const newVal = ev.detail?.value || (ev.currentTarget as any)?.value; if ((element.condition[name] || "") === newVal) { return; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-device.ts b/src/panels/config/automation/condition/types/ha-automation-condition-device.ts index b158625876..77b9a94b89 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-device.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-device.ts @@ -1,4 +1,4 @@ -import { html, LitElement } from "lit"; +import { css, html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; @@ -11,7 +11,7 @@ import { DeviceCondition, fetchDeviceConditionCapabilities, } from "../../../../../data/device_automation"; -import { HomeAssistant } from "../../../../../types"; +import type { HomeAssistant } from "../../../../../types"; @customElement("ha-automation-condition-device") export class HaDeviceCondition extends LitElement { @@ -147,6 +147,13 @@ export class HaDeviceCondition extends LitElement { `ui.panel.config.automation.editor.conditions.type.device.extra_fields.${schema.name}` ) || schema.name; } + + static styles = css` + ha-device-picker { + display: block; + margin-bottom: 24px; + } + `; } declare global { diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts b/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts index 35e9685463..18933eb6df 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts @@ -1,17 +1,20 @@ import { html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; -import { Condition, LogicalCondition } from "../../../../../data/automation"; -import { HomeAssistant } from "../../../../../types"; +import type { + Condition, + LogicalCondition, +} from "../../../../../data/automation"; +import type { HomeAssistant } from "../../../../../types"; import "../ha-automation-condition"; -import { ConditionElement } from "../ha-automation-condition-row"; +import type { ConditionElement } from "../ha-automation-condition-row"; import { HaStateCondition } from "./ha-automation-condition-state"; @customElement("ha-automation-condition-logical") export class HaLogicalCondition extends LitElement implements ConditionElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public condition!: LogicalCondition; + @property({ attribute: false }) public condition!: LogicalCondition; public static get defaultConfig() { return { diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts b/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts index 37216fdab4..56944306d0 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts @@ -1,17 +1,17 @@ -import "@polymer/paper-input/paper-input"; -import "@polymer/paper-input/paper-textarea"; +import "../../../../../components/ha-form/ha-form"; import { html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; -import "../../../../../components/entity/ha-entity-picker"; +import memoizeOne from "memoize-one"; +import { fireEvent } from "../../../../../common/dom/fire_event"; +import type { HaFormSchema } from "../../../../../components/ha-form/types"; import { NumericStateCondition } from "../../../../../data/automation"; -import { HomeAssistant } from "../../../../../types"; -import { handleChangeEvent } from "../ha-automation-condition-row"; +import type { HomeAssistant } from "../../../../../types"; @customElement("ha-automation-condition-numeric_state") export default class HaNumericStateCondition extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public condition!: NumericStateCondition; + @property({ attribute: false }) public condition!: NumericStateCondition; public static get defaultConfig() { return { @@ -19,60 +19,54 @@ export default class HaNumericStateCondition extends LitElement { }; } + private _schema = memoizeOne((entityId): HaFormSchema[] => [ + { name: "entity_id", required: true, selector: { entity: {} } }, + { + name: "attribute", + selector: { attribute: { entity_id: entityId } }, + }, + { name: "above", selector: { text: {} } }, + { name: "below", selector: { text: {} } }, + { + name: "value_template", + selector: { text: { multiline: true } }, + }, + ]); + public render() { - const { value_template, entity_id, attribute, below, above } = - this.condition; + const schema = this._schema(this.condition.entity_id); return html` - - - - - + .computeLabel=${this._computeLabelCallback} + > `; } private _valueChanged(ev: CustomEvent): void { - handleChangeEvent(this, ev); + ev.stopPropagation(); + const newTrigger = ev.detail.value; + fireEvent(this, "value-changed", { value: newTrigger }); } + + private _computeLabelCallback = (schema: HaFormSchema): string => { + switch (schema.name) { + case "entity_id": + return this.hass.localize("ui.components.entity.entity-picker.entity"); + case "attribute": + return this.hass.localize( + "ui.components.entity.entity-attribute-picker.attribute" + ); + default: + return this.hass.localize( + `ui.panel.config.automation.editor.triggers.type.numeric_state.${schema.name}` + ); + } + }; } declare global { diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-state.ts b/src/panels/config/automation/condition/types/ha-automation-condition-state.ts index 4a6e5a86ef..9c88cdfb50 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-state.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-state.ts @@ -1,19 +1,14 @@ -import "@polymer/paper-input/paper-input"; import { html, LitElement, PropertyValues } from "lit"; import { customElement, property } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { assert, literal, object, optional, string, union } from "superstruct"; import { createDurationData } from "../../../../../common/datetime/create_duration_data"; import { fireEvent } from "../../../../../common/dom/fire_event"; -import "../../../../../components/entity/ha-entity-attribute-picker"; -import "../../../../../components/entity/ha-entity-picker"; -import "../../../../../components/ha-duration-input"; -import { StateCondition } from "../../../../../data/automation"; -import { HomeAssistant } from "../../../../../types"; +import type { HaFormSchema } from "../../../../../components/ha-form/types"; +import type { StateCondition } from "../../../../../data/automation"; +import type { HomeAssistant } from "../../../../../types"; import { forDictStruct } from "../../structs"; -import { - ConditionElement, - handleChangeEvent, -} from "../ha-automation-condition-row"; +import type { ConditionElement } from "../ha-automation-condition-row"; const stateConditionStruct = object({ condition: literal("state"), @@ -27,12 +22,22 @@ const stateConditionStruct = object({ export class HaStateCondition extends LitElement implements ConditionElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public condition!: StateCondition; + @property({ attribute: false }) public condition!: StateCondition; public static get defaultConfig() { return { entity_id: "", state: "" }; } + private _schema = memoizeOne((entityId) => [ + { name: "entity_id", required: true, selector: { entity: {} } }, + { + name: "attribute", + selector: { attribute: { entity_id: entityId } }, + }, + { name: "state", selector: { text: {} } }, + { name: "for", selector: { duration: {} } }, + ]); + public shouldUpdate(changedProperties: PropertyValues) { if (changedProperties.has("condition")) { try { @@ -46,50 +51,52 @@ export class HaStateCondition extends LitElement implements ConditionElement { } protected render() { - const { entity_id, attribute, state } = this.condition; - const forTime = createDurationData(this.condition.for); + const trgFor = createDurationData(this.condition.for); + const data = { ...this.condition, ...{ for: trgFor } }; + const schema = this._schema(this.condition.entity_id); return html` - - - - + .computeLabel=${this._computeLabelCallback} + > `; } private _valueChanged(ev: CustomEvent): void { - handleChangeEvent(this, ev); + ev.stopPropagation(); + const newTrigger = ev.detail.value; + + Object.keys(newTrigger).forEach((key) => + newTrigger[key] === undefined || newTrigger[key] === "" + ? delete newTrigger[key] + : {} + ); + + fireEvent(this, "value-changed", { value: newTrigger }); } + + private _computeLabelCallback = (schema: HaFormSchema): string => { + switch (schema.name) { + case "entity_id": + return this.hass.localize("ui.components.entity.entity-picker.entity"); + case "attribute": + return this.hass.localize( + "ui.components.entity.entity-attribute-picker.attribute" + ); + case "for": + return this.hass.localize( + `ui.panel.config.automation.editor.triggers.type.state.for` + ); + default: + return this.hass.localize( + `ui.panel.config.automation.editor.conditions.type.state.${schema.name}` + ); + } + }; } declare global { diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts b/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts index 0cbf5a339a..e3d466ca6e 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts @@ -1,16 +1,12 @@ -import "@polymer/paper-input/paper-input"; -import { css, html, LitElement } from "lit"; +import { html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; import type { SunCondition } from "../../../../../data/automation"; import type { HomeAssistant } from "../../../../../types"; -import { - ConditionElement, - handleChangeEvent, -} from "../ha-automation-condition-row"; -import "../../../../../components/ha-radio"; -import "../../../../../components/ha-formfield"; -import type { HaRadio } from "../../../../../components/ha-radio"; +import type { ConditionElement } from "../ha-automation-condition-row"; +import type { LocalizeFunc } from "../../../../../common/translations/localize"; +import type { HaFormSchema } from "../../../../../components/ha-form/types"; @customElement("ha-automation-condition-sun") export class HaSunCondition extends LitElement implements ConditionElement { @@ -22,111 +18,72 @@ export class HaSunCondition extends LitElement implements ConditionElement { return {}; } + private _schema = memoizeOne((localize: LocalizeFunc) => [ + { + name: "before", + type: "select", + required: true, + options: [ + [ + "sunrise", + localize( + "ui.panel.config.automation.editor.conditions.type.sun.sunrise" + ), + ], + [ + "sunset", + localize( + "ui.panel.config.automation.editor.conditions.type.sun.sunset" + ), + ], + ], + }, + { name: "before_offset", selector: { text: {} } }, + { + name: "after", + type: "select", + required: true, + options: [ + [ + "sunrise", + localize( + "ui.panel.config.automation.editor.conditions.type.sun.sunrise" + ), + ], + [ + "sunset", + localize( + "ui.panel.config.automation.editor.conditions.type.sun.sunset" + ), + ], + ], + }, + { name: "after_offset", selector: { text: {} } }, + ]); + protected render() { - const { after, after_offset, before, before_offset } = this.condition; + const schema = this._schema(this.hass.localize); return html` - - - - - - - + > `; } private _valueChanged(ev: CustomEvent): void { - handleChangeEvent(this, ev); - } - - private _radioGroupPicked(ev: CustomEvent) { - const key = (ev.target as HaRadio).name; ev.stopPropagation(); - fireEvent(this, "value-changed", { - value: { - ...this.condition, - [key]: (ev.target as HaRadio).value, - }, - }); + const newTrigger = ev.detail.value; + fireEvent(this, "value-changed", { value: newTrigger }); } - static styles = css` - label { - display: flex; - align-items: center; - } - `; + private _computeLabelCallback = (schema: HaFormSchema): string => + this.hass.localize( + `ui.panel.config.automation.editor.conditions.type.sun.${schema.name}` + ); } declare global { diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-template.ts b/src/panels/config/automation/condition/types/ha-automation-condition-template.ts index d83eea64e2..6ada82f152 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-template.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-template.ts @@ -1,15 +1,15 @@ -import "@polymer/paper-input/paper-textarea"; -import { html, LitElement } from "lit"; +import "../../../../../components/ha-textarea"; +import { css, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; -import { TemplateCondition } from "../../../../../data/automation"; -import { HomeAssistant } from "../../../../../types"; +import type { TemplateCondition } from "../../../../../data/automation"; +import type { HomeAssistant } from "../../../../../types"; import { handleChangeEvent } from "../ha-automation-condition-row"; @customElement("ha-automation-condition-template") export class HaTemplateCondition extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public condition!: TemplateCondition; + @property({ attribute: false }) public condition!: TemplateCondition; public static get defaultConfig() { return { value_template: "" }; @@ -18,19 +18,32 @@ export class HaTemplateCondition extends LitElement { protected render() { const { value_template } = this.condition; return html` - + autogrow + > `; } private _valueChanged(ev: CustomEvent): void { handleChangeEvent(this, ev); } + + static styles = css` + ha-textarea { + display: block; + } + `; +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-condition-template": HaTemplateCondition; + } } diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-time.ts b/src/panels/config/automation/condition/types/ha-automation-condition-time.ts index f227847a3f..f09a132ff2 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-time.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-time.ts @@ -1,20 +1,12 @@ -import { Radio } from "@material/mwc-radio"; -import { css, CSSResultGroup, html, LitElement } from "lit"; +import { html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; -import { computeRTLDirection } from "../../../../../common/util/compute_rtl"; -import "../../../../../components/ha-formfield"; -import "../../../../../components/ha-radio"; -import { HaSwitch } from "../../../../../components/ha-switch"; -import { TimeCondition } from "../../../../../data/automation"; -import { HomeAssistant } from "../../../../../types"; -import { - ConditionElement, - handleChangeEvent, -} from "../ha-automation-condition-row"; -import "../../../../../components/ha-time-input"; - -const includeDomains = ["input_datetime"]; +import type { TimeCondition } from "../../../../../data/automation"; +import type { HomeAssistant } from "../../../../../types"; +import type { ConditionElement } from "../ha-automation-condition-row"; +import type { LocalizeFunc } from "../../../../../common/translations/localize"; +import type { HaFormSchema } from "../../../../../components/ha-form/types"; const DAYS = { mon: 1, @@ -26,10 +18,6 @@ const DAYS = { sun: 7, }; -interface WeekdayHaSwitch extends HaSwitch { - day: string; -} - @customElement("ha-automation-condition-time") export class HaTimeCondition extends LitElement implements ConditionElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -44,176 +32,136 @@ export class HaTimeCondition extends LitElement implements ConditionElement { return {}; } - protected render() { - const { after, before, weekday } = this.condition; + private _schema = memoizeOne( + ( + localize: LocalizeFunc, + inputModeAfter?: boolean, + inputModeBefore?: boolean + ): HaFormSchema[] => { + const modeAfterSchema = inputModeAfter + ? { name: "after", selector: { entity: { domain: "input_datetime" } } } + : { name: "after", selector: { time: {} } }; + const modeBeforeSchema = inputModeBefore + ? { name: "before", selector: { entity: { domain: "input_datetime" } } } + : { name: "before", selector: { time: {} } }; + + return [ + { + name: "mode_after", + type: "select", + required: true, + options: [ + [ + "value", + localize( + "ui.panel.config.automation.editor.conditions.type.time.type_value" + ), + ], + [ + "input", + localize( + "ui.panel.config.automation.editor.conditions.type.time.type_input" + ), + ], + ], + }, + modeAfterSchema, + { + name: "mode_before", + type: "select", + required: true, + options: [ + [ + "value", + localize( + "ui.panel.config.automation.editor.conditions.type.time.type_value" + ), + ], + [ + "input", + localize( + "ui.panel.config.automation.editor.conditions.type.time.type_input" + ), + ], + ], + }, + modeBeforeSchema, + { + type: "multi_select", + name: "weekday", + options: Object.keys(DAYS).map((day) => [ + day, + localize( + `ui.panel.config.automation.editor.conditions.type.time.weekdays.${day}` + ), + ]), + }, + ]; + } + ); + + protected render() { const inputModeBefore = - this._inputModeBefore ?? before?.startsWith("input_datetime."); + this._inputModeBefore ?? + this.condition.before?.startsWith("input_datetime."); const inputModeAfter = - this._inputModeAfter ?? after?.startsWith("input_datetime."); + this._inputModeAfter ?? + this.condition.after?.startsWith("input_datetime."); + + const schema: HaFormSchema[] = this._schema( + this.hass.localize, + inputModeAfter, + inputModeBefore + ); + + const data = { + mode_before: "value", + mode_after: "value", + ...this.condition, + }; return html` - - - - - - - ${inputModeAfter - ? html`` - : html``} - - - - - - - - ${inputModeBefore - ? html`` - : html``} - ${Object.keys(DAYS).map( - (day) => html` - - - - - ` - )} + `; } - private _handleModeChanged(ev: Event) { - const target = ev.target as Radio; - if (target.getAttribute("name") === "mode_after") { - this._inputModeAfter = target.value === "input"; - } else { - this._inputModeBefore = target.value === "input"; - } - } - private _valueChanged(ev: CustomEvent): void { - handleChangeEvent(this, ev); - } + ev.stopPropagation(); + const newValue = ev.detail.value; - private _dayValueChanged(ev: CustomEvent): void { - const daySwitch = ev.currentTarget as WeekdayHaSwitch; + const newModeAfter = newValue.mode_after === "input"; + const newModeBefore = newValue.mode_before === "input"; - let days: string[]; - - if (!this.condition.weekday) { - days = Object.keys(DAYS); - } else { - days = !Array.isArray(this.condition.weekday) - ? [this.condition.weekday] - : this.condition.weekday; + if (newModeAfter !== this._inputModeAfter) { + this._inputModeAfter = newModeAfter; + newValue.after = undefined; } - if (daySwitch.checked) { - days.push(daySwitch.day); - } else { - days = days.filter((d) => d !== daySwitch.day); + if (newModeBefore !== this._inputModeBefore) { + this._inputModeBefore = newModeBefore; + newValue.before = undefined; } - days.sort((a: string, b: string) => DAYS[a] - DAYS[b]); + Object.keys(newValue).forEach((key) => + newValue[key] === undefined || newValue[key] === "" + ? delete newValue[key] + : {} + ); - fireEvent(this, "value-changed", { - value: { ...this.condition, weekday: days }, - }); + fireEvent(this, "value-changed", { value: newValue }); } - static get styles(): CSSResultGroup { - return css` - .weekday-toggle { - display: flex; - height: 40px; - } - `; - } + private _computeLabelCallback = (schema: HaFormSchema): string => + this.hass.localize( + `ui.panel.config.automation.editor.conditions.type.time.${schema.name}` + ); } declare global { diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts b/src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts index ea867147bd..4b81afc26b 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts @@ -5,12 +5,12 @@ import { html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { ensureArray } from "../../../../../common/ensure-array"; -import { +import type { AutomationConfig, Trigger, TriggerCondition, } from "../../../../../data/automation"; -import { HomeAssistant } from "../../../../../types"; +import type { HomeAssistant } from "../../../../../types"; @customElement("ha-automation-condition-trigger") export class HaTriggerCondition extends LitElement { diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts b/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts index cf79928402..6c748351a9 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts @@ -1,4 +1,4 @@ -import { html, LitElement } from "lit"; +import { css, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { computeStateDomain } from "../../../../../common/entity/compute_state_domain"; @@ -71,6 +71,13 @@ export class HaZoneCondition extends LitElement { value: { ...this.condition, zone: ev.detail.value }, }); } + + static styles = css` + ha-entity-picker { + display: block; + margin-bottom: 24px; + } + `; } declare global { diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts index 82ee809f72..5747edd342 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts @@ -154,7 +154,7 @@ export class HaDeviceTrigger extends LitElement { static styles = css` ha-device-picker { display: block; - margin-bottom: 8px; + margin-bottom: 24px; } `; } diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts index 1a43407438..c156d2b9aa 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts @@ -16,19 +16,18 @@ export class HaNumericStateTrigger extends LitElement { @property() public trigger!: NumericStateTrigger; private _schema = memoizeOne((entityId): HaFormSchema[] => [ - { name: "entity_id", selector: { entity: {} } }, + { name: "entity_id", required: true, selector: { entity: {} } }, { name: "attribute", selector: { attribute: { entity_id: entityId } }, }, - { name: "above", required: false, selector: { text: {} } }, - { name: "below", required: false, selector: { text: {} } }, + { name: "above", selector: { text: {} } }, + { name: "below", selector: { text: {} } }, { name: "value_template", - required: false, selector: { text: { multiline: true } }, }, - { name: "for", required: false, selector: { duration: {} } }, + { name: "for", selector: { duration: {} } }, ]); public willUpdate(changedProperties: PropertyValues) { diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts index d50304561a..44d3183e0d 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts @@ -32,14 +32,6 @@ const stateTriggerStruct = assign( }) ); -const SCHEMA = [ - { name: "entity_id", selector: { entity: {} } }, - { name: "attribute", selector: { attribute: { entity_id: "" } } }, - { name: "from", required: false, selector: { text: {} } }, - { name: "to", required: false, selector: { text: {} } }, - { name: "for", required: false, selector: { duration: {} } }, -]; - @customElement("ha-automation-trigger-state") export class HaStateTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -50,14 +42,16 @@ export class HaStateTrigger extends LitElement implements TriggerElement { return { entity_id: "" }; } - private _schema = memoizeOne((entityId) => { - const schema = [...SCHEMA]; - schema[1] = { + private _schema = memoizeOne((entityId) => [ + { name: "entity_id", required: true, selector: { entity: {} } }, + { name: "attribute", selector: { attribute: { entity_id: entityId } }, - }; - return schema; - }); + }, + { name: "from", selector: { text: {} } }, + { name: "to", selector: { text: {} } }, + { name: "for", selector: { duration: {} } }, + ]); public shouldUpdate(changedProperties: PropertyValues) { if (!changedProperties.has("trigger")) { @@ -118,13 +112,12 @@ export class HaStateTrigger extends LitElement implements TriggerElement { fireEvent(this, "value-changed", { value: newTrigger }); } - private _computeLabelCallback(schema: HaFormSchema): string { - return this.hass.localize( + private _computeLabelCallback = (schema: HaFormSchema): string => + this.hass.localize( schema.name === "entity_id" ? "ui.components.entity.entity-picker.entity" : `ui.panel.config.automation.editor.triggers.type.state.${schema.name}` ); - } } declare global { diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts index a6efcf9d95..0be06923b8 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts @@ -45,9 +45,10 @@ export class HaSunTrigger extends LitElement implements TriggerElement { } protected render() { + const schema = this._schema(this.hass.localize); return html` + autogrow + > `; } private _valueChanged(ev: CustomEvent): void { handleChangeEvent(this, ev); } + + static styles = css` + ha-textarea { + display: block; + } + `; +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-template": HaTemplateTrigger; + } } diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts index a72c5a9749..bdac66a6a1 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts @@ -1,23 +1,19 @@ +import memoizeOne from "memoize-one"; import { html, LitElement, PropertyValues } from "lit"; import { customElement, property, state } from "lit/decorators"; -import "../../../../../components/entity/ha-entity-picker"; -import "../../../../../components/ha-formfield"; -import "../../../../../components/ha-radio"; -import { TimeTrigger } from "../../../../../data/automation"; -import { HomeAssistant } from "../../../../../types"; -import { - handleChangeEvent, - TriggerElement, -} from "../ha-automation-trigger-row"; -import "../../../../../components/ha-time-input"; +import type { TimeTrigger } from "../../../../../data/automation"; +import type { HomeAssistant } from "../../../../../types"; +import type { TriggerElement } from "../ha-automation-trigger-row"; +import type { LocalizeFunc } from "../../../../../common/translations/localize"; +import type { HaFormSchema } from "../../../../../components/ha-form/types"; import { fireEvent } from "../../../../../common/dom/fire_event"; +import "../../../../../components/ha-form/ha-form"; -const includeDomains = ["input_datetime"]; @customElement("ha-automation-trigger-time") export class HaTimeTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public trigger!: TimeTrigger; + @property({ attribute: false }) public trigger!: TimeTrigger; @state() private _inputMode?: boolean; @@ -25,6 +21,37 @@ export class HaTimeTrigger extends LitElement implements TriggerElement { return { at: "" }; } + private _schema = memoizeOne( + (localize: LocalizeFunc, inputMode?: boolean): HaFormSchema[] => { + const modeSchema = inputMode + ? { name: "at", selector: { entity: { domain: "input_datetime" } } } + : { name: "at", selector: { time: {} } }; + + return [ + { + name: "mode", + type: "select", + required: true, + options: [ + [ + "value", + localize( + "ui.panel.config.automation.editor.triggers.type.time.type_value" + ), + ], + [ + "input", + localize( + "ui.panel.config.automation.editor.triggers.type.time.type_input" + ), + ], + ], + }, + modeSchema, + ]; + } + ); + public willUpdate(changedProperties: PropertyValues) { if (!changedProperties.has("trigger")) { return; @@ -50,67 +77,43 @@ export class HaTimeTrigger extends LitElement implements TriggerElement { this._inputMode ?? (at?.startsWith("input_datetime.") || at?.startsWith("sensor.")); - return html` - - - - - + const schema: HaFormSchema[] = this._schema(this.hass.localize, inputMode); - ${inputMode - ? html`` - : html``} `; - } + const data = { + mode: "value", + ...this.trigger, + }; - private _handleModeChanged(ev: Event) { - this._inputMode = (ev.target as any).value === "input"; + return html` + + `; } private _valueChanged(ev: CustomEvent): void { - handleChangeEvent(this, ev); + ev.stopPropagation(); + const newValue = ev.detail.value; + + this._inputMode = newValue.mode.value === "input"; + + Object.keys(newValue).forEach((key) => + newValue[key] === undefined || newValue[key] === "" + ? delete newValue[key] + : {} + ); + + fireEvent(this, "value-changed", { value: newValue }); } + + private _computeLabelCallback = (schema: HaFormSchema): string => + this.hass.localize( + `ui.panel.config.automation.editor.triggers.type.time.${schema.name}` + ); } declare global { diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts index 333f3dc529..7b97d9a5eb 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts @@ -1,14 +1,13 @@ +import "../../../../../components/entity/ha-entity-picker"; +import "../../../../../components/ha-formfield"; import { css, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { computeStateDomain } from "../../../../../common/entity/compute_state_domain"; import { hasLocation } from "../../../../../common/entity/has_location"; -import "../../../../../components/entity/ha-entity-picker"; import type { ZoneTrigger } from "../../../../../data/automation"; import type { PolymerChangedEvent } from "../../../../../polymer-types"; import type { HomeAssistant } from "../../../../../types"; -import "../../../../../components/ha-radio"; -import "../../../../../components/ha-formfield"; import type { HaRadio } from "../../../../../components/ha-radio"; function zoneAndLocationFilter(stateObj) { @@ -116,6 +115,10 @@ export class HaZoneTrigger extends LitElement { display: flex; align-items: center; } + ha-entity-picker { + display: block; + margin-bottom: 24px; + } `; } diff --git a/src/translations/en.json b/src/translations/en.json index df493b082b..b7bb981739 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1653,7 +1653,7 @@ "label": "Geolocation", "source": "Source", "zone": "Zone", - "event": "Event:", + "event": "Event", "enter": "Enter", "leave": "Leave" }, @@ -1699,7 +1699,8 @@ "type_value": "Fixed time", "type_input": "Value of a date/time helper", "label": "Time", - "at": "At time" + "at": "At time", + "mode": "Mode" }, "time_pattern": { "label": "Time Pattern", @@ -1767,8 +1768,8 @@ }, "sun": { "label": "[%key:ui::panel::config::automation::editor::triggers::type::sun::label%]", - "before": "Before:", - "after": "After:", + "before": "Before", + "after": "After", "before_offset": "Before offset (optional)", "after_offset": "After offset (optional)", "sunrise": "Sunrise", @@ -1784,6 +1785,9 @@ "label": "[%key:ui::panel::config::automation::editor::triggers::type::time::label%]", "after": "After", "before": "Before", + "weekday": "Weekdays", + "mode_after": "[%key:ui::panel::config::automation::editor::conditions::type::time::after%]", + "mode_before": "[%key:ui::panel::config::automation::editor::conditions::type::time::before%]", "weekdays": { "mon": "Monday", "tue": "Tuesday",