mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Collapse automation/script editor sections by default (#13390)
This commit is contained in:
parent
d7b888f761
commit
47b820d28f
5
gallery/src/pages/components/ha-expansion-panel.markdown
Normal file
5
gallery/src/pages/components/ha-expansion-panel.markdown
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
title: Expansion Panel
|
||||||
|
---
|
||||||
|
|
||||||
|
Expansion panel following all the ARIA guidelines.
|
157
gallery/src/pages/components/ha-expansion-panel.ts
Normal file
157
gallery/src/pages/components/ha-expansion-panel.ts
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import { mdiPacMan } from "@mdi/js";
|
||||||
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/components/ha-expansion-panel";
|
||||||
|
import "../../../../src/components/ha-markdown";
|
||||||
|
import "../../components/demo-black-white-row";
|
||||||
|
import { LONG_TEXT } from "../../data/text";
|
||||||
|
|
||||||
|
const SHORT_TEXT = LONG_TEXT.substring(0, 113);
|
||||||
|
|
||||||
|
const SAMPLES: {
|
||||||
|
template: (slot: string, leftChevron: boolean) => TemplateResult;
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
template(slot, leftChevron) {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel
|
||||||
|
slot=${slot}
|
||||||
|
.leftChevron=${leftChevron}
|
||||||
|
header="Attr header"
|
||||||
|
>
|
||||||
|
${SHORT_TEXT}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template(slot, leftChevron) {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel
|
||||||
|
slot=${slot}
|
||||||
|
.leftChevron=${leftChevron}
|
||||||
|
header="Attr header"
|
||||||
|
secondary="Attr secondary"
|
||||||
|
>
|
||||||
|
${SHORT_TEXT}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template(slot, leftChevron) {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel
|
||||||
|
slot=${slot}
|
||||||
|
.leftChevron=${leftChevron}
|
||||||
|
.header=${"Prop header"}
|
||||||
|
>
|
||||||
|
${SHORT_TEXT}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template(slot, leftChevron) {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel
|
||||||
|
slot=${slot}
|
||||||
|
.leftChevron=${leftChevron}
|
||||||
|
.header=${"Prop header"}
|
||||||
|
.secondary=${"Prop secondary"}
|
||||||
|
>
|
||||||
|
${SHORT_TEXT}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template(slot, leftChevron) {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel
|
||||||
|
slot=${slot}
|
||||||
|
.leftChevron=${leftChevron}
|
||||||
|
.header=${"Prop header"}
|
||||||
|
>
|
||||||
|
<span slot="secondary">Slot Secondary</span>
|
||||||
|
${SHORT_TEXT}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template(slot, leftChevron) {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel slot=${slot} .leftChevron=${leftChevron}>
|
||||||
|
<span slot="header">Slot header</span>
|
||||||
|
${SHORT_TEXT}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template(slot, leftChevron) {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel slot=${slot} .leftChevron=${leftChevron}>
|
||||||
|
<span slot="header">Slot header with actions</span>
|
||||||
|
<ha-icon-button
|
||||||
|
slot="icons"
|
||||||
|
label="Some Action"
|
||||||
|
.path=${mdiPacMan}
|
||||||
|
></ha-icon-button>
|
||||||
|
${SHORT_TEXT}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template(slot, leftChevron) {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel
|
||||||
|
slot=${slot}
|
||||||
|
.leftChevron=${leftChevron}
|
||||||
|
header="Attr Header with actions"
|
||||||
|
>
|
||||||
|
<ha-icon-button
|
||||||
|
slot="icons"
|
||||||
|
label="Some Action"
|
||||||
|
.path=${mdiPacMan}
|
||||||
|
></ha-icon-button>
|
||||||
|
${SHORT_TEXT}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("demo-components-ha-expansion-panel")
|
||||||
|
export class DemoHaExpansionPanel extends LitElement {
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${SAMPLES.map(
|
||||||
|
(sample) => html`
|
||||||
|
<demo-black-white-row>
|
||||||
|
${["light", "dark"].map((slot) =>
|
||||||
|
sample.template(slot, slot === "dark")
|
||||||
|
)}
|
||||||
|
</demo-black-white-row>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-expansion-panel {
|
||||||
|
margin: -16px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-components-ha-expansion-panel": DemoHaExpansionPanel;
|
||||||
|
}
|
||||||
|
}
|
@ -172,8 +172,7 @@ export abstract class HaDeviceAutomationPicker<
|
|||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
ha-select {
|
ha-select {
|
||||||
width: 100%;
|
display: block;
|
||||||
margin-top: 4px;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ class HaExpansionPanel extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean, reflect: true }) outlined = false;
|
@property({ type: Boolean, reflect: true }) outlined = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean, reflect: true }) leftChevron = false;
|
||||||
|
|
||||||
@property() header?: string;
|
@property() header?: string;
|
||||||
|
|
||||||
@property() secondary?: string;
|
@property() secondary?: string;
|
||||||
@ -29,23 +31,42 @@ class HaExpansionPanel extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div class="top">
|
||||||
id="summary"
|
<div
|
||||||
@click=${this._toggleContainer}
|
id="summary"
|
||||||
@keydown=${this._toggleContainer}
|
@click=${this._toggleContainer}
|
||||||
role="button"
|
@keydown=${this._toggleContainer}
|
||||||
tabindex="0"
|
@focus=${this._focusChanged}
|
||||||
aria-expanded=${this.expanded}
|
@blur=${this._focusChanged}
|
||||||
aria-controls="sect1"
|
role="button"
|
||||||
>
|
tabindex="0"
|
||||||
<slot class="header" name="header">
|
aria-expanded=${this.expanded}
|
||||||
${this.header}
|
aria-controls="sect1"
|
||||||
<slot class="secondary" name="secondary">${this.secondary}</slot>
|
>
|
||||||
</slot>
|
${this.leftChevron
|
||||||
<ha-svg-icon
|
? html`
|
||||||
.path=${mdiChevronDown}
|
<ha-svg-icon
|
||||||
class="summary-icon ${classMap({ expanded: this.expanded })}"
|
.path=${mdiChevronDown}
|
||||||
></ha-svg-icon>
|
class="summary-icon ${classMap({ expanded: this.expanded })}"
|
||||||
|
></ha-svg-icon>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<slot name="header">
|
||||||
|
<div class="header">
|
||||||
|
${this.header}
|
||||||
|
<slot class="secondary" name="secondary">${this.secondary}</slot>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
${!this.leftChevron
|
||||||
|
? html`
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${mdiChevronDown}
|
||||||
|
class="summary-icon ${classMap({ expanded: this.expanded })}"
|
||||||
|
></ha-svg-icon>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
<slot name="icons"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="container ${classMap({ expanded: this.expanded })}"
|
class="container ${classMap({ expanded: this.expanded })}"
|
||||||
@ -61,6 +82,7 @@ class HaExpansionPanel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected willUpdate(changedProps: PropertyValues) {
|
protected willUpdate(changedProps: PropertyValues) {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
if (changedProps.has("expanded") && this.expanded) {
|
if (changedProps.has("expanded") && this.expanded) {
|
||||||
this._showContent = this.expanded;
|
this._showContent = this.expanded;
|
||||||
}
|
}
|
||||||
@ -72,6 +94,9 @@ class HaExpansionPanel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _toggleContainer(ev): Promise<void> {
|
private async _toggleContainer(ev): Promise<void> {
|
||||||
|
if (ev.defaultPrevented) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ev.type === "keydown" && ev.key !== "Enter" && ev.key !== " ") {
|
if (ev.type === "keydown" && ev.key !== "Enter" && ev.key !== " ") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -98,12 +123,28 @@ class HaExpansionPanel extends LitElement {
|
|||||||
fireEvent(this, "expanded-changed", { expanded: this.expanded });
|
fireEvent(this, "expanded-changed", { expanded: this.expanded });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _focusChanged(ev) {
|
||||||
|
this.shadowRoot!.querySelector(".top")!.classList.toggle(
|
||||||
|
"focused",
|
||||||
|
ev.type === "focus"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top.focused {
|
||||||
|
background: var(--input-fill-color);
|
||||||
|
}
|
||||||
|
|
||||||
:host([outlined]) {
|
:host([outlined]) {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
@ -115,7 +156,17 @@ class HaExpansionPanel extends LitElement {
|
|||||||
border-radius: var(--ha-card-border-radius, 4px);
|
border-radius: var(--ha-card-border-radius, 4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.summary-icon {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([leftchevron]) .summary-icon {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
#summary {
|
#summary {
|
||||||
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: var(--expansion-panel-summary-padding, 0 8px);
|
padding: var(--expansion-panel-summary-padding, 0 8px);
|
||||||
min-height: 48px;
|
min-height: 48px;
|
||||||
@ -126,15 +177,8 @@ class HaExpansionPanel extends LitElement {
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#summary:focus {
|
|
||||||
background: var(--input-fill-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary-icon {
|
.summary-icon {
|
||||||
transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
margin-left: auto;
|
|
||||||
margin-inline-start: auto;
|
|
||||||
margin-inline-end: initial;
|
|
||||||
direction: var(--direction);
|
direction: var(--direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +186,11 @@ class HaExpansionPanel extends LitElement {
|
|||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header,
|
||||||
|
::slotted([slot="header"]) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
padding: var(--expansion-panel-content-padding, 0 8px);
|
padding: var(--expansion-panel-content-padding, 0 8px);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -153,10 +202,6 @@ class HaExpansionPanel extends LitElement {
|
|||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
.secondary {
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { html, LitElement } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
@ -48,6 +48,14 @@ export class HaTemplateSelector extends LitElement {
|
|||||||
}
|
}
|
||||||
fireEvent(this, "value-changed", { value });
|
fireEvent(this, "value-changed", { value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -230,7 +230,9 @@ export class HaServiceControl extends LitElement {
|
|||||||
@value-changed=${this._serviceChanged}
|
@value-changed=${this._serviceChanged}
|
||||||
></ha-service-picker>
|
></ha-service-picker>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<p>${serviceData?.description}</p>
|
${serviceData?.description
|
||||||
|
? html`<p>${serviceData?.description}</p>`
|
||||||
|
: ""}
|
||||||
${this._manifest
|
${this._manifest
|
||||||
? html` <a
|
? html` <a
|
||||||
href=${this._manifest.is_built_in
|
href=${this._manifest.is_built_in
|
||||||
|
16
src/data/action.ts
Normal file
16
src/data/action.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export const ACTION_TYPES = [
|
||||||
|
"condition",
|
||||||
|
"delay",
|
||||||
|
"event",
|
||||||
|
"play_media",
|
||||||
|
"activate_scene",
|
||||||
|
"service",
|
||||||
|
"wait_template",
|
||||||
|
"wait_for_trigger",
|
||||||
|
"repeat",
|
||||||
|
"choose",
|
||||||
|
"if",
|
||||||
|
"device_id",
|
||||||
|
"stop",
|
||||||
|
"parallel",
|
||||||
|
];
|
@ -1,7 +1,7 @@
|
|||||||
import { Condition, Trigger } from "./automation";
|
import { Condition, Trigger } from "./automation";
|
||||||
|
|
||||||
export const describeTrigger = (trigger: Trigger) =>
|
export const describeTrigger = (trigger: Trigger) =>
|
||||||
`${trigger.platform} trigger`;
|
`${trigger.platform || "Unknown"} trigger`;
|
||||||
|
|
||||||
export const describeCondition = (condition: Condition) => {
|
export const describeCondition = (condition: Condition) => {
|
||||||
if (condition.alias) {
|
if (condition.alias) {
|
||||||
|
15
src/data/condition.ts
Normal file
15
src/data/condition.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import type { Condition } from "./automation";
|
||||||
|
|
||||||
|
export const CONDITION_TYPES: Condition["condition"][] = [
|
||||||
|
"device",
|
||||||
|
"and",
|
||||||
|
"or",
|
||||||
|
"not",
|
||||||
|
"state",
|
||||||
|
"numeric_state",
|
||||||
|
"sun",
|
||||||
|
"template",
|
||||||
|
"time",
|
||||||
|
"trigger",
|
||||||
|
"zone",
|
||||||
|
];
|
@ -123,7 +123,7 @@ export const describeAction = <T extends ActionType>(
|
|||||||
? computeStateName(sceneStateObj)
|
? computeStateName(sceneStateObj)
|
||||||
: "scene" in config
|
: "scene" in config
|
||||||
? config.scene
|
? config.scene
|
||||||
: config.target?.entity_id || config.entity_id
|
: config.target?.entity_id || config.entity_id || ""
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
src/data/trigger.ts
Normal file
19
src/data/trigger.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import type { Trigger } from "./automation";
|
||||||
|
|
||||||
|
export const TRIGGER_TYPES: Trigger["platform"][] = [
|
||||||
|
"calendar",
|
||||||
|
"device",
|
||||||
|
"event",
|
||||||
|
"state",
|
||||||
|
"geo_location",
|
||||||
|
"homeassistant",
|
||||||
|
"mqtt",
|
||||||
|
"numeric_state",
|
||||||
|
"sun",
|
||||||
|
"tag",
|
||||||
|
"template",
|
||||||
|
"time",
|
||||||
|
"time_pattern",
|
||||||
|
"webhook",
|
||||||
|
"zone",
|
||||||
|
];
|
@ -3,21 +3,19 @@ import "@material/mwc-list/mwc-list-item";
|
|||||||
import { mdiArrowDown, mdiArrowUp, mdiDotsVertical } from "@mdi/js";
|
import { mdiArrowDown, mdiArrowUp, mdiDotsVertical } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { stringCompare } from "../../../../common/string/compare";
|
|
||||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||||
import { LocalizeFunc } from "../../../../common/translations/localize";
|
|
||||||
import "../../../../components/ha-alert";
|
import "../../../../components/ha-alert";
|
||||||
import "../../../../components/ha-button-menu";
|
import "../../../../components/ha-button-menu";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
import "../../../../components/ha-icon-button";
|
import "../../../../components/ha-icon-button";
|
||||||
import "../../../../components/ha-select";
|
import "../../../../components/ha-expansion-panel";
|
||||||
import type { HaSelect } from "../../../../components/ha-select";
|
|
||||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||||
import { validateConfig } from "../../../../data/config";
|
import { validateConfig } from "../../../../data/config";
|
||||||
import { Action, getActionType } from "../../../../data/script";
|
import { Action, getActionType } from "../../../../data/script";
|
||||||
|
import { describeAction } from "../../../../data/script_i18n";
|
||||||
import { callExecuteScript } from "../../../../data/service";
|
import { callExecuteScript } from "../../../../data/service";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
@ -40,23 +38,7 @@ import "./types/ha-automation-action-service";
|
|||||||
import "./types/ha-automation-action-stop";
|
import "./types/ha-automation-action-stop";
|
||||||
import "./types/ha-automation-action-wait_for_trigger";
|
import "./types/ha-automation-action-wait_for_trigger";
|
||||||
import "./types/ha-automation-action-wait_template";
|
import "./types/ha-automation-action-wait_template";
|
||||||
|
import { ACTION_TYPES } from "../../../../data/action";
|
||||||
const OPTIONS = [
|
|
||||||
"condition",
|
|
||||||
"delay",
|
|
||||||
"event",
|
|
||||||
"play_media",
|
|
||||||
"activate_scene",
|
|
||||||
"service",
|
|
||||||
"wait_template",
|
|
||||||
"wait_for_trigger",
|
|
||||||
"repeat",
|
|
||||||
"choose",
|
|
||||||
"if",
|
|
||||||
"device_id",
|
|
||||||
"stop",
|
|
||||||
"parallel",
|
|
||||||
];
|
|
||||||
|
|
||||||
const getType = (action: Action | undefined) => {
|
const getType = (action: Action | undefined) => {
|
||||||
if (!action) {
|
if (!action) {
|
||||||
@ -68,7 +50,7 @@ const getType = (action: Action | undefined) => {
|
|||||||
if (["and", "or", "not"].some((key) => key in action)) {
|
if (["and", "or", "not"].some((key) => key in action)) {
|
||||||
return "condition";
|
return "condition";
|
||||||
}
|
}
|
||||||
return OPTIONS.find((option) => option in action);
|
return ACTION_TYPES.find((option) => option in action);
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -104,6 +86,8 @@ export const handleChangeEvent = (element: ActionElement, ev: CustomEvent) => {
|
|||||||
fireEvent(element, "value-changed", { value: newAction });
|
fireEvent(element, "value-changed", { value: newAction });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const preventDefault = (ev) => ev.preventDefault();
|
||||||
|
|
||||||
@customElement("ha-automation-action-row")
|
@customElement("ha-automation-action-row")
|
||||||
export default class HaAutomationActionRow extends LitElement {
|
export default class HaAutomationActionRow extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -124,19 +108,6 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
|
|
||||||
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
||||||
|
|
||||||
private _processedTypes = memoizeOne(
|
|
||||||
(localize: LocalizeFunc): [string, string][] =>
|
|
||||||
OPTIONS.map(
|
|
||||||
(action) =>
|
|
||||||
[
|
|
||||||
action,
|
|
||||||
localize(
|
|
||||||
`ui.panel.config.automation.editor.actions.type.${action}.label`
|
|
||||||
),
|
|
||||||
] as [string, string]
|
|
||||||
).sort((a, b) => stringCompare(a[1], b[1]))
|
|
||||||
);
|
|
||||||
|
|
||||||
protected willUpdate(changedProperties: PropertyValues) {
|
protected willUpdate(changedProperties: PropertyValues) {
|
||||||
if (!changedProperties.has("action")) {
|
if (!changedProperties.has("action")) {
|
||||||
return;
|
return;
|
||||||
@ -172,10 +143,14 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</div>`
|
</div>`
|
||||||
: ""}
|
: ""}
|
||||||
<div class="card-menu">
|
<ha-expansion-panel
|
||||||
|
leftChevron
|
||||||
|
.header=${describeAction(this.hass, this.action)}
|
||||||
|
>
|
||||||
${this.index !== 0
|
${this.index !== 0
|
||||||
? html`
|
? html`
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
|
slot="icons"
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.move_up"
|
"ui.panel.config.automation.editor.move_up"
|
||||||
)}
|
)}
|
||||||
@ -187,6 +162,7 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
${this.index !== this.totalActions - 1
|
${this.index !== this.totalActions - 1
|
||||||
? html`
|
? html`
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
|
slot="icons"
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.move_down"
|
"ui.panel.config.automation.editor.move_down"
|
||||||
)}
|
)}
|
||||||
@ -195,7 +171,13 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
<ha-button-menu
|
||||||
|
slot="icons"
|
||||||
|
fixed
|
||||||
|
corner="BOTTOM_START"
|
||||||
|
@action=${this._handleAction}
|
||||||
|
@click=${preventDefault}
|
||||||
|
>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
.label=${this.hass.localize("ui.common.menu")}
|
.label=${this.hass.localize("ui.common.menu")}
|
||||||
@ -235,76 +217,65 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
</div>
|
<div
|
||||||
<div
|
class=${classMap({
|
||||||
class="card-content ${this.action.enabled === false
|
"card-content": true,
|
||||||
? "disabled"
|
disabled: this.action.enabled === false,
|
||||||
: ""}"
|
})}
|
||||||
>
|
>
|
||||||
${this._warnings
|
${this._warnings
|
||||||
? html`<ha-alert
|
? html`<ha-alert
|
||||||
alert-type="warning"
|
alert-type="warning"
|
||||||
.title=${this.hass.localize(
|
.title=${this.hass.localize(
|
||||||
"ui.errors.config.editor_not_supported"
|
"ui.errors.config.editor_not_supported"
|
||||||
)}
|
|
||||||
>
|
|
||||||
${this._warnings!.length > 0 && this._warnings![0] !== undefined
|
|
||||||
? html` <ul>
|
|
||||||
${this._warnings!.map(
|
|
||||||
(warning) => html`<li>${warning}</li>`
|
|
||||||
)}
|
|
||||||
</ul>`
|
|
||||||
: ""}
|
|
||||||
${this.hass.localize("ui.errors.config.edit_in_yaml_supported")}
|
|
||||||
</ha-alert>`
|
|
||||||
: ""}
|
|
||||||
${yamlMode
|
|
||||||
? html`
|
|
||||||
${type === undefined
|
|
||||||
? html`
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.actions.unsupported_action",
|
|
||||||
"action",
|
|
||||||
type
|
|
||||||
)}
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<h2>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.edit_yaml"
|
|
||||||
)}
|
)}
|
||||||
</h2>
|
|
||||||
<ha-yaml-editor
|
|
||||||
.hass=${this.hass}
|
|
||||||
.defaultValue=${this.action}
|
|
||||||
@value-changed=${this._onYamlChange}
|
|
||||||
></ha-yaml-editor>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<ha-select
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.actions.type_select"
|
|
||||||
)}
|
|
||||||
.value=${getType(this.action)}
|
|
||||||
naturalMenuWidth
|
|
||||||
@selected=${this._typeChanged}
|
|
||||||
>
|
>
|
||||||
${this._processedTypes(this.hass.localize).map(
|
${this._warnings!.length > 0 &&
|
||||||
([opt, label]) => html`
|
this._warnings![0] !== undefined
|
||||||
<mwc-list-item .value=${opt}>${label}</mwc-list-item>
|
? html` <ul>
|
||||||
`
|
${this._warnings!.map(
|
||||||
|
(warning) => html`<li>${warning}</li>`
|
||||||
|
)}
|
||||||
|
</ul>`
|
||||||
|
: ""}
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.errors.config.edit_in_yaml_supported"
|
||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-alert>`
|
||||||
|
: ""}
|
||||||
<div @ui-mode-not-available=${this._handleUiModeNotAvailable}>
|
${yamlMode
|
||||||
${dynamicElement(`ha-automation-action-${type}`, {
|
? html`
|
||||||
hass: this.hass,
|
${type === undefined
|
||||||
action: this.action,
|
? html`
|
||||||
narrow: this.narrow,
|
${this.hass.localize(
|
||||||
})}
|
"ui.panel.config.automation.editor.actions.unsupported_action",
|
||||||
</div>
|
"action",
|
||||||
`}
|
type
|
||||||
</div>
|
)}
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<h2>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.edit_yaml"
|
||||||
|
)}
|
||||||
|
</h2>
|
||||||
|
<ha-yaml-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.defaultValue=${this.action}
|
||||||
|
@value-changed=${this._onYamlChange}
|
||||||
|
></ha-yaml-editor>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<div @ui-mode-not-available=${this._handleUiModeNotAvailable}>
|
||||||
|
${dynamicElement(`ha-automation-action-${type}`, {
|
||||||
|
hass: this.hass,
|
||||||
|
action: this.action,
|
||||||
|
narrow: this.narrow,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
</ha-expansion-panel>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -319,11 +290,13 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _moveUp() {
|
private _moveUp(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
fireEvent(this, "move-action", { direction: "up" });
|
fireEvent(this, "move-action", { direction: "up" });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _moveDown() {
|
private _moveDown(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
fireEvent(this, "move-action", { direction: "down" });
|
fireEvent(this, "move-action", { direction: "down" });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,31 +376,6 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _typeChanged(ev: CustomEvent) {
|
|
||||||
const type = (ev.target as HaSelect).value;
|
|
||||||
|
|
||||||
if (!type) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._uiModeAvailable = OPTIONS.includes(type);
|
|
||||||
if (!this._uiModeAvailable && !this._yamlMode) {
|
|
||||||
this._yamlMode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type !== getType(this.action)) {
|
|
||||||
const elClass = customElements.get(
|
|
||||||
`ha-automation-action-${type}`
|
|
||||||
) as CustomElementConstructor & { defaultConfig: Action };
|
|
||||||
|
|
||||||
fireEvent(this, "value-changed", {
|
|
||||||
value: {
|
|
||||||
...elClass.defaultConfig,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onYamlChange(ev: CustomEvent) {
|
private _onYamlChange(ev: CustomEvent) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
if (!ev.detail.isValid) {
|
if (!ev.detail.isValid) {
|
||||||
@ -441,17 +389,30 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
this._yamlMode = !this._yamlMode;
|
this._yamlMode = !this._yamlMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public expand() {
|
||||||
|
this.updateComplete.then(() => {
|
||||||
|
this.shadowRoot!.querySelector("ha-expansion-panel")!.expanded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
|
ha-button-menu,
|
||||||
|
ha-icon-button {
|
||||||
|
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||||
|
}
|
||||||
.disabled {
|
.disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
ha-expansion-panel {
|
||||||
|
--expansion-panel-summary-padding: 0 0 0 8px;
|
||||||
|
--expansion-panel-content-padding: 0;
|
||||||
|
}
|
||||||
.card-content {
|
.card-content {
|
||||||
padding-top: 16px;
|
padding: 16px;
|
||||||
margin-top: 0;
|
|
||||||
}
|
}
|
||||||
.disabled-bar {
|
.disabled-bar {
|
||||||
background: var(--divider-color, #e0e0e0);
|
background: var(--divider-color, #e0e0e0);
|
||||||
@ -459,14 +420,7 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
border-top-right-radius: var(--ha-card-border-radius);
|
border-top-right-radius: var(--ha-card-border-radius);
|
||||||
border-top-left-radius: var(--ha-card-border-radius);
|
border-top-left-radius: var(--ha-card-border-radius);
|
||||||
}
|
}
|
||||||
.card-menu {
|
|
||||||
float: var(--float-end, right);
|
|
||||||
z-index: 3;
|
|
||||||
margin: 4px;
|
|
||||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
mwc-list-item[disabled] {
|
mwc-list-item[disabled] {
|
||||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||||
}
|
}
|
||||||
@ -476,9 +430,6 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
.warning ul {
|
.warning ul {
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
ha-select {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,36 @@
|
|||||||
|
import { repeat } from "lit/directives/repeat";
|
||||||
|
import { mdiPlus } from "@mdi/js";
|
||||||
import deepClone from "deep-clone-simple";
|
import deepClone from "deep-clone-simple";
|
||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
import type { ActionDetail } from "@material/mwc-list";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-svg-icon";
|
||||||
|
import "../../../../components/ha-button-menu";
|
||||||
import { Action } from "../../../../data/script";
|
import { Action } from "../../../../data/script";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
import "./ha-automation-action-row";
|
import "./ha-automation-action-row";
|
||||||
import { HaDeviceAction } from "./types/ha-automation-action-device_id";
|
import type HaAutomationActionRow from "./ha-automation-action-row";
|
||||||
|
import "./types/ha-automation-action-activate_scene";
|
||||||
|
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-if";
|
||||||
|
import "./types/ha-automation-action-parallel";
|
||||||
|
import "./types/ha-automation-action-play_media";
|
||||||
|
import "./types/ha-automation-action-repeat";
|
||||||
|
import "./types/ha-automation-action-service";
|
||||||
|
import "./types/ha-automation-action-stop";
|
||||||
|
import "./types/ha-automation-action-wait_for_trigger";
|
||||||
|
import "./types/ha-automation-action-wait_template";
|
||||||
|
import { ACTION_TYPES } from "../../../../data/action";
|
||||||
|
import { stringCompare } from "../../../../common/string/compare";
|
||||||
|
import { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
|
import type { HaSelect } from "../../../../components/ha-select";
|
||||||
|
|
||||||
@customElement("ha-automation-action")
|
@customElement("ha-automation-action")
|
||||||
export default class HaAutomationAction extends LitElement {
|
export default class HaAutomationAction extends LitElement {
|
||||||
@ -17,9 +40,15 @@ export default class HaAutomationAction extends LitElement {
|
|||||||
|
|
||||||
@property() public actions!: Action[];
|
@property() public actions!: Action[];
|
||||||
|
|
||||||
|
private _focusLastActionOnChange = false;
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
${this.actions.map(
|
${repeat(
|
||||||
|
this.actions,
|
||||||
|
// Use the action as key, so moving around keeps the same DOM,
|
||||||
|
// including expand state
|
||||||
|
(action) => action,
|
||||||
(action, idx) => html`
|
(action, idx) => html`
|
||||||
<ha-automation-action-row
|
<ha-automation-action-row
|
||||||
.index=${idx}
|
.index=${idx}
|
||||||
@ -33,23 +62,51 @@ export default class HaAutomationAction extends LitElement {
|
|||||||
></ha-automation-action-row>
|
></ha-automation-action-row>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
<ha-card outlined>
|
<ha-button-menu fixed @action=${this._addAction}>
|
||||||
<div class="card-actions add-card">
|
<mwc-button
|
||||||
<mwc-button @click=${this._addAction}>
|
slot="trigger"
|
||||||
${this.hass.localize(
|
outlined
|
||||||
"ui.panel.config.automation.editor.actions.add"
|
.label=${this.hass.localize(
|
||||||
)}
|
"ui.panel.config.automation.editor.actions.add"
|
||||||
</mwc-button>
|
)}
|
||||||
</div>
|
>
|
||||||
</ha-card>
|
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||||
|
</mwc-button>
|
||||||
|
${this._processedTypes(this.hass.localize).map(
|
||||||
|
([opt, label]) => html`
|
||||||
|
<mwc-list-item .value=${opt}>${label}</mwc-list-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-button-menu>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _addAction() {
|
protected updated(changedProps: PropertyValues) {
|
||||||
const actions = this.actions.concat({
|
super.updated(changedProps);
|
||||||
...HaDeviceAction.defaultConfig,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
if (changedProps.has("actions") && this._focusLastActionOnChange) {
|
||||||
|
this._focusLastActionOnChange = false;
|
||||||
|
|
||||||
|
const row = this.shadowRoot!.querySelector<HaAutomationActionRow>(
|
||||||
|
"ha-automation-action-row:last-of-type"
|
||||||
|
)!;
|
||||||
|
row.expand();
|
||||||
|
row.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addAction(ev: CustomEvent<ActionDetail>) {
|
||||||
|
const action = (ev.currentTarget as HaSelect).items[ev.detail.index]
|
||||||
|
.value as typeof ACTION_TYPES[number];
|
||||||
|
|
||||||
|
const elClass = customElements.get(
|
||||||
|
`ha-automation-action-${action}`
|
||||||
|
) as CustomElementConstructor & { defaultConfig: Action };
|
||||||
|
|
||||||
|
const actions = this.actions.concat({
|
||||||
|
...elClass.defaultConfig,
|
||||||
|
});
|
||||||
|
this._focusLastActionOnChange = true;
|
||||||
fireEvent(this, "value-changed", { value: actions });
|
fireEvent(this, "value-changed", { value: actions });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,16 +145,27 @@ export default class HaAutomationAction extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _processedTypes = memoizeOne(
|
||||||
|
(localize: LocalizeFunc): [string, string][] =>
|
||||||
|
ACTION_TYPES.map(
|
||||||
|
(action) =>
|
||||||
|
[
|
||||||
|
action,
|
||||||
|
localize(
|
||||||
|
`ui.panel.config.automation.editor.actions.type.${action}.label`
|
||||||
|
),
|
||||||
|
] as [string, string]
|
||||||
|
).sort((a, b) => stringCompare(a[1], b[1]))
|
||||||
|
);
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
ha-automation-action-row,
|
ha-automation-action-row {
|
||||||
ha-card {
|
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
.add-card mwc-button {
|
ha-svg-icon {
|
||||||
display: block;
|
height: 20px;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,9 @@ export class HaSceneAction extends LitElement implements ActionElement {
|
|||||||
return html`
|
return html`
|
||||||
<ha-entity-picker
|
<ha-entity-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.actions.type.activate_scene.scene"
|
||||||
|
)}
|
||||||
.value=${scene}
|
.value=${scene}
|
||||||
@value-changed=${this._entityPicked}
|
@value-changed=${this._entityPicked}
|
||||||
.includeDomains=${includeDomains}
|
.includeDomains=${includeDomains}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { mdiDelete } from "@mdi/js";
|
import { mdiDelete, mdiPlus } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
@ -69,15 +69,15 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
|||||||
</div>
|
</div>
|
||||||
</ha-card>`
|
</ha-card>`
|
||||||
)}
|
)}
|
||||||
<ha-card outlined>
|
<mwc-button
|
||||||
<div class="card-actions add-card">
|
outlined
|
||||||
<mwc-button @click=${this._addOption}>
|
.label=${this.hass.localize(
|
||||||
${this.hass.localize(
|
"ui.panel.config.automation.editor.actions.type.choose.add_option"
|
||||||
"ui.panel.config.automation.editor.actions.type.choose.add_option"
|
)}
|
||||||
)}
|
@click=${this._addOption}
|
||||||
</mwc-button>
|
>
|
||||||
</div>
|
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||||
</ha-card>
|
</mwc-button>
|
||||||
<h2>
|
<h2>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.actions.type.choose.default"
|
"ui.panel.config.automation.editor.actions.type.choose.default"
|
||||||
@ -154,7 +154,7 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
|||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
ha-card {
|
ha-card {
|
||||||
margin-top: 16px;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
.add-card mwc-button {
|
.add-card mwc-button {
|
||||||
display: block;
|
display: block;
|
||||||
@ -168,6 +168,9 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
|||||||
ha-form::part(root) {
|
ha-form::part(root) {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
ha-svg-icon {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
import { html, LitElement } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
import { Condition } from "../../../../../data/automation";
|
import { stringCompare } from "../../../../../common/string/compare";
|
||||||
|
import type { LocalizeFunc } from "../../../../../common/translations/localize";
|
||||||
|
import "../../../../../components/ha-select";
|
||||||
|
import type { HaSelect } from "../../../../../components/ha-select";
|
||||||
|
import type { Condition } from "../../../../../data/automation";
|
||||||
|
import { CONDITION_TYPES } from "../../../../../data/condition";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../condition/ha-automation-condition-editor";
|
import "../../condition/ha-automation-condition-editor";
|
||||||
import { ActionElement } from "../ha-automation-action-row";
|
import type { ActionElement } from "../ha-automation-action-row";
|
||||||
|
|
||||||
@customElement("ha-automation-action-condition")
|
@customElement("ha-automation-action-condition")
|
||||||
export class HaConditionAction extends LitElement implements ActionElement {
|
export class HaConditionAction extends LitElement implements ActionElement {
|
||||||
@ -18,6 +24,21 @@ export class HaConditionAction extends LitElement implements ActionElement {
|
|||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
|
<ha-select
|
||||||
|
fixedMenuPosition
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.conditions.type_select"
|
||||||
|
)}
|
||||||
|
.value=${this.action.condition}
|
||||||
|
naturalMenuWidth
|
||||||
|
@selected=${this._typeChanged}
|
||||||
|
>
|
||||||
|
${this._processedTypes(this.hass.localize).map(
|
||||||
|
([opt, label]) => html`
|
||||||
|
<mwc-list-item .value=${opt}>${label}</mwc-list-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-select>
|
||||||
<ha-automation-condition-editor
|
<ha-automation-condition-editor
|
||||||
.condition=${this.action}
|
.condition=${this.action}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -26,6 +47,19 @@ export class HaConditionAction extends LitElement implements ActionElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _processedTypes = memoizeOne(
|
||||||
|
(localize: LocalizeFunc): [string, string][] =>
|
||||||
|
CONDITION_TYPES.map(
|
||||||
|
(condition) =>
|
||||||
|
[
|
||||||
|
condition,
|
||||||
|
localize(
|
||||||
|
`ui.panel.config.automation.editor.conditions.type.${condition}.label`
|
||||||
|
),
|
||||||
|
] as [string, string]
|
||||||
|
).sort((a, b) => stringCompare(a[1], b[1]))
|
||||||
|
);
|
||||||
|
|
||||||
private _conditionChanged(ev: CustomEvent) {
|
private _conditionChanged(ev: CustomEvent) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
@ -33,6 +67,37 @@ export class HaConditionAction extends LitElement implements ActionElement {
|
|||||||
value: ev.detail.value,
|
value: ev.detail.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _typeChanged(ev: CustomEvent) {
|
||||||
|
const type = (ev.target as HaSelect).value;
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elClass = customElements.get(
|
||||||
|
`ha-automation-condition-${type}`
|
||||||
|
) as CustomElementConstructor & {
|
||||||
|
defaultConfig: Omit<Condition, "condition">;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type !== this.action.condition) {
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: {
|
||||||
|
condition: type,
|
||||||
|
...elClass.defaultConfig,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-select {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -52,42 +52,42 @@ export class HaRepeatAction extends LitElement implements ActionElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
${type === "count"
|
<div>
|
||||||
? html`
|
${type === "count"
|
||||||
<ha-textfield
|
? html`
|
||||||
.label=${this.hass.localize(
|
<ha-textfield
|
||||||
"ui.panel.config.automation.editor.actions.type.repeat.type.count.label"
|
.label=${this.hass.localize(
|
||||||
)}
|
"ui.panel.config.automation.editor.actions.type.repeat.type.count.label"
|
||||||
name="count"
|
)}
|
||||||
.value=${(action as CountRepeat).count || "0"}
|
name="count"
|
||||||
@change=${this._countChanged}
|
.value=${(action as CountRepeat).count || "0"}
|
||||||
></ha-textfield>
|
@change=${this._countChanged}
|
||||||
`
|
></ha-textfield>
|
||||||
: ""}
|
`
|
||||||
${type === "while"
|
: type === "while"
|
||||||
? html` <h3>
|
? html` <h3>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
`ui.panel.config.automation.editor.actions.type.repeat.type.while.conditions`
|
`ui.panel.config.automation.editor.actions.type.repeat.type.while.conditions`
|
||||||
)}:
|
)}:
|
||||||
</h3>
|
</h3>
|
||||||
<ha-automation-condition
|
<ha-automation-condition
|
||||||
.conditions=${(action as WhileRepeat).while || []}
|
.conditions=${(action as WhileRepeat).while || []}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@value-changed=${this._conditionChanged}
|
@value-changed=${this._conditionChanged}
|
||||||
></ha-automation-condition>`
|
></ha-automation-condition>`
|
||||||
: ""}
|
: type === "until"
|
||||||
${type === "until"
|
? html` <h3>
|
||||||
? html` <h3>
|
${this.hass.localize(
|
||||||
${this.hass.localize(
|
`ui.panel.config.automation.editor.actions.type.repeat.type.until.conditions`
|
||||||
`ui.panel.config.automation.editor.actions.type.repeat.type.until.conditions`
|
)}:
|
||||||
)}:
|
</h3>
|
||||||
</h3>
|
<ha-automation-condition
|
||||||
<ha-automation-condition
|
.conditions=${(action as UntilRepeat).until || []}
|
||||||
.conditions=${(action as UntilRepeat).until || []}
|
.hass=${this.hass}
|
||||||
.hass=${this.hass}
|
@value-changed=${this._conditionChanged}
|
||||||
@value-changed=${this._conditionChanged}
|
></ha-automation-condition>`
|
||||||
></ha-automation-condition>`
|
: ""}
|
||||||
: ""}
|
</div>
|
||||||
<h3>
|
<h3>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.actions.type.repeat.sequence"
|
"ui.panel.config.automation.editor.actions.type.repeat.sequence"
|
||||||
|
@ -68,6 +68,10 @@ export class HaWaitForTriggerAction
|
|||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
ha-automation-trigger {
|
||||||
|
display: block;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import { css, html, LitElement } from "lit";
|
import { html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { stringCompare } from "../../../../common/string/compare";
|
|
||||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
|
||||||
import "../../../../components/ha-select";
|
|
||||||
import type { HaSelect } from "../../../../components/ha-select";
|
|
||||||
import "../../../../components/ha-yaml-editor";
|
import "../../../../components/ha-yaml-editor";
|
||||||
import type { Condition } from "../../../../data/automation";
|
import type { Condition } from "../../../../data/automation";
|
||||||
import { expandConditionWithShorthand } from "../../../../data/automation";
|
import { expandConditionWithShorthand } from "../../../../data/automation";
|
||||||
@ -24,20 +20,6 @@ import "./types/ha-automation-condition-time";
|
|||||||
import "./types/ha-automation-condition-trigger";
|
import "./types/ha-automation-condition-trigger";
|
||||||
import "./types/ha-automation-condition-zone";
|
import "./types/ha-automation-condition-zone";
|
||||||
|
|
||||||
const OPTIONS = [
|
|
||||||
"device",
|
|
||||||
"and",
|
|
||||||
"or",
|
|
||||||
"not",
|
|
||||||
"state",
|
|
||||||
"numeric_state",
|
|
||||||
"sun",
|
|
||||||
"template",
|
|
||||||
"time",
|
|
||||||
"trigger",
|
|
||||||
"zone",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
@customElement("ha-automation-condition-editor")
|
@customElement("ha-automation-condition-editor")
|
||||||
export default class HaAutomationConditionEditor extends LitElement {
|
export default class HaAutomationConditionEditor extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -50,27 +32,16 @@ export default class HaAutomationConditionEditor extends LitElement {
|
|||||||
expandConditionWithShorthand(condition)
|
expandConditionWithShorthand(condition)
|
||||||
);
|
);
|
||||||
|
|
||||||
private _processedTypes = memoizeOne(
|
|
||||||
(localize: LocalizeFunc): [string, string][] =>
|
|
||||||
OPTIONS.map(
|
|
||||||
(condition) =>
|
|
||||||
[
|
|
||||||
condition,
|
|
||||||
localize(
|
|
||||||
`ui.panel.config.automation.editor.conditions.type.${condition}.label`
|
|
||||||
),
|
|
||||||
] as [string, string]
|
|
||||||
).sort((a, b) => stringCompare(a[1], b[1]))
|
|
||||||
);
|
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
const condition = this._processedCondition(this.condition);
|
const condition = this._processedCondition(this.condition);
|
||||||
const selected = OPTIONS.indexOf(condition.condition);
|
const supported =
|
||||||
const yamlMode = this.yamlMode || selected === -1;
|
customElements.get(`ha-automation-condition-${condition.condition}`) !==
|
||||||
|
undefined;
|
||||||
|
const yamlMode = this.yamlMode || !supported;
|
||||||
return html`
|
return html`
|
||||||
${yamlMode
|
${yamlMode
|
||||||
? html`
|
? html`
|
||||||
${selected === -1
|
${!supported
|
||||||
? html`
|
? html`
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.conditions.unsupported_condition",
|
"ui.panel.config.automation.editor.conditions.unsupported_condition",
|
||||||
@ -91,21 +62,6 @@ export default class HaAutomationConditionEditor extends LitElement {
|
|||||||
></ha-yaml-editor>
|
></ha-yaml-editor>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<ha-select
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.conditions.type_select"
|
|
||||||
)}
|
|
||||||
.value=${condition.condition}
|
|
||||||
naturalMenuWidth
|
|
||||||
@selected=${this._typeChanged}
|
|
||||||
>
|
|
||||||
${this._processedTypes(this.hass.localize).map(
|
|
||||||
([opt, label]) => html`
|
|
||||||
<mwc-list-item .value=${opt}>${label}</mwc-list-item>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-select>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
${dynamicElement(
|
${dynamicElement(
|
||||||
`ha-automation-condition-${condition.condition}`,
|
`ha-automation-condition-${condition.condition}`,
|
||||||
@ -116,29 +72,6 @@ export default class HaAutomationConditionEditor extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _typeChanged(ev: CustomEvent) {
|
|
||||||
const type = (ev.target as HaSelect).value;
|
|
||||||
|
|
||||||
if (!type) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const elClass = customElements.get(
|
|
||||||
`ha-automation-condition-${type}`
|
|
||||||
) as CustomElementConstructor & {
|
|
||||||
defaultConfig: Omit<Condition, "condition">;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type !== this._processedCondition(this.condition).condition) {
|
|
||||||
fireEvent(this, "value-changed", {
|
|
||||||
value: {
|
|
||||||
condition: type,
|
|
||||||
...elClass.defaultConfig,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onYamlChange(ev: CustomEvent) {
|
private _onYamlChange(ev: CustomEvent) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
if (!ev.detail.isValid) {
|
if (!ev.detail.isValid) {
|
||||||
@ -148,14 +81,7 @@ export default class HaAutomationConditionEditor extends LitElement {
|
|||||||
fireEvent(this, "value-changed", { value: ev.detail.value, yaml: true });
|
fireEvent(this, "value-changed", { value: ev.detail.value, yaml: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = [
|
static styles = haStyle;
|
||||||
haStyle,
|
|
||||||
css`
|
|
||||||
ha-select {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -3,6 +3,7 @@ import "@material/mwc-list/mwc-list-item";
|
|||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||||
import "../../../../components/ha-button-menu";
|
import "../../../../components/ha-button-menu";
|
||||||
@ -10,6 +11,7 @@ import "../../../../components/ha-card";
|
|||||||
import "../../../../components/buttons/ha-progress-button";
|
import "../../../../components/buttons/ha-progress-button";
|
||||||
import type { HaProgressButton } from "../../../../components/buttons/ha-progress-button";
|
import type { HaProgressButton } from "../../../../components/buttons/ha-progress-button";
|
||||||
import "../../../../components/ha-icon-button";
|
import "../../../../components/ha-icon-button";
|
||||||
|
import "../../../../components/ha-expansion-panel";
|
||||||
import { Condition, testCondition } from "../../../../data/automation";
|
import { Condition, testCondition } from "../../../../data/automation";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
@ -20,11 +22,14 @@ import { HomeAssistant } from "../../../../types";
|
|||||||
import "./ha-automation-condition-editor";
|
import "./ha-automation-condition-editor";
|
||||||
import { validateConfig } from "../../../../data/config";
|
import { validateConfig } from "../../../../data/config";
|
||||||
import { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
import { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||||
|
import { describeCondition } from "../../../../data/automation_i18n";
|
||||||
|
|
||||||
export interface ConditionElement extends LitElement {
|
export interface ConditionElement extends LitElement {
|
||||||
condition: Condition;
|
condition: Condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const preventDefault = (ev) => ev.preventDefault();
|
||||||
|
|
||||||
export const handleChangeEvent = (
|
export const handleChangeEvent = (
|
||||||
element: ConditionElement,
|
element: ConditionElement,
|
||||||
ev: CustomEvent
|
ev: CustomEvent
|
||||||
@ -75,13 +80,23 @@ export default class HaAutomationConditionRow extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</div>`
|
</div>`
|
||||||
: ""}
|
: ""}
|
||||||
<div class="card-menu">
|
|
||||||
<ha-progress-button @click=${this._testCondition}>
|
<ha-expansion-panel
|
||||||
|
leftChevron
|
||||||
|
.header=${describeCondition(this.condition)}
|
||||||
|
>
|
||||||
|
<ha-progress-button slot="icons" @click=${this._testCondition}>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.conditions.test"
|
"ui.panel.config.automation.editor.conditions.test"
|
||||||
)}
|
)}
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
<ha-button-menu
|
||||||
|
slot="icons"
|
||||||
|
fixed
|
||||||
|
corner="BOTTOM_START"
|
||||||
|
@action=${this._handleAction}
|
||||||
|
@click=${preventDefault}
|
||||||
|
>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
.label=${this.hass.localize("ui.common.menu")}
|
.label=${this.hass.localize("ui.common.menu")}
|
||||||
@ -117,37 +132,42 @@ export default class HaAutomationConditionRow extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="card-content ${this.condition.enabled === false
|
class=${classMap({
|
||||||
? "disabled"
|
"card-content": true,
|
||||||
: ""}"
|
disabled: this.condition.enabled === false,
|
||||||
>
|
})}
|
||||||
${this._warnings
|
>
|
||||||
? html`<ha-alert
|
${this._warnings
|
||||||
alert-type="warning"
|
? html`<ha-alert
|
||||||
.title=${this.hass.localize(
|
alert-type="warning"
|
||||||
"ui.errors.config.editor_not_supported"
|
.title=${this.hass.localize(
|
||||||
)}
|
"ui.errors.config.editor_not_supported"
|
||||||
>
|
)}
|
||||||
${this._warnings!.length > 0 && this._warnings![0] !== undefined
|
>
|
||||||
? html` <ul>
|
${this._warnings!.length > 0 &&
|
||||||
${this._warnings!.map(
|
this._warnings![0] !== undefined
|
||||||
(warning) => html`<li>${warning}</li>`
|
? html` <ul>
|
||||||
)}
|
${this._warnings!.map(
|
||||||
</ul>`
|
(warning) => html`<li>${warning}</li>`
|
||||||
: ""}
|
)}
|
||||||
${this.hass.localize("ui.errors.config.edit_in_yaml_supported")}
|
</ul>`
|
||||||
</ha-alert>`
|
: ""}
|
||||||
: ""}
|
${this.hass.localize(
|
||||||
<ha-automation-condition-editor
|
"ui.errors.config.edit_in_yaml_supported"
|
||||||
@ui-mode-not-available=${this._handleUiModeNotAvailable}
|
)}
|
||||||
@value-changed=${this._handleChangeEvent}
|
</ha-alert>`
|
||||||
.yamlMode=${this._yamlMode}
|
: ""}
|
||||||
.hass=${this.hass}
|
<ha-automation-condition-editor
|
||||||
.condition=${this.condition}
|
@ui-mode-not-available=${this._handleUiModeNotAvailable}
|
||||||
></ha-automation-condition-editor>
|
@value-changed=${this._handleChangeEvent}
|
||||||
</div>
|
.yamlMode=${this._yamlMode}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.condition=${this.condition}
|
||||||
|
></ha-automation-condition-editor>
|
||||||
|
</div>
|
||||||
|
</ha-expansion-panel>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -212,6 +232,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _testCondition(ev) {
|
private async _testCondition(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
const condition = this.condition;
|
const condition = this.condition;
|
||||||
const button = ev.target as HaProgressButton;
|
const button = ev.target as HaProgressButton;
|
||||||
if (button.progress) {
|
if (button.progress) {
|
||||||
@ -269,17 +290,30 @@ export default class HaAutomationConditionRow extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public expand() {
|
||||||
|
this.updateComplete.then(() => {
|
||||||
|
this.shadowRoot!.querySelector("ha-expansion-panel")!.expanded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
|
ha-button-menu,
|
||||||
|
ha-progress-button {
|
||||||
|
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||||
|
}
|
||||||
.disabled {
|
.disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
ha-expansion-panel {
|
||||||
|
--expansion-panel-summary-padding: 0 0 0 8px;
|
||||||
|
--expansion-panel-content-padding: 0;
|
||||||
|
}
|
||||||
.card-content {
|
.card-content {
|
||||||
padding-top: 16px;
|
padding: 16px;
|
||||||
margin-top: 0;
|
|
||||||
}
|
}
|
||||||
.disabled-bar {
|
.disabled-bar {
|
||||||
background: var(--divider-color, #e0e0e0);
|
background: var(--divider-color, #e0e0e0);
|
||||||
@ -287,14 +321,6 @@ export default class HaAutomationConditionRow extends LitElement {
|
|||||||
border-top-right-radius: var(--ha-card-border-radius);
|
border-top-right-radius: var(--ha-card-border-radius);
|
||||||
border-top-left-radius: var(--ha-card-border-radius);
|
border-top-left-radius: var(--ha-card-border-radius);
|
||||||
}
|
}
|
||||||
.card-menu {
|
|
||||||
float: var(--float-end, right);
|
|
||||||
z-index: 3;
|
|
||||||
margin: 4px;
|
|
||||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
mwc-list-item[disabled] {
|
mwc-list-item[disabled] {
|
||||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,34 @@
|
|||||||
|
import { mdiPlus } from "@mdi/js";
|
||||||
|
import { repeat } from "lit/directives/repeat";
|
||||||
import deepClone from "deep-clone-simple";
|
import deepClone from "deep-clone-simple";
|
||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import type { ActionDetail } from "@material/mwc-list";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-svg-icon";
|
||||||
import { Condition } from "../../../../data/automation";
|
import "../../../../components/ha-button-menu";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import type { Condition } from "../../../../data/automation";
|
||||||
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import "./ha-automation-condition-row";
|
import "./ha-automation-condition-row";
|
||||||
import { HaDeviceCondition } from "./types/ha-automation-condition-device";
|
import type HaAutomationConditionRow from "./ha-automation-condition-row";
|
||||||
|
// Uncommenting these and this element doesn't load
|
||||||
|
// import "./types/ha-automation-condition-not";
|
||||||
|
// import "./types/ha-automation-condition-or";
|
||||||
|
import "./types/ha-automation-condition-and";
|
||||||
|
import "./types/ha-automation-condition-device";
|
||||||
|
import "./types/ha-automation-condition-numeric_state";
|
||||||
|
import "./types/ha-automation-condition-state";
|
||||||
|
import "./types/ha-automation-condition-sun";
|
||||||
|
import "./types/ha-automation-condition-template";
|
||||||
|
import "./types/ha-automation-condition-time";
|
||||||
|
import "./types/ha-automation-condition-trigger";
|
||||||
|
import "./types/ha-automation-condition-zone";
|
||||||
|
import { CONDITION_TYPES } from "../../../../data/condition";
|
||||||
|
import { stringCompare } from "../../../../common/string/compare";
|
||||||
|
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
|
import type { HaSelect } from "../../../../components/ha-select";
|
||||||
|
|
||||||
@customElement("ha-automation-condition")
|
@customElement("ha-automation-condition")
|
||||||
export default class HaAutomationCondition extends LitElement {
|
export default class HaAutomationCondition extends LitElement {
|
||||||
@ -15,10 +36,13 @@ export default class HaAutomationCondition extends LitElement {
|
|||||||
|
|
||||||
@property() public conditions!: Condition[];
|
@property() public conditions!: Condition[];
|
||||||
|
|
||||||
|
private _focusLastConditionOnChange = false;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues) {
|
protected updated(changedProperties: PropertyValues) {
|
||||||
if (!changedProperties.has("conditions")) {
|
if (!changedProperties.has("conditions")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let updatedConditions: Condition[] | undefined;
|
let updatedConditions: Condition[] | undefined;
|
||||||
if (!Array.isArray(this.conditions)) {
|
if (!Array.isArray(this.conditions)) {
|
||||||
updatedConditions = [this.conditions];
|
updatedConditions = [this.conditions];
|
||||||
@ -38,6 +62,13 @@ export default class HaAutomationCondition extends LitElement {
|
|||||||
fireEvent(this, "value-changed", {
|
fireEvent(this, "value-changed", {
|
||||||
value: updatedConditions,
|
value: updatedConditions,
|
||||||
});
|
});
|
||||||
|
} else if (this._focusLastConditionOnChange) {
|
||||||
|
this._focusLastConditionOnChange = false;
|
||||||
|
const row = this.shadowRoot!.querySelector<HaAutomationConditionRow>(
|
||||||
|
"ha-automation-condition-row:last-of-type"
|
||||||
|
)!;
|
||||||
|
row.expand();
|
||||||
|
row.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +77,11 @@ export default class HaAutomationCondition extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
${this.conditions.map(
|
${repeat(
|
||||||
|
this.conditions,
|
||||||
|
// Use the condition as key, so moving around keeps the same DOM,
|
||||||
|
// including expand state
|
||||||
|
(condition) => condition,
|
||||||
(cond, idx) => html`
|
(cond, idx) => html`
|
||||||
<ha-automation-condition-row
|
<ha-automation-condition-row
|
||||||
.index=${idx}
|
.index=${idx}
|
||||||
@ -57,24 +92,40 @@ export default class HaAutomationCondition extends LitElement {
|
|||||||
></ha-automation-condition-row>
|
></ha-automation-condition-row>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
<ha-card outlined>
|
<ha-button-menu fixed @action=${this._addCondition}>
|
||||||
<div class="card-actions add-card">
|
<mwc-button
|
||||||
<mwc-button @click=${this._addCondition}>
|
slot="trigger"
|
||||||
${this.hass.localize(
|
outlined
|
||||||
"ui.panel.config.automation.editor.conditions.add"
|
.label=${this.hass.localize(
|
||||||
)}
|
"ui.panel.config.automation.editor.conditions.add"
|
||||||
</mwc-button>
|
)}
|
||||||
</div>
|
>
|
||||||
</ha-card>
|
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||||
|
</mwc-button>
|
||||||
|
${this._processedTypes(this.hass.localize).map(
|
||||||
|
([opt, label]) => html`
|
||||||
|
<mwc-list-item .value=${opt}>${label}</mwc-list-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-button-menu>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _addCondition() {
|
private _addCondition(ev: CustomEvent<ActionDetail>) {
|
||||||
const conditions = this.conditions.concat({
|
const condition = (ev.currentTarget as HaSelect).items[ev.detail.index]
|
||||||
condition: "device",
|
.value as Condition["condition"];
|
||||||
...HaDeviceCondition.defaultConfig,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const elClass = customElements.get(
|
||||||
|
`ha-automation-condition-${condition}`
|
||||||
|
) as CustomElementConstructor & {
|
||||||
|
defaultConfig: Omit<Condition, "condition">;
|
||||||
|
};
|
||||||
|
|
||||||
|
const conditions = this.conditions.concat({
|
||||||
|
condition: condition as any,
|
||||||
|
...elClass.defaultConfig,
|
||||||
|
});
|
||||||
|
this._focusLastConditionOnChange = true;
|
||||||
fireEvent(this, "value-changed", { value: conditions });
|
fireEvent(this, "value-changed", { value: conditions });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,16 +152,27 @@ export default class HaAutomationCondition extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _processedTypes = memoizeOne(
|
||||||
|
(localize: LocalizeFunc): [string, string][] =>
|
||||||
|
CONDITION_TYPES.map(
|
||||||
|
(condition) =>
|
||||||
|
[
|
||||||
|
condition,
|
||||||
|
localize(
|
||||||
|
`ui.panel.config.automation.editor.conditions.type.${condition}.label`
|
||||||
|
),
|
||||||
|
] as [string, string]
|
||||||
|
).sort((a, b) => stringCompare(a[1], b[1]))
|
||||||
|
);
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
ha-automation-condition-row,
|
ha-automation-condition-row {
|
||||||
ha-card {
|
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
.add-card mwc-button {
|
ha-svg-icon {
|
||||||
display: block;
|
height: 20px;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { html, LitElement } from "lit";
|
import { html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
import type {
|
import type { LogicalCondition } from "../../../../../data/automation";
|
||||||
Condition,
|
|
||||||
LogicalCondition,
|
|
||||||
} from "../../../../../data/automation";
|
|
||||||
import type { HomeAssistant } from "../../../../../types";
|
import type { HomeAssistant } from "../../../../../types";
|
||||||
import "../ha-automation-condition";
|
import "../ha-automation-condition";
|
||||||
import type { 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")
|
@customElement("ha-automation-condition-logical")
|
||||||
export class HaLogicalCondition extends LitElement implements ConditionElement {
|
export class HaLogicalCondition extends LitElement implements ConditionElement {
|
||||||
@ -18,12 +14,7 @@ export class HaLogicalCondition extends LitElement implements ConditionElement {
|
|||||||
|
|
||||||
public static get defaultConfig() {
|
public static get defaultConfig() {
|
||||||
return {
|
return {
|
||||||
conditions: [
|
conditions: [],
|
||||||
{
|
|
||||||
condition: "state",
|
|
||||||
...HaStateCondition.defaultConfig,
|
|
||||||
},
|
|
||||||
] as Condition[],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { html, LitElement } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import "../../../../../components/ha-textarea";
|
import "../../../../../components/ha-textarea";
|
||||||
import type { TemplateCondition } from "../../../../../data/automation";
|
import type { TemplateCondition } from "../../../../../data/automation";
|
||||||
@ -39,6 +39,14 @@ export class HaTemplateCondition extends LitElement {
|
|||||||
private _valueChanged(ev: CustomEvent): void {
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
handleChangeEvent(this, ev);
|
handleChangeEvent(this, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -73,7 +73,7 @@ export class HaZoneCondition extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
ha-entity-picker {
|
ha-entity-picker:first-child {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
@ -50,10 +50,8 @@ import { HomeAssistant, Route } from "../../../types";
|
|||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import { HaDeviceAction } from "./action/types/ha-automation-action-device_id";
|
|
||||||
import "./blueprint-automation-editor";
|
import "./blueprint-automation-editor";
|
||||||
import "./manual-automation-editor";
|
import "./manual-automation-editor";
|
||||||
import { HaDeviceTrigger } from "./trigger/types/ha-automation-trigger-device";
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
@ -329,9 +327,9 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
baseConfig = {
|
baseConfig = {
|
||||||
...baseConfig,
|
...baseConfig,
|
||||||
mode: "single",
|
mode: "single",
|
||||||
trigger: [{ platform: "device", ...HaDeviceTrigger.defaultConfig }],
|
trigger: [],
|
||||||
condition: [],
|
condition: [],
|
||||||
action: [{ ...HaDeviceAction.defaultConfig }],
|
action: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this._config = {
|
this._config = {
|
||||||
@ -570,6 +568,11 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
manual-automation-editor {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 1040px;
|
||||||
|
padding: 28px 20px 0;
|
||||||
|
}
|
||||||
ha-yaml-editor {
|
ha-yaml-editor {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
--code-mirror-height: 100%;
|
--code-mirror-height: 100%;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
|
import { mdiHelpCircle } from "@mdi/js";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
@ -7,6 +8,7 @@ import "../../../components/entity/ha-entity-toggle";
|
|||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-textarea";
|
import "../../../components/ha-textarea";
|
||||||
import "../../../components/ha-textfield";
|
import "../../../components/ha-textfield";
|
||||||
|
import "../../../components/ha-icon-button";
|
||||||
import {
|
import {
|
||||||
AUTOMATION_DEFAULT_MODE,
|
AUTOMATION_DEFAULT_MODE,
|
||||||
Condition,
|
Condition,
|
||||||
@ -18,7 +20,6 @@ import { Action, isMaxMode, MODES } from "../../../data/script";
|
|||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import "../ha-config-section";
|
|
||||||
import "./action/ha-automation-action";
|
import "./action/ha-automation-action";
|
||||||
import "./condition/ha-automation-condition";
|
import "./condition/ha-automation-condition";
|
||||||
import "./trigger/ha-automation-trigger";
|
import "./trigger/ha-automation-trigger";
|
||||||
@ -38,218 +39,198 @@ export class HaManualAutomationEditor extends LitElement {
|
|||||||
@state() private _showDescription = false;
|
@state() private _showDescription = false;
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`<ha-config-section vertical .isWide=${this.isWide}>
|
return html`
|
||||||
${!this.narrow
|
<ha-card outlined>
|
||||||
? html`<span slot="header">${this.config.alias}</span>`
|
<div class="card-content">
|
||||||
: ""}
|
<ha-textfield
|
||||||
<span slot="introduction">
|
.label=${this.hass.localize(
|
||||||
${this.hass.localize(
|
"ui.panel.config.automation.editor.alias"
|
||||||
"ui.panel.config.automation.editor.introduction"
|
)}
|
||||||
)}
|
name="alias"
|
||||||
</span>
|
.value=${this.config.alias || ""}
|
||||||
<ha-card outlined>
|
@change=${this._valueChanged}
|
||||||
<div class="card-content">
|
>
|
||||||
<ha-textfield
|
</ha-textfield>
|
||||||
.label=${this.hass.localize(
|
${this._showDescription
|
||||||
"ui.panel.config.automation.editor.alias"
|
|
||||||
)}
|
|
||||||
name="alias"
|
|
||||||
.value=${this.config.alias || ""}
|
|
||||||
@change=${this._valueChanged}
|
|
||||||
>
|
|
||||||
</ha-textfield>
|
|
||||||
${this._showDescription
|
|
||||||
? html`
|
|
||||||
<ha-textarea
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.description.label"
|
|
||||||
)}
|
|
||||||
.placeholder=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.description.placeholder"
|
|
||||||
)}
|
|
||||||
name="description"
|
|
||||||
autogrow
|
|
||||||
.value=${this.config.description || ""}
|
|
||||||
@change=${this._valueChanged}
|
|
||||||
></ha-textarea>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<div class="link-button-row">
|
|
||||||
<button class="link" @click=${this._addDescription}>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.description.add"
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`}
|
|
||||||
<p>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.modes.description",
|
|
||||||
"documentation_link",
|
|
||||||
html`<a
|
|
||||||
href=${documentationUrl(this.hass, "/docs/automation/modes/")}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.modes.documentation"
|
|
||||||
)}</a
|
|
||||||
>`
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<ha-select
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.modes.label"
|
|
||||||
)}
|
|
||||||
.value=${this.config.mode || AUTOMATION_DEFAULT_MODE}
|
|
||||||
@selected=${this._modeChanged}
|
|
||||||
fixedMenuPosition
|
|
||||||
>
|
|
||||||
${MODES.map(
|
|
||||||
(mode) => html`
|
|
||||||
<mwc-list-item .value=${mode}>
|
|
||||||
${this.hass.localize(
|
|
||||||
`ui.panel.config.automation.editor.modes.${mode}`
|
|
||||||
) || mode}
|
|
||||||
</mwc-list-item>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-select>
|
|
||||||
${this.config.mode && isMaxMode(this.config.mode)
|
|
||||||
? html`
|
|
||||||
<br /><ha-textfield
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
`ui.panel.config.automation.editor.max.${this.config.mode}`
|
|
||||||
)}
|
|
||||||
type="number"
|
|
||||||
name="max"
|
|
||||||
.value=${this.config.max || "10"}
|
|
||||||
@change=${this._valueChanged}
|
|
||||||
class="max"
|
|
||||||
>
|
|
||||||
</ha-textfield>
|
|
||||||
`
|
|
||||||
: html``}
|
|
||||||
</div>
|
|
||||||
${this.stateObj
|
|
||||||
? html`
|
? html`
|
||||||
<div class="card-actions layout horizontal justified center">
|
<ha-textarea
|
||||||
<div class="layout horizontal center">
|
.label=${this.hass.localize(
|
||||||
<ha-entity-toggle
|
"ui.panel.config.automation.editor.description.label"
|
||||||
.hass=${this.hass}
|
)}
|
||||||
.stateObj=${this.stateObj!}
|
.placeholder=${this.hass.localize(
|
||||||
></ha-entity-toggle>
|
"ui.panel.config.automation.editor.description.placeholder"
|
||||||
${this.hass.localize(
|
)}
|
||||||
"ui.panel.config.automation.editor.enable_disable"
|
name="description"
|
||||||
)}
|
autogrow
|
||||||
</div>
|
.value=${this.config.description || ""}
|
||||||
<div>
|
@change=${this._valueChanged}
|
||||||
<a href="/config/automation/trace/${this.config.id}">
|
></ha-textarea>
|
||||||
<mwc-button>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.show_trace"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
|
||||||
</a>
|
|
||||||
<mwc-button
|
|
||||||
@click=${this._runActions}
|
|
||||||
.stateObj=${this.stateObj}
|
|
||||||
>
|
|
||||||
${this.hass.localize("ui.card.automation.trigger")}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: html`
|
||||||
</ha-card>
|
<div class="link-button-row">
|
||||||
</ha-config-section>
|
<button class="link" @click=${this._addDescription}>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.description.add"
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
<ha-select
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.modes.label"
|
||||||
|
)}
|
||||||
|
.value=${this.config.mode || AUTOMATION_DEFAULT_MODE}
|
||||||
|
@selected=${this._modeChanged}
|
||||||
|
fixedMenuPosition
|
||||||
|
.helper=${html`
|
||||||
|
<a
|
||||||
|
style="color: var(--secondary-text-color)"
|
||||||
|
href=${documentationUrl(this.hass, "/docs/automation/modes/")}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.modes.learn_more"
|
||||||
|
)}</a
|
||||||
|
>
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
${MODES.map(
|
||||||
|
(mode) => html`
|
||||||
|
<mwc-list-item .value=${mode}>
|
||||||
|
${this.hass.localize(
|
||||||
|
`ui.panel.config.automation.editor.modes.${mode}`
|
||||||
|
) || mode}
|
||||||
|
</mwc-list-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-select>
|
||||||
|
${this.config.mode && isMaxMode(this.config.mode)
|
||||||
|
? html`
|
||||||
|
<br /><ha-textfield
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.panel.config.automation.editor.max.${this.config.mode}`
|
||||||
|
)}
|
||||||
|
type="number"
|
||||||
|
name="max"
|
||||||
|
.value=${this.config.max || "10"}
|
||||||
|
@change=${this._valueChanged}
|
||||||
|
class="max"
|
||||||
|
>
|
||||||
|
</ha-textfield>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
</div>
|
||||||
|
${this.stateObj
|
||||||
|
? html`
|
||||||
|
<div class="card-actions layout horizontal justified center">
|
||||||
|
<div class="layout horizontal center">
|
||||||
|
<ha-entity-toggle
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${this.stateObj!}
|
||||||
|
></ha-entity-toggle>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.enable_disable"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="/config/automation/trace/${this.config.id}">
|
||||||
|
<mwc-button>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.show_trace"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</a>
|
||||||
|
<mwc-button
|
||||||
|
@click=${this._runActions}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.card.automation.trigger")}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</ha-card>
|
||||||
|
|
||||||
<ha-config-section vertical .isWide=${this.isWide}>
|
<div class="header">
|
||||||
<span slot="header">
|
<div class="name">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.triggers.header"
|
"ui.panel.config.automation.editor.triggers.header"
|
||||||
)}
|
)}
|
||||||
</span>
|
</div>
|
||||||
<span slot="introduction">
|
<a
|
||||||
<p>
|
href=${documentationUrl(this.hass, "/docs/automation/trigger/")}
|
||||||
${this.hass.localize(
|
target="_blank"
|
||||||
"ui.panel.config.automation.editor.triggers.introduction"
|
rel="noreferrer"
|
||||||
)}
|
>
|
||||||
</p>
|
<ha-icon-button
|
||||||
<a
|
.path=${mdiHelpCircle}
|
||||||
href=${documentationUrl(this.hass, "/docs/automation/trigger/")}
|
.label=${this.hass.localize(
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.triggers.learn_more"
|
"ui.panel.config.automation.editor.triggers.learn_more"
|
||||||
)}
|
)}
|
||||||
</a>
|
></ha-icon-button>
|
||||||
</span>
|
</a>
|
||||||
<ha-automation-trigger
|
</div>
|
||||||
.triggers=${this.config.trigger}
|
|
||||||
@value-changed=${this._triggerChanged}
|
|
||||||
.hass=${this.hass}
|
|
||||||
></ha-automation-trigger>
|
|
||||||
</ha-config-section>
|
|
||||||
|
|
||||||
<ha-config-section vertical .isWide=${this.isWide}>
|
<ha-automation-trigger
|
||||||
<span slot="header">
|
.triggers=${this.config.trigger}
|
||||||
|
@value-changed=${this._triggerChanged}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-automation-trigger>
|
||||||
|
|
||||||
|
<div class="header">
|
||||||
|
<div class="name">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.conditions.header"
|
"ui.panel.config.automation.editor.conditions.header"
|
||||||
)}
|
)}
|
||||||
</span>
|
</div>
|
||||||
<span slot="introduction">
|
<a
|
||||||
<p>
|
href=${documentationUrl(this.hass, "/docs/automation/condition/")}
|
||||||
${this.hass.localize(
|
target="_blank"
|
||||||
"ui.panel.config.automation.editor.conditions.introduction"
|
rel="noreferrer"
|
||||||
)}
|
>
|
||||||
</p>
|
<ha-icon-button
|
||||||
<a
|
.path=${mdiHelpCircle}
|
||||||
href=${documentationUrl(this.hass, "/docs/scripts/conditions/")}
|
.label=${this.hass.localize(
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.conditions.learn_more"
|
"ui.panel.config.automation.editor.conditions.learn_more"
|
||||||
)}
|
)}
|
||||||
</a>
|
></ha-icon-button>
|
||||||
</span>
|
</a>
|
||||||
<ha-automation-condition
|
</div>
|
||||||
.conditions=${this.config.condition || []}
|
|
||||||
@value-changed=${this._conditionChanged}
|
|
||||||
.hass=${this.hass}
|
|
||||||
></ha-automation-condition>
|
|
||||||
</ha-config-section>
|
|
||||||
|
|
||||||
<ha-config-section vertical .isWide=${this.isWide}>
|
<ha-automation-condition
|
||||||
<span slot="header">
|
.conditions=${this.config.condition || []}
|
||||||
|
@value-changed=${this._conditionChanged}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-automation-condition>
|
||||||
|
|
||||||
|
<div class="header">
|
||||||
|
<div class="name">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.actions.header"
|
"ui.panel.config.automation.editor.actions.header"
|
||||||
)}
|
)}
|
||||||
</span>
|
</div>
|
||||||
<span slot="introduction">
|
<a
|
||||||
<p>
|
href=${documentationUrl(this.hass, "/docs/automation/action/")}
|
||||||
${this.hass.localize(
|
target="_blank"
|
||||||
"ui.panel.config.automation.editor.actions.introduction"
|
rel="noreferrer"
|
||||||
)}
|
>
|
||||||
</p>
|
<ha-icon-button
|
||||||
<a
|
.path=${mdiHelpCircle}
|
||||||
href=${documentationUrl(this.hass, "/docs/automation/action/")}
|
.label=${this.hass.localize(
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.actions.learn_more"
|
"ui.panel.config.automation.editor.actions.learn_more"
|
||||||
)}
|
)}
|
||||||
</a>
|
></ha-icon-button>
|
||||||
</span>
|
</a>
|
||||||
<ha-automation-action
|
</div>
|
||||||
.actions=${this.config.action}
|
|
||||||
@value-changed=${this._actionChanged}
|
<ha-automation-action
|
||||||
.hass=${this.hass}
|
.actions=${this.config.action}
|
||||||
.narrow=${this.narrow}
|
@value-changed=${this._actionChanged}
|
||||||
></ha-automation-action>
|
.hass=${this.hass}
|
||||||
</ha-config-section>`;
|
.narrow=${this.narrow}
|
||||||
|
></ha-automation-action>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected willUpdate(changedProps: PropertyValues): void {
|
protected willUpdate(changedProps: PropertyValues): void {
|
||||||
@ -341,6 +322,9 @@ export class HaManualAutomationEditor extends LitElement {
|
|||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
ha-card {
|
ha-card {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@ -351,9 +335,7 @@ export class HaManualAutomationEditor extends LitElement {
|
|||||||
ha-textfield {
|
ha-textfield {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
span[slot="introduction"] a {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
@ -365,6 +347,19 @@ export class HaManualAutomationEditor extends LitElement {
|
|||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
margin: 16px 0;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.header .name {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.header a {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,16 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
|||||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { stringCompare } from "../../../../common/string/compare";
|
|
||||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||||
import { LocalizeFunc } from "../../../../common/translations/localize";
|
|
||||||
import { debounce } from "../../../../common/util/debounce";
|
import { debounce } from "../../../../common/util/debounce";
|
||||||
import "../../../../components/ha-alert";
|
import "../../../../components/ha-alert";
|
||||||
import "../../../../components/ha-button-menu";
|
import "../../../../components/ha-button-menu";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
|
import "../../../../components/ha-expansion-panel";
|
||||||
import "../../../../components/ha-icon-button";
|
import "../../../../components/ha-icon-button";
|
||||||
import { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
import { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||||
import "../../../../components/ha-select";
|
|
||||||
import type { HaSelect } from "../../../../components/ha-select";
|
|
||||||
import "../../../../components/ha-textfield";
|
import "../../../../components/ha-textfield";
|
||||||
import { subscribeTrigger, Trigger } from "../../../../data/automation";
|
import { subscribeTrigger, Trigger } from "../../../../data/automation";
|
||||||
import { validateConfig } from "../../../../data/config";
|
import { validateConfig } from "../../../../data/config";
|
||||||
@ -43,24 +39,7 @@ import "./types/ha-automation-trigger-time";
|
|||||||
import "./types/ha-automation-trigger-time_pattern";
|
import "./types/ha-automation-trigger-time_pattern";
|
||||||
import "./types/ha-automation-trigger-webhook";
|
import "./types/ha-automation-trigger-webhook";
|
||||||
import "./types/ha-automation-trigger-zone";
|
import "./types/ha-automation-trigger-zone";
|
||||||
|
import { describeTrigger } from "../../../../data/automation_i18n";
|
||||||
const OPTIONS = [
|
|
||||||
"calendar",
|
|
||||||
"device",
|
|
||||||
"event",
|
|
||||||
"state",
|
|
||||||
"geo_location",
|
|
||||||
"homeassistant",
|
|
||||||
"mqtt",
|
|
||||||
"numeric_state",
|
|
||||||
"sun",
|
|
||||||
"tag",
|
|
||||||
"template",
|
|
||||||
"time",
|
|
||||||
"time_pattern",
|
|
||||||
"webhook",
|
|
||||||
"zone",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export interface TriggerElement extends LitElement {
|
export interface TriggerElement extends LitElement {
|
||||||
trigger: Trigger;
|
trigger: Trigger;
|
||||||
@ -88,6 +67,8 @@ export const handleChangeEvent = (element: TriggerElement, ev: CustomEvent) => {
|
|||||||
fireEvent(element, "value-changed", { value: newTrigger });
|
fireEvent(element, "value-changed", { value: newTrigger });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const preventDefault = (ev) => ev.preventDefault();
|
||||||
|
|
||||||
@customElement("ha-automation-trigger-row")
|
@customElement("ha-automation-trigger-row")
|
||||||
export default class HaAutomationTriggerRow extends LitElement {
|
export default class HaAutomationTriggerRow extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -108,35 +89,36 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
|
|
||||||
private _triggerUnsub?: Promise<UnsubscribeFunc>;
|
private _triggerUnsub?: Promise<UnsubscribeFunc>;
|
||||||
|
|
||||||
private _processedTypes = memoizeOne(
|
|
||||||
(localize: LocalizeFunc): [string, string][] =>
|
|
||||||
OPTIONS.map(
|
|
||||||
(action) =>
|
|
||||||
[
|
|
||||||
action,
|
|
||||||
localize(
|
|
||||||
`ui.panel.config.automation.editor.triggers.type.${action}.label`
|
|
||||||
),
|
|
||||||
] as [string, string]
|
|
||||||
).sort((a, b) => stringCompare(a[1], b[1]))
|
|
||||||
);
|
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
const selected = OPTIONS.indexOf(this.trigger.platform);
|
const supported =
|
||||||
const yamlMode = this._yamlMode || selected === -1;
|
customElements.get(`ha-automation-trigger-${this.trigger.platform}`) !==
|
||||||
|
undefined;
|
||||||
|
const yamlMode = this._yamlMode || !supported;
|
||||||
const showId = "id" in this.trigger || this._requestShowId;
|
const showId = "id" in this.trigger || this._requestShowId;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card outlined>
|
<ha-card outlined>
|
||||||
${this.trigger.enabled === false
|
${this.trigger.enabled === false
|
||||||
? html`<div class="disabled-bar">
|
? html`
|
||||||
${this.hass.localize(
|
<div class="disabled-bar">
|
||||||
"ui.panel.config.automation.editor.actions.disabled"
|
${this.hass.localize(
|
||||||
)}
|
"ui.panel.config.automation.editor.actions.disabled"
|
||||||
</div>`
|
)}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
: ""}
|
: ""}
|
||||||
<div class="card-menu">
|
|
||||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
<ha-expansion-panel
|
||||||
|
leftChevron
|
||||||
|
.header=${describeTrigger(this.trigger)}
|
||||||
|
>
|
||||||
|
<ha-button-menu
|
||||||
|
slot="icons"
|
||||||
|
fixed
|
||||||
|
corner="BOTTOM_START"
|
||||||
|
@action=${this._handleAction}
|
||||||
|
@click=${preventDefault}
|
||||||
|
>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
.label=${this.hass.localize("ui.common.menu")}
|
.label=${this.hass.localize("ui.common.menu")}
|
||||||
@ -147,7 +129,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
"ui.panel.config.automation.editor.triggers.edit_id"
|
"ui.panel.config.automation.editor.triggers.edit_id"
|
||||||
)}
|
)}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
<mwc-list-item .disabled=${selected === -1}>
|
<mwc-list-item .disabled=${!supported}>
|
||||||
${yamlMode
|
${yamlMode
|
||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.edit_ui"
|
"ui.panel.config.automation.editor.edit_ui"
|
||||||
@ -176,86 +158,77 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="card-content ${this.trigger.enabled === false
|
class=${classMap({
|
||||||
? "disabled"
|
"card-content": true,
|
||||||
: ""}"
|
disabled: this.trigger.enabled === false,
|
||||||
>
|
})}
|
||||||
${this._warnings
|
>
|
||||||
? html`<ha-alert
|
${this._warnings
|
||||||
alert-type="warning"
|
? html`<ha-alert
|
||||||
.title=${this.hass.localize(
|
alert-type="warning"
|
||||||
"ui.errors.config.editor_not_supported"
|
.title=${this.hass.localize(
|
||||||
)}
|
"ui.errors.config.editor_not_supported"
|
||||||
>
|
|
||||||
${this._warnings.length && this._warnings[0] !== undefined
|
|
||||||
? html` <ul>
|
|
||||||
${this._warnings.map(
|
|
||||||
(warning) => html`<li>${warning}</li>`
|
|
||||||
)}
|
|
||||||
</ul>`
|
|
||||||
: ""}
|
|
||||||
${this.hass.localize("ui.errors.config.edit_in_yaml_supported")}
|
|
||||||
</ha-alert>`
|
|
||||||
: ""}
|
|
||||||
${yamlMode
|
|
||||||
? html`
|
|
||||||
${selected === -1
|
|
||||||
? html`
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.triggers.unsupported_platform",
|
|
||||||
"platform",
|
|
||||||
this.trigger.platform
|
|
||||||
)}
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<h2>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.edit_yaml"
|
|
||||||
)}
|
)}
|
||||||
</h2>
|
|
||||||
<ha-yaml-editor
|
|
||||||
.hass=${this.hass}
|
|
||||||
.defaultValue=${this.trigger}
|
|
||||||
@value-changed=${this._onYamlChange}
|
|
||||||
></ha-yaml-editor>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<ha-select
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.triggers.type_select"
|
|
||||||
)}
|
|
||||||
.value=${this.trigger.platform}
|
|
||||||
naturalMenuWidth
|
|
||||||
@selected=${this._typeChanged}
|
|
||||||
>
|
>
|
||||||
${this._processedTypes(this.hass.localize).map(
|
${this._warnings.length && this._warnings[0] !== undefined
|
||||||
([opt, label]) => html`
|
? html` <ul>
|
||||||
<mwc-list-item .value=${opt}>${label}</mwc-list-item>
|
${this._warnings.map(
|
||||||
`
|
(warning) => html`<li>${warning}</li>`
|
||||||
)}
|
|
||||||
</ha-select>
|
|
||||||
${showId
|
|
||||||
? html`
|
|
||||||
<ha-textfield
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.triggers.id"
|
|
||||||
)}
|
)}
|
||||||
.value=${this.trigger.id || ""}
|
</ul>`
|
||||||
@change=${this._idChanged}
|
: ""}
|
||||||
>
|
${this.hass.localize(
|
||||||
</ha-textfield>
|
"ui.errors.config.edit_in_yaml_supported"
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<div @ui-mode-not-available=${this._handleUiModeNotAvailable}>
|
|
||||||
${dynamicElement(
|
|
||||||
`ha-automation-trigger-${this.trigger.platform}`,
|
|
||||||
{ hass: this.hass, trigger: this.trigger }
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</ha-alert>`
|
||||||
`}
|
: ""}
|
||||||
</div>
|
${yamlMode
|
||||||
|
? html`
|
||||||
|
${!supported
|
||||||
|
? html`
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.triggers.unsupported_platform",
|
||||||
|
"platform",
|
||||||
|
this.trigger.platform
|
||||||
|
)}
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<h2>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.edit_yaml"
|
||||||
|
)}
|
||||||
|
</h2>
|
||||||
|
<ha-yaml-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.defaultValue=${this.trigger}
|
||||||
|
@value-changed=${this._onYamlChange}
|
||||||
|
></ha-yaml-editor>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
${showId
|
||||||
|
? html`
|
||||||
|
<ha-textfield
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.triggers.id"
|
||||||
|
)}
|
||||||
|
.value=${this.trigger.id || ""}
|
||||||
|
@change=${this._idChanged}
|
||||||
|
>
|
||||||
|
</ha-textfield>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<div @ui-mode-not-available=${this._handleUiModeNotAvailable}>
|
||||||
|
${dynamicElement(
|
||||||
|
`ha-automation-trigger-${this.trigger.platform}`,
|
||||||
|
{ hass: this.hass, trigger: this.trigger }
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
</ha-expansion-panel>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="triggered ${classMap({
|
class="triggered ${classMap({
|
||||||
active: this._triggered !== undefined,
|
active: this._triggered !== undefined,
|
||||||
@ -360,6 +333,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
switch (ev.detail.index) {
|
switch (ev.detail.index) {
|
||||||
case 0:
|
case 0:
|
||||||
this._requestShowId = true;
|
this._requestShowId = true;
|
||||||
|
this.expand();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
this._switchYamlMode();
|
this._switchYamlMode();
|
||||||
@ -398,33 +372,6 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _typeChanged(ev: CustomEvent) {
|
|
||||||
const type = (ev.target as HaSelect).value;
|
|
||||||
|
|
||||||
if (!type) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const elClass = customElements.get(
|
|
||||||
`ha-automation-trigger-${type}`
|
|
||||||
) as CustomElementConstructor & {
|
|
||||||
defaultConfig: Omit<Trigger, "platform">;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type !== this.trigger.platform) {
|
|
||||||
const value = {
|
|
||||||
platform: type,
|
|
||||||
...elClass.defaultConfig,
|
|
||||||
};
|
|
||||||
if (this.trigger.id) {
|
|
||||||
value.id = this.trigger.id;
|
|
||||||
}
|
|
||||||
fireEvent(this, "value-changed", {
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _idChanged(ev: CustomEvent) {
|
private _idChanged(ev: CustomEvent) {
|
||||||
const newId = (ev.target as any).value;
|
const newId = (ev.target as any).value;
|
||||||
if (newId === (this.trigger.id ?? "")) {
|
if (newId === (this.trigger.id ?? "")) {
|
||||||
@ -468,17 +415,29 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public expand() {
|
||||||
|
this.updateComplete.then(() => {
|
||||||
|
this.shadowRoot!.querySelector("ha-expansion-panel")!.expanded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
|
ha-button-menu {
|
||||||
|
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||||
|
}
|
||||||
.disabled {
|
.disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
ha-expansion-panel {
|
||||||
|
--expansion-panel-summary-padding: 0 0 0 8px;
|
||||||
|
--expansion-panel-content-padding: 0;
|
||||||
|
}
|
||||||
.card-content {
|
.card-content {
|
||||||
padding-top: 16px;
|
padding: 16px;
|
||||||
margin-top: 0;
|
|
||||||
}
|
}
|
||||||
.disabled-bar {
|
.disabled-bar {
|
||||||
background: var(--divider-color, #e0e0e0);
|
background: var(--divider-color, #e0e0e0);
|
||||||
@ -486,14 +445,6 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
border-top-right-radius: var(--ha-card-border-radius);
|
border-top-right-radius: var(--ha-card-border-radius);
|
||||||
border-top-left-radius: var(--ha-card-border-radius);
|
border-top-left-radius: var(--ha-card-border-radius);
|
||||||
}
|
}
|
||||||
.card-menu {
|
|
||||||
float: var(--float-end, right);
|
|
||||||
z-index: 3;
|
|
||||||
margin: 4px;
|
|
||||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.triggered {
|
.triggered {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -525,9 +476,6 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
mwc-list-item[disabled] {
|
mwc-list-item[disabled] {
|
||||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||||
}
|
}
|
||||||
ha-select {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
ha-textfield {
|
ha-textfield {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
|
@ -1,13 +1,37 @@
|
|||||||
|
import { repeat } from "lit/directives/repeat";
|
||||||
|
import { mdiPlus } from "@mdi/js";
|
||||||
import deepClone from "deep-clone-simple";
|
import deepClone from "deep-clone-simple";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import type { ActionDetail } from "@material/mwc-list";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-svg-icon";
|
||||||
|
import "../../../../components/ha-button-menu";
|
||||||
import { Trigger } from "../../../../data/automation";
|
import { Trigger } from "../../../../data/automation";
|
||||||
|
import { TRIGGER_TYPES } from "../../../../data/trigger";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
import "./ha-automation-trigger-row";
|
import "./ha-automation-trigger-row";
|
||||||
import { HaDeviceTrigger } from "./types/ha-automation-trigger-device";
|
import type HaAutomationTriggerRow from "./ha-automation-trigger-row";
|
||||||
|
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
|
import { stringCompare } from "../../../../common/string/compare";
|
||||||
|
import type { HaSelect } from "../../../../components/ha-select";
|
||||||
|
import "./types/ha-automation-trigger-calendar";
|
||||||
|
import "./types/ha-automation-trigger-device";
|
||||||
|
import "./types/ha-automation-trigger-event";
|
||||||
|
import "./types/ha-automation-trigger-geo_location";
|
||||||
|
import "./types/ha-automation-trigger-homeassistant";
|
||||||
|
import "./types/ha-automation-trigger-mqtt";
|
||||||
|
import "./types/ha-automation-trigger-numeric_state";
|
||||||
|
import "./types/ha-automation-trigger-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";
|
||||||
|
|
||||||
@customElement("ha-automation-trigger")
|
@customElement("ha-automation-trigger")
|
||||||
export default class HaAutomationTrigger extends LitElement {
|
export default class HaAutomationTrigger extends LitElement {
|
||||||
@ -15,9 +39,15 @@ export default class HaAutomationTrigger extends LitElement {
|
|||||||
|
|
||||||
@property() public triggers!: Trigger[];
|
@property() public triggers!: Trigger[];
|
||||||
|
|
||||||
|
private _focusLastTriggerOnChange = false;
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
${this.triggers.map(
|
${repeat(
|
||||||
|
this.triggers,
|
||||||
|
// Use the trigger as key, so moving around keeps the same DOM,
|
||||||
|
// including expand state
|
||||||
|
(trigger) => trigger,
|
||||||
(trg, idx) => html`
|
(trg, idx) => html`
|
||||||
<ha-automation-trigger-row
|
<ha-automation-trigger-row
|
||||||
.index=${idx}
|
.index=${idx}
|
||||||
@ -28,24 +58,54 @@ export default class HaAutomationTrigger extends LitElement {
|
|||||||
></ha-automation-trigger-row>
|
></ha-automation-trigger-row>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
<ha-card outlined>
|
<ha-button-menu @action=${this._addTrigger}>
|
||||||
<div class="card-actions add-card">
|
<mwc-button
|
||||||
<mwc-button @click=${this._addTrigger}>
|
slot="trigger"
|
||||||
${this.hass.localize(
|
outlined
|
||||||
"ui.panel.config.automation.editor.triggers.add"
|
.label=${this.hass.localize(
|
||||||
)}
|
"ui.panel.config.automation.editor.triggers.add"
|
||||||
</mwc-button>
|
)}
|
||||||
</div>
|
>
|
||||||
</ha-card>
|
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||||
|
</mwc-button>
|
||||||
|
${this._processedTypes(this.hass.localize).map(
|
||||||
|
([opt, label]) => html`
|
||||||
|
<mwc-list-item .value=${opt}>${label}</mwc-list-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-button-menu>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _addTrigger() {
|
protected updated(changedProps: PropertyValues) {
|
||||||
const triggers = this.triggers.concat({
|
super.updated(changedProps);
|
||||||
platform: "device",
|
|
||||||
...HaDeviceTrigger.defaultConfig,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
if (changedProps.has("triggers") && this._focusLastTriggerOnChange) {
|
||||||
|
this._focusLastTriggerOnChange = false;
|
||||||
|
|
||||||
|
const row = this.shadowRoot!.querySelector<HaAutomationTriggerRow>(
|
||||||
|
"ha-automation-trigger-row:last-of-type"
|
||||||
|
)!;
|
||||||
|
row.expand();
|
||||||
|
row.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addTrigger(ev: CustomEvent<ActionDetail>) {
|
||||||
|
const platform = (ev.currentTarget as HaSelect).items[ev.detail.index]
|
||||||
|
.value as Trigger["platform"];
|
||||||
|
|
||||||
|
const elClass = customElements.get(
|
||||||
|
`ha-automation-trigger-${platform}`
|
||||||
|
) as CustomElementConstructor & {
|
||||||
|
defaultConfig: Omit<Trigger, "platform">;
|
||||||
|
};
|
||||||
|
|
||||||
|
const triggers = this.triggers.concat({
|
||||||
|
platform: platform as any,
|
||||||
|
...elClass.defaultConfig,
|
||||||
|
});
|
||||||
|
this._focusLastTriggerOnChange = true;
|
||||||
fireEvent(this, "value-changed", { value: triggers });
|
fireEvent(this, "value-changed", { value: triggers });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,16 +132,27 @@ export default class HaAutomationTrigger extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _processedTypes = memoizeOne(
|
||||||
|
(localize: LocalizeFunc): [string, string][] =>
|
||||||
|
TRIGGER_TYPES.map(
|
||||||
|
(action) =>
|
||||||
|
[
|
||||||
|
action,
|
||||||
|
localize(
|
||||||
|
`ui.panel.config.automation.editor.triggers.type.${action}.label`
|
||||||
|
),
|
||||||
|
] as [string, string]
|
||||||
|
).sort((a, b) => stringCompare(a[1], b[1]))
|
||||||
|
);
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
ha-automation-trigger-row,
|
ha-automation-trigger-row {
|
||||||
ha-card {
|
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
.add-card mwc-button {
|
ha-svg-icon {
|
||||||
display: block;
|
height: 20px;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { html, LitElement, PropertyValues } from "lit";
|
import { css, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
import { caseInsensitiveStringCompare } from "../../../../../common/string/compare";
|
import { caseInsensitiveStringCompare } from "../../../../../common/string/compare";
|
||||||
@ -63,6 +63,14 @@ export class HaTagTrigger extends LitElement implements TriggerElement {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-select {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import "../../../../../components/ha-textarea";
|
import "../../../../../components/ha-textarea";
|
||||||
import { html, LitElement } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import type { TemplateTrigger } from "../../../../../data/automation";
|
import type { TemplateTrigger } from "../../../../../data/automation";
|
||||||
import type { HomeAssistant } from "../../../../../types";
|
import type { HomeAssistant } from "../../../../../types";
|
||||||
@ -39,6 +39,14 @@ export class HaTemplateTrigger extends LitElement {
|
|||||||
private _valueChanged(ev: CustomEvent): void {
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
handleChangeEvent(this, ev);
|
handleChangeEvent(this, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
mdiContentSave,
|
mdiContentSave,
|
||||||
mdiDelete,
|
mdiDelete,
|
||||||
mdiDotsVertical,
|
mdiDotsVertical,
|
||||||
|
mdiHelpCircle,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import "@polymer/app-layout/app-header/app-header";
|
import "@polymer/app-layout/app-header/app-header";
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
@ -56,7 +57,6 @@ import type { HomeAssistant, Route } from "../../../types";
|
|||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import { HaDeviceAction } from "../automation/action/types/ha-automation-action-device_id";
|
import { HaDeviceAction } from "../automation/action/types/ha-automation-action-device_id";
|
||||||
import "../ha-config-section";
|
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "./blueprint-script-editor";
|
import "./blueprint-script-editor";
|
||||||
|
|
||||||
@ -276,59 +276,47 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
>
|
>
|
||||||
${this._config
|
${this._config
|
||||||
? html`
|
? html`
|
||||||
<ha-config-section vertical .isWide=${this.isWide}>
|
<ha-card outlined>
|
||||||
${!this.narrow
|
<div class="card-content">
|
||||||
|
<ha-form
|
||||||
|
.schema=${schema}
|
||||||
|
.data=${data}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.computeLabel=${this._computeLabelCallback}
|
||||||
|
.computeHelper=${this._computeHelperCallback}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></ha-form>
|
||||||
|
</div>
|
||||||
|
${this.scriptEntityId
|
||||||
? html`
|
? html`
|
||||||
<span slot="header">${this._config.alias}</span>
|
<div
|
||||||
`
|
class="card-actions layout horizontal justified center"
|
||||||
: ""}
|
>
|
||||||
<span slot="introduction">
|
<a
|
||||||
${this.hass.localize(
|
href="/config/script/trace/${this
|
||||||
"ui.panel.config.script.editor.introduction"
|
.scriptEntityId}"
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<ha-card outlined>
|
|
||||||
<div class="card-content">
|
|
||||||
<ha-form
|
|
||||||
.schema=${schema}
|
|
||||||
.data=${data}
|
|
||||||
.hass=${this.hass}
|
|
||||||
.computeLabel=${this._computeLabelCallback}
|
|
||||||
.computeHelper=${this._computeHelperCallback}
|
|
||||||
@value-changed=${this._valueChanged}
|
|
||||||
></ha-form>
|
|
||||||
</div>
|
|
||||||
${this.scriptEntityId
|
|
||||||
? html`
|
|
||||||
<div
|
|
||||||
class="card-actions layout horizontal justified center"
|
|
||||||
>
|
>
|
||||||
<a
|
<mwc-button>
|
||||||
href="/config/script/trace/${this
|
|
||||||
.scriptEntityId}"
|
|
||||||
>
|
|
||||||
<mwc-button>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.script.editor.show_trace"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
|
||||||
</a>
|
|
||||||
<mwc-button
|
|
||||||
@click=${this._runScript}
|
|
||||||
title=${this.hass.localize(
|
|
||||||
"ui.panel.config.script.picker.run_script"
|
|
||||||
)}
|
|
||||||
?disabled=${this._dirty}
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.script.picker.run_script"
|
"ui.panel.config.script.editor.show_trace"
|
||||||
)}
|
)}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>
|
</a>
|
||||||
`
|
<mwc-button
|
||||||
: ``}
|
@click=${this._runScript}
|
||||||
</ha-card>
|
title=${this.hass.localize(
|
||||||
</ha-config-section>
|
"ui.panel.config.script.picker.run_script"
|
||||||
|
)}
|
||||||
|
?disabled=${this._dirty}
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.script.picker.run_script"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ``}
|
||||||
|
</ha-card>
|
||||||
|
|
||||||
${"use_blueprint" in this._config
|
${"use_blueprint" in this._config
|
||||||
? html`
|
? html`
|
||||||
@ -341,40 +329,34 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
></blueprint-script-editor>
|
></blueprint-script-editor>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<ha-config-section
|
<div class="header">
|
||||||
vertical
|
<div class="name">
|
||||||
.isWide=${this.isWide}
|
|
||||||
>
|
|
||||||
<span slot="header">
|
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.script.editor.sequence"
|
"ui.panel.config.script.editor.sequence"
|
||||||
)}
|
)}
|
||||||
</span>
|
</div>
|
||||||
<span slot="introduction">
|
<a
|
||||||
<p>
|
href=${documentationUrl(
|
||||||
${this.hass.localize(
|
this.hass,
|
||||||
"ui.panel.config.script.editor.sequence_sentence"
|
"/docs/scripts/"
|
||||||
)}
|
)}
|
||||||
</p>
|
target="_blank"
|
||||||
<a
|
rel="noreferrer"
|
||||||
href=${documentationUrl(
|
>
|
||||||
this.hass,
|
<ha-icon-button
|
||||||
"/docs/scripts/"
|
.path=${mdiHelpCircle}
|
||||||
)}
|
.label=${this.hass.localize(
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.script.editor.link_available_actions"
|
"ui.panel.config.script.editor.link_available_actions"
|
||||||
)}
|
)}
|
||||||
</a>
|
></ha-icon-button>
|
||||||
</span>
|
</a>
|
||||||
<ha-automation-action
|
</div>
|
||||||
.actions=${this._config.sequence}
|
|
||||||
@value-changed=${this._sequenceChanged}
|
<ha-automation-action
|
||||||
.hass=${this.hass}
|
.actions=${this._config.sequence}
|
||||||
></ha-automation-action>
|
@value-changed=${this._sequenceChanged}
|
||||||
</ha-config-section>
|
.hass=${this.hass}
|
||||||
|
></ha-automation-action>
|
||||||
`}
|
`}
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@ -525,25 +507,22 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
private _computeHelperCallback = (
|
private _computeHelperCallback = (
|
||||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||||
): string | undefined => {
|
): string | undefined | TemplateResult => {
|
||||||
if (schema.name === "mode") {
|
if (schema.name === "mode") {
|
||||||
return this.hass.localize(
|
return html`
|
||||||
"ui.panel.config.script.editor.modes.description",
|
<a
|
||||||
"documentation_link",
|
style="color: var(--secondary-text-color)"
|
||||||
html`
|
href=${documentationUrl(
|
||||||
<a
|
this.hass,
|
||||||
href=${documentationUrl(
|
"/integrations/script/#script-modes"
|
||||||
this.hass,
|
)}
|
||||||
"/integrations/script/#script-modes"
|
target="_blank"
|
||||||
)}
|
rel="noreferrer"
|
||||||
target="_blank"
|
>${this.hass.localize(
|
||||||
rel="noreferrer"
|
"ui.panel.config.script.editor.modes.learn_more"
|
||||||
>${this.hass.localize(
|
)}</a
|
||||||
"ui.panel.config.script.editor.modes.documentation"
|
>
|
||||||
)}</a
|
`;
|
||||||
>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
@ -806,7 +785,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
padding-bottom: 20px;
|
padding: 16px 16px 20px;
|
||||||
}
|
}
|
||||||
.yaml-mode {
|
.yaml-mode {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -841,6 +820,16 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
li[role="separator"] {
|
li[role="separator"] {
|
||||||
border-bottom-color: var(--divider-color);
|
border-bottom-color: var(--divider-color);
|
||||||
}
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
margin: 16px 0;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.header .name {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1833,9 +1833,8 @@
|
|||||||
},
|
},
|
||||||
"modes": {
|
"modes": {
|
||||||
"label": "Mode",
|
"label": "Mode",
|
||||||
"description": "The mode controls what happens when the automation is triggered while the actions are still running from a previous trigger. Check the {documentation_link} for more info.",
|
"learn_more": "Learn about modes",
|
||||||
"documentation": "automation documentation",
|
"single": "Single",
|
||||||
"single": "Single (default)",
|
|
||||||
"restart": "Restart",
|
"restart": "Restart",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"parallel": "Parallel"
|
"parallel": "Parallel"
|
||||||
@ -1848,10 +1847,7 @@
|
|||||||
"edit_ui": "Edit in visual editor",
|
"edit_ui": "Edit in visual editor",
|
||||||
"copy_to_clipboard": "Copy to Clipboard",
|
"copy_to_clipboard": "Copy to Clipboard",
|
||||||
"triggers": {
|
"triggers": {
|
||||||
"name": "Trigger",
|
|
||||||
"header": "Triggers",
|
"header": "Triggers",
|
||||||
"introduction": "Triggers are what starts the processing of an automation rule. It is possible to specify multiple triggers for the same rule. Once a trigger starts, Home Assistant will validate the conditions, if any, and call the action.",
|
|
||||||
"learn_more": "Learn more about triggers",
|
|
||||||
"triggered": "Triggered",
|
"triggered": "Triggered",
|
||||||
"add": "Add trigger",
|
"add": "Add trigger",
|
||||||
"id": "Trigger ID",
|
"id": "Trigger ID",
|
||||||
@ -1965,10 +1961,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"conditions": {
|
"conditions": {
|
||||||
"name": "Condition",
|
|
||||||
"header": "Conditions",
|
"header": "Conditions",
|
||||||
"introduction": "Conditions are optional and will prevent the automation from running unless all conditions are satisfied.",
|
|
||||||
"learn_more": "Learn more about conditions",
|
|
||||||
"add": "Add condition",
|
"add": "Add condition",
|
||||||
"test": "Test",
|
"test": "Test",
|
||||||
"invalid_condition": "Invalid condition configuration",
|
"invalid_condition": "Invalid condition configuration",
|
||||||
@ -2054,10 +2047,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"name": "Action",
|
|
||||||
"header": "Actions",
|
"header": "Actions",
|
||||||
"introduction": "The actions are what Home Assistant will do when the automation is triggered.",
|
|
||||||
"learn_more": "Learn more about actions",
|
|
||||||
"add": "Add action",
|
"add": "Add action",
|
||||||
"invalid_action": "Invalid action",
|
"invalid_action": "Invalid action",
|
||||||
"run_action": "Run action",
|
"run_action": "Run action",
|
||||||
@ -2117,7 +2107,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"activate_scene": {
|
"activate_scene": {
|
||||||
"label": "Activate scene"
|
"label": "Activate scene",
|
||||||
|
"scene": "Scene"
|
||||||
},
|
},
|
||||||
"repeat": {
|
"repeat": {
|
||||||
"label": "Repeat",
|
"label": "Repeat",
|
||||||
@ -2261,13 +2252,12 @@
|
|||||||
"header": "Script: {name}",
|
"header": "Script: {name}",
|
||||||
"default_name": "New Script",
|
"default_name": "New Script",
|
||||||
"modes": {
|
"modes": {
|
||||||
"label": "Mode",
|
"label": "[%key:ui::panel::config::automation::editor::modes::label%]",
|
||||||
"description": "The mode controls what happens when script is invoked while it is still running from one or more previous invocations. Check the {documentation_link} for more info.",
|
"learn_more": "[%key:ui::panel::config::automation::editor::modes::learn_more%]",
|
||||||
"documentation": "script documentation",
|
"single": "[%key:ui::panel::config::automation::editor::modes::single%]",
|
||||||
"single": "Single (default)",
|
"restart": "[%key:ui::panel::config::automation::editor::modes::restart%]",
|
||||||
"restart": "Restart",
|
"queued": "[%key:ui::panel::config::automation::editor::modes::queued%]",
|
||||||
"queued": "Queued",
|
"parallel": "[%key:ui::panel::config::automation::editor::modes::parallel%]"
|
||||||
"parallel": "Parallel"
|
|
||||||
},
|
},
|
||||||
"max": {
|
"max": {
|
||||||
"queued": "Queue length",
|
"queued": "Queue length",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user