mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-09 09:27:46 +00:00
Automation editor tweaks (#6713)
Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
This commit is contained in:
parent
80224e6974
commit
de7ffb10cb
178
src/components/entity/ha-entity-attribute-picker.ts
Normal file
178
src/components/entity/ha-entity-attribute-picker.ts
Normal file
@ -0,0 +1,178 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@vaadin/vaadin-combo-box/theme/material/vaadin-combo-box-light";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
query,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { PolymerChangedEvent } from "../../polymer-types";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "../ha-icon-button";
|
||||
import "./state-badge";
|
||||
|
||||
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
|
||||
|
||||
const rowRenderer = (root: HTMLElement, _owner, model: { item: string }) => {
|
||||
if (!root.firstElementChild) {
|
||||
root.innerHTML = `
|
||||
<style>
|
||||
paper-item {
|
||||
margin: -10px;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
<paper-item></paper-item>
|
||||
`;
|
||||
}
|
||||
root.querySelector("paper-item")!.textContent = model.item;
|
||||
};
|
||||
|
||||
@customElement("ha-entity-attribute-picker")
|
||||
class HaEntityAttributePicker extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public entityId?: string;
|
||||
|
||||
@property({ type: Boolean }) public autofocus = false;
|
||||
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
||||
@property({ type: Boolean, attribute: "allow-custom-value" })
|
||||
public allowCustomValue;
|
||||
|
||||
@property() public label?: string;
|
||||
|
||||
@property() public value?: string;
|
||||
|
||||
@property({ type: Boolean }) private _opened = false;
|
||||
|
||||
@query("vaadin-combo-box-light") private _comboBox!: HTMLElement;
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues) {
|
||||
return !(!changedProps.has("_opened") && this._opened);
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
if (changedProps.has("_opened") && this._opened) {
|
||||
const state = this.entityId ? this.hass.states[this.entityId] : undefined;
|
||||
(this._comboBox as any).items = state
|
||||
? Object.keys(state.attributes)
|
||||
: [];
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<vaadin-combo-box-light
|
||||
.value=${this._value}
|
||||
.allowCustomValue=${this.allowCustomValue}
|
||||
.renderer=${rowRenderer}
|
||||
@opened-changed=${this._openedChanged}
|
||||
@value-changed=${this._valueChanged}
|
||||
>
|
||||
<paper-input
|
||||
.autofocus=${this.autofocus}
|
||||
.label=${this.label ??
|
||||
this.hass.localize(
|
||||
"ui.components.entity.entity-attribute-picker.attribute"
|
||||
)}
|
||||
.value=${this._value}
|
||||
.disabled=${this.disabled || !this.entityId}
|
||||
class="input"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
>
|
||||
${this.value
|
||||
? html`
|
||||
<ha-icon-button
|
||||
aria-label=${this.hass.localize(
|
||||
"ui.components.entity.entity-picker.clear"
|
||||
)}
|
||||
slot="suffix"
|
||||
class="clear-button"
|
||||
icon="hass:close"
|
||||
@click=${this._clearValue}
|
||||
no-ripple
|
||||
>
|
||||
Clear
|
||||
</ha-icon-button>
|
||||
`
|
||||
: ""}
|
||||
|
||||
<ha-icon-button
|
||||
aria-label=${this.hass.localize(
|
||||
"ui.components.entity.entity-attribute-picker.show_attributes"
|
||||
)}
|
||||
slot="suffix"
|
||||
class="toggle-button"
|
||||
.icon=${this._opened ? "hass:menu-up" : "hass:menu-down"}
|
||||
>
|
||||
Toggle
|
||||
</ha-icon-button>
|
||||
</paper-input>
|
||||
</vaadin-combo-box-light>
|
||||
`;
|
||||
}
|
||||
|
||||
private _clearValue(ev: Event) {
|
||||
ev.stopPropagation();
|
||||
this._setValue("");
|
||||
}
|
||||
|
||||
private get _value() {
|
||||
return this.value || "";
|
||||
}
|
||||
|
||||
private _openedChanged(ev: PolymerChangedEvent<boolean>) {
|
||||
this._opened = ev.detail.value;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: PolymerChangedEvent<string>) {
|
||||
const newValue = ev.detail.value;
|
||||
if (newValue !== this._value) {
|
||||
this._setValue(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
private _setValue(value: string) {
|
||||
this.value = value;
|
||||
setTimeout(() => {
|
||||
fireEvent(this, "value-changed", { value });
|
||||
fireEvent(this, "change");
|
||||
}, 0);
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
paper-input > ha-icon-button {
|
||||
--mdc-icon-button-size: 24px;
|
||||
padding: 0px 2px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-entity-attribute-picker": HaEntityAttributePicker;
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import "../ha-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
@ -20,6 +19,7 @@ import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { PolymerChangedEvent } from "../../polymer-types";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "../ha-icon-button";
|
||||
import "./state-badge";
|
||||
|
||||
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
|
||||
@ -95,6 +95,8 @@ class HaEntityPicker extends LitElement {
|
||||
|
||||
@query("vaadin-combo-box-light") private _comboBox!: HTMLElement;
|
||||
|
||||
private _initedStates = false;
|
||||
|
||||
private _getStates = memoizeOne(
|
||||
(
|
||||
_opened: boolean,
|
||||
@ -148,11 +150,18 @@ class HaEntityPicker extends LitElement {
|
||||
);
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues) {
|
||||
if (
|
||||
changedProps.has("value") ||
|
||||
changedProps.has("label") ||
|
||||
changedProps.has("disabled")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return !(!changedProps.has("_opened") && this._opened);
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
if (changedProps.has("_opened") && this._opened) {
|
||||
if (!this._initedStates || (changedProps.has("_opened") && this._opened)) {
|
||||
const states = this._getStates(
|
||||
this._opened,
|
||||
this.hass,
|
||||
@ -162,6 +171,7 @@ class HaEntityPicker extends LitElement {
|
||||
this.includeDeviceClasses
|
||||
);
|
||||
(this._comboBox as any).items = states;
|
||||
this._initedStates = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +179,6 @@ class HaEntityPicker extends LitElement {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<vaadin-combo-box-light
|
||||
item-value-path="entity_id"
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { navigate } from "../common/navigate";
|
||||
import { HomeAssistant, Context } from "../types";
|
||||
import { Context, HomeAssistant } from "../types";
|
||||
import { DeviceCondition, DeviceTrigger } from "./device_automation";
|
||||
import { Action } from "./script";
|
||||
|
||||
@ -15,6 +15,7 @@ export interface AutomationEntity extends HassEntityBase {
|
||||
}
|
||||
|
||||
export interface AutomationConfig {
|
||||
id?: string;
|
||||
alias: string;
|
||||
description: string;
|
||||
trigger: Trigger[];
|
||||
@ -32,7 +33,8 @@ export interface ForDict {
|
||||
|
||||
export interface StateTrigger {
|
||||
platform: "state";
|
||||
entity_id?: string;
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
from?: string | number;
|
||||
to?: string | number;
|
||||
for?: string | number | ForDict;
|
||||
@ -59,6 +61,7 @@ export interface HassTrigger {
|
||||
export interface NumericStateTrigger {
|
||||
platform: "numeric_state";
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
above?: number;
|
||||
below?: number;
|
||||
value_template?: string;
|
||||
@ -136,12 +139,14 @@ export interface LogicalCondition {
|
||||
export interface StateCondition {
|
||||
condition: "state";
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
state: string | number;
|
||||
}
|
||||
|
||||
export interface NumericStateCondition {
|
||||
condition: "numeric_state";
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
above?: number;
|
||||
below?: number;
|
||||
value_template?: string;
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
import { computeObjectId } from "../common/entity/compute_object_id";
|
||||
import { navigate } from "../common/navigate";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { Condition } from "./automation";
|
||||
import { Condition, Trigger } from "./automation";
|
||||
|
||||
export const MODES = ["single", "restart", "queued", "parallel"];
|
||||
export const MODES_MAX = ["queued", "parallel"];
|
||||
@ -56,6 +56,13 @@ export interface SceneAction {
|
||||
export interface WaitAction {
|
||||
wait_template: string;
|
||||
timeout?: number;
|
||||
continue_on_timeout?: boolean;
|
||||
}
|
||||
|
||||
export interface WaitForTriggerAction {
|
||||
wait_for_trigger: Trigger[];
|
||||
timeout?: number;
|
||||
continue_on_timeout?: boolean;
|
||||
}
|
||||
|
||||
export interface RepeatAction {
|
||||
@ -91,6 +98,7 @@ export type Action =
|
||||
| DelayAction
|
||||
| SceneAction
|
||||
| WaitAction
|
||||
| WaitForTriggerAction
|
||||
| RepeatAction
|
||||
| ChooseAction;
|
||||
|
||||
|
@ -5,19 +5,19 @@ import {
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
internalProperty,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import "../../components/ha-dialog";
|
||||
import "../../components/ha-switch";
|
||||
import { PolymerChangedEvent } from "../../polymer-types";
|
||||
import { haStyleDialog } from "../../resources/styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { DialogParams } from "./show-dialog-box";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
|
||||
@customElement("dialog-box")
|
||||
class DialogBox extends LitElement {
|
||||
@ -114,8 +114,8 @@ class DialogBox extends LitElement {
|
||||
}
|
||||
|
||||
private _dismiss(): void {
|
||||
if (this._params!.cancel) {
|
||||
this._params!.cancel();
|
||||
if (this._params?.cancel) {
|
||||
this._params.cancel();
|
||||
}
|
||||
this._close();
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import "@material/mwc-icon-button";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import { mdiDotsVertical, mdiArrowUp, mdiArrowDown } from "@mdi/js";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiArrowDown, mdiArrowUp, mdiDotsVertical } from "@mdi/js";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox";
|
||||
@ -12,29 +11,31 @@ import {
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
internalProperty,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import type { Action } from "../../../../data/script";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { handleStructError } from "../../../lovelace/common/structs/handle-errors";
|
||||
import "./types/ha-automation-action-choose";
|
||||
import "./types/ha-automation-action-condition";
|
||||
import "./types/ha-automation-action-delay";
|
||||
import "./types/ha-automation-action-device_id";
|
||||
import "./types/ha-automation-action-event";
|
||||
import "./types/ha-automation-action-repeat";
|
||||
import "./types/ha-automation-action-scene";
|
||||
import "./types/ha-automation-action-service";
|
||||
import "./types/ha-automation-action-wait_for_trigger";
|
||||
import "./types/ha-automation-action-wait_template";
|
||||
import "./types/ha-automation-action-repeat";
|
||||
import "./types/ha-automation-action-choose";
|
||||
import { handleStructError } from "../../../lovelace/common/structs/handle-errors";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
|
||||
const OPTIONS = [
|
||||
"condition",
|
||||
@ -44,6 +45,7 @@ const OPTIONS = [
|
||||
"scene",
|
||||
"service",
|
||||
"wait_template",
|
||||
"wait_for_trigger",
|
||||
"repeat",
|
||||
"choose",
|
||||
];
|
||||
@ -166,7 +168,7 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item disabled>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
@ -261,6 +263,7 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
this._switchYamlMode();
|
||||
break;
|
||||
case 1:
|
||||
fireEvent(this, "duplicate");
|
||||
break;
|
||||
case 2:
|
||||
this._onDelete();
|
||||
|
@ -28,6 +28,7 @@ export default class HaAutomationAction extends LitElement {
|
||||
.index=${idx}
|
||||
.totalActions=${this.actions.length}
|
||||
.action=${action}
|
||||
@duplicate=${this._duplicateAction}
|
||||
@move-action=${this._move}
|
||||
@value-changed=${this._actionChanged}
|
||||
.hass=${this.hass}
|
||||
@ -78,6 +79,14 @@ export default class HaAutomationAction extends LitElement {
|
||||
fireEvent(this, "value-changed", { value: actions });
|
||||
}
|
||||
|
||||
private _duplicateAction(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
fireEvent(this, "value-changed", {
|
||||
value: this.actions.concat(this.actions[index]),
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
ha-automation-action-row,
|
||||
|
@ -1,22 +1,21 @@
|
||||
import { mdiDelete } from "@mdi/js";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
LitElement,
|
||||
property,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import { html } from "lit-html";
|
||||
import { Action, ChooseAction } from "../../../../../data/script";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { ActionElement } from "../ha-automation-action-row";
|
||||
import "../../condition/ha-automation-condition-editor";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../ha-automation-action";
|
||||
import { Condition } from "../../../../../data/automation";
|
||||
import { Action, ChooseAction } from "../../../../../data/script";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { mdiDelete } from "@mdi/js";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../ha-automation-action";
|
||||
import { ActionElement } from "../ha-automation-action-row";
|
||||
|
||||
@customElement("ha-automation-action-choose")
|
||||
export class HaChooseAction extends LitElement implements ActionElement {
|
||||
|
@ -1,22 +1,21 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { customElement, LitElement, property, CSSResult } from "lit-element";
|
||||
import { html } from "lit-html";
|
||||
import {
|
||||
RepeatAction,
|
||||
Action,
|
||||
CountRepeat,
|
||||
WhileRepeat,
|
||||
UntilRepeat,
|
||||
} from "../../../../../data/script";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { ActionElement } from "../ha-automation-action-row";
|
||||
import "../../condition/ha-automation-condition-editor";
|
||||
import type { PaperListboxElement } from "@polymer/paper-listbox";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { CSSResult, customElement, LitElement, property } from "lit-element";
|
||||
import { html } from "lit-html";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../ha-automation-action";
|
||||
import { Condition } from "../../../../lovelace/common/validate-condition";
|
||||
import {
|
||||
Action,
|
||||
CountRepeat,
|
||||
RepeatAction,
|
||||
UntilRepeat,
|
||||
WhileRepeat,
|
||||
} from "../../../../../data/script";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { Condition } from "../../../../lovelace/common/validate-condition";
|
||||
import "../ha-automation-action";
|
||||
import { ActionElement } from "../ha-automation-action-row";
|
||||
|
||||
const OPTIONS = ["count", "while", "until"];
|
||||
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
} from "lit-element";
|
||||
import { html } from "lit-html";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { any, assert, object, optional, string } from "superstruct";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../../../common/entity/compute_domain";
|
||||
import { computeObjectId } from "../../../../../common/entity/compute_object_id";
|
||||
@ -18,14 +19,13 @@ import type { HaYamlEditor } from "../../../../../components/ha-yaml-editor";
|
||||
import { ServiceAction } from "../../../../../data/script";
|
||||
import type { PolymerChangedEvent } from "../../../../../polymer-types";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { ActionElement, handleChangeEvent } from "../ha-automation-action-row";
|
||||
import { assert, optional, object, string } from "superstruct";
|
||||
import { EntityId } from "../../../../lovelace/common/structs/is-entity-id";
|
||||
import { ActionElement, handleChangeEvent } from "../ha-automation-action-row";
|
||||
|
||||
const actionStruct = object({
|
||||
service: optional(string()),
|
||||
entity_id: optional(EntityId),
|
||||
data: optional(object()),
|
||||
data: optional(any()),
|
||||
});
|
||||
|
||||
@customElement("ha-automation-action-service")
|
||||
|
@ -0,0 +1,70 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { customElement, LitElement, property } from "lit-element";
|
||||
import { html } from "lit-html";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-formfield";
|
||||
import { WaitForTriggerAction } from "../../../../../data/script";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../trigger/ha-automation-trigger";
|
||||
import { ActionElement, handleChangeEvent } from "../ha-automation-action-row";
|
||||
|
||||
@customElement("ha-automation-action-wait_for_trigger")
|
||||
export class HaWaitForTriggerAction extends LitElement
|
||||
implements ActionElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public action!: WaitForTriggerAction;
|
||||
|
||||
public static get defaultConfig() {
|
||||
return { wait_for_trigger: [], timeout: "" };
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { wait_for_trigger, continue_on_timeout, timeout } = this.action;
|
||||
|
||||
return html`
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.wait_for_trigger.timeout"
|
||||
)}
|
||||
.name=${"timeout"}
|
||||
.value=${timeout}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
<br />
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.wait_for_trigger.timeout"
|
||||
)}
|
||||
>
|
||||
<ha-switch
|
||||
.checked=${continue_on_timeout}
|
||||
@change=${this._continueChanged}
|
||||
></ha-switch>
|
||||
</ha-formfield>
|
||||
<ha-automation-trigger
|
||||
.triggers=${wait_for_trigger}
|
||||
.hass=${this.hass}
|
||||
.name=${"wait_for_trigger"}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-automation-trigger>
|
||||
`;
|
||||
}
|
||||
|
||||
private _continueChanged(ev) {
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.action, continue_on_timeout: ev.target.checked },
|
||||
});
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
handleChangeEvent(this, ev);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-action-wait_for_trigger": HaWaitForTriggerAction;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { customElement, LitElement, property } from "lit-element";
|
||||
import { html } from "lit-html";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { WaitAction } from "../../../../../data/script";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { ActionElement, handleChangeEvent } from "../ha-automation-action-row";
|
||||
@ -13,11 +14,11 @@ export class HaWaitAction extends LitElement implements ActionElement {
|
||||
@property() public action!: WaitAction;
|
||||
|
||||
public static get defaultConfig() {
|
||||
return { wait_template: "", timeout: "" };
|
||||
return { wait_template: "" };
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { wait_template, timeout } = this.action;
|
||||
const { wait_template, timeout, continue_on_timeout } = this.action;
|
||||
|
||||
return html`
|
||||
<paper-textarea
|
||||
@ -37,9 +38,24 @@ export class HaWaitAction extends LitElement implements ActionElement {
|
||||
.value=${timeout}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
<br />
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize("ui.panel.config.automation.editor.actions.type.wait_template.continue_timeout")}
|
||||
>
|
||||
<ha-switch
|
||||
.checked=${continue_on_timeout}
|
||||
@change=${this._continueChanged}
|
||||
></ha-switch>
|
||||
</ha-formfield>
|
||||
`;
|
||||
}
|
||||
|
||||
private _continueChanged(ev) {
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.action, continue_on_timeout: ev.target.checked },
|
||||
});
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
handleChangeEvent(this, ev);
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
import "../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
internalProperty,
|
||||
} from "lit-element";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import { Condition } from "../../../../data/automation";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "./ha-automation-condition-editor";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
|
||||
export interface ConditionElement extends LitElement {
|
||||
condition: Condition;
|
||||
@ -81,7 +81,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item disabled>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
@ -109,6 +109,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
this._switchYamlMode();
|
||||
break;
|
||||
case 1:
|
||||
fireEvent(this, "duplicate");
|
||||
break;
|
||||
case 2:
|
||||
this._onDelete();
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-card";
|
||||
@ -20,13 +21,43 @@ export default class HaAutomationCondition extends LitElement {
|
||||
|
||||
@property() public conditions!: Condition[];
|
||||
|
||||
protected updated(changedProperties: PropertyValues) {
|
||||
if (!changedProperties.has("conditions")) {
|
||||
return;
|
||||
}
|
||||
let updatedConditions: Condition[] | undefined;
|
||||
if (!Array.isArray(this.conditions)) {
|
||||
updatedConditions = [this.conditions];
|
||||
}
|
||||
|
||||
(updatedConditions || this.conditions).forEach((condition, index) => {
|
||||
if (typeof condition === "string") {
|
||||
updatedConditions = updatedConditions || [...this.conditions];
|
||||
updatedConditions[index] = {
|
||||
condition: "template",
|
||||
value_template: condition,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
if (updatedConditions) {
|
||||
fireEvent(this, "value-changed", {
|
||||
value: updatedConditions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!Array.isArray(this.conditions)) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
${this.conditions.map(
|
||||
(cond, idx) => html`
|
||||
<ha-automation-condition-row
|
||||
.index=${idx}
|
||||
.condition=${cond}
|
||||
@duplicate=${this._duplicateCondition}
|
||||
@value-changed=${this._conditionChanged}
|
||||
.hass=${this.hass}
|
||||
></ha-automation-condition-row>
|
||||
@ -68,6 +99,14 @@ export default class HaAutomationCondition extends LitElement {
|
||||
fireEvent(this, "value-changed", { value: conditions });
|
||||
}
|
||||
|
||||
private _duplicateCondition(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
fireEvent(this, "value-changed", {
|
||||
value: this.conditions.concat(this.conditions[index]),
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
ha-automation-condition-row,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { NumericStateCondition } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
@ -19,16 +18,34 @@ export default class HaNumericStateCondition extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { value_template, entity_id, below, above } = this.condition;
|
||||
public render() {
|
||||
const {
|
||||
value_template,
|
||||
entity_id,
|
||||
attribute,
|
||||
below,
|
||||
above,
|
||||
} = this.condition;
|
||||
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
.value="${entity_id}"
|
||||
@value-changed="${this._entityPicked}"
|
||||
.value=${entity_id}
|
||||
.name=${"entity_id"}
|
||||
@value-changed=${this._valueChanged}
|
||||
.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"
|
||||
)}
|
||||
@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"
|
||||
@ -60,13 +77,6 @@ export default class HaNumericStateCondition extends LitElement {
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
handleChangeEvent(this, ev);
|
||||
}
|
||||
|
||||
private _entityPicked(ev) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.condition, entity_id: ev.detail.value },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -1,9 +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-attribute-picker";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { StateCondition } from "../../../../../data/automation";
|
||||
import { PolymerChangedEvent } from "../../../../../polymer-types";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import {
|
||||
ConditionElement,
|
||||
@ -21,15 +20,27 @@ export class HaStateCondition extends LitElement implements ConditionElement {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { entity_id, state } = this.condition;
|
||||
const { entity_id, attribute, state } = this.condition;
|
||||
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
.value=${entity_id}
|
||||
@value-changed=${this._entityPicked}
|
||||
.name=${"entity_id"}
|
||||
@value-changed=${this._valueChanged}
|
||||
.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"
|
||||
)}
|
||||
@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"
|
||||
@ -44,13 +55,6 @@ export class HaStateCondition extends LitElement implements ConditionElement {
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
handleChangeEvent(this, ev);
|
||||
}
|
||||
|
||||
private _entityPicked(ev: PolymerChangedEvent<string>) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.condition, entity_id: ev.detail.value },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -1,5 +1,14 @@
|
||||
import { Radio } from "@material/mwc-radio";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import "../../../../../components/ha-formfield";
|
||||
import "../../../../../components/ha-radio";
|
||||
import { TimeCondition } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import {
|
||||
@ -7,38 +16,130 @@ import {
|
||||
handleChangeEvent,
|
||||
} from "../ha-automation-condition-row";
|
||||
|
||||
const includeDomains = ["input_datetime"];
|
||||
|
||||
@customElement("ha-automation-condition-time")
|
||||
export class HaTimeCondition extends LitElement implements ConditionElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public condition!: TimeCondition;
|
||||
|
||||
@internalProperty() private _inputModeBefore?: boolean;
|
||||
|
||||
@internalProperty() private _inputModeAfter?: boolean;
|
||||
|
||||
public static get defaultConfig() {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { after, before } = this.condition;
|
||||
|
||||
const inputModeBefore =
|
||||
this._inputModeBefore ?? before?.startsWith("input_datetime.");
|
||||
const inputModeAfter =
|
||||
this._inputModeAfter ?? after?.startsWith("input_datetime.");
|
||||
|
||||
return html`
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.time.after"
|
||||
<ha-formfield
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.time.type_value"
|
||||
)}
|
||||
name="after"
|
||||
.value=${after}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.time.before"
|
||||
>
|
||||
<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"
|
||||
)}
|
||||
name="before"
|
||||
.value=${before}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-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}
|
||||
.hass=${this.hass}
|
||||
></ha-entity-picker>`
|
||||
: html`<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.time.after"
|
||||
)}
|
||||
name="after"
|
||||
.value=${after?.startsWith("input_datetime.") ? "" : after}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-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}
|
||||
></ha-entity-picker>`
|
||||
: html`<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.time.before"
|
||||
)}
|
||||
name="before"
|
||||
.value=${before?.startsWith("input_datetime.") ? "" : before}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>`}
|
||||
`;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1,28 +1,32 @@
|
||||
import "@material/mwc-fab";
|
||||
import { mdiContentDuplicate, mdiContentSave, mdiDelete } from "@mdi/js";
|
||||
import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import "../../../components/ha-icon-button";
|
||||
import { PaperListboxElement } from "@polymer/paper-listbox";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
internalProperty,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "@material/mwc-fab";
|
||||
import {
|
||||
AutomationConfig,
|
||||
AutomationEntity,
|
||||
Condition,
|
||||
deleteAutomation,
|
||||
getAutomationEditorInitData,
|
||||
showAutomationEditor,
|
||||
Trigger,
|
||||
triggerAutomation,
|
||||
} from "../../../data/automation";
|
||||
@ -42,9 +46,6 @@ import { HaDeviceAction } from "./action/types/ha-automation-action-device_id";
|
||||
import "./condition/ha-automation-condition";
|
||||
import "./trigger/ha-automation-trigger";
|
||||
import { HaDeviceTrigger } from "./trigger/types/ha-automation-trigger-device";
|
||||
import { mdiContentSave } from "@mdi/js";
|
||||
import { PaperListboxElement } from "@polymer/paper-listbox";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
const MODES = ["single", "restart", "queued", "parallel"];
|
||||
const MODES_MAX = ["queued", "parallel"];
|
||||
@ -53,6 +54,7 @@ declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"ui-mode-not-available": Error;
|
||||
duplicate: undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,14 +94,24 @@ export class HaAutomationEditor extends LitElement {
|
||||
${!this.automationId
|
||||
? ""
|
||||
: html`
|
||||
<ha-icon-button
|
||||
<mwc-icon-button
|
||||
slot="toolbar-icon"
|
||||
title="${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.duplicate_automation"
|
||||
)}"
|
||||
@click=${this._duplicate}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiContentDuplicate}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<mwc-icon-button
|
||||
slot="toolbar-icon"
|
||||
title="${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.delete_automation"
|
||||
)}"
|
||||
icon="hass:delete"
|
||||
@click=${this._deleteConfirm}
|
||||
></ha-icon-button>
|
||||
>
|
||||
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
`}
|
||||
${this._config
|
||||
? html`
|
||||
@ -473,6 +485,31 @@ export class HaAutomationEditor extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _duplicate() {
|
||||
if (this._dirty) {
|
||||
if (
|
||||
!(await showConfirmationDialog(this, {
|
||||
text: this.hass!.localize(
|
||||
"ui.panel.config.automation.editor.unsaved_confirm"
|
||||
),
|
||||
confirmText: this.hass!.localize("ui.common.yes"),
|
||||
dismissText: this.hass!.localize("ui.common.no"),
|
||||
}))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Wait for dialog to complate closing
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
showAutomationEditor(this, {
|
||||
...this._config,
|
||||
id: undefined,
|
||||
alias: `${this._config?.alias} (${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.duplicate"
|
||||
)})`,
|
||||
});
|
||||
}
|
||||
|
||||
private async _deleteConfirm() {
|
||||
showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
|
@ -1,25 +1,27 @@
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
internalProperty,
|
||||
} from "lit-element";
|
||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import type { Trigger } from "../../../../data/automation";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import "./types/ha-automation-trigger-device";
|
||||
import "./types/ha-automation-trigger-event";
|
||||
@ -29,14 +31,12 @@ import "./types/ha-automation-trigger-mqtt";
|
||||
import "./types/ha-automation-trigger-numeric_state";
|
||||
import "./types/ha-automation-trigger-state";
|
||||
import "./types/ha-automation-trigger-sun";
|
||||
import "./types/ha-automation-trigger-tag";
|
||||
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 "./types/ha-automation-trigger-tag";
|
||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
|
||||
const OPTIONS = [
|
||||
"device",
|
||||
@ -113,7 +113,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item disabled>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
@ -183,6 +183,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
this._switchYamlMode();
|
||||
break;
|
||||
case 1:
|
||||
fireEvent(this, "duplicate");
|
||||
break;
|
||||
case 2:
|
||||
this._onDelete();
|
||||
|
@ -27,6 +27,7 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
<ha-automation-trigger-row
|
||||
.index=${idx}
|
||||
.trigger=${trg}
|
||||
@duplicate=${this._duplicateTrigger}
|
||||
@value-changed=${this._triggerChanged}
|
||||
.hass=${this.hass}
|
||||
></ha-automation-trigger-row>
|
||||
@ -68,6 +69,14 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
fireEvent(this, "value-changed", { value: triggers });
|
||||
}
|
||||
|
||||
private _duplicateTrigger(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
fireEvent(this, "value-changed", {
|
||||
value: this.triggers.concat(this.triggers[index]),
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
ha-automation-trigger-row,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { ForDict, NumericStateTrigger } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
@ -19,8 +18,8 @@ export default class HaNumericStateTrigger extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { value_template, entity_id, below, above } = this.trigger;
|
||||
public render() {
|
||||
const { value_template, entity_id, attribute, below, above } = this.trigger;
|
||||
let trgFor = this.trigger.for;
|
||||
|
||||
if (
|
||||
@ -41,10 +40,22 @@ export default class HaNumericStateTrigger extends LitElement {
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
.value="${entity_id}"
|
||||
@value-changed="${this._entityPicked}"
|
||||
@value-changed="${this._valueChanged}"
|
||||
.name=${"entity_id"}
|
||||
.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"
|
||||
)}
|
||||
@value-changed=${this._valueChanged}
|
||||
allow-custom-value
|
||||
></ha-entity-attribute-picker>
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.numeric_state.above"
|
||||
@ -84,13 +95,6 @@ export default class HaNumericStateTrigger extends LitElement {
|
||||
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 {
|
||||
|
@ -1,9 +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-attribute-picker";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { ForDict, StateTrigger } from "../../../../../data/automation";
|
||||
import { PolymerChangedEvent } from "../../../../../polymer-types";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import {
|
||||
handleChangeEvent,
|
||||
@ -21,7 +20,7 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { entity_id, to, from } = this.trigger;
|
||||
const { entity_id, attribute, to, from } = this.trigger;
|
||||
let trgFor = this.trigger.for;
|
||||
|
||||
if (
|
||||
@ -43,10 +42,22 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
.value=${entity_id}
|
||||
@value-changed=${this._entityPicked}
|
||||
@value-changed=${this._valueChanged}
|
||||
.name=${"entity_id"}
|
||||
.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"
|
||||
)}
|
||||
@value-changed=${this._valueChanged}
|
||||
allow-custom-value
|
||||
></ha-entity-attribute-picker>
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.state.from"
|
||||
@ -77,13 +88,6 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
handleChangeEvent(this, ev);
|
||||
}
|
||||
|
||||
private _entityPicked(ev: PolymerChangedEvent<string>) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.trigger, entity_id: ev.detail.value },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -1,5 +1,14 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../../components/ha-formfield";
|
||||
import "../../../../../components/ha-radio";
|
||||
import { TimeTrigger } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import {
|
||||
@ -7,31 +16,81 @@ import {
|
||||
TriggerElement,
|
||||
} from "../ha-automation-trigger-row";
|
||||
|
||||
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;
|
||||
|
||||
@internalProperty() private _inputMode?: boolean;
|
||||
|
||||
public static get defaultConfig() {
|
||||
return { at: "" };
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { at } = this.trigger;
|
||||
const inputMode = this._inputMode ?? at?.startsWith("input_datetime.");
|
||||
return html`
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time.at"
|
||||
<ha-formfield
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time.type_value"
|
||||
)}
|
||||
name="at"
|
||||
.value=${at}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
>
|
||||
<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>
|
||||
${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 : ""}
|
||||
@value-changed=${this._valueChanged}
|
||||
.hass=${this.hass}
|
||||
></ha-entity-picker>`
|
||||
: html`<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time.at"
|
||||
)}
|
||||
name="at"
|
||||
.value=${at?.startsWith("input_datetime.") ? "" : at}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>`}
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleModeChanged(ev: Event) {
|
||||
this._inputMode = (ev.target as any).value === "input";
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
handleChangeEvent(this, ev);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-trigger-time": HaTimeTrigger;
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,15 @@ import "@polymer/paper-input/paper-input";
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
internalProperty,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { assert, object, optional, string } from "superstruct";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stateIcon } from "../../../../common/entity/state_icon";
|
||||
import "../../../../components/entity/ha-entity-attribute-picker";
|
||||
import "../../../../components/ha-icon-input";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { EntityCardConfig } from "../../cards/types";
|
||||
@ -19,7 +21,6 @@ import { headerFooterConfigStructs } from "../../header-footer/types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { string, object, optional, assert } from "superstruct";
|
||||
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
@ -113,7 +114,9 @@ export class HuiEntityCardEditor extends LitElement
|
||||
></ha-icon-input>
|
||||
</div>
|
||||
<div class="side-by-side">
|
||||
<paper-input
|
||||
<ha-entity-attribute-picker
|
||||
.hass=${this.hass}
|
||||
.entityId=${this._entity}
|
||||
.label="${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.generic.attribute"
|
||||
)} (${this.hass.localize(
|
||||
@ -122,7 +125,7 @@ export class HuiEntityCardEditor extends LitElement
|
||||
.value=${this._attribute}
|
||||
.configValue=${"attribute"}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
></ha-entity-attribute-picker>
|
||||
<paper-input
|
||||
.label="${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.generic.unit"
|
||||
|
@ -1,14 +1,14 @@
|
||||
/* eslint-disable no-console */
|
||||
import { UpdatingElement } from "lit-element";
|
||||
import { HASSDomEvent } from "../common/dom/fire_event";
|
||||
import {
|
||||
closeDialog,
|
||||
showDialog,
|
||||
DialogState,
|
||||
DialogClosedParams,
|
||||
DialogState,
|
||||
showDialog,
|
||||
} from "../dialogs/make-dialog-manager";
|
||||
import { Constructor } from "../types";
|
||||
import { HASSDomEvent } from "../common/dom/fire_event";
|
||||
import { UpdatingElement } from "lit-element";
|
||||
import { ProvideHassElement } from "../mixins/provide-hass-lit-mixin";
|
||||
import { Constructor } from "../types";
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
|
@ -286,6 +286,10 @@
|
||||
"entity": "Entity",
|
||||
"clear": "Clear",
|
||||
"show_entities": "Show entities"
|
||||
},
|
||||
"entity-attribute-picker": {
|
||||
"attribute": "Attribute",
|
||||
"show_attributes": "Show attributes"
|
||||
}
|
||||
},
|
||||
"device-picker": {
|
||||
@ -915,6 +919,8 @@
|
||||
"show_info_automation": "Show info about automation",
|
||||
"delete_automation": "Delete automation",
|
||||
"delete_confirm": "Are you sure you want to delete this automation?",
|
||||
"duplicate_automation": "Duplicate automation",
|
||||
"duplicate": "Duplicate",
|
||||
"headers": {
|
||||
"name": "Name"
|
||||
}
|
||||
@ -985,6 +991,7 @@
|
||||
},
|
||||
"state": {
|
||||
"label": "State",
|
||||
"attribute": "Attribute (Optional)",
|
||||
"from": "From",
|
||||
"for": "For",
|
||||
"to": "To"
|
||||
@ -1021,8 +1028,10 @@
|
||||
"value_template": "Value template"
|
||||
},
|
||||
"time": {
|
||||
"type_value": "Fixed time",
|
||||
"type_input": "Value of a date/time helper",
|
||||
"label": "Time",
|
||||
"at": "At"
|
||||
"at": "At time"
|
||||
},
|
||||
"time_pattern": {
|
||||
"label": "Time Pattern",
|
||||
@ -1098,6 +1107,8 @@
|
||||
"value_template": "[%key:ui::panel::config::automation::editor::triggers::type::template::value_template%]"
|
||||
},
|
||||
"time": {
|
||||
"type_value": "[%key:ui::panel::config::automation::editor::triggers::type::time::type_value%]",
|
||||
"type_input": "[%key:ui::panel::config::automation::editor::triggers::type::time::type_input%]",
|
||||
"label": "[%key:ui::panel::config::automation::editor::triggers::type::time::label%]",
|
||||
"after": "After",
|
||||
"before": "Before"
|
||||
@ -1132,7 +1143,13 @@
|
||||
"wait_template": {
|
||||
"label": "Wait",
|
||||
"wait_template": "Wait Template",
|
||||
"timeout": "Timeout (optional)"
|
||||
"timeout": "Timeout (optional)",
|
||||
"continue_timeout": "Continue on timeout"
|
||||
},
|
||||
"wait_for_trigger": {
|
||||
"label": "Wait for trigger",
|
||||
"timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::timeout%]",
|
||||
"continue_timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::continue_timeout%]"
|
||||
},
|
||||
"condition": {
|
||||
"label": "Condition"
|
||||
|
Loading…
x
Reference in New Issue
Block a user