From 4931471df2c8d6a13667e4bb46a580211be1b7a6 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 3 Dec 2019 21:43:24 +0100 Subject: [PATCH 1/6] Convert automation trigger to Lit --- .../trigger/ha-automation-trigger-row.ts | 234 ++++++++++++++++++ .../trigger/ha-automation-trigger.ts | 87 +++++++ .../types/ha-automation-trigger-state.ts | 90 +++++++ src/panels/config/js/automation.tsx | 14 +- src/panels/config/js/preact-types.ts | 1 + 5 files changed, 419 insertions(+), 7 deletions(-) create mode 100644 src/panels/config/automation/trigger/ha-automation-trigger-row.ts create mode 100644 src/panels/config/automation/trigger/ha-automation-trigger.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts new file mode 100644 index 000000000000..8c130e367c6c --- /dev/null +++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts @@ -0,0 +1,234 @@ +import "@polymer/paper-menu-button/paper-menu-button"; +import "@polymer/paper-icon-button/paper-icon-button"; +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; +import "../../../../components/ha-card"; +import { + LitElement, + property, + html, + PropertyValues, + query, + customElement, + CSSResult, + css, +} from "lit-element"; +import { HomeAssistant } from "../../../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; + +import "./types/ha-automation-trigger-state"; +import { safeDump, safeLoad } from "js-yaml"; + +const OPTIONS = [ + "device", + "event", + "state", + "geo_location", + "homeassistant", + "mqtt", + "numeric_state", + "sun", + "template", + "time", + "time_pattern", + "webhook", + "zone", +]; + +@customElement("ha-automation-trigger-row") +export default class HaAutomationTriggerRow extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger; + @property() private _yamlMode = false; + @property() private _yaml = ""; + @property() private error = ""; + @query("#element") private _elementContainer?: HTMLDivElement; + + protected updated(changedProps: PropertyValues) { + let triggerChanged = changedProps.has("trigger"); + const oldTrigger = changedProps.get("trigger"); + + if (changedProps.has("_yamlMode") && this._yamlMode) { + this._yaml = safeDump(this.trigger); + } else if (!this._yamlMode) { + triggerChanged = true; + } + + if (triggerChanged) { + const element = document.createElement( + `ha-automation-trigger-${this.trigger.platform}` + ); + element.trigger = this.trigger; + element.hass = this.hass; + if (this._elementContainer!.lastChild) { + this._elementContainer!.removeChild(this._elementContainer!.lastChild); + } + this._elementContainer!.appendChild(element); + } else if (this._elementContainer && this._elementContainer.lastChild) { + const element = this._elementContainer!.lastChild; + element.trigger = this.trigger; + element.hass = this.hass; + } + } + + protected render() { + if (!this.trigger) { + return html``; + } + const hasEditor = OPTIONS.includes(this.trigger.platform); + if (!hasEditor) { + this._yamlMode = true; + } + const selected = OPTIONS.indexOf(this.trigger.platform); + return html` + +
+
+ + + + + ${this._yamlMode + ? this.hass.localize( + "ui.panel.config.automation.editor.edit_ui" + ) + : this.hass.localize( + "ui.panel.config.automation.editor.edit_yaml" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.duplicate" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.delete" + )} + + + +
+ ${this.error} + ${this._yamlMode + ? html` +
+ ${!hasEditor + ? html` + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.unsupported_platform", + "platform", + this.trigger.platform + )} + ` + : ""} + +
+ ` + : html` + + + ${OPTIONS.map( + (opt) => html` + + ${this.hass.localize( + `ui.panel.config.automation.editor.triggers.type.${opt}.label` + )} + + ` + )} + + +
+ `} +
+
+ `; + } + + private _onDelete() { + if ( + confirm( + this.hass.localize( + "ui.panel.config.automation.editor.triggers.delete_confirm" + ) + ) + ) { + fireEvent(this, "value-changed", { value: null }); + } + } + + private _typeChanged(ev) { + const type = ev.target.selectedItem.platform; + + const elClass = customElements.get(`ha-automation-trigger-${type}`); + + if (type !== this.trigger.platform) { + fireEvent(this, "value-changed", { + value: { + platform: type, + ...elClass.defaultConfig, + }, + }); + } + } + + private _onYamlChange(ev: CustomEvent) { + ev.stopPropagation(); + let value; + try { + value = safeLoad(ev.detail.value); + this.error = ""; + } catch (err) { + this.error = err; + } + if (value) { + fireEvent(this, "value-changed", { value }); + } + } + + private _switchYamlMode() { + this._yamlMode = !this._yamlMode; + } + + static get styles(): CSSResult { + return css` + .card-menu { + position: absolute; + top: 0; + right: 0; + z-index: 3; + color: var(--primary-text-color); + } + .rtl .card-menu { + right: auto; + left: 0; + } + .card-menu paper-item { + cursor: pointer; + } + `; + } +} diff --git a/src/panels/config/automation/trigger/ha-automation-trigger.ts b/src/panels/config/automation/trigger/ha-automation-trigger.ts new file mode 100644 index 000000000000..bf04bc857ea0 --- /dev/null +++ b/src/panels/config/automation/trigger/ha-automation-trigger.ts @@ -0,0 +1,87 @@ +import { + LitElement, + customElement, + html, + property, + CSSResult, + css, +} from "lit-element"; +import "@material/mwc-button"; +import "../../../../components/ha-card"; + +import { fireEvent } from "../../../../common/dom/fire_event"; +import { HomeAssistant } from "../../../../types"; + +import "./ha-automation-trigger-row"; + +@customElement("ha-automation-trigger") +export default class HaAutomationTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public triggers; + + protected render() { + return html` +
+ ${this.triggers.map( + (trg, idx) => html` + + ` + )} + +
+ + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.add" + )} + +
+
+
+ `; + } + + private _addTrigger() { + const triggers = this.triggers.concat({ + platform: "state", + }); + + fireEvent(this, "value-changed", { value: triggers }); + } + + private _triggerChanged(ev: CustomEvent) { + ev.stopPropagation(); + const triggers = [...this.triggers]; + const newValue = ev.detail.value; + const index = ev.target.index; + + if (newValue === null) { + triggers.splice(index, 1); + } else { + triggers[index] = newValue; + } + + fireEvent(this, "value-changed", { value: triggers }); + } + + static get styles(): CSSResult { + return css` + .triggers, + .script { + margin-top: -16px; + } + .triggers ha-card, + .script ha-card { + margin-top: 16px; + } + .add-card mwc-button { + display: block; + text-align: center; + } + `; + } +} 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 new file mode 100644 index 000000000000..542d334dd7a4 --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts @@ -0,0 +1,90 @@ +import "@polymer/paper-input/paper-input"; +import "../../../../../components/entity/ha-entity-picker"; +import { LitElement, property, html, customElement } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { fireEvent } from "../../../../../common/dom/fire_event"; + +@customElement("ha-automation-trigger-state") +export class HaStateTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger; + + public static get defaultConfig() { + return { entity_id: "" }; + } + + protected render() { + const { entity_id, to, from } = this.trigger; + let trgFor = this.trigger.for; + + if (trgFor && (trgFor.hours || trgFor.minutes || trgFor.seconds)) { + // If the trigger was defined using the yaml dict syntax, convert it to + // the equivalent string format + let { hours = 0, minutes = 0, seconds = 0 } = trgFor; + hours = hours.toString(); + minutes = minutes.toString().padStart(2, "0"); + seconds = seconds.toString().padStart(2, "0"); + + trgFor = `${hours}:${minutes}:${seconds}`; + } + + return html` + + + + + `; + } + + private _valueChanged(ev): void { + ev.stopPropagation(); + const name = ev.target.name; + const newVal = ev.detail.value; + + if (this.trigger[name] === newVal) { + return; + } + let trigger; + if (!newVal) { + trigger = { ...this.trigger }; + delete trigger[name]; + } else { + trigger = { ...this.trigger, [name]: newVal }; + } + fireEvent(this, "value-changed", { value: trigger }); + } + + private _entityPicked(ev: CustomEvent) { + ev.stopPropagation(); + + fireEvent(this, "value-changed", { + value: { ...this.trigger, entity_id: ev.target.value }, + }); + } +} diff --git a/src/panels/config/js/automation.tsx b/src/panels/config/js/automation.tsx index e94284cbf228..fdabbc953bab 100644 --- a/src/panels/config/js/automation.tsx +++ b/src/panels/config/js/automation.tsx @@ -5,7 +5,8 @@ import "../ha-config-section"; import "../../../components/ha-card"; import "../../../components/ha-textarea"; -import Trigger from "./trigger/index"; +import "../automation/trigger/ha-automation-trigger"; + import Condition from "./condition/index"; import Script from "./script/index"; @@ -26,8 +27,8 @@ export default class Automation extends Component { }); } - public triggerChanged(trigger) { - this.props.onChange({ ...this.props.automation, trigger }); + public triggerChanged(ev: CustomEvent) { + this.props.onChange({ ...this.props.automation, trigger: ev.detail.value }); } public conditionChanged(condition) { @@ -90,11 +91,10 @@ export default class Automation extends Component { )} - diff --git a/src/panels/config/js/preact-types.ts b/src/panels/config/js/preact-types.ts index 617fe5d2ddb0..25f7ba08eb1f 100644 --- a/src/panels/config/js/preact-types.ts +++ b/src/panels/config/js/preact-types.ts @@ -23,6 +23,7 @@ declare global { "ha-code-editor": any; "ha-service-picker": any; "mwc-button": any; + "ha-automation-trigger": any; "ha-device-trigger-picker": any; "ha-device-action-picker": any; "ha-form": any; From a3ac4dc2ff2782ea138e52ff80dde0b79c52c260 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 3 Dec 2019 21:43:55 +0100 Subject: [PATCH 2/6] Update ha-automation-trigger-row.ts --- .../config/automation/trigger/ha-automation-trigger-row.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts index 8c130e367c6c..5ba80e0dba61 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts @@ -54,7 +54,10 @@ export default class HaAutomationTriggerRow extends LitElement { triggerChanged = true; } - if (triggerChanged) { + if ( + triggerChanged && + (!oldTrigger || this.trigger.platform !== oldTrigger.platform) + ) { const element = document.createElement( `ha-automation-trigger-${this.trigger.platform}` ); From f8511d3f11c6d2d3f2adadfed5c4d5fb441dfc74 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 3 Dec 2019 23:18:51 +0100 Subject: [PATCH 3/6] dynamicContentDirective --- src/common/dom/dynamic-content-directive.ts | 29 +++++++++++ .../trigger/ha-automation-trigger-row.ts | 50 ++++++------------- .../types/ha-automation-trigger-state.ts | 8 +-- 3 files changed, 47 insertions(+), 40 deletions(-) create mode 100644 src/common/dom/dynamic-content-directive.ts diff --git a/src/common/dom/dynamic-content-directive.ts b/src/common/dom/dynamic-content-directive.ts new file mode 100644 index 000000000000..31a8a1ead722 --- /dev/null +++ b/src/common/dom/dynamic-content-directive.ts @@ -0,0 +1,29 @@ +import { directive, Part, NodePart } from "lit-html"; + +export const dynamicContentDirective = directive( + (tag: string, properties: { [key: string]: any }) => (part: Part): void => { + if (!(part instanceof NodePart)) { + throw new Error( + "dynamicContentDirective can only be used in content bindings" + ); + } + + let element = part.value as HTMLElement | undefined; + + if ( + element !== undefined && + tag.toUpperCase() === (element as HTMLElement).tagName + ) { + Object.entries(properties).forEach(([key, value]) => { + element![key] = value; + }); + return; + } + + element = document.createElement(tag); + Object.entries(properties).forEach(([key, value]) => { + element![key] = value; + }); + part.setValue(element); + } +); diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts index 5ba80e0dba61..5b432453039c 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts @@ -1,23 +1,23 @@ -import "@polymer/paper-menu-button/paper-menu-button"; import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import "../../../../components/ha-card"; +import "@polymer/paper-menu-button/paper-menu-button"; +import { safeDump, safeLoad } from "js-yaml"; import { + css, + CSSResult, + customElement, + html, LitElement, property, - html, PropertyValues, - query, - customElement, - CSSResult, - css, } from "lit-element"; -import { HomeAssistant } from "../../../../types"; +import { dynamicContentDirective } from "../../../../common/dom/dynamic-content-directive"; import { fireEvent } from "../../../../common/dom/fire_event"; - +import "../../../../components/ha-card"; +import { HomeAssistant } from "../../../../types"; +import "./types/ha-automation-trigger-device"; import "./types/ha-automation-trigger-state"; -import { safeDump, safeLoad } from "js-yaml"; const OPTIONS = [ "device", @@ -42,35 +42,10 @@ export default class HaAutomationTriggerRow extends LitElement { @property() private _yamlMode = false; @property() private _yaml = ""; @property() private error = ""; - @query("#element") private _elementContainer?: HTMLDivElement; protected updated(changedProps: PropertyValues) { - let triggerChanged = changedProps.has("trigger"); - const oldTrigger = changedProps.get("trigger"); - if (changedProps.has("_yamlMode") && this._yamlMode) { this._yaml = safeDump(this.trigger); - } else if (!this._yamlMode) { - triggerChanged = true; - } - - if ( - triggerChanged && - (!oldTrigger || this.trigger.platform !== oldTrigger.platform) - ) { - const element = document.createElement( - `ha-automation-trigger-${this.trigger.platform}` - ); - element.trigger = this.trigger; - element.hass = this.hass; - if (this._elementContainer!.lastChild) { - this._elementContainer!.removeChild(this._elementContainer!.lastChild); - } - this._elementContainer!.appendChild(element); - } else if (this._elementContainer && this._elementContainer.lastChild) { - const element = this._elementContainer!.lastChild; - element.trigger = this.trigger; - element.hass = this.hass; } } @@ -164,7 +139,10 @@ export default class HaAutomationTriggerRow extends LitElement { )} -
+ ${dynamicContentDirective( + `ha-automation-trigger-${this.trigger.platform}`, + { hass: this.hass, trigger: this.trigger } + )} `} 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 542d334dd7a4..d4786217d6bd 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 @@ -1,8 +1,8 @@ import "@polymer/paper-input/paper-input"; +import { customElement, html, LitElement, property } from "lit-element"; +import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/entity/ha-entity-picker"; -import { LitElement, property, html, customElement } from "lit-element"; import { HomeAssistant } from "../../../../../types"; -import { fireEvent } from "../../../../../common/dom/fire_event"; @customElement("ha-automation-trigger-state") export class HaStateTrigger extends LitElement { @@ -67,9 +67,10 @@ export class HaStateTrigger extends LitElement { const name = ev.target.name; const newVal = ev.detail.value; - if (this.trigger[name] === newVal) { + if ((this.trigger[name] || "") === newVal) { return; } + let trigger; if (!newVal) { trigger = { ...this.trigger }; @@ -82,7 +83,6 @@ export class HaStateTrigger extends LitElement { private _entityPicked(ev: CustomEvent) { ev.stopPropagation(); - fireEvent(this, "value-changed", { value: { ...this.trigger, entity_id: ev.target.value }, }); From e23dffd09bc5740afedd54f3827e5ce43988d180 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 4 Dec 2019 10:29:20 +0100 Subject: [PATCH 4/6] update --- .../config/automation/ha-automation-editor.ts | 1 + .../trigger/ha-automation-trigger-row.ts | 70 +++++++++++++++++-- .../trigger/ha-automation-trigger.ts | 6 ++ .../types/ha-automation-trigger-mqtt.ts | 50 +++++++++++++ .../types/ha-automation-trigger-state.ts | 49 +++++++------ 5 files changed, 148 insertions(+), 28 deletions(-) create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index ba8985252b5d..a040da9f8ad3 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -33,6 +33,7 @@ import { import { navigate } from "../../../common/navigate"; import { computeRTL } from "../../../common/util/compute_rtl"; import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialog-confirmation"; +import { fireEvent } from "../../../common/dom/fire_event"; function AutomationEditor(mountEl, props, mergeEl) { return render(h(Automation, props), mountEl, mergeEl); diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts index 5b432453039c..98daa69a7b73 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts @@ -16,8 +16,10 @@ import { dynamicContentDirective } from "../../../../common/dom/dynamic-content- import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-card"; import { HomeAssistant } from "../../../../types"; -import "./types/ha-automation-trigger-device"; +import "./types/ha-automation-trigger-mqtt"; import "./types/ha-automation-trigger-state"; +// tslint:disable-next-line +import { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox"; const OPTIONS = [ "device", @@ -35,10 +37,58 @@ const OPTIONS = [ "zone", ]; +export interface ForDict { + hours?: number | string; + minutes?: number | string; + seconds?: number | string; +} + +export interface StateTrigger { + platform: "state"; + entity_id: string; + from?: string | number; + to?: string | number; + for?: string | number | ForDict; +} + +export interface MqttTrigger { + platform: "mqtt"; + topic: string; + payload?: string; +} + +export type Trigger = StateTrigger | MqttTrigger; + +export interface TriggerElement extends LitElement { + trigger: Trigger; +} + +export const handleChangeEvent = (element: TriggerElement, ev: CustomEvent) => { + ev.stopPropagation(); + const name = ev.target?.name; + if (!name) { + return; + } + const newVal = ev.detail.value; + + if ((element.trigger[name] || "") === newVal) { + return; + } + + let newTrigger: Trigger; + if (!newVal) { + newTrigger = { ...element.trigger }; + delete newTrigger[name]; + } else { + newTrigger = { ...element.trigger, [name]: newVal }; + } + fireEvent(element, "value-changed", { value: newTrigger }); +}; + @customElement("ha-automation-trigger-row") export default class HaAutomationTriggerRow extends LitElement { @property() public hass!: HomeAssistant; - @property() public trigger; + @property() public trigger!: Trigger; @property() private _yamlMode = false; @property() private _yaml = ""; @property() private error = ""; @@ -161,8 +211,12 @@ export default class HaAutomationTriggerRow extends LitElement { } } - private _typeChanged(ev) { - const type = ev.target.selectedItem.platform; + private _typeChanged(ev: CustomEvent) { + const type = (ev.target as PaperListboxElement)?.selectedItem?.platform; + + if (!type) { + return; + } const elClass = customElements.get(`ha-automation-trigger-${type}`); @@ -178,7 +232,7 @@ export default class HaAutomationTriggerRow extends LitElement { private _onYamlChange(ev: CustomEvent) { ev.stopPropagation(); - let value; + let value: Trigger | undefined; try { value = safeLoad(ev.detail.value); this.error = ""; @@ -213,3 +267,9 @@ export default class HaAutomationTriggerRow extends LitElement { `; } } + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-row": HaAutomationTriggerRow; + } +} diff --git a/src/panels/config/automation/trigger/ha-automation-trigger.ts b/src/panels/config/automation/trigger/ha-automation-trigger.ts index bf04bc857ea0..951b19265a33 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger.ts @@ -85,3 +85,9 @@ export default class HaAutomationTrigger extends LitElement { `; } } + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger": HaAutomationTrigger; + } +} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts new file mode 100644 index 000000000000..ccf951be806d --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts @@ -0,0 +1,50 @@ +import "@polymer/paper-input/paper-input"; +import { LitElement, customElement, property, html } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { + handleChangeEvent, + TriggerElement, + MqttTrigger, +} from "../ha-automation-trigger-row"; + +@customElement("ha-automation-trigger-mqtt") +export class HaMQTTTrigger extends LitElement implements TriggerElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: MqttTrigger; + + public static get defaultConfig() { + return { topic: "" }; + } + + protected render() { + const { topic, payload } = this.trigger; + return html` + + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-mqtt": HaMQTTTrigger; + } +} 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 d4786217d6bd..13ff38961b82 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 @@ -3,11 +3,18 @@ import { customElement, html, LitElement, property } from "lit-element"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/entity/ha-entity-picker"; import { HomeAssistant } from "../../../../../types"; +import { + handleChangeEvent, + TriggerElement, + StateTrigger, + ForDict, +} from "../ha-automation-trigger-row"; +import { PolymerChangedEvent } from "../../../../../polymer-types"; @customElement("ha-automation-trigger-state") -export class HaStateTrigger extends LitElement { +export class HaStateTrigger extends LitElement implements TriggerElement { @property() public hass!: HomeAssistant; - @property() public trigger; + @property() public trigger!: StateTrigger; public static get defaultConfig() { return { entity_id: "" }; @@ -17,10 +24,15 @@ export class HaStateTrigger extends LitElement { const { entity_id, to, from } = this.trigger; let trgFor = this.trigger.for; - if (trgFor && (trgFor.hours || trgFor.minutes || trgFor.seconds)) { + if ( + trgFor && + ((trgFor as ForDict).hours || + (trgFor as ForDict).minutes || + (trgFor as ForDict).seconds) + ) { // If the trigger was defined using the yaml dict syntax, convert it to // the equivalent string format - let { hours = 0, minutes = 0, seconds = 0 } = trgFor; + let { hours = 0, minutes = 0, seconds = 0 } = trgFor as ForDict; hours = hours.toString(); minutes = minutes.toString().padStart(2, "0"); seconds = seconds.toString().padStart(2, "0"); @@ -62,29 +74,20 @@ export class HaStateTrigger extends LitElement { `; } - private _valueChanged(ev): void { - ev.stopPropagation(); - const name = ev.target.name; - const newVal = ev.detail.value; - - if ((this.trigger[name] || "") === newVal) { - return; - } - - let trigger; - if (!newVal) { - trigger = { ...this.trigger }; - delete trigger[name]; - } else { - trigger = { ...this.trigger, [name]: newVal }; - } - fireEvent(this, "value-changed", { value: trigger }); + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); } - private _entityPicked(ev: CustomEvent) { + private _entityPicked(ev: PolymerChangedEvent) { ev.stopPropagation(); fireEvent(this, "value-changed", { - value: { ...this.trigger, entity_id: ev.target.value }, + value: { ...this.trigger, entity_id: ev.detail.value }, }); } } + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-state": HaStateTrigger; + } +} From 8c9d9ce2a15a144ce34dce2d40b07b3973224523 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 4 Dec 2019 11:35:11 +0100 Subject: [PATCH 5/6] Lint --- src/panels/config/automation/ha-automation-editor.ts | 1 - src/panels/config/automation/trigger/ha-automation-trigger.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index a040da9f8ad3..ba8985252b5d 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -33,7 +33,6 @@ import { import { navigate } from "../../../common/navigate"; import { computeRTL } from "../../../common/util/compute_rtl"; import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialog-confirmation"; -import { fireEvent } from "../../../common/dom/fire_event"; function AutomationEditor(mountEl, props, mergeEl) { return render(h(Automation, props), mountEl, mergeEl); diff --git a/src/panels/config/automation/trigger/ha-automation-trigger.ts b/src/panels/config/automation/trigger/ha-automation-trigger.ts index 951b19265a33..108c4c02487c 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger.ts @@ -57,7 +57,7 @@ export default class HaAutomationTrigger extends LitElement { ev.stopPropagation(); const triggers = [...this.triggers]; const newValue = ev.detail.value; - const index = ev.target.index; + const index = (ev.target as any).index; if (newValue === null) { triggers.splice(index, 1); From cdf74e1f377b91e1d985378711a806edd47da1b1 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 4 Dec 2019 16:21:18 +0100 Subject: [PATCH 6/6] Implement other types --- .../device/ha-device-automation-picker.ts | 1 + src/components/ha-yaml-editor.ts | 81 ++++++++++ src/data/device_automation.ts | 2 +- .../trigger/ha-automation-trigger-row.ts | 140 +++++++++++++----- .../types/ha-automation-trigger-device.ts | 128 ++++++++++++++++ .../types/ha-automation-trigger-event.ts | 53 +++++++ .../ha-automation-trigger-geo_location.ts | 99 +++++++++++++ .../ha-automation-trigger-homeassistant.ts | 63 ++++++++ .../ha-automation-trigger-numeric_state.ts | 103 +++++++++++++ .../types/ha-automation-trigger-sun.ts | 75 ++++++++++ .../types/ha-automation-trigger-template.ts | 36 +++++ .../types/ha-automation-trigger-time.ts | 36 +++++ .../ha-automation-trigger-time_pattern.ts | 58 ++++++++ .../types/ha-automation-trigger-webhook.ts | 43 ++++++ .../types/ha-automation-trigger-zone.ts | 108 ++++++++++++++ src/panels/config/js/trigger/device.tsx | 133 ----------------- src/panels/config/js/trigger/event.tsx | 54 ------- src/panels/config/js/trigger/geo_location.tsx | 88 ----------- .../config/js/trigger/homeassistant.tsx | 58 -------- src/panels/config/js/trigger/index.tsx | 59 -------- src/panels/config/js/trigger/mqtt.tsx | 44 ------ .../config/js/trigger/numeric_state.tsx | 90 ----------- src/panels/config/js/trigger/state.tsx | 81 ---------- src/panels/config/js/trigger/sun.tsx | 71 --------- src/panels/config/js/trigger/template.tsx | 37 ----- src/panels/config/js/trigger/time.tsx | 36 ----- src/panels/config/js/trigger/time_pattern.tsx | 50 ------- src/panels/config/js/trigger/trigger_edit.tsx | 120 --------------- src/panels/config/js/trigger/trigger_row.tsx | 86 ----------- src/panels/config/js/trigger/webhook.tsx | 35 ----- src/panels/config/js/trigger/zone.tsx | 109 -------------- 31 files changed, 990 insertions(+), 1187 deletions(-) create mode 100644 src/components/ha-yaml-editor.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts create mode 100644 src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts delete mode 100644 src/panels/config/js/trigger/device.tsx delete mode 100644 src/panels/config/js/trigger/event.tsx delete mode 100644 src/panels/config/js/trigger/geo_location.tsx delete mode 100644 src/panels/config/js/trigger/homeassistant.tsx delete mode 100644 src/panels/config/js/trigger/index.tsx delete mode 100644 src/panels/config/js/trigger/mqtt.tsx delete mode 100644 src/panels/config/js/trigger/numeric_state.tsx delete mode 100644 src/panels/config/js/trigger/state.tsx delete mode 100644 src/panels/config/js/trigger/sun.tsx delete mode 100644 src/panels/config/js/trigger/template.tsx delete mode 100644 src/panels/config/js/trigger/time.tsx delete mode 100644 src/panels/config/js/trigger/time_pattern.tsx delete mode 100644 src/panels/config/js/trigger/trigger_edit.tsx delete mode 100644 src/panels/config/js/trigger/trigger_row.tsx delete mode 100644 src/panels/config/js/trigger/webhook.tsx delete mode 100644 src/panels/config/js/trigger/zone.tsx diff --git a/src/components/device/ha-device-automation-picker.ts b/src/components/device/ha-device-automation-picker.ts index 98c5ce492a34..34eacfaa2532 100644 --- a/src/components/device/ha-device-automation-picker.ts +++ b/src/components/device/ha-device-automation-picker.ts @@ -176,6 +176,7 @@ export abstract class HaDeviceAutomationPicker< this.value = automation; setTimeout(() => { fireEvent(this, "change"); + fireEvent(this, "value-changed", { value: automation }); }, 0); } diff --git a/src/components/ha-yaml-editor.ts b/src/components/ha-yaml-editor.ts new file mode 100644 index 000000000000..dc3a0cb08eb3 --- /dev/null +++ b/src/components/ha-yaml-editor.ts @@ -0,0 +1,81 @@ +import { safeDump, safeLoad } from "js-yaml"; +import "./ha-code-editor"; +import { LitElement, property, customElement, html } from "lit-element"; +import { fireEvent } from "../common/dom/fire_event"; + +const isEmpty = (obj: object) => { + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + return false; + } + } + return true; +}; + +@customElement("ha-yaml-editor") +export class HaYamlEditor extends LitElement { + @property() public value?: any; + @property() public isValid = true; + @property() public label?: string; + @property() private _yaml?: string; + + protected firstUpdated() { + try { + this._yaml = + this.value && !isEmpty(this.value) ? safeDump(this.value) : ""; + } catch (err) { + alert(`There was an error converting to YAML: ${err}`); + } + } + + protected render() { + if (this._yaml === undefined) { + return; + } + return html` + ${this.label + ? html` +

${this.label}

+ ` + : ""} + + `; + } + + private _onChange(ev: CustomEvent) { + ev.stopPropagation(); + const value = ev.detail.value; + let parsed; + let isValid = true; + + if (value) { + try { + parsed = safeLoad(value); + isValid = true; + } catch (err) { + // Invalid YAML + isValid = false; + } + } else { + parsed = {}; + } + + this.value = parsed; + this.isValid = isValid; + + if (isValid) { + fireEvent(this, "value-changed", { value: parsed }); + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-yaml-editor": HaYamlEditor; + } +} diff --git a/src/data/device_automation.ts b/src/data/device_automation.ts index 2653171643e8..bc58f1b00a43 100644 --- a/src/data/device_automation.ts +++ b/src/data/device_automation.ts @@ -18,7 +18,7 @@ export interface DeviceCondition extends DeviceAutomation { } export interface DeviceTrigger extends DeviceAutomation { - platform: string; + platform: "device"; } export const fetchDeviceActions = (hass: HomeAssistant, deviceId: string) => diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts index 98daa69a7b73..ea5b52b38772 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts @@ -1,8 +1,9 @@ import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; +// tslint:disable-next-line +import { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-menu-button/paper-menu-button"; -import { safeDump, safeLoad } from "js-yaml"; import { css, CSSResult, @@ -10,16 +11,26 @@ import { html, LitElement, property, - PropertyValues, } from "lit-element"; import { dynamicContentDirective } from "../../../../common/dom/dynamic-content-directive"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-card"; import { HomeAssistant } from "../../../../types"; -import "./types/ha-automation-trigger-mqtt"; + +import "./types/ha-automation-trigger-device"; +import "./types/ha-automation-trigger-event"; import "./types/ha-automation-trigger-state"; -// tslint:disable-next-line -import { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox"; +import "./types/ha-automation-trigger-geo_location"; +import "./types/ha-automation-trigger-homeassistant"; +import "./types/ha-automation-trigger-mqtt"; +import "./types/ha-automation-trigger-numeric_state"; +import "./types/ha-automation-trigger-sun"; +import "./types/ha-automation-trigger-template"; +import "./types/ha-automation-trigger-time"; +import "./types/ha-automation-trigger-time_pattern"; +import "./types/ha-automation-trigger-webhook"; +import "./types/ha-automation-trigger-zone"; +import { DeviceTrigger } from "../../../../data/device_automation"; const OPTIONS = [ "device", @@ -57,7 +68,82 @@ export interface MqttTrigger { payload?: string; } -export type Trigger = StateTrigger | MqttTrigger; +export interface GeoLocationTrigger { + platform: "geo_location"; + source: "string"; + zone: "string"; + event: "enter" | "leave"; +} + +export interface HassTrigger { + platform: "homeassistant"; + event: "start" | "shutdown"; +} + +export interface NumericStateTrigger { + platform: "numeric_state"; + entity_id: string; + above?: number; + below?: number; + value_template?: string; + for?: string | number | ForDict; +} + +export interface SunTrigger { + platform: "sun"; + offset: number; + event: "sunrise" | "sunset"; +} + +export interface TimePatternTrigger { + platform: "time_pattern"; + hours?: number | string; + minutes?: number | string; + seconds?: number | string; +} + +export interface WebhookTrigger { + platform: "webhook"; + webhook_id: string; +} + +export interface ZoneTrigger { + platform: "zone"; + entity_id: string; + zone: string; + event: "enter" | "leave"; +} + +export interface TimeTrigger { + platform: "time"; + at: string; +} + +export interface TemplateTrigger { + platform: "template"; + value_template: string; +} + +export interface EventTrigger { + platform: "event"; + event_type: string; + event_data: any; +} + +export type Trigger = + | StateTrigger + | MqttTrigger + | GeoLocationTrigger + | HassTrigger + | NumericStateTrigger + | SunTrigger + | TimePatternTrigger + | WebhookTrigger + | ZoneTrigger + | TimeTrigger + | TemplateTrigger + | EventTrigger + | DeviceTrigger; export interface TriggerElement extends LitElement { trigger: Trigger; @@ -65,7 +151,7 @@ export interface TriggerElement extends LitElement { export const handleChangeEvent = (element: TriggerElement, ev: CustomEvent) => { ev.stopPropagation(); - const name = ev.target?.name; + const name = (ev.target as any)?.name; if (!name) { return; } @@ -90,14 +176,6 @@ export default class HaAutomationTriggerRow extends LitElement { @property() public hass!: HomeAssistant; @property() public trigger!: Trigger; @property() private _yamlMode = false; - @property() private _yaml = ""; - @property() private error = ""; - - protected updated(changedProps: PropertyValues) { - if (changedProps.has("_yamlMode") && this._yamlMode) { - this._yaml = safeDump(this.trigger); - } - } protected render() { if (!this.trigger) { @@ -146,7 +224,6 @@ export default class HaAutomationTriggerRow extends LitElement { - ${this.error} ${this._yamlMode ? html`
@@ -159,11 +236,10 @@ export default class HaAutomationTriggerRow extends LitElement { )} ` : ""} - + >
` : html` @@ -189,10 +265,12 @@ export default class HaAutomationTriggerRow extends LitElement { )} - ${dynamicContentDirective( - `ha-automation-trigger-${this.trigger.platform}`, - { hass: this.hass, trigger: this.trigger } - )} +
+ ${dynamicContentDirective( + `ha-automation-trigger-${this.trigger.platform}`, + { hass: this.hass, trigger: this.trigger } + )} +
`} @@ -212,7 +290,8 @@ export default class HaAutomationTriggerRow extends LitElement { } private _typeChanged(ev: CustomEvent) { - const type = (ev.target as PaperListboxElement)?.selectedItem?.platform; + const type = ((ev.target as PaperListboxElement)?.selectedItem as any) + ?.platform; if (!type) { return; @@ -232,16 +311,7 @@ export default class HaAutomationTriggerRow extends LitElement { private _onYamlChange(ev: CustomEvent) { ev.stopPropagation(); - let value: Trigger | undefined; - try { - value = safeLoad(ev.detail.value); - this.error = ""; - } catch (err) { - this.error = err; - } - if (value) { - fireEvent(this, "value-changed", { value }); - } + fireEvent(this, "value-changed", { value: ev.detail.value }); } private _switchYamlMode() { 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 new file mode 100644 index 000000000000..8ea5a96cfe68 --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts @@ -0,0 +1,128 @@ +import "../../../../../components/device/ha-device-picker"; +import "../../../../../components/device/ha-device-trigger-picker"; +import "../../../../../components/ha-form/ha-form"; + +import { + fetchDeviceTriggerCapabilities, + deviceAutomationsEqual, + DeviceTrigger, +} from "../../../../../data/device_automation"; +import { LitElement, customElement, property, html } from "lit-element"; +import { fireEvent } from "../../../../../common/dom/fire_event"; +import { HomeAssistant } from "../../../../../types"; + +@customElement("ha-automation-trigger-device") +export class HaDeviceTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: DeviceTrigger; + @property() private _deviceId?: string; + @property() private _capabilities?; + private _origTrigger?: DeviceTrigger; + + public static get defaultConfig() { + return { + device_id: "", + domain: "", + entity_id: "", + }; + } + + protected render() { + if (this._deviceId === undefined) { + this._deviceId = this.trigger.device_id; + } + const extraFieldsData = + this._capabilities && this._capabilities.extra_fields + ? this._capabilities.extra_fields.map((item) => { + return { [item.name]: this.trigger[item.name] }; + }) + : undefined; + + return html` + + + ${extraFieldsData + ? html` + + ` + : ""} + `; + } + + protected firstUpdated() { + if (!this._capabilities) { + this._getCapabilities(); + } + if (this.trigger) { + this._origTrigger = this.trigger; + } + } + + protected updated(changedPros) { + const prevTrigger = changedPros.get("trigger"); + if (prevTrigger && !deviceAutomationsEqual(prevTrigger, this.trigger)) { + this._getCapabilities(); + } + } + + private async _getCapabilities() { + const trigger = this.trigger; + + this._capabilities = trigger.domain + ? await fetchDeviceTriggerCapabilities(this.hass, trigger) + : null; + } + + private _devicePicked(ev) { + ev.stopPropagation(); + this._deviceId = ev.target.value; + } + + private _deviceTriggerPicked(ev) { + ev.stopPropagation(); + let trigger = ev.detail.value; + if ( + this._origTrigger && + deviceAutomationsEqual(this._origTrigger, trigger) + ) { + trigger = this._origTrigger; + } + fireEvent(this, "value-changed", { value: trigger }); + } + + private _extraFieldsChanged(ev) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { + ...this.trigger, + ...ev.detail.value, + }, + }); + } + + private _extraFieldsComputeLabelCallback(localize) { + // Returns a callback for ha-form to calculate labels per schema object + return (schema) => + localize( + `ui.panel.config.automation.editor.triggers.type.device.extra_fields.${schema.name}` + ) || schema.name; + } +} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts new file mode 100644 index 000000000000..130a5f4e5b2e --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts @@ -0,0 +1,53 @@ +import "@polymer/paper-input/paper-input"; +import "../../../../../components/ha-yaml-editor"; + +import { LitElement, property, customElement } from "lit-element"; +import { + TriggerElement, + EventTrigger, + handleChangeEvent, +} from "../ha-automation-trigger-row"; +import { HomeAssistant } from "../../../../../types"; +import { html } from "lit-html"; + +@customElement("ha-automation-trigger-event") +export class HaEventTrigger extends LitElement implements TriggerElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: EventTrigger; + + public static get defaultConfig() { + return { event_type: "", event_data: {} }; + } + + public render() { + const { event_type, event_data } = this.trigger; + return html` + + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-event": HaEventTrigger; + } +} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts new file mode 100644 index 000000000000..491bcb9d91cc --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts @@ -0,0 +1,99 @@ +import "@polymer/paper-radio-button/paper-radio-button"; +import "@polymer/paper-radio-group/paper-radio-group"; +// tslint:disable-next-line +import { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; +import "../../../../../components/entity/ha-entity-picker"; +import { LitElement, customElement, property, html } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { + GeoLocationTrigger, + handleChangeEvent, +} from "../ha-automation-trigger-row"; +import { fireEvent } from "../../../../../common/dom/fire_event"; + +@customElement("ha-automation-trigger-geo_location") +export default class HaGeolocationTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: GeoLocationTrigger; + + public static get defaultConfig() { + return { + source: "", + zone: "", + event: "enter", + }; + } + + protected render() { + const { source, zone, event } = this.trigger; + + return html` + + + + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.type.geo_location.enter" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.type.geo_location.leave" + )} + + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } + + private _zonePicked(ev: CustomEvent) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { ...this.trigger, zone: ev.detail.value }, + }); + } + + private _radioGroupPicked(ev: CustomEvent) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { + ...this.trigger, + event: (ev.target as PaperRadioGroupElement).selected, + }, + }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-geo_location": HaGeolocationTrigger; + } +} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts new file mode 100644 index 000000000000..328df5ae7d4b --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts @@ -0,0 +1,63 @@ +import "@polymer/paper-radio-button/paper-radio-button"; +import "@polymer/paper-radio-group/paper-radio-group"; +// tslint:disable-next-line +import { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; +import { LitElement, html, property, customElement } from "lit-element"; +import { fireEvent } from "../../../../../common/dom/fire_event"; +import { HomeAssistant } from "../../../../../types"; +import { HassTrigger } from "../ha-automation-trigger-row"; + +@customElement("ha-automation-trigger-homeassistant") +export default class HaHassTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: HassTrigger; + + public static get defaultConfig() { + return { + event: "start", + }; + } + + public render() { + const { event } = this.trigger; + return html` + + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.type.homeassistant.start" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.type.homeassistant.shutdown" + )} + + + `; + } + + private _radioGroupPicked(ev) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { + ...this.trigger, + event: (ev.target as PaperRadioGroupElement).selected, + }, + }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-homeassistant": HaHassTrigger; + } +} 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 new file mode 100644 index 000000000000..5ac8310b4e63 --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts @@ -0,0 +1,103 @@ +import "@polymer/paper-input/paper-input"; +import "../../../../../components/ha-textarea"; + +import "../../../../../components/entity/ha-entity-picker"; +import { LitElement, html, customElement, property } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { fireEvent } from "../../../../../common/dom/fire_event"; +import { + NumericStateTrigger, + ForDict, + handleChangeEvent, +} from "../ha-automation-trigger-row"; + +@customElement("ha-automation-trigger-numeric_state") +export default class HaNumericStateTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: NumericStateTrigger; + + public static get defaultConfig() { + return { + entity_id: "", + }; + } + + public render() { + const { value_template, entity_id, below, above } = this.trigger; + let trgFor = this.trigger.for; + + if ( + trgFor && + ((trgFor as ForDict).hours || + (trgFor as ForDict).minutes || + (trgFor as ForDict).seconds) + ) { + // If the trigger was defined using the yaml dict syntax, convert it to + // the equivalent string format + let { hours = 0, minutes = 0, seconds = 0 } = trgFor as ForDict; + hours = hours.toString(); + minutes = minutes.toString().padStart(2, "0"); + seconds = seconds.toString().padStart(2, "0"); + + trgFor = `${hours}:${minutes}:${seconds}`; + } + return html` + + + + + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } + + private _entityPicked(ev) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { ...this.trigger, entity_id: ev.detail.value }, + }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-numeric_state": HaNumericStateTrigger; + } +} 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 new file mode 100644 index 000000000000..9a855f96fd97 --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts @@ -0,0 +1,75 @@ +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-radio-button/paper-radio-button"; +import "@polymer/paper-radio-group/paper-radio-group"; +// tslint:disable-next-line +import { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; +import { LitElement, customElement, property, html } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { + SunTrigger, + handleChangeEvent, + TriggerElement, +} from "../ha-automation-trigger-row"; +import { fireEvent } from "../../../../../common/dom/fire_event"; + +@customElement("ha-automation-trigger-sun") +export class HaSunTrigger extends LitElement implements TriggerElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: SunTrigger; + + public static get defaultConfig() { + return { + event: "sunrise", + }; + } + + protected render() { + const { offset, event } = this.trigger; + return html` + + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.type.sun.sunrise" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.type.sun.sunset" + )} + + + + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } + + private _radioGroupPicked(ev) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { + ...this.trigger, + event: (ev.target as PaperRadioGroupElement).selected, + }, + }); + } +} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts new file mode 100644 index 000000000000..b229f2e065e3 --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts @@ -0,0 +1,36 @@ +import "../../../../../components/ha-textarea"; +import { LitElement, property, html, customElement } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { + TemplateTrigger, + handleChangeEvent, +} from "../ha-automation-trigger-row"; + +@customElement("ha-automation-trigger-template") +export class HaTemplateTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: TemplateTrigger; + + public static get defaultConfig() { + return { value_template: "" }; + } + + protected render() { + const { value_template } = this.trigger; + return html` + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } +} 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 new file mode 100644 index 000000000000..1222a72ff5dc --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts @@ -0,0 +1,36 @@ +import "@polymer/paper-input/paper-input"; +import { LitElement, html, property, customElement } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { + TimeTrigger, + handleChangeEvent, + TriggerElement, +} from "../ha-automation-trigger-row"; + +@customElement("ha-automation-trigger-time") +export class HaTimeTrigger extends LitElement implements TriggerElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: TimeTrigger; + + public static get defaultConfig() { + return { at: "" }; + } + + protected render() { + const { at } = this.trigger; + return html` + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } +} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts new file mode 100644 index 000000000000..95b534961acf --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts @@ -0,0 +1,58 @@ +import "@polymer/paper-input/paper-input"; +import { LitElement, property, html, customElement } from "lit-element"; +import { + TriggerElement, + handleChangeEvent, + TimePatternTrigger, +} from "../ha-automation-trigger-row"; +import { HomeAssistant } from "../../../../../types"; + +@customElement("ha-automation-trigger-time_pattern") +export class HaTimePatternTrigger extends LitElement implements TriggerElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: TimePatternTrigger; + + public static get defaultConfig() { + return {}; + } + + protected render() { + const { hours, minutes, seconds } = this.trigger; + return html` + + + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-time_pattern": HaTimePatternTrigger; + } +} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts new file mode 100644 index 000000000000..fa7c1fcf27d7 --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts @@ -0,0 +1,43 @@ +import "@polymer/paper-input/paper-input"; +import { LitElement, customElement, property, html } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { + WebhookTrigger, + handleChangeEvent, +} from "../ha-automation-trigger-row"; + +@customElement("ha-automation-trigger-webhook") +export class HaWebhookTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: WebhookTrigger; + + public static get defaultConfig() { + return { + webhook_id: "", + }; + } + + protected render() { + const { webhook_id: webhookId } = this.trigger; + return html` + + `; + } + + private _valueChanged(ev: CustomEvent): void { + handleChangeEvent(this, ev); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-webhook": HaWebhookTrigger; + } +} 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 new file mode 100644 index 000000000000..d1f71598b061 --- /dev/null +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts @@ -0,0 +1,108 @@ +import "@polymer/paper-radio-button/paper-radio-button"; +import "@polymer/paper-radio-group/paper-radio-group"; +// tslint:disable-next-line +import { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; +import "../../../../../components/entity/ha-entity-picker"; + +import { hasLocation } from "../../../../../common/entity/has_location"; +import { computeStateDomain } from "../../../../../common/entity/compute_state_domain"; +import { LitElement, property, html, customElement } from "lit-element"; +import { HomeAssistant } from "../../../../../types"; +import { ZoneTrigger } from "../ha-automation-trigger-row"; +import { PolymerChangedEvent } from "../../../../../polymer-types"; +import { fireEvent } from "../../../../../common/dom/fire_event"; + +function zoneAndLocationFilter(stateObj) { + return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone"; +} + +@customElement("ha-automation-trigger-zone") +export class HaZoneTrigger extends LitElement { + @property() public hass!: HomeAssistant; + @property() public trigger!: ZoneTrigger; + + public static get defaultConfig() { + return { + entity_id: "", + zone: "", + event: "enter", + }; + } + + protected render() { + const { entity_id, zone, event } = this.trigger; + return html` + + + + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.type.zone.enter" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.type.zone.leave" + )} + + + `; + } + + private _entityPicked(ev: PolymerChangedEvent) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { ...this.trigger, entity_id: ev.detail.value }, + }); + } + + private _zonePicked(ev: PolymerChangedEvent) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { ...this.trigger, zone: ev.detail.value }, + }); + } + + private _radioGroupPicked(ev: CustomEvent) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { + ...this.trigger, + event: (ev.target as PaperRadioGroupElement).selected, + }, + }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-trigger-zone": HaZoneTrigger; + } +} diff --git a/src/panels/config/js/trigger/device.tsx b/src/panels/config/js/trigger/device.tsx deleted file mode 100644 index 81e202fc0368..000000000000 --- a/src/panels/config/js/trigger/device.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { h } from "preact"; - -import "../../../../components/device/ha-device-picker"; -import "../../../../components/device/ha-device-trigger-picker"; -import "../../../../components/ha-form/ha-form"; - -import { - fetchDeviceTriggerCapabilities, - deviceAutomationsEqual, -} from "../../../../data/device_automation"; - -import { AutomationComponent } from "../automation-component"; - -export default class DeviceTrigger extends AutomationComponent { - private _origTrigger; - - constructor() { - super(); - this.devicePicked = this.devicePicked.bind(this); - this.deviceTriggerPicked = this.deviceTriggerPicked.bind(this); - this._extraFieldsChanged = this._extraFieldsChanged.bind(this); - this.state = { device_id: undefined, capabilities: undefined }; - } - - public devicePicked(ev) { - if (!this.initialized) { - return; - } - this.setState({ ...this.state, device_id: ev.target.value }); - } - - public deviceTriggerPicked(ev) { - if (!this.initialized) { - return; - } - let trigger = ev.target.value; - if ( - this._origTrigger && - deviceAutomationsEqual(this._origTrigger, trigger) - ) { - trigger = this._origTrigger; - } - this.props.onChange(this.props.index, trigger); - } - - /* eslint-disable camelcase */ - public render({ trigger, hass }, { device_id, capabilities }) { - if (device_id === undefined) { - device_id = trigger.device_id; - } - const extraFieldsData = - capabilities && capabilities.extra_fields - ? capabilities.extra_fields.map((item) => { - return { [item.name]: this.props.trigger[item.name] }; - }) - : undefined; - - return ( -
- - - {extraFieldsData && ( - - )} -
- ); - } - - public componentDidMount() { - this.initialized = true; - if (!this.state.capabilities) { - this._getCapabilities(); - } - if (this.props.trigger) { - this._origTrigger = this.props.trigger; - } - } - - public componentDidUpdate(prevProps) { - if (!deviceAutomationsEqual(prevProps.trigger, this.props.trigger)) { - this._getCapabilities(); - } - } - - private async _getCapabilities() { - const trigger = this.props.trigger; - - const capabilities = trigger.domain - ? await fetchDeviceTriggerCapabilities(this.props.hass, trigger) - : null; - this.setState({ ...this.state, capabilities }); - } - - private _extraFieldsChanged(ev) { - if (!this.initialized) { - return; - } - this.props.onChange(this.props.index, { - ...this.props.trigger, - ...ev.detail.value, - }); - } - - private _extraFieldsComputeLabelCallback(localize) { - // Returns a callback for ha-form to calculate labels per schema object - return (schema) => - localize( - `ui.panel.config.automation.editor.triggers.type.device.extra_fields.${schema.name}` - ) || schema.name; - } -} - -(DeviceTrigger as any).defaultConfig = { - device_id: "", - domain: "", - entity_id: "", -}; diff --git a/src/panels/config/js/trigger/event.tsx b/src/panels/config/js/trigger/event.tsx deleted file mode 100644 index da3ab66baf76..000000000000 --- a/src/panels/config/js/trigger/event.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-input/paper-input"; - -import YAMLTextArea from "../yaml_textarea"; -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class EventTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor() { - super(); - - this.onChange = onChangeEvent.bind(this, "trigger"); - this.eventDataChanged = this.eventDataChanged.bind(this); - } - - /* eslint-disable camelcase */ - // tslint:disable-next-line: variable-name - public eventDataChanged(event_data) { - this.props.onChange(this.props.index, { - ...this.props.trigger, - event_data, - }); - } - - public render({ trigger, localize }) { - const { event_type, event_data } = trigger; - return ( -
- - -
- ); - } -} - -(EventTrigger as any).defaultConfig = { - event_type: "", - event_data: {}, -}; diff --git a/src/panels/config/js/trigger/geo_location.tsx b/src/panels/config/js/trigger/geo_location.tsx deleted file mode 100644 index 836c04f42bc6..000000000000 --- a/src/panels/config/js/trigger/geo_location.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-radio-button/paper-radio-button"; -import "@polymer/paper-radio-group/paper-radio-group"; -import "../../../../components/entity/ha-entity-picker"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class GeolocationTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor() { - super(); - - this.onChange = onChangeEvent.bind(this, "trigger"); - this.zonePicked = this.zonePicked.bind(this); - this.radioGroupPicked = this.radioGroupPicked.bind(this); - } - - public zonePicked(ev) { - this.props.onChange(this.props.index, { - ...this.props.trigger, - zone: ev.target.value, - }); - } - - public radioGroupPicked(ev) { - this.props.onChange(this.props.index, { - ...this.props.trigger, - event: ev.target.selected, - }); - } - - /* eslint-disable camelcase */ - public render({ trigger, hass, localize }) { - const { source, zone, event } = trigger; - - return ( -
- - - - - - {localize( - "ui.panel.config.automation.editor.triggers.type.geo_location.enter" - )} - - - {localize( - "ui.panel.config.automation.editor.triggers.type.geo_location.leave" - )} - - -
- ); - } -} - -(GeolocationTrigger as any).defaultConfig = { - source: "", - zone: "", - event: "enter", -}; diff --git a/src/panels/config/js/trigger/homeassistant.tsx b/src/panels/config/js/trigger/homeassistant.tsx deleted file mode 100644 index 52bf5ac192a9..000000000000 --- a/src/panels/config/js/trigger/homeassistant.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-radio-button/paper-radio-button"; -import "@polymer/paper-radio-group/paper-radio-group"; - -import { AutomationComponent } from "../automation-component"; - -export default class HassTrigger extends AutomationComponent { - constructor() { - super(); - - this.radioGroupPicked = this.radioGroupPicked.bind(this); - } - - public radioGroupPicked(ev) { - if (!this.initialized) { - return; - } - this.props.onChange(this.props.index, { - ...this.props.trigger, - event: ev.target.selected, - }); - } - - /* eslint-disable camelcase */ - public render({ trigger, localize }) { - const { event } = trigger; - return ( -
- - - - {localize( - "ui.panel.config.automation.editor.triggers.type.homeassistant.start" - )} - - - {localize( - "ui.panel.config.automation.editor.triggers.type.homeassistant.shutdown" - )} - - -
- ); - } -} - -(HassTrigger as any).defaultConfig = { - event: "start", -}; diff --git a/src/panels/config/js/trigger/index.tsx b/src/panels/config/js/trigger/index.tsx deleted file mode 100644 index fa196e418e10..000000000000 --- a/src/panels/config/js/trigger/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { h, Component } from "preact"; -import "@material/mwc-button"; -import "../../../../components/ha-card"; - -import TriggerRow from "./trigger_row"; -import StateTrigger from "./state"; - -export default class Trigger extends Component { - constructor() { - super(); - - this.addTrigger = this.addTrigger.bind(this); - this.triggerChanged = this.triggerChanged.bind(this); - } - - public addTrigger() { - const trigger = this.props.trigger.concat({ - platform: "state", - ...(StateTrigger as any).defaultConfig, - }); - - this.props.onChange(trigger); - } - - public triggerChanged(index, newValue) { - const trigger = this.props.trigger.concat(); - - if (newValue === null) { - trigger.splice(index, 1); - } else { - trigger[index] = newValue; - } - - this.props.onChange(trigger); - } - - public render({ trigger, hass, localize }) { - return ( -
- {trigger.map((trg, idx) => ( - - ))} - -
- - {localize("ui.panel.config.automation.editor.triggers.add")} - -
-
-
- ); - } -} diff --git a/src/panels/config/js/trigger/mqtt.tsx b/src/panels/config/js/trigger/mqtt.tsx deleted file mode 100644 index 16cfdb612e5b..000000000000 --- a/src/panels/config/js/trigger/mqtt.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-input/paper-input"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class MQTTTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor(props) { - super(props); - - this.onChange = onChangeEvent.bind(this, "trigger"); - } - - /* eslint-disable camelcase */ - public render({ trigger, localize }) { - const { topic, payload } = trigger; - return ( -
- - -
- ); - } -} - -(MQTTTrigger as any).defaultConfig = { - topic: "", -}; diff --git a/src/panels/config/js/trigger/numeric_state.tsx b/src/panels/config/js/trigger/numeric_state.tsx deleted file mode 100644 index 366ee4f32f3b..000000000000 --- a/src/panels/config/js/trigger/numeric_state.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-input/paper-input"; -import "../../../../components/ha-textarea"; - -import "../../../../components/entity/ha-entity-picker"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class NumericStateTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor(props) { - super(props); - - this.onChange = onChangeEvent.bind(this, "trigger"); - this.entityPicked = this.entityPicked.bind(this); - } - - public entityPicked(ev) { - this.props.onChange(this.props.index, { - ...this.props.trigger, - entity_id: ev.target.value, - }); - } - - /* eslint-disable camelcase */ - public render({ trigger, hass, localize }) { - const { value_template, entity_id, below, above } = trigger; - let trgFor = trigger.for; - - if (trgFor && (trgFor.hours || trgFor.minutes || trgFor.seconds)) { - // If the trigger was defined using the yaml dict syntax, convert it to - // the equivalent string format - let { hours = 0, minutes = 0, seconds = 0 } = trgFor; - hours = hours.toString(); - minutes = minutes.toString().padStart(2, "0"); - seconds = seconds.toString().padStart(2, "0"); - - trgFor = `${hours}:${minutes}:${seconds}`; - } - return ( -
- - - - - -
- ); - } -} - -(NumericStateTrigger as any).defaultConfig = { - entity_id: "", -}; diff --git a/src/panels/config/js/trigger/state.tsx b/src/panels/config/js/trigger/state.tsx deleted file mode 100644 index 6450ccfae30b..000000000000 --- a/src/panels/config/js/trigger/state.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-input/paper-input"; -import "../../../../components/entity/ha-entity-picker"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class StateTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor(props) { - super(props); - this.onChange = onChangeEvent.bind(this, "trigger"); - this.entityPicked = this.entityPicked.bind(this); - } - - public entityPicked(ev) { - if (!this.initialized) { - return; - } - this.props.onChange(this.props.index, { - ...this.props.trigger, - entity_id: ev.target.value, - }); - } - - /* eslint-disable camelcase */ - public render({ trigger, hass, localize }) { - const { entity_id, to, from } = trigger; - let trgFor = trigger.for; - - if (trgFor && (trgFor.hours || trgFor.minutes || trgFor.seconds)) { - // If the trigger was defined using the yaml dict syntax, convert it to - // the equivalent string format - let { hours = 0, minutes = 0, seconds = 0 } = trgFor; - hours = hours.toString(); - minutes = minutes.toString().padStart(2, "0"); - seconds = seconds.toString().padStart(2, "0"); - - trgFor = `${hours}:${minutes}:${seconds}`; - } - return ( -
- - - - -
- ); - } -} - -(StateTrigger as any).defaultConfig = { - entity_id: "", -}; diff --git a/src/panels/config/js/trigger/sun.tsx b/src/panels/config/js/trigger/sun.tsx deleted file mode 100644 index c8d9b01616f1..000000000000 --- a/src/panels/config/js/trigger/sun.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-input/paper-input"; -import "@polymer/paper-radio-button/paper-radio-button"; -import "@polymer/paper-radio-group/paper-radio-group"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class SunTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor() { - super(); - - this.onChange = onChangeEvent.bind(this, "trigger"); - this.radioGroupPicked = this.radioGroupPicked.bind(this); - } - - public radioGroupPicked(ev) { - if (!this.initialized) { - return; - } - this.props.onChange(this.props.index, { - ...this.props.trigger, - event: ev.target.selected, - }); - } - - /* eslint-disable camelcase */ - public render({ trigger, localize }) { - const { offset, event } = trigger; - return ( -
- - - - {localize( - "ui.panel.config.automation.editor.triggers.type.sun.sunrise" - )} - - - {localize( - "ui.panel.config.automation.editor.triggers.type.sun.sunset" - )} - - - - -
- ); - } -} - -(SunTrigger as any).defaultConfig = { - event: "sunrise", -}; diff --git a/src/panels/config/js/trigger/template.tsx b/src/panels/config/js/trigger/template.tsx deleted file mode 100644 index aa25103043f8..000000000000 --- a/src/panels/config/js/trigger/template.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { h } from "preact"; - -import "../../../../components/ha-textarea"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class TemplateTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor() { - super(); - - this.onChange = onChangeEvent.bind(this, "trigger"); - } - - public render({ trigger, localize }) { - /* eslint-disable camelcase */ - const { value_template } = trigger; - return ( -
- -
- ); - } -} - -(TemplateTrigger as any).defaultConfig = { - value_template: "", -}; diff --git a/src/panels/config/js/trigger/time.tsx b/src/panels/config/js/trigger/time.tsx deleted file mode 100644 index 70a2c718c63c..000000000000 --- a/src/panels/config/js/trigger/time.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-input/paper-input"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class TimeTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor() { - super(); - - this.onChange = onChangeEvent.bind(this, "trigger"); - } - - /* eslint-disable camelcase */ - public render({ trigger, localize }) { - const { at } = trigger; - return ( -
- -
- ); - } -} - -(TimeTrigger as any).defaultConfig = { - at: "", -}; diff --git a/src/panels/config/js/trigger/time_pattern.tsx b/src/panels/config/js/trigger/time_pattern.tsx deleted file mode 100644 index b6af8172bd78..000000000000 --- a/src/panels/config/js/trigger/time_pattern.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-input/paper-input"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class TimePatternTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor() { - super(); - - this.onChange = onChangeEvent.bind(this, "trigger"); - } - - /* eslint-disable camelcase */ - public render({ trigger, localize }) { - const { hours, minutes, seconds } = trigger; - return ( -
- - - -
- ); - } -} - -(TimePatternTrigger as any).defaultConfig = {}; diff --git a/src/panels/config/js/trigger/trigger_edit.tsx b/src/panels/config/js/trigger/trigger_edit.tsx deleted file mode 100644 index 4715b7d45697..000000000000 --- a/src/panels/config/js/trigger/trigger_edit.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { h, Component } from "preact"; - -import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; - -import "../../../../components/ha-code-editor"; - -import YAMLTextArea from "../yaml_textarea"; - -import DeviceTrigger from "./device"; -import EventTrigger from "./event"; -import GeolocationTrigger from "./geo_location"; -import HassTrigger from "./homeassistant"; -import MQTTTrigger from "./mqtt"; -import NumericStateTrigger from "./numeric_state"; -import TimePatternTrigger from "./time_pattern"; -import StateTrigger from "./state"; -import SunTrigger from "./sun"; -import TemplateTrigger from "./template"; -import TimeTrigger from "./time"; -import WebhookTrigger from "./webhook"; -import ZoneTrigger from "./zone"; - -const TYPES = { - device: DeviceTrigger, - event: EventTrigger, - state: StateTrigger, - geo_location: GeolocationTrigger, - homeassistant: HassTrigger, - mqtt: MQTTTrigger, - numeric_state: NumericStateTrigger, - sun: SunTrigger, - template: TemplateTrigger, - time: TimeTrigger, - time_pattern: TimePatternTrigger, - webhook: WebhookTrigger, - zone: ZoneTrigger, -}; - -const OPTIONS = Object.keys(TYPES).sort(); - -export default class TriggerEdit extends Component { - constructor() { - super(); - - this.typeChanged = this.typeChanged.bind(this); - this.onYamlChange = this.onYamlChange.bind(this); - } - - public render({ index, trigger, onChange, hass, localize, yamlMode }) { - // tslint:disable-next-line: variable-name - const Comp = TYPES[trigger.platform]; - const selected = OPTIONS.indexOf(trigger.platform); - - if (yamlMode || !Comp) { - return ( -
- {!Comp && ( -
- {localize( - "ui.panel.config.automation.editor.triggers.unsupported_platform", - "platform", - trigger.platform - )} -
- )} - -
- ); - } - - return ( -
- - - {OPTIONS.map((opt) => ( - - {localize( - `ui.panel.config.automation.editor.triggers.type.${opt}.label` - )} - - ))} - - - -
- ); - } - - private typeChanged(ev) { - const type = ev.target.selectedItem.attributes.platform.value; - - if (type !== this.props.trigger.platform) { - this.props.onChange(this.props.index, { - platform: type, - ...TYPES[type].defaultConfig, - }); - } - } - - private onYamlChange(trigger) { - this.props.onChange(this.props.index, trigger); - } -} diff --git a/src/panels/config/js/trigger/trigger_row.tsx b/src/panels/config/js/trigger/trigger_row.tsx deleted file mode 100644 index 9ca51d93cfb4..000000000000 --- a/src/panels/config/js/trigger/trigger_row.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { h, Component } from "preact"; -import "@polymer/paper-menu-button/paper-menu-button"; -import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; -import "../../../../components/ha-card"; - -import TriggerEdit from "./trigger_edit"; - -export default class TriggerRow extends Component { - public state: { yamlMode: boolean }; - constructor() { - super(); - - this.state = { - yamlMode: false, - }; - - this.onDelete = this.onDelete.bind(this); - this.switchYamlMode = this.switchYamlMode.bind(this); - } - - public render(props, { yamlMode }) { - return ( - -
-
- - - - - {yamlMode - ? props.localize( - "ui.panel.config.automation.editor.edit_ui" - ) - : props.localize( - "ui.panel.config.automation.editor.edit_yaml" - )} - - - {props.localize( - "ui.panel.config.automation.editor.triggers.duplicate" - )} - - - {props.localize( - "ui.panel.config.automation.editor.triggers.delete" - )} - - - -
- -
-
- ); - } - - private onDelete() { - // eslint-disable-next-line - if ( - confirm( - this.props.localize( - "ui.panel.config.automation.editor.triggers.delete_confirm" - ) - ) - ) { - this.props.onChange(this.props.index, null); - } - } - - private switchYamlMode() { - this.setState({ - yamlMode: !this.state.yamlMode, - }); - } -} diff --git a/src/panels/config/js/trigger/webhook.tsx b/src/panels/config/js/trigger/webhook.tsx deleted file mode 100644 index 59806e65fa40..000000000000 --- a/src/panels/config/js/trigger/webhook.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-input/paper-input"; - -import { onChangeEvent } from "../../../../common/preact/event"; -import { AutomationComponent } from "../automation-component"; - -export default class WebhookTrigger extends AutomationComponent { - private onChange: (obj: any) => void; - constructor() { - super(); - - this.onChange = onChangeEvent.bind(this, "trigger"); - } - - public render({ trigger, localize }) { - const { webhook_id: webhookId } = trigger; - return ( -
- -
- ); - } -} - -(WebhookTrigger as any).defaultConfig = { - webhook_id: "", -}; diff --git a/src/panels/config/js/trigger/zone.tsx b/src/panels/config/js/trigger/zone.tsx deleted file mode 100644 index 81914a3d527c..000000000000 --- a/src/panels/config/js/trigger/zone.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { h } from "preact"; - -import "@polymer/paper-radio-button/paper-radio-button"; -import "@polymer/paper-radio-group/paper-radio-group"; -import "../../../../components/entity/ha-entity-picker"; - -import { hasLocation } from "../../../../common/entity/has_location"; -import { computeStateDomain } from "../../../../common/entity/compute_state_domain"; -import { AutomationComponent } from "../automation-component"; - -function zoneAndLocationFilter(stateObj) { - return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone"; -} - -export default class ZoneTrigger extends AutomationComponent { - constructor() { - super(); - - this.radioGroupPicked = this.radioGroupPicked.bind(this); - this.entityPicked = this.entityPicked.bind(this); - this.zonePicked = this.zonePicked.bind(this); - } - - /* eslint-disable camelcase */ - public render({ trigger, hass, localize }) { - const { entity_id, zone, event } = trigger; - return ( -
- - - - - - {localize( - "ui.panel.config.automation.editor.triggers.type.zone.enter" - )} - - - {localize( - "ui.panel.config.automation.editor.triggers.type.zone.leave" - )} - - -
- ); - } - - private entityPicked(ev) { - if (!this.initialized) { - return; - } - this.props.onChange(this.props.index, { - ...this.props.trigger, - entity_id: ev.target.value, - }); - } - - private zonePicked(ev) { - if (!this.initialized) { - return; - } - this.props.onChange(this.props.index, { - ...this.props.trigger, - zone: ev.target.value, - }); - } - - private radioGroupPicked(ev) { - if (!this.initialized) { - return; - } - this.props.onChange(this.props.index, { - ...this.props.trigger, - event: ev.target.selected, - }); - } -} - -(ZoneTrigger as any).defaultConfig = { - entity_id: "", - zone: "", - event: "enter", -};