Add UI for new script functions (#6491)

This commit is contained in:
Bram Kragten 2020-08-02 20:56:26 +02:00 committed by GitHub
parent ca171afe6f
commit a2153bc6aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 442 additions and 8 deletions

View File

@ -58,6 +58,31 @@ export interface WaitAction {
timeout?: number;
}
export interface RepeatAction {
repeat: CountRepeat | WhileRepeat | UntilRepeat;
}
interface BaseRepeat {
sequence: Action[];
}
export interface CountRepeat extends BaseRepeat {
count: number;
}
export interface WhileRepeat extends BaseRepeat {
while: Condition[];
}
export interface UntilRepeat extends BaseRepeat {
until: Condition[];
}
export interface ChooseAction {
choose: [{ conditions: Condition[]; sequence: Action[] }];
default?: Action[];
}
export type Action =
| EventAction
| DeviceAction
@ -65,7 +90,9 @@ export type Action =
| Condition
| DelayAction
| SceneAction
| WaitAction;
| WaitAction
| RepeatAction
| ChooseAction;
export const triggerScript = (
hass: HomeAssistant,

View File

@ -15,6 +15,7 @@ import {
LitElement,
property,
internalProperty,
PropertyValues,
} from "lit-element";
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
import { fireEvent } from "../../../../common/dom/fire_event";
@ -29,6 +30,8 @@ import "./types/ha-automation-action-event";
import "./types/ha-automation-action-scene";
import "./types/ha-automation-action-service";
import "./types/ha-automation-action-wait_template";
import "./types/ha-automation-action-repeat";
import "./types/ha-automation-action-choose";
import { handleStructError } from "../../../lovelace/common/structs/handle-errors";
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
import { haStyle } from "../../../../resources/styles";
@ -41,6 +44,8 @@ const OPTIONS = [
"scene",
"service",
"wait_template",
"repeat",
"choose",
];
const getType = (action: Action) => {
@ -96,6 +101,16 @@ export default class HaAutomationActionRow extends LitElement {
@internalProperty() private _yamlMode = false;
protected updated(changedProperties: PropertyValues) {
if (!changedProperties.has("action")) {
return;
}
this._uiModeAvailable = Boolean(getType(this.action));
if (!this._uiModeAvailable && !this._yamlMode) {
this._yamlMode = true;
}
}
protected render() {
const type = getType(this.action);
const selected = type ? OPTIONS.indexOf(type) : -1;

View File

@ -0,0 +1,176 @@
import "@polymer/paper-input/paper-input";
import {
customElement,
LitElement,
property,
CSSResult,
css,
} from "lit-element";
import { html } from "lit-html";
import { Action, ChooseAction } from "../../../../../data/script";
import { HomeAssistant } from "../../../../../types";
import { ActionElement } from "../ha-automation-action-row";
import "../../condition/ha-automation-condition-editor";
import "@polymer/paper-listbox/paper-listbox";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../ha-automation-action";
import { Condition } from "../../../../../data/automation";
import { haStyle } from "../../../../../resources/styles";
import { mdiDelete } from "@mdi/js";
@customElement("ha-automation-action-choose")
export class HaChooseAction extends LitElement implements ActionElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public action!: ChooseAction;
public static get defaultConfig() {
return { choose: [{ conditions: [], sequence: [] }], default: [] };
}
protected render() {
const action = this.action;
return html`
${action.choose.map(
(option, idx) => html`<ha-card>
<mwc-icon-button
.idx=${idx}
@click=${this._removeOption}
title=${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.remove_option"
)}
>
<ha-svg-icon path=${mdiDelete}></ha-svg-icon>
</mwc-icon-button>
<div class="card-content">
<h2>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.option",
"number",
idx + 1
)}:
</h2>
<h3>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.conditions"
)}:
</h3>
<ha-automation-condition
.conditions=${option.conditions}
.hass=${this.hass}
.idx=${idx}
@value-changed=${this._conditionChanged}
></ha-automation-condition>
<h3>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.sequence"
)}:
</h3>
<ha-automation-action
.actions=${option.sequence}
.hass=${this.hass}
.idx=${idx}
@value-changed=${this._actionChanged}
></ha-automation-action>
</div>
</ha-card>`
)}
<ha-card>
<div class="card-actions add-card">
<mwc-button @click=${this._addOption}>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.add_option"
)}
</mwc-button>
</div>
</ha-card>
<h2>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.default"
)}:
</h2>
<ha-automation-action
.actions=${action.default || []}
@value-changed=${this._defaultChanged}
.hass=${this.hass}
></ha-automation-action>
`;
}
private _conditionChanged(ev: CustomEvent) {
ev.stopPropagation();
const value = ev.detail.value as Condition[];
const index = (ev.target as any).idx;
const choose = [...this.action.choose];
choose[index].conditions = value;
fireEvent(this, "value-changed", {
value: { ...this.action, choose },
});
}
private _actionChanged(ev: CustomEvent) {
ev.stopPropagation();
const value = ev.detail.value as Action[];
const index = (ev.target as any).idx;
const choose = [...this.action.choose];
choose[index].sequence = value;
fireEvent(this, "value-changed", {
value: { ...this.action, choose },
});
}
private _addOption() {
const choose = [...this.action.choose];
choose.push({ conditions: [], sequence: [] });
fireEvent(this, "value-changed", {
value: { ...this.action, choose },
});
}
private _removeOption(ev: CustomEvent) {
const index = (ev.currentTarget as any).idx;
const choose = [...this.action.choose];
choose.splice(index, 1);
fireEvent(this, "value-changed", {
value: { ...this.action, choose },
});
}
private _defaultChanged(ev: CustomEvent) {
ev.stopPropagation();
const value = ev.detail.value as Action[];
fireEvent(this, "value-changed", {
value: {
...this.action,
default: value,
},
});
}
static get styles(): CSSResult[] {
return [
haStyle,
css`
ha-card {
margin-top: 16px;
}
.add-card mwc-button {
display: block;
text-align: center;
}
mwc-icon-button {
position: absolute;
right: 0;
padding: 4px;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-action-choose": HaChooseAction;
}
}

View File

@ -0,0 +1,180 @@
import "@polymer/paper-input/paper-input";
import { customElement, LitElement, property, CSSResult } from "lit-element";
import { html } from "lit-html";
import {
RepeatAction,
Action,
CountRepeat,
WhileRepeat,
UntilRepeat,
} from "../../../../../data/script";
import { HomeAssistant } from "../../../../../types";
import { ActionElement } from "../ha-automation-action-row";
import "../../condition/ha-automation-condition-editor";
import type { PaperListboxElement } from "@polymer/paper-listbox";
import "@polymer/paper-listbox/paper-listbox";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../ha-automation-action";
import { Condition } from "../../../../lovelace/common/validate-condition";
import { haStyle } from "../../../../../resources/styles";
const OPTIONS = ["count", "while", "until"];
const getType = (action) => {
return OPTIONS.find((option) => option in action);
};
@customElement("ha-automation-action-repeat")
export class HaRepeatAction extends LitElement implements ActionElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public action!: RepeatAction;
public static get defaultConfig() {
return { repeat: { count: 2, sequence: [] } };
}
protected render() {
const action = this.action.repeat;
const type = getType(action);
const selected = type ? OPTIONS.indexOf(type) : -1;
return html`
<paper-dropdown-menu-light
.label=${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.repeat.type_select"
)}
no-animations
>
<paper-listbox
slot="dropdown-content"
.selected=${selected}
@iron-select=${this._typeChanged}
>
${OPTIONS.map(
(opt) => html`
<paper-item .action=${opt}>
${this.hass.localize(
`ui.panel.config.automation.editor.actions.type.repeat.type.${opt}.label`
)}
</paper-item>
`
)}
</paper-listbox>
</paper-dropdown-menu-light>
${type === "count"
? html`<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.repeat.type.count.label"
)}
name="count"
.value=${(action as CountRepeat).count || "0"}
@value-changed=${this._countChanged}
></paper-input>`
: ""}
${type === "while"
? html` <h3>
${this.hass.localize(
`ui.panel.config.automation.editor.actions.type.repeat.type.while.conditions`
)}:
</h3>
<ha-automation-condition
.conditions=${(action as WhileRepeat).while || []}
.hass=${this.hass}
@value-changed=${this._conditionChanged}
></ha-automation-condition>`
: ""}
${type === "until"
? html` <h3>
${this.hass.localize(
`ui.panel.config.automation.editor.actions.type.repeat.type.until.conditions`
)}:
</h3>
<ha-automation-condition
.conditions=${(action as UntilRepeat).until || []}
.hass=${this.hass}
@value-changed=${this._conditionChanged}
></ha-automation-condition>`
: ""}
<h3>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.repeat.sequence"
)}:
</h3>
<ha-automation-action
.actions=${action.sequence}
@value-changed=${this._actionChanged}
.hass=${this.hass}
></ha-automation-action>
`;
}
private _typeChanged(ev: CustomEvent) {
const type = ((ev.target as PaperListboxElement)?.selectedItem as any)
?.action;
if (!type || type === getType(this.action.repeat)) {
return;
}
const value = type === "count" ? 2 : [];
fireEvent(this, "value-changed", {
value: {
repeat: { [type]: value, sequence: this.action.repeat.sequence },
},
});
}
private _conditionChanged(ev: CustomEvent) {
ev.stopPropagation();
const value = ev.detail.value as Condition[];
fireEvent(this, "value-changed", {
value: {
repeat: {
...this.action.repeat,
[getType(this.action.repeat)!]: value,
},
},
});
}
private _actionChanged(ev: CustomEvent) {
ev.stopPropagation();
const value = ev.detail.value as Action[];
fireEvent(this, "value-changed", {
value: {
repeat: {
...this.action.repeat,
sequence: value,
},
},
});
}
private _countChanged(ev: CustomEvent): void {
const newVal = ev.detail.value;
if ((this.action.repeat as CountRepeat).count === newVal) {
return;
}
fireEvent(this, "value-changed", {
value: {
repeat: {
...this.action.repeat,
count: newVal,
},
},
});
}
static get styles(): CSSResult {
return haStyle;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-action-repeat": HaRepeatAction;
}
}

View File

@ -106,9 +106,9 @@ export class HaIntegrationCard extends LitElement {
@error=${this._onImageError}
@load=${this._onImageLoad}
/>
<h1>
<h2>
${domainToName(this.hass.localize, this.domain)}
</h1>
</h2>
</div>
<paper-listbox>
${this.items.map(
@ -156,12 +156,12 @@ export class HaIntegrationCard extends LitElement {
@load=${this._onImageLoad}
/>
</div>
<h1>
${item.localized_domain_name}
</h1>
<h2>
${item.localized_domain_name === item.title ? "" : item.title}
${item.localized_domain_name}
</h2>
<h3>
${item.localized_domain_name === item.title ? "" : item.title}
</h3>
${devices.length || entities.length
? html`
<div>

View File

@ -79,6 +79,17 @@ export const haStyle = css`
}
h1 {
font-family: var(--paper-font-headline_-_font-family);
-webkit-font-smoothing: var(--paper-font-headline_-_-webkit-font-smoothing);
white-space: var(--paper-font-headline_-_white-space);
overflow: var(--paper-font-headline_-_overflow);
text-overflow: var(--paper-font-headline_-_text-overflow);
font-size: var(--paper-font-headline_-_font-size);
font-weight: var(--paper-font-headline_-_font-weight);
line-height: var(--paper-font-headline_-_line-height);
}
h2 {
font-family: var(--paper-font-title_-_font-family);
-webkit-font-smoothing: var(--paper-font-title_-_-webkit-font-smoothing);
white-space: var(--paper-font-title_-_white-space);
@ -89,7 +100,7 @@ export const haStyle = css`
line-height: var(--paper-font-title_-_line-height);
}
h2 {
h3 {
font-family: var(--paper-font-subhead_-_font-family);
-webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing);
white-space: var(--paper-font-subhead_-_white-space);

View File

@ -1058,6 +1058,31 @@
},
"scene": {
"label": "Activate scene"
},
"repeat": {
"label": "Repeat",
"type_select": "Repeat type",
"type": {
"count": { "label": "Count" },
"while": {
"label": "While",
"conditions": "While conditions"
},
"until": {
"label": "Until",
"conditions": "Until conditions"
}
},
"sequence": "Actions"
},
"choose": {
"label": "Choose",
"default": "Default actions",
"option": "Option {number}",
"add_option": "Add option",
"remove_option": "Remove option",
"conditions": "Conditions",
"sequence": "Actions"
}
}
}