From 07d37dd89f25dae045ce21856db243276a8a8b3a Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Tue, 20 Jun 2023 23:50:01 -0700 Subject: [PATCH] Handle multiple triggers in trigger condition UI (#16983) --- .../ha-selector/ha-selector-select.ts | 34 ++++---- .../types/ha-automation-condition-trigger.ts | 81 ++++++++++++------- 2 files changed, 72 insertions(+), 43 deletions(-) diff --git a/src/components/ha-selector/ha-selector-select.ts b/src/components/ha-selector/ha-selector-select.ts index f4b07b55aa..e8bd3ac4b4 100644 --- a/src/components/ha-selector/ha-selector-select.ts +++ b/src/components/ha-selector/ha-selector-select.ts @@ -4,6 +4,7 @@ import { css, html, LitElement } from "lit"; import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { stopPropagation } from "../../common/dom/stop_propagation"; +import { ensureArray } from "../../common/array/ensure-array"; import type { SelectOption, SelectSelector } from "../../data/selector"; import type { HomeAssistant } from "../../types"; import "../ha-checkbox"; @@ -40,7 +41,7 @@ export class HaSelectSelector extends LitElement { protected render() { const options = - this.selector.select?.options.map((option) => + this.selector.select?.options?.map((option) => typeof option === "object" ? (option as SelectOption) : ({ value: option, label: option } as SelectOption) @@ -77,7 +78,8 @@ export class HaSelectSelector extends LitElement { ${this._renderHelper()} `; } - + const value = + !this.value || this.value === "" ? [] : ensureArray(this.value); return html`
${this.label} @@ -85,7 +87,7 @@ export class HaSelectSelector extends LitElement { (item: SelectOption) => html` !option.disabled && !value?.includes(option.value) @@ -231,19 +233,19 @@ export class HaSelectSelector extends LitElement { const value: string = ev.target.value; const checked = ev.target.checked; + const oldValue = + !this.value || this.value === "" ? [] : ensureArray(this.value); + if (checked) { - if (!this.value) { - newValue = [value]; - } else if (this.value.includes(value)) { + if (oldValue.includes(value)) { return; - } else { - newValue = [...this.value, value]; } + newValue = [...oldValue, value]; } else { - if (!this.value?.includes(value)) { + if (!oldValue?.includes(value)) { return; } - newValue = (this.value as string[]).filter((v) => v !== value); + newValue = oldValue.filter((v) => v !== value); } fireEvent(this, "value-changed", { @@ -252,7 +254,7 @@ export class HaSelectSelector extends LitElement { } private async _removeItem(ev) { - const value: string[] = [...(this.value! as string[])]; + const value: string[] = [...ensureArray(this.value!)]; value.splice(ev.target.idx, 1); fireEvent(this, "value-changed", { @@ -277,7 +279,10 @@ export class HaSelectSelector extends LitElement { return; } - if (newValue !== undefined && this.value?.includes(newValue)) { + const currentValue = + !this.value || this.value === "" ? [] : ensureArray(this.value); + + if (newValue !== undefined && currentValue.includes(newValue)) { return; } @@ -286,9 +291,6 @@ export class HaSelectSelector extends LitElement { this.comboBox.setInputValue(""); }, 0); - const currentValue = - !this.value || this.value === "" ? [] : (this.value as string[]); - fireEvent(this, "value-changed", { value: [...currentValue, newValue], }); 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 3eb72d48d2..8935668618 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 @@ -1,9 +1,11 @@ import "@material/mwc-list/mwc-list-item"; +import memoizeOne from "memoize-one"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { ensureArray } from "../../../../../common/array/ensure-array"; +import type { SchemaUnion } from "../../../../../components/ha-form/types"; import "../../../../../components/ha-select"; import type { AutomationConfig, @@ -30,6 +32,22 @@ export class HaTriggerCondition extends LitElement { }; } + private _schema = memoizeOne( + (triggers: Trigger[]) => + [ + { + name: "id", + selector: { + select: { + multiple: true, + options: triggers.map((trigger) => trigger.id!), + }, + }, + required: true, + }, + ] as const + ); + connectedCallback() { super.connectedCallback(); const details = { callback: (config) => this._automationUpdated(config) }; @@ -45,30 +63,33 @@ export class HaTriggerCondition extends LitElement { } protected render() { - const { id } = this.condition; - if (!this._triggers.length) { return this.hass.localize( "ui.panel.config.automation.editor.conditions.type.trigger.no_triggers" ); } - return html` - ${this._triggers.map( - (trigger) => - html` - ${trigger.id} - ` - )} - `; + + const schema = this._schema(this._triggers); + + return html` + + `; } + private _computeLabelCallback = ( + schema: SchemaUnion> + ): string => + this.hass.localize( + `ui.panel.config.automation.editor.conditions.type.trigger.${schema.name}` + ); + private _automationUpdated(config?: AutomationConfig) { const seenIds = new Set(); this._triggers = config?.trigger @@ -78,18 +99,24 @@ export class HaTriggerCondition extends LitElement { : []; } - private _triggerPicked(ev) { + private _valueChanged(ev: CustomEvent): void { ev.stopPropagation(); - if (!ev.target.value) { - return; + const newValue = ev.detail.value; + + if (typeof newValue.id === "string") { + if (!this._triggers.some((trigger) => trigger.id === newValue.id)) { + newValue.id = ""; + } + } else if (Array.isArray(newValue.id)) { + newValue.id = newValue.id.filter((id) => + this._triggers.some((trigger) => trigger.id === id) + ); + if (!newValue.id.length) { + newValue.id = ""; + } } - const newTrigger = ev.target.value; - if (this.condition.id === newTrigger) { - return; - } - fireEvent(this, "value-changed", { - value: { ...this.condition, id: newTrigger }, - }); + + fireEvent(this, "value-changed", { value: newValue }); } }