Automation Conditions to conversion to ha-form or mwc (#11727)

This commit is contained in:
Zack Barett 2022-02-18 14:48:17 -06:00 committed by GitHub
parent cc177ef911
commit 494cc3a569
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 452 additions and 499 deletions

View File

@ -49,7 +49,7 @@ export interface HaFormSelectSchema extends HaFormBaseSchema {
export interface HaFormMultiSelectSchema extends HaFormBaseSchema {
type: "multi_select";
options: Record<string, string> | string[];
options: Record<string, string> | string[] | Array<[string, string]>;
}
export interface HaFormFloatSchema extends HaFormBaseSchema {

View File

@ -22,6 +22,7 @@ export class HaTimeSelector extends LitElement {
.value=${this.value}
.locale=${this.hass.locale}
.disabled=${this.disabled}
.label=${this.label}
enable-second
></ha-time-input>
`;

View File

@ -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";

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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`
<ha-entity-picker
.value=${entity_id}
.name=${"entity_id"}
@value-changed=${this._valueChanged}
<ha-form
.hass=${this.hass}
allow-custom-entity
></ha-entity-picker>
<ha-entity-attribute-picker
.hass=${this.hass}
.entityId=${entity_id}
.value=${attribute}
.name=${"attribute"}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.type.state.attribute"
)}
.data=${this.condition}
.schema=${schema}
@value-changed=${this._valueChanged}
allow-custom-value
></ha-entity-attribute-picker>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.above"
)}
name="above"
.value=${above}
@value-changed=${this._valueChanged}
></paper-input>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.below"
)}
name="below"
.value=${below}
@value-changed=${this._valueChanged}
></paper-input>
<paper-textarea
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.value_template"
)}
name="value_template"
.value=${value_template}
@value-changed=${this._valueChanged}
dir="ltr"
></paper-textarea>
.computeLabel=${this._computeLabelCallback}
></ha-form>
`;
}
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 {

View File

@ -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`
<ha-entity-picker
.value=${entity_id}
.name=${"entity_id"}
@value-changed=${this._valueChanged}
<ha-form
.hass=${this.hass}
allow-custom-entity
></ha-entity-picker>
<ha-entity-attribute-picker
.hass=${this.hass}
.entityId=${entity_id}
.value=${attribute}
.name=${"attribute"}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.type.state.attribute"
)}
.data=${data}
.schema=${schema}
@value-changed=${this._valueChanged}
allow-custom-value
></ha-entity-attribute-picker>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.state.state"
)}
.name=${"state"}
.value=${state}
@value-changed=${this._valueChanged}
></paper-input>
<ha-duration-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.type.state.for"
)}
.name=${"for"}
.data=${forTime}
@value-changed=${this._valueChanged}
></ha-duration-input>
.computeLabel=${this._computeLabelCallback}
></ha-form>
`;
}
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 {

View File

@ -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`
<label>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.before"
)}
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunrise"
)}
>
<ha-radio
name="before"
value="sunrise"
.checked=${before === "sunrise"}
@change=${this._radioGroupPicked}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunset"
)}
>
<ha-radio
name="before"
value="sunset"
.checked=${before === "sunset"}
@change=${this._radioGroupPicked}
></ha-radio>
</ha-formfield>
</label>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.before_offset"
)}
name="before_offset"
.value=${before_offset}
<ha-form
.schema=${schema}
.data=${this.condition}
.hass=${this.hass}
.computeLabel=${this._computeLabelCallback}
@value-changed=${this._valueChanged}
></paper-input>
<label>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.after"
)}
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunrise"
)}
>
<ha-radio
name="after"
value="sunrise"
.checked=${after === "sunrise"}
@change=${this._radioGroupPicked}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunset"
)}
>
<ha-radio
name="after"
value="sunset"
.checked=${after === "sunset"}
@change=${this._radioGroupPicked}
></ha-radio>
</ha-formfield>
</label>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.after_offset"
)}
name="after_offset"
.value=${after_offset}
@value-changed=${this._valueChanged}
></paper-input>
></ha-form>
`;
}
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 {

View File

@ -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`
<paper-textarea
<ha-textarea
name="value_template"
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.template.value_template"
)}
name="value_template"
.value=${value_template}
@value-changed=${this._valueChanged}
@input=${this._valueChanged}
dir="ltr"
></paper-textarea>
autogrow
></ha-textarea>
`;
}
private _valueChanged(ev: CustomEvent): void {
handleChangeEvent(this, ev);
}
static styles = css`
ha-textarea {
display: block;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-template": HaTemplateCondition;
}
}

View File

@ -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`
<ha-formfield
.label=${this.hass!.localize(
"ui.panel.config.automation.editor.conditions.type.time.type_value"
)}
>
<ha-radio
@change=${this._handleModeChanged}
name="mode_after"
value="value"
?checked=${!inputModeAfter}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass!.localize(
"ui.panel.config.automation.editor.conditions.type.time.type_input"
)}
>
<ha-radio
@change=${this._handleModeChanged}
name="mode_after"
value="input"
?checked=${inputModeAfter}
></ha-radio>
</ha-formfield>
${inputModeAfter
? html`<ha-entity-picker
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.time.after"
)}
.includeDomains=${includeDomains}
.name=${"after"}
.value=${after?.startsWith("input_datetime.") ? after : ""}
@value-changed=${this._valueChanged}
<ha-form
.hass=${this.hass}
allow-custom-entity
></ha-entity-picker>`
: html`<ha-time-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.time.after"
)}
.locale=${this.hass.locale}
.name=${"after"}
.value=${after?.startsWith("input_datetime.") ? "" : after}
.data=${data}
.schema=${schema}
@value-changed=${this._valueChanged}
></ha-time-input>`}
<ha-formfield
.label=${this.hass!.localize(
"ui.panel.config.automation.editor.conditions.type.time.type_value"
)}
>
<ha-radio
@change=${this._handleModeChanged}
name="mode_before"
value="value"
?checked=${!inputModeBefore}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass!.localize(
"ui.panel.config.automation.editor.conditions.type.time.type_input"
)}
>
<ha-radio
@change=${this._handleModeChanged}
name="mode_before"
value="input"
?checked=${inputModeBefore}
></ha-radio>
</ha-formfield>
${inputModeBefore
? html`<ha-entity-picker
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.time.before"
)}
.includeDomains=${includeDomains}
.name=${"before"}
.value=${before?.startsWith("input_datetime.") ? before : ""}
@value-changed=${this._valueChanged}
.hass=${this.hass}
allow-custom-entity
></ha-entity-picker>`
: html`<ha-time-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.time.before"
)}
.name=${"before"}
.locale=${this.hass.locale}
.value=${before?.startsWith("input_datetime.") ? "" : before}
@value-changed=${this._valueChanged}
></ha-time-input>`}
${Object.keys(DAYS).map(
(day) => html`
<ha-formfield
alignEnd
spaceBetween
class="weekday-toggle"
.label=${this.hass!.localize(
`ui.panel.config.automation.editor.conditions.type.time.weekdays.${day}`
)}
.dir=${computeRTLDirection(this.hass!)}
>
<ha-switch
.day=${day}
.checked=${!weekday || weekday === day || weekday.includes(day)}
@change=${this._dayValueChanged}
>
</ha-switch>
</ha-formfield>
`
)}
.computeLabel=${this._computeLabelCallback}
></ha-form>
`;
}
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;
const newModeAfter = newValue.mode_after === "input";
const newModeBefore = newValue.mode_before === "input";
if (newModeAfter !== this._inputModeAfter) {
this._inputModeAfter = newModeAfter;
newValue.after = undefined;
}
private _dayValueChanged(ev: CustomEvent): void {
const daySwitch = ev.currentTarget as WeekdayHaSwitch;
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 (newModeBefore !== this._inputModeBefore) {
this._inputModeBefore = newModeBefore;
newValue.before = undefined;
}
if (daySwitch.checked) {
days.push(daySwitch.day);
} else {
days = days.filter((d) => d !== daySwitch.day);
Object.keys(newValue).forEach((key) =>
newValue[key] === undefined || newValue[key] === ""
? delete newValue[key]
: {}
);
fireEvent(this, "value-changed", { value: newValue });
}
days.sort((a: string, b: string) => DAYS[a] - DAYS[b]);
fireEvent(this, "value-changed", {
value: { ...this.condition, weekday: days },
});
}
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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -154,7 +154,7 @@ export class HaDeviceTrigger extends LitElement {
static styles = css`
ha-device-picker {
display: block;
margin-bottom: 8px;
margin-bottom: 24px;
}
`;
}

View File

@ -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) {

View File

@ -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 {

View File

@ -45,9 +45,10 @@ export class HaSunTrigger extends LitElement implements TriggerElement {
}
protected render() {
const schema = this._schema(this.hass.localize);
return html`
<ha-form
.schema=${this._schema(this.hass.localize)}
.schema=${schema}
.data=${this.trigger}
.hass=${this.hass}
.computeLabel=${this._computeLabelCallback}

View File

@ -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 { TemplateTrigger } from "../../../../../data/automation";
import { HomeAssistant } from "../../../../../types";
import type { TemplateTrigger } from "../../../../../data/automation";
import type { HomeAssistant } from "../../../../../types";
import { handleChangeEvent } from "../ha-automation-trigger-row";
@customElement("ha-automation-trigger-template")
export class HaTemplateTrigger extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public trigger!: TemplateTrigger;
@property({ attribute: false }) public trigger!: TemplateTrigger;
public static get defaultConfig() {
return { value_template: "" };
@ -18,19 +18,32 @@ export class HaTemplateTrigger extends LitElement {
protected render() {
const { value_template } = this.trigger;
return html`
<paper-textarea
<ha-textarea
name="value_template"
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.type.template.value_template"
)}
name="value_template"
.value=${value_template}
@value-changed=${this._valueChanged}
@input=${this._valueChanged}
dir="ltr"
></paper-textarea>
autogrow
></ha-textarea>
`;
}
private _valueChanged(ev: CustomEvent): void {
handleChangeEvent(this, ev);
}
static styles = css`
ha-textarea {
display: block;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-trigger-template": HaTemplateTrigger;
}
}

View File

@ -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`<ha-formfield
.label=${this.hass!.localize(
"ui.panel.config.automation.editor.triggers.type.time.type_value"
)}
>
<ha-radio
@change=${this._handleModeChanged}
name="mode"
value="value"
?checked=${!inputMode}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass!.localize(
"ui.panel.config.automation.editor.triggers.type.time.type_input"
)}
>
<ha-radio
@change=${this._handleModeChanged}
name="mode"
value="input"
?checked=${inputMode}
></ha-radio>
</ha-formfield>
const schema: HaFormSchema[] = this._schema(this.hass.localize, inputMode);
${inputMode
? html`<ha-entity-picker
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.type.time.at"
)}
.includeDomains=${includeDomains}
.name=${"at"}
.value=${at?.startsWith("input_datetime.") ||
at?.startsWith("sensor.")
? at
: ""}
@value-changed=${this._valueChanged}
const data = {
mode: "value",
...this.trigger,
};
return html`
<ha-form
.hass=${this.hass}
allow-custom-entity
></ha-entity-picker>`
: html`<ha-time-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.type.time.at"
)}
.name=${"at"}
.value=${at?.startsWith("input_datetime.") ||
at?.startsWith("sensor.")
? ""
: at}
.locale=${this.hass.locale}
.data=${data}
.schema=${schema}
@value-changed=${this._valueChanged}
></ha-time-input>`} `;
}
private _handleModeChanged(ev: Event) {
this._inputMode = (ev.target as any).value === "input";
.computeLabel=${this._computeLabelCallback}
></ha-form>
`;
}
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 {

View File

@ -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;
}
`;
}

View File

@ -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",