mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 19:56:42 +00:00
WIP initial Blueprint UI (#7695)
* WIP initial Blueprint UI * Review comments * localize
This commit is contained in:
parent
3aff4c96c4
commit
4973d8f629
119
src/components/ha-blueprint-picker.ts
Normal file
119
src/components/ha-blueprint-picker.ts
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { compare } from "../common/string/compare";
|
||||||
|
import { Blueprints, fetchBlueprints } from "../data/blueprint";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
@customElement("ha-blueprint-picker")
|
||||||
|
class HaBluePrintPicker extends LitElement {
|
||||||
|
public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public label?: string;
|
||||||
|
|
||||||
|
@property() public value = "";
|
||||||
|
|
||||||
|
@property() public domain = "automation";
|
||||||
|
|
||||||
|
@property() public blueprints?: Blueprints;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
|
private _processedBlueprints = memoizeOne((blueprints?: Blueprints) => {
|
||||||
|
if (!blueprints) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const result = Object.entries(blueprints).map(([path, blueprint]) => ({
|
||||||
|
...blueprint.metadata,
|
||||||
|
path,
|
||||||
|
}));
|
||||||
|
return result.sort((a, b) => compare(a.name, b.name));
|
||||||
|
});
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.hass) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<paper-dropdown-menu-light
|
||||||
|
.label=${this.label ||
|
||||||
|
this.hass.localize("ui.components.blueprint-picker.label")}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
>
|
||||||
|
<paper-listbox
|
||||||
|
slot="dropdown-content"
|
||||||
|
.selected=${this.value}
|
||||||
|
attr-for-selected="data-blueprint-path"
|
||||||
|
@iron-select=${this._blueprintChanged}
|
||||||
|
>
|
||||||
|
<paper-item data-blueprint-path="">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.components.blueprint-picker.select_blueprint"
|
||||||
|
)}
|
||||||
|
</paper-item>
|
||||||
|
${this._processedBlueprints(this.blueprints).map(
|
||||||
|
(blueprint) => html`
|
||||||
|
<paper-item data-blueprint-path=${blueprint.path}>
|
||||||
|
${blueprint.name}
|
||||||
|
</paper-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</paper-listbox>
|
||||||
|
</paper-dropdown-menu-light>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
if (this.blueprints === undefined) {
|
||||||
|
fetchBlueprints(this.hass!, this.domain).then((blueprints) => {
|
||||||
|
this.blueprints = blueprints;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _blueprintChanged(ev) {
|
||||||
|
const newValue = ev.detail.item.dataset.blueprintPath;
|
||||||
|
|
||||||
|
if (newValue !== this.value) {
|
||||||
|
this.value = ev.detail.value;
|
||||||
|
setTimeout(() => {
|
||||||
|
fireEvent(this, "value-changed", { value: newValue });
|
||||||
|
fireEvent(this, "change");
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
paper-dropdown-menu-light {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 200px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
paper-listbox {
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-blueprint-picker": HaBluePrintPicker;
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import {
|
|||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { navigate } from "../common/navigate";
|
import { navigate } from "../common/navigate";
|
||||||
import { Context, HomeAssistant } from "../types";
|
import { Context, HomeAssistant } from "../types";
|
||||||
|
import { BlueprintInput } from "./blueprint";
|
||||||
import { DeviceCondition, DeviceTrigger } from "./device_automation";
|
import { DeviceCondition, DeviceTrigger } from "./device_automation";
|
||||||
import { Action } from "./script";
|
import { Action } from "./script";
|
||||||
|
|
||||||
@ -14,10 +15,14 @@ export interface AutomationEntity extends HassEntityBase {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AutomationConfig {
|
export type AutomationConfig =
|
||||||
|
| ManualAutomationConfig
|
||||||
|
| BlueprintAutomationConfig;
|
||||||
|
|
||||||
|
export interface ManualAutomationConfig {
|
||||||
id?: string;
|
id?: string;
|
||||||
alias: string;
|
alias?: string;
|
||||||
description: string;
|
description?: string;
|
||||||
trigger: Trigger[];
|
trigger: Trigger[];
|
||||||
condition?: Condition[];
|
condition?: Condition[];
|
||||||
action: Action[];
|
action: Action[];
|
||||||
@ -25,6 +30,10 @@ export interface AutomationConfig {
|
|||||||
max?: number;
|
max?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BlueprintAutomationConfig extends ManualAutomationConfig {
|
||||||
|
use_blueprint: { path: string; input?: BlueprintInput };
|
||||||
|
}
|
||||||
|
|
||||||
export interface ForDict {
|
export interface ForDict {
|
||||||
hours?: number | string;
|
hours?: number | string;
|
||||||
minutes?: number | string;
|
minutes?: number | string;
|
||||||
|
54
src/data/blueprint.ts
Normal file
54
src/data/blueprint.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
export type Blueprints = Record<string, Blueprint>;
|
||||||
|
|
||||||
|
export interface Blueprint {
|
||||||
|
metadata: BlueprintMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BlueprintMetaData {
|
||||||
|
domain: string;
|
||||||
|
name: string;
|
||||||
|
input: BlueprintInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BlueprintInput = Record<string, any>;
|
||||||
|
|
||||||
|
export interface BlueprintImportResult {
|
||||||
|
url: string;
|
||||||
|
suggested_filename: string;
|
||||||
|
raw_data: string;
|
||||||
|
blueprint: Blueprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchBlueprints = (hass: HomeAssistant, domain: string) =>
|
||||||
|
hass.callWS<Blueprints>({ type: "blueprint/list", domain });
|
||||||
|
|
||||||
|
export const importBlueprint = (hass: HomeAssistant, url: string) =>
|
||||||
|
hass.callWS<BlueprintImportResult>({ type: "blueprint/import", url });
|
||||||
|
|
||||||
|
export const saveBlueprint = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
domain: string,
|
||||||
|
path: string,
|
||||||
|
yaml: string,
|
||||||
|
source_url?: string
|
||||||
|
) =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "blueprint/save",
|
||||||
|
domain,
|
||||||
|
path,
|
||||||
|
yaml,
|
||||||
|
source_url,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const deleteBlueprint = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
domain: string,
|
||||||
|
path: string
|
||||||
|
) =>
|
||||||
|
hass.callWS<BlueprintImportResult>({
|
||||||
|
type: "blueprint/delete",
|
||||||
|
domain,
|
||||||
|
path,
|
||||||
|
});
|
306
src/panels/config/automation/blueprint-automation-editor.ts
Normal file
306
src/panels/config/automation/blueprint-automation-editor.ts
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
} from "lit-element";
|
||||||
|
import { html } from "lit-html";
|
||||||
|
import {
|
||||||
|
BlueprintAutomationConfig,
|
||||||
|
triggerAutomation,
|
||||||
|
} from "../../../data/automation";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import "../ha-config-section";
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "@polymer/paper-input/paper-textarea";
|
||||||
|
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||||
|
import "../../../components/entity/ha-entity-toggle";
|
||||||
|
import "@material/mwc-button/mwc-button";
|
||||||
|
import "./trigger/ha-automation-trigger";
|
||||||
|
import "./condition/ha-automation-condition";
|
||||||
|
import "./action/ha-automation-action";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { haStyle } from "../../../resources/styles";
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { navigate } from "../../../common/navigate";
|
||||||
|
import {
|
||||||
|
Blueprint,
|
||||||
|
Blueprints,
|
||||||
|
fetchBlueprints,
|
||||||
|
} from "../../../data/blueprint";
|
||||||
|
import "../../../components/ha-blueprint-picker";
|
||||||
|
import "../../../components/ha-circular-progress";
|
||||||
|
|
||||||
|
@customElement("blueprint-automation-editor")
|
||||||
|
export class HaBlueprintAutomationEditor extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public isWide!: boolean;
|
||||||
|
|
||||||
|
@property() public narrow!: boolean;
|
||||||
|
|
||||||
|
@property() public config!: BlueprintAutomationConfig;
|
||||||
|
|
||||||
|
@property() public stateObj?: HassEntity;
|
||||||
|
|
||||||
|
@internalProperty() private _blueprints?: Blueprints;
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this._getBlueprints();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _blueprint(): Blueprint | undefined {
|
||||||
|
if (!this._blueprints) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return this._blueprints[this.config.use_blueprint.path];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
const blueprint = this._blueprint;
|
||||||
|
return html`<ha-config-section .isWide=${this.isWide}>
|
||||||
|
${!this.narrow
|
||||||
|
? html` <span slot="header">${this.config.alias}</span> `
|
||||||
|
: ""}
|
||||||
|
<span slot="introduction">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.introduction"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<ha-card>
|
||||||
|
<div class="card-content">
|
||||||
|
<paper-input
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.alias"
|
||||||
|
)}
|
||||||
|
name="alias"
|
||||||
|
.value=${this.config.alias}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
>
|
||||||
|
</paper-input>
|
||||||
|
<paper-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"
|
||||||
|
.value=${this.config.description}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></paper-textarea>
|
||||||
|
</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>
|
||||||
|
<mwc-button
|
||||||
|
@click=${this._excuteAutomation}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.card.automation.trigger")}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</ha-card>
|
||||||
|
</ha-config-section>
|
||||||
|
|
||||||
|
<ha-config-section .isWide=${this.isWide}>
|
||||||
|
<span slot="header"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.blueprint.header"
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
<ha-card>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="blueprint-picker-container">
|
||||||
|
${this._blueprints
|
||||||
|
? Object.keys(this._blueprints).length
|
||||||
|
? html`
|
||||||
|
<ha-blueprint-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.blueprint.blueprint_to_use"
|
||||||
|
)}
|
||||||
|
.blueprints=${this._blueprints}
|
||||||
|
.value=${this.config.use_blueprint.path}
|
||||||
|
@value-changed=${this._blueprintChanged}
|
||||||
|
></ha-blueprint-picker>
|
||||||
|
`
|
||||||
|
: this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.blueprint.no_blueprints"
|
||||||
|
)
|
||||||
|
: html`<ha-circular-progress active></ha-circular-progress>`}
|
||||||
|
<mwc-button @click=${this._navigateBlueprints}>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.blueprint.manage_blueprints"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
${this.config.use_blueprint.path
|
||||||
|
? blueprint?.metadata?.input &&
|
||||||
|
Object.keys(blueprint.metadata.input).length
|
||||||
|
? html`<h3>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.blueprint.inputs"
|
||||||
|
)}
|
||||||
|
</h3>
|
||||||
|
${Object.entries(blueprint.metadata.input).map(
|
||||||
|
([key, value]) =>
|
||||||
|
html`<div>
|
||||||
|
${value?.description}
|
||||||
|
<paper-input
|
||||||
|
.key=${key}
|
||||||
|
.label=${value?.name || key}
|
||||||
|
.value=${this.config.use_blueprint.input &&
|
||||||
|
this.config.use_blueprint.input[key]}
|
||||||
|
@value-changed=${this._inputChanged}
|
||||||
|
></paper-input>
|
||||||
|
</div>`
|
||||||
|
)}`
|
||||||
|
: this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.blueprint.no_inputs"
|
||||||
|
)
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
</ha-config-section>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _getBlueprints() {
|
||||||
|
this._blueprints = await fetchBlueprints(this.hass, "automation");
|
||||||
|
}
|
||||||
|
|
||||||
|
private _excuteAutomation(ev: Event) {
|
||||||
|
triggerAutomation(this.hass, (ev.target as any).stateObj.entity_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _blueprintChanged(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (this.config.use_blueprint.path === ev.detail.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: {
|
||||||
|
...this.config!,
|
||||||
|
use_blueprint: {
|
||||||
|
path: ev.detail.value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _inputChanged(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const target = ev.target as any;
|
||||||
|
const key = target.key;
|
||||||
|
const value = target.value;
|
||||||
|
if (
|
||||||
|
(this.config.use_blueprint.input &&
|
||||||
|
this.config.use_blueprint.input[key] === value) ||
|
||||||
|
(!this.config.use_blueprint.input && value === "")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: {
|
||||||
|
...this.config!,
|
||||||
|
use_blueprint: {
|
||||||
|
...this.config.use_blueprint,
|
||||||
|
input: { ...this.config.use_blueprint.input, [key]: value },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const target = ev.target as any;
|
||||||
|
const name = target.name;
|
||||||
|
if (!name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let newVal = ev.detail.value;
|
||||||
|
if (target.type === "number") {
|
||||||
|
newVal = Number(newVal);
|
||||||
|
}
|
||||||
|
if ((this.config![name] || "") === newVal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: { ...this.config!, [name]: newVal },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _navigateBlueprints() {
|
||||||
|
navigate(this, "/config/blueprint");
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
ha-card {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.errors {
|
||||||
|
padding: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.blueprint-picker-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
span[slot="introduction"] a {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
ha-entity-toggle {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
mwc-fab {
|
||||||
|
position: relative;
|
||||||
|
bottom: calc(-80px - env(safe-area-inset-bottom));
|
||||||
|
transition: bottom 0.3s;
|
||||||
|
}
|
||||||
|
mwc-fab.dirty {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.selected_menu_item {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
li[role="separator"] {
|
||||||
|
border-bottom-color: var(--divider-color);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"blueprint-automation-editor": HaBlueprintAutomationEditor;
|
||||||
|
}
|
||||||
|
}
|
175
src/panels/config/automation/dialog-new-automation.ts
Normal file
175
src/panels/config/automation/dialog-new-automation.ts
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
import "@material/mwc-button";
|
||||||
|
import "../../../components/ha-circular-progress";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
internalProperty,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import "../../../components/ha-dialog";
|
||||||
|
import { haStyle, haStyleDialog } from "../../../resources/styles";
|
||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
|
import {
|
||||||
|
AutomationConfig,
|
||||||
|
showAutomationEditor,
|
||||||
|
} from "../../../data/automation";
|
||||||
|
import { showThingtalkDialog } from "./thingtalk/show-dialog-thingtalk";
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-blueprint-picker";
|
||||||
|
|
||||||
|
@customElement("ha-dialog-new-automation")
|
||||||
|
class DialogNewAutomation extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@internalProperty() private _opened = false;
|
||||||
|
|
||||||
|
public showDialog(): void {
|
||||||
|
this._opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog(): void {
|
||||||
|
this._opened = false;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._opened) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
.heading=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.dialog_new.header"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
${this.hass.localize("ui.panel.config.automation.dialog_new.how")}
|
||||||
|
<div class="container">
|
||||||
|
${isComponentLoaded(this.hass, "cloud")
|
||||||
|
? html`<ha-card outlined>
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.dialog_new.thingtalk.header"
|
||||||
|
)}
|
||||||
|
</h3>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.dialog_new.thingtalk.intro"
|
||||||
|
)}
|
||||||
|
<div class="side-by-side">
|
||||||
|
<paper-input
|
||||||
|
id="input"
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.dialog_new.thingtalk.input_label"
|
||||||
|
)}
|
||||||
|
></paper-input>
|
||||||
|
<mwc-button @click=${this._thingTalk}
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.dialog_new.thingtalk.create"
|
||||||
|
)}</mwc-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ha-card>`
|
||||||
|
: html``}
|
||||||
|
${isComponentLoaded(this.hass, "blueprint")
|
||||||
|
? html`<ha-card outlined>
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.dialog_new.blueprint.use_blueprint"
|
||||||
|
)}
|
||||||
|
</h3>
|
||||||
|
<ha-blueprint-picker
|
||||||
|
@value-changed=${this._blueprintPicked}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-blueprint-picker>
|
||||||
|
</div>
|
||||||
|
</ha-card>`
|
||||||
|
: html``}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mwc-button slot="primaryAction" @click=${this._blank}>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.dialog_new.start_empty"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _thingTalk() {
|
||||||
|
this.closeDialog();
|
||||||
|
showThingtalkDialog(this, {
|
||||||
|
callback: (config: Partial<AutomationConfig> | undefined) =>
|
||||||
|
showAutomationEditor(this, config),
|
||||||
|
input: this.shadowRoot!.querySelector("paper-input")!.value as string,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _blueprintPicked(ev: CustomEvent) {
|
||||||
|
showAutomationEditor(this, { use_blueprint: { path: ev.detail.value } });
|
||||||
|
this.closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _blank() {
|
||||||
|
showAutomationEditor(this);
|
||||||
|
this.closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
ha-card {
|
||||||
|
width: calc(50% - 8px);
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
|
ha-card div {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
ha-card {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
ha-blueprint-picker {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.side-by-side {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
@media all and (max-width: 500px) {
|
||||||
|
.container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
ha-card {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-dialog-new-automation": DialogNewAutomation;
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,6 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
|||||||
import "@polymer/paper-input/paper-textarea";
|
import "@polymer/paper-input/paper-textarea";
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||||
import { PaperListboxElement } from "@polymer/paper-listbox";
|
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResult,
|
CSSResult,
|
||||||
@ -36,14 +35,11 @@ import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
|
|||||||
import {
|
import {
|
||||||
AutomationConfig,
|
AutomationConfig,
|
||||||
AutomationEntity,
|
AutomationEntity,
|
||||||
Condition,
|
|
||||||
deleteAutomation,
|
deleteAutomation,
|
||||||
getAutomationEditorInitData,
|
getAutomationEditorInitData,
|
||||||
showAutomationEditor,
|
showAutomationEditor,
|
||||||
Trigger,
|
|
||||||
triggerAutomation,
|
triggerAutomation,
|
||||||
} from "../../../data/automation";
|
} from "../../../data/automation";
|
||||||
import { Action } from "../../../data/script";
|
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@ -53,7 +49,6 @@ import "../../../layouts/hass-tabs-subpage";
|
|||||||
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
|
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "./action/ha-automation-action";
|
import "./action/ha-automation-action";
|
||||||
@ -61,11 +56,13 @@ import { HaDeviceAction } from "./action/types/ha-automation-action-device_id";
|
|||||||
import "./condition/ha-automation-condition";
|
import "./condition/ha-automation-condition";
|
||||||
import "./trigger/ha-automation-trigger";
|
import "./trigger/ha-automation-trigger";
|
||||||
import { HaDeviceTrigger } from "./trigger/types/ha-automation-trigger-device";
|
import { HaDeviceTrigger } from "./trigger/types/ha-automation-trigger-device";
|
||||||
|
import "./manual-automation-editor";
|
||||||
const MODES = ["single", "restart", "queued", "parallel"];
|
import "./blueprint-automation-editor";
|
||||||
const MODES_MAX = ["queued", "parallel"];
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-automation-editor": HaAutomationEditor;
|
||||||
|
}
|
||||||
// for fire event
|
// for fire event
|
||||||
interface HASSDomEvents {
|
interface HASSDomEvents {
|
||||||
"ui-mode-not-available": Error;
|
"ui-mode-not-available": Error;
|
||||||
@ -193,6 +190,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
</ha-svg-icon>
|
</ha-svg-icon>
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
|
|
||||||
${this._config
|
${this._config
|
||||||
? html`
|
? html`
|
||||||
${this.narrow
|
${this.narrow
|
||||||
@ -204,217 +202,19 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
: ""}
|
: ""}
|
||||||
${this._mode === "gui"
|
${this._mode === "gui"
|
||||||
? html`
|
? html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
${"use_blueprint" in this._config
|
||||||
${!this.narrow
|
? html`<blueprint-automation-editor
|
||||||
? html`
|
.hass=${this.hass}
|
||||||
<span slot="header">${this._config.alias}</span>
|
.stateObj=${stateObj}
|
||||||
`
|
.config=${this._config}
|
||||||
: ""}
|
@value-changed=${this._valueChanged}
|
||||||
<span slot="introduction">
|
></blueprint-automation-editor>`
|
||||||
${this.hass.localize(
|
: html`<manual-automation-editor
|
||||||
"ui.panel.config.automation.editor.introduction"
|
.hass=${this.hass}
|
||||||
)}
|
.stateObj=${stateObj}
|
||||||
</span>
|
.config=${this._config}
|
||||||
<ha-card>
|
@value-changed=${this._valueChanged}
|
||||||
<div class="card-content">
|
></manual-automation-editor>`}
|
||||||
<paper-input
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.alias"
|
|
||||||
)}
|
|
||||||
name="alias"
|
|
||||||
.value=${this._config.alias}
|
|
||||||
@value-changed=${this._valueChanged}
|
|
||||||
>
|
|
||||||
</paper-input>
|
|
||||||
<paper-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"
|
|
||||||
.value=${this._config.description}
|
|
||||||
@value-changed=${this._valueChanged}
|
|
||||||
></paper-textarea>
|
|
||||||
<p>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.modes.description",
|
|
||||||
"documentation_link",
|
|
||||||
html`<a
|
|
||||||
href="${documentationUrl(
|
|
||||||
this.hass,
|
|
||||||
"/integrations/automation/#automation-modes"
|
|
||||||
)}"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.modes.documentation"
|
|
||||||
)}</a
|
|
||||||
>`
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<paper-dropdown-menu-light
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.modes.label"
|
|
||||||
)}
|
|
||||||
no-animations
|
|
||||||
>
|
|
||||||
<paper-listbox
|
|
||||||
slot="dropdown-content"
|
|
||||||
.selected=${this._config.mode
|
|
||||||
? MODES.indexOf(this._config.mode)
|
|
||||||
: 0}
|
|
||||||
@iron-select=${this._modeChanged}
|
|
||||||
>
|
|
||||||
${MODES.map(
|
|
||||||
(mode) => html`
|
|
||||||
<paper-item .mode=${mode}>
|
|
||||||
${this.hass.localize(
|
|
||||||
`ui.panel.config.automation.editor.modes.${mode}`
|
|
||||||
) || mode}
|
|
||||||
</paper-item>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</paper-listbox>
|
|
||||||
</paper-dropdown-menu-light>
|
|
||||||
${this._config.mode &&
|
|
||||||
MODES_MAX.includes(this._config.mode)
|
|
||||||
? html`<paper-input
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
`ui.panel.config.automation.editor.max.${this._config.mode}`
|
|
||||||
)}
|
|
||||||
type="number"
|
|
||||||
name="max"
|
|
||||||
.value=${this._config.max || "10"}
|
|
||||||
@value-changed=${this._valueChanged}
|
|
||||||
>
|
|
||||||
</paper-input>`
|
|
||||||
: html``}
|
|
||||||
</div>
|
|
||||||
${stateObj
|
|
||||||
? html`
|
|
||||||
<div
|
|
||||||
class="card-actions layout horizontal justified center"
|
|
||||||
>
|
|
||||||
<div class="layout horizontal center">
|
|
||||||
<ha-entity-toggle
|
|
||||||
.hass=${this.hass}
|
|
||||||
.stateObj=${stateObj}
|
|
||||||
></ha-entity-toggle>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.enable_disable"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<mwc-button
|
|
||||||
@click=${this._excuteAutomation}
|
|
||||||
.stateObj=${stateObj}
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.card.automation.trigger"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</ha-card>
|
|
||||||
</ha-config-section>
|
|
||||||
|
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<span slot="header">
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.triggers.header"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span slot="introduction">
|
|
||||||
<p>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.triggers.introduction"
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
href="${documentationUrl(
|
|
||||||
this.hass,
|
|
||||||
"/docs/automation/trigger/"
|
|
||||||
)}"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.triggers.learn_more"
|
|
||||||
)}
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
<ha-automation-trigger
|
|
||||||
.triggers=${this._config.trigger}
|
|
||||||
@value-changed=${this._triggerChanged}
|
|
||||||
.hass=${this.hass}
|
|
||||||
></ha-automation-trigger>
|
|
||||||
</ha-config-section>
|
|
||||||
|
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<span slot="header">
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.conditions.header"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span slot="introduction">
|
|
||||||
<p>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.conditions.introduction"
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
href="${documentationUrl(
|
|
||||||
this.hass,
|
|
||||||
"/docs/scripts/conditions/"
|
|
||||||
)}"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.conditions.learn_more"
|
|
||||||
)}
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
<ha-automation-condition
|
|
||||||
.conditions=${this._config.condition || []}
|
|
||||||
@value-changed=${this._conditionChanged}
|
|
||||||
.hass=${this.hass}
|
|
||||||
></ha-automation-condition>
|
|
||||||
</ha-config-section>
|
|
||||||
|
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<span slot="header">
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.actions.header"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span slot="introduction">
|
|
||||||
<p>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.actions.introduction"
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
href="${documentationUrl(
|
|
||||||
this.hass,
|
|
||||||
"/docs/automation/action/"
|
|
||||||
)}"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.automation.editor.actions.learn_more"
|
|
||||||
)}
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
<ha-automation-action
|
|
||||||
.actions=${this._config.action}
|
|
||||||
@value-changed=${this._actionChanged}
|
|
||||||
.hass=${this.hass}
|
|
||||||
></ha-automation-action>
|
|
||||||
</ha-config-section>
|
|
||||||
`
|
`
|
||||||
: this._mode === "yaml"
|
: this._mode === "yaml"
|
||||||
? html`
|
? html`
|
||||||
@ -531,17 +331,25 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
if (changedProps.has("automationId") && !this.automationId && this.hass) {
|
if (changedProps.has("automationId") && !this.automationId && this.hass) {
|
||||||
const initData = getAutomationEditorInitData();
|
const initData = getAutomationEditorInitData();
|
||||||
this._dirty = !!initData;
|
let baseConfig: Partial<AutomationConfig> = {
|
||||||
this._config = {
|
|
||||||
alias: this.hass.localize(
|
alias: this.hass.localize(
|
||||||
"ui.panel.config.automation.editor.default_name"
|
"ui.panel.config.automation.editor.default_name"
|
||||||
),
|
),
|
||||||
description: "",
|
description: "",
|
||||||
trigger: [{ platform: "device", ...HaDeviceTrigger.defaultConfig }],
|
|
||||||
condition: [],
|
|
||||||
action: [{ ...HaDeviceAction.defaultConfig }],
|
|
||||||
...initData,
|
|
||||||
};
|
};
|
||||||
|
if (!initData || !("use_blueprint" in initData)) {
|
||||||
|
baseConfig = {
|
||||||
|
...baseConfig,
|
||||||
|
mode: "single",
|
||||||
|
trigger: [{ platform: "device", ...HaDeviceTrigger.defaultConfig }],
|
||||||
|
condition: [],
|
||||||
|
action: [{ ...HaDeviceAction.defaultConfig }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this._config = {
|
||||||
|
...baseConfig,
|
||||||
|
...initData,
|
||||||
|
} as AutomationConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -560,58 +368,11 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
this._entityId = automation?.entity_id;
|
this._entityId = automation?.entity_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _modeChanged(ev: CustomEvent) {
|
private _valueChanged(ev: CustomEvent<{ value: AutomationConfig }>) {
|
||||||
const mode = ((ev.target as PaperListboxElement)?.selectedItem as any)
|
|
||||||
?.mode;
|
|
||||||
|
|
||||||
if (mode === this._config!.mode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._config = { ...this._config!, mode };
|
|
||||||
if (!MODES_MAX.includes(mode)) {
|
|
||||||
delete this._config.max;
|
|
||||||
}
|
|
||||||
this._dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _valueChanged(ev: CustomEvent) {
|
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
const target = ev.target as any;
|
this._config = ev.detail.value;
|
||||||
const name = target.name;
|
|
||||||
if (!name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let newVal = ev.detail.value;
|
|
||||||
if (target.type === "number") {
|
|
||||||
newVal = Number(newVal);
|
|
||||||
}
|
|
||||||
if ((this._config![name] || "") === newVal) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._config = { ...this._config!, [name]: newVal };
|
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
}
|
|
||||||
|
|
||||||
private _triggerChanged(ev: CustomEvent): void {
|
|
||||||
this._config = { ...this._config!, trigger: ev.detail.value as Trigger[] };
|
|
||||||
this._errors = undefined;
|
this._errors = undefined;
|
||||||
this._dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _conditionChanged(ev: CustomEvent): void {
|
|
||||||
this._config = {
|
|
||||||
...this._config!,
|
|
||||||
condition: ev.detail.value as Condition[],
|
|
||||||
};
|
|
||||||
this._errors = undefined;
|
|
||||||
this._dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _actionChanged(ev: CustomEvent): void {
|
|
||||||
this._config = { ...this._config!, action: ev.detail.value as Action[] };
|
|
||||||
this._errors = undefined;
|
|
||||||
this._dirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _excuteAutomation(ev: Event) {
|
private _excuteAutomation(ev: Event) {
|
||||||
|
@ -12,7 +12,6 @@ import {
|
|||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
|
||||||
import { formatDateTime } from "../../../common/datetime/format_date_time";
|
import { formatDateTime } from "../../../common/datetime/format_date_time";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
@ -20,19 +19,16 @@ import { DataTableColumnContainer } from "../../../components/data-table/ha-data
|
|||||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||||
import "../../../components/entity/ha-entity-toggle";
|
import "../../../components/entity/ha-entity-toggle";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import {
|
import { AutomationEntity, triggerAutomation } from "../../../data/automation";
|
||||||
AutomationConfig,
|
|
||||||
AutomationEntity,
|
|
||||||
showAutomationEditor,
|
|
||||||
triggerAutomation,
|
|
||||||
} from "../../../data/automation";
|
|
||||||
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
||||||
import "../../../layouts/hass-tabs-subpage-data-table";
|
import "../../../layouts/hass-tabs-subpage-data-table";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import { showThingtalkDialog } from "./show-dialog-thingtalk";
|
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
|
import { showNewAutomationDialog } from "./show-dialog-new-automation";
|
||||||
|
import { navigate } from "../../../common/navigate";
|
||||||
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
|
|
||||||
@customElement("ha-automation-picker")
|
@customElement("ha-automation-picker")
|
||||||
class HaAutomationPicker extends LitElement {
|
class HaAutomationPicker extends LitElement {
|
||||||
@ -220,14 +216,14 @@ class HaAutomationPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _createNew() {
|
private _createNew() {
|
||||||
if (!isComponentLoaded(this.hass, "cloud")) {
|
if (
|
||||||
showAutomationEditor(this);
|
isComponentLoaded(this.hass, "cloud") ||
|
||||||
return;
|
isComponentLoaded(this.hass, "blueprint")
|
||||||
|
) {
|
||||||
|
showNewAutomationDialog(this);
|
||||||
|
} else {
|
||||||
|
navigate(this, "/config/automation/edit/new");
|
||||||
}
|
}
|
||||||
showThingtalkDialog(this, {
|
|
||||||
callback: (config: Partial<AutomationConfig> | undefined) =>
|
|
||||||
showAutomationEditor(this, config),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult {
|
static get styles(): CSSResult {
|
||||||
|
349
src/panels/config/automation/manual-automation-editor.ts
Normal file
349
src/panels/config/automation/manual-automation-editor.ts
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
} from "lit-element";
|
||||||
|
import { html } from "lit-html";
|
||||||
|
import {
|
||||||
|
Condition,
|
||||||
|
ManualAutomationConfig,
|
||||||
|
Trigger,
|
||||||
|
triggerAutomation,
|
||||||
|
} from "../../../data/automation";
|
||||||
|
import { Action, MODES, MODES_MAX } from "../../../data/script";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
|
import "../ha-config-section";
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "@polymer/paper-input/paper-textarea";
|
||||||
|
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||||
|
import "../../../components/entity/ha-entity-toggle";
|
||||||
|
import "@material/mwc-button/mwc-button";
|
||||||
|
import "./trigger/ha-automation-trigger";
|
||||||
|
import "./condition/ha-automation-condition";
|
||||||
|
import "./action/ha-automation-action";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { PaperListboxElement } from "@polymer/paper-listbox";
|
||||||
|
import { haStyle } from "../../../resources/styles";
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
|
||||||
|
@customElement("manual-automation-editor")
|
||||||
|
export class HaManualAutomationEditor extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public isWide!: boolean;
|
||||||
|
|
||||||
|
@property() public narrow!: boolean;
|
||||||
|
|
||||||
|
@property() public config!: ManualAutomationConfig;
|
||||||
|
|
||||||
|
@property() public stateObj?: HassEntity;
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`<ha-config-section .isWide=${this.isWide}>
|
||||||
|
${!this.narrow
|
||||||
|
? html` <span slot="header">${this.config.alias}</span> `
|
||||||
|
: ""}
|
||||||
|
<span slot="introduction">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.introduction"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<ha-card>
|
||||||
|
<div class="card-content">
|
||||||
|
<paper-input
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.alias"
|
||||||
|
)}
|
||||||
|
name="alias"
|
||||||
|
.value=${this.config.alias}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
>
|
||||||
|
</paper-input>
|
||||||
|
<paper-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"
|
||||||
|
.value=${this.config.description}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></paper-textarea>
|
||||||
|
<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.modes.description",
|
||||||
|
"documentation_link",
|
||||||
|
html`<a
|
||||||
|
href="${documentationUrl(
|
||||||
|
this.hass,
|
||||||
|
"/integrations/automation/#automation-modes"
|
||||||
|
)}"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.modes.documentation"
|
||||||
|
)}</a
|
||||||
|
>`
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<paper-dropdown-menu-light
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.modes.label"
|
||||||
|
)}
|
||||||
|
no-animations
|
||||||
|
>
|
||||||
|
<paper-listbox
|
||||||
|
slot="dropdown-content"
|
||||||
|
.selected=${this.config.mode
|
||||||
|
? MODES.indexOf(this.config.mode)
|
||||||
|
: 0}
|
||||||
|
@iron-select=${this._modeChanged}
|
||||||
|
>
|
||||||
|
${MODES.map(
|
||||||
|
(mode) => html`
|
||||||
|
<paper-item .mode=${mode}>
|
||||||
|
${this.hass.localize(
|
||||||
|
`ui.panel.config.automation.editor.modes.${mode}`
|
||||||
|
) || mode}
|
||||||
|
</paper-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</paper-listbox>
|
||||||
|
</paper-dropdown-menu-light>
|
||||||
|
${this.config.mode && MODES_MAX.includes(this.config.mode)
|
||||||
|
? html`<paper-input
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.panel.config.automation.editor.max.${this.config.mode}`
|
||||||
|
)}
|
||||||
|
type="number"
|
||||||
|
name="max"
|
||||||
|
.value=${this.config.max || "10"}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
>
|
||||||
|
</paper-input>`
|
||||||
|
: 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>
|
||||||
|
<mwc-button
|
||||||
|
@click=${this._excuteAutomation}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.card.automation.trigger")}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</ha-card>
|
||||||
|
</ha-config-section>
|
||||||
|
|
||||||
|
<ha-config-section .isWide=${this.isWide}>
|
||||||
|
<span slot="header">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.triggers.header"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span slot="introduction">
|
||||||
|
<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.triggers.introduction"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href="${documentationUrl(this.hass, "/docs/automation/trigger/")}"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.triggers.learn_more"
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<ha-automation-trigger
|
||||||
|
.triggers=${this.config.trigger}
|
||||||
|
@value-changed=${this._triggerChanged}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-automation-trigger>
|
||||||
|
</ha-config-section>
|
||||||
|
|
||||||
|
<ha-config-section .isWide=${this.isWide}>
|
||||||
|
<span slot="header">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.conditions.header"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span slot="introduction">
|
||||||
|
<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.conditions.introduction"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href="${documentationUrl(this.hass, "/docs/scripts/conditions/")}"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.conditions.learn_more"
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<ha-automation-condition
|
||||||
|
.conditions=${this.config.condition || []}
|
||||||
|
@value-changed=${this._conditionChanged}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-automation-condition>
|
||||||
|
</ha-config-section>
|
||||||
|
|
||||||
|
<ha-config-section .isWide=${this.isWide}>
|
||||||
|
<span slot="header">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.actions.header"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span slot="introduction">
|
||||||
|
<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.actions.introduction"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href="${documentationUrl(this.hass, "/docs/automation/action/")}"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.actions.learn_more"
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<ha-automation-action
|
||||||
|
.actions=${this.config.action}
|
||||||
|
@value-changed=${this._actionChanged}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-automation-action>
|
||||||
|
</ha-config-section>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _excuteAutomation(ev: Event) {
|
||||||
|
triggerAutomation(this.hass, (ev.target as any).stateObj.entity_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const target = ev.target as any;
|
||||||
|
const name = target.name;
|
||||||
|
if (!name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let newVal = ev.detail.value;
|
||||||
|
if (target.type === "number") {
|
||||||
|
newVal = Number(newVal);
|
||||||
|
}
|
||||||
|
if ((this.config![name] || "") === newVal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: { ...this.config!, [name]: newVal },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _modeChanged(ev: CustomEvent) {
|
||||||
|
const mode = ((ev.target as PaperListboxElement)?.selectedItem as any)
|
||||||
|
?.mode;
|
||||||
|
|
||||||
|
if (mode === this.config!.mode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: {
|
||||||
|
...this.config!,
|
||||||
|
mode,
|
||||||
|
max: !MODES_MAX.includes(mode) ? undefined : this.config.max,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _triggerChanged(ev: CustomEvent): void {
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: { ...this.config!, trigger: ev.detail.value as Trigger[] },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _conditionChanged(ev: CustomEvent): void {
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: {
|
||||||
|
...this.config!,
|
||||||
|
condition: ev.detail.value as Condition[],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _actionChanged(ev: CustomEvent): void {
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: { ...this.config!, action: ev.detail.value as Action[] },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
ha-card {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.errors {
|
||||||
|
padding: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
span[slot="introduction"] a {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
ha-entity-toggle {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
mwc-fab {
|
||||||
|
position: relative;
|
||||||
|
bottom: calc(-80px - env(safe-area-inset-bottom));
|
||||||
|
transition: bottom 0.3s;
|
||||||
|
}
|
||||||
|
mwc-fab.dirty {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.selected_menu_item {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
li[role="separator"] {
|
||||||
|
border-bottom-color: var(--divider-color);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"manual-automation-editor": HaManualAutomationEditor;
|
||||||
|
}
|
||||||
|
}
|
12
src/panels/config/automation/show-dialog-new-automation.ts
Normal file
12
src/panels/config/automation/show-dialog-new-automation.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
export const loadNewAutomationDialog = () =>
|
||||||
|
import(/* webpackChunkName: "thingtalk-dialog" */ "./dialog-new-automation");
|
||||||
|
|
||||||
|
export const showNewAutomationDialog = (element: HTMLElement): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "ha-dialog-new-automation",
|
||||||
|
dialogImport: loadNewAutomationDialog,
|
||||||
|
dialogParams: {},
|
||||||
|
});
|
||||||
|
};
|
@ -20,7 +20,7 @@ import { convertThingTalk } from "../../../../data/cloud";
|
|||||||
import type { PolymerChangedEvent } from "../../../../polymer-types";
|
import type { PolymerChangedEvent } from "../../../../polymer-types";
|
||||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import type { ThingtalkDialogParams } from "../show-dialog-thingtalk";
|
import type { ThingtalkDialogParams } from "./show-dialog-thingtalk";
|
||||||
import "./ha-thingtalk-placeholders";
|
import "./ha-thingtalk-placeholders";
|
||||||
import type { PlaceholderValues } from "./ha-thingtalk-placeholders";
|
import type { PlaceholderValues } from "./ha-thingtalk-placeholders";
|
||||||
|
|
||||||
@ -50,16 +50,21 @@ class DialogThingtalk extends LitElement {
|
|||||||
|
|
||||||
@internalProperty() private _placeholders?: PlaceholderContainer;
|
@internalProperty() private _placeholders?: PlaceholderContainer;
|
||||||
|
|
||||||
@query("#input", true) private _input?: PaperInputElement;
|
@query("#input") private _input?: PaperInputElement;
|
||||||
|
|
||||||
private _value!: string;
|
private _value?: string;
|
||||||
|
|
||||||
private _config!: Partial<AutomationConfig>;
|
private _config!: Partial<AutomationConfig>;
|
||||||
|
|
||||||
public showDialog(params: ThingtalkDialogParams): void {
|
public async showDialog(params: ThingtalkDialogParams): Promise<void> {
|
||||||
this._params = params;
|
this._params = params;
|
||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
this._opened = true;
|
this._opened = true;
|
||||||
|
if (params.input) {
|
||||||
|
this._value = params.input;
|
||||||
|
await this.updateComplete;
|
||||||
|
this._generate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@ -126,6 +131,7 @@ class DialogThingtalk extends LitElement {
|
|||||||
<paper-input
|
<paper-input
|
||||||
id="input"
|
id="input"
|
||||||
label="What should this automation do?"
|
label="What should this automation do?"
|
||||||
|
.value=${this._value}
|
||||||
autofocus
|
autofocus
|
||||||
@keyup=${this._handleKeyUp}
|
@keyup=${this._handleKeyUp}
|
||||||
></paper-input>
|
></paper-input>
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { AutomationConfig } from "../../../data/automation";
|
import { AutomationConfig } from "../../../../data/automation";
|
||||||
|
|
||||||
export interface ThingtalkDialogParams {
|
export interface ThingtalkDialogParams {
|
||||||
callback: (config: Partial<AutomationConfig> | undefined) => void;
|
callback: (config: Partial<AutomationConfig> | undefined) => void;
|
||||||
|
input?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadThingtalkDialog = () =>
|
export const loadThingtalkDialog = () =>
|
||||||
import(
|
import(/* webpackChunkName: "thingtalk-dialog" */ "./dialog-thingtalk");
|
||||||
/* webpackChunkName: "thingtalk-dialog" */ "./thingtalk/dialog-thingtalk"
|
|
||||||
);
|
|
||||||
|
|
||||||
export const showThingtalkDialog = (
|
export const showThingtalkDialog = (
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
186
src/panels/config/blueprint/dialog-import-blueprint.ts
Normal file
186
src/panels/config/blueprint/dialog-import-blueprint.ts
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
import "@material/mwc-button";
|
||||||
|
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||||
|
import "@polymer/paper-input/paper-input";
|
||||||
|
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||||
|
import "../../../components/ha-circular-progress";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
internalProperty,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import "../../../components/ha-dialog";
|
||||||
|
import { haStyleDialog } from "../../../resources/styles";
|
||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import {
|
||||||
|
BlueprintImportResult,
|
||||||
|
importBlueprint,
|
||||||
|
saveBlueprint,
|
||||||
|
} from "../../../data/blueprint";
|
||||||
|
|
||||||
|
@customElement("ha-dialog-import-blueprint")
|
||||||
|
class DialogImportBlueprint extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@internalProperty() private _params?;
|
||||||
|
|
||||||
|
@internalProperty() private _importing = false;
|
||||||
|
|
||||||
|
@internalProperty() private _saving = false;
|
||||||
|
|
||||||
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
|
@internalProperty() private _result?: BlueprintImportResult;
|
||||||
|
|
||||||
|
@query("#input") private _input?: PaperInputElement;
|
||||||
|
|
||||||
|
public showDialog(params): void {
|
||||||
|
this._params = params;
|
||||||
|
this._error = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog(): void {
|
||||||
|
this._error = undefined;
|
||||||
|
this._result = undefined;
|
||||||
|
this._params = undefined;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._params) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
.heading=${this.hass.localize("ui.panel.config.blueprint.add.header")}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
|
||||||
|
${this._result
|
||||||
|
? html`${this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.add.import",
|
||||||
|
"name",
|
||||||
|
"domain",
|
||||||
|
html`<b>${this._result.blueprint.metadata.name}</b>`,
|
||||||
|
this._result.blueprint.metadata.domain
|
||||||
|
)}
|
||||||
|
<paper-input
|
||||||
|
id="input"
|
||||||
|
.value=${this._result.suggested_filename}
|
||||||
|
label="Filename"
|
||||||
|
></paper-input>
|
||||||
|
<pre>${this._result.raw_data}</pre>`
|
||||||
|
: html`${this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.add.import_introduction"
|
||||||
|
)}<paper-input
|
||||||
|
id="input"
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.add.url"
|
||||||
|
)}
|
||||||
|
dialogInitialFocus
|
||||||
|
></paper-input>`}
|
||||||
|
</div>
|
||||||
|
${!this._result
|
||||||
|
? html`<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${this._import}
|
||||||
|
.disabled=${this._importing}
|
||||||
|
>
|
||||||
|
${this._importing
|
||||||
|
? html`<ha-circular-progress
|
||||||
|
active
|
||||||
|
size="small"
|
||||||
|
.title=${this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.add.importing"
|
||||||
|
)}
|
||||||
|
></ha-circular-progress>`
|
||||||
|
: ""}
|
||||||
|
${this.hass.localize("ui.panel.config.blueprint.add.import_btn")}
|
||||||
|
</mwc-button>`
|
||||||
|
: html`<mwc-button
|
||||||
|
slot="secondaryAction"
|
||||||
|
@click=${this.closeDialog}
|
||||||
|
.disabled=${this._saving}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.common.cancel")}
|
||||||
|
</mwc-button>
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${this._save}
|
||||||
|
.disabled=${this._saving}
|
||||||
|
>
|
||||||
|
${this._saving
|
||||||
|
? html`<ha-circular-progress
|
||||||
|
active
|
||||||
|
size="small"
|
||||||
|
.title=${this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.add.saving"
|
||||||
|
)}
|
||||||
|
></ha-circular-progress>`
|
||||||
|
: ""}
|
||||||
|
${this.hass.localize("ui.panel.config.blueprint.add.save_btn")}
|
||||||
|
</mwc-button>`}
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _import() {
|
||||||
|
this._importing = true;
|
||||||
|
this._error = undefined;
|
||||||
|
try {
|
||||||
|
const url = this._input?.value;
|
||||||
|
if (!url) {
|
||||||
|
this._error = this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.add.error_no_url"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._result = await importBlueprint(this.hass, url);
|
||||||
|
} catch (e) {
|
||||||
|
this._error = e.message;
|
||||||
|
} finally {
|
||||||
|
this._importing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _save() {
|
||||||
|
this._saving = true;
|
||||||
|
try {
|
||||||
|
const filename = this._input?.value;
|
||||||
|
if (!filename) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await saveBlueprint(
|
||||||
|
this.hass,
|
||||||
|
this._result!.blueprint.metadata.domain,
|
||||||
|
filename,
|
||||||
|
this._result!.raw_data,
|
||||||
|
this._result!.url
|
||||||
|
);
|
||||||
|
this._params.importedCallback();
|
||||||
|
this.closeDialog();
|
||||||
|
} catch (e) {
|
||||||
|
this._error = e.message;
|
||||||
|
} finally {
|
||||||
|
this._saving = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [haStyleDialog, css``];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-dialog-import-blueprint": DialogImportBlueprint;
|
||||||
|
}
|
||||||
|
}
|
212
src/panels/config/blueprint/ha-blueprint-overview.ts
Normal file
212
src/panels/config/blueprint/ha-blueprint-overview.ts
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
import "@material/mwc-fab";
|
||||||
|
import "@material/mwc-icon-button";
|
||||||
|
import { mdiPlus, mdiHelpCircle, mdiDelete } from "@mdi/js";
|
||||||
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
|
import {
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { DataTableColumnContainer } from "../../../components/data-table/ha-data-table";
|
||||||
|
import {
|
||||||
|
showAlertDialog,
|
||||||
|
showConfirmationDialog,
|
||||||
|
} from "../../../dialogs/generic/show-dialog-box";
|
||||||
|
import "../../../components/entity/ha-entity-toggle";
|
||||||
|
import "../../../components/ha-svg-icon";
|
||||||
|
import "../../../layouts/hass-tabs-subpage-data-table";
|
||||||
|
import { haStyle } from "../../../resources/styles";
|
||||||
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
|
import { configSections } from "../ha-panel-config";
|
||||||
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
|
import {
|
||||||
|
BlueprintMetaData,
|
||||||
|
Blueprints,
|
||||||
|
deleteBlueprint,
|
||||||
|
} from "../../../data/blueprint";
|
||||||
|
import { showAddBlueprintDialog } from "./show-dialog-import-blueprint";
|
||||||
|
import { showAutomationEditor } from "../../../data/automation";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
interface BlueprintMetaDataPath extends BlueprintMetaData {
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const createNewFunctions = {
|
||||||
|
automation: (
|
||||||
|
context: HaBlueprintOverview,
|
||||||
|
blueprintMeta: BlueprintMetaDataPath
|
||||||
|
) => {
|
||||||
|
showAutomationEditor(context, {
|
||||||
|
alias: blueprintMeta.name,
|
||||||
|
use_blueprint: { path: blueprintMeta.path },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("ha-blueprint-overview")
|
||||||
|
class HaBlueprintOverview extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public isWide!: boolean;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
|
@property() public route!: Route;
|
||||||
|
|
||||||
|
@property() public blueprints!: Blueprints;
|
||||||
|
|
||||||
|
private _processedBlueprints = memoizeOne((blueprints: Blueprints) => {
|
||||||
|
const result = Object.entries(blueprints).map(([path, blueprint]) => ({
|
||||||
|
...blueprint.metadata,
|
||||||
|
path,
|
||||||
|
}));
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
private _columns = memoizeOne(
|
||||||
|
(_language): DataTableColumnContainer => {
|
||||||
|
const columns: DataTableColumnContainer = {
|
||||||
|
name: {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.overview.headers.name"
|
||||||
|
),
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
grows: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
columns.domain = {
|
||||||
|
title: "Domain",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
width: "20%",
|
||||||
|
};
|
||||||
|
columns.path = {
|
||||||
|
title: "Path",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
width: "20%",
|
||||||
|
};
|
||||||
|
columns.create = {
|
||||||
|
title: "",
|
||||||
|
type: "icon-button",
|
||||||
|
template: (_, blueprint) => html`<mwc-icon-button
|
||||||
|
.blueprint=${blueprint}
|
||||||
|
@click=${(ev) => this._createNew(ev)}
|
||||||
|
><ha-svg-icon .path=${mdiPlus}></ha-svg-icon
|
||||||
|
></mwc-icon-button>`,
|
||||||
|
};
|
||||||
|
columns.delete = {
|
||||||
|
title: "",
|
||||||
|
type: "icon-button",
|
||||||
|
template: (_, blueprint) => html`<mwc-icon-button
|
||||||
|
.blueprint=${blueprint}
|
||||||
|
@click=${(ev) => this._delete(ev)}
|
||||||
|
><ha-svg-icon .path=${mdiDelete}></ha-svg-icon
|
||||||
|
></mwc-icon-button>`,
|
||||||
|
};
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<hass-tabs-subpage-data-table
|
||||||
|
.hass=${this.hass}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
back-path="/config"
|
||||||
|
.route=${this.route}
|
||||||
|
.tabs=${configSections.automation}
|
||||||
|
.columns=${this._columns(this.hass.language)}
|
||||||
|
.data=${this._processedBlueprints(this.blueprints)}
|
||||||
|
id="entity_id"
|
||||||
|
.noDataText=${this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.overview.no_blueprints"
|
||||||
|
)}
|
||||||
|
hasFab
|
||||||
|
>
|
||||||
|
<mwc-icon-button slot="toolbar-icon" @click=${this._showHelp}>
|
||||||
|
<ha-svg-icon .path=${mdiHelpCircle}></ha-svg-icon>
|
||||||
|
</mwc-icon-button>
|
||||||
|
<mwc-fab
|
||||||
|
slot="fab"
|
||||||
|
title=${this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.overview.add_blueprint"
|
||||||
|
)}
|
||||||
|
@click=${this._addBlueprint}
|
||||||
|
>
|
||||||
|
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||||
|
</mwc-fab>
|
||||||
|
</hass-tabs-subpage-data-table>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _showHelp() {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.hass.localize("ui.panel.config.blueprint.caption"),
|
||||||
|
text: html`
|
||||||
|
${this.hass.localize("ui.panel.config.blueprint.overview.introduction")}
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href="${documentationUrl(this.hass, "/docs/blueprint/editor/")}"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.overview.learn_more"
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addBlueprint() {
|
||||||
|
showAddBlueprintDialog(this, { importedCallback: () => this._reload() });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _reload() {
|
||||||
|
fireEvent(this, "reload-blueprints");
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createNew(ev) {
|
||||||
|
const blueprint = ev.currentTarget.blueprint as BlueprintMetaDataPath;
|
||||||
|
createNewFunctions[blueprint.domain](this, blueprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _delete(ev) {
|
||||||
|
const blueprint = ev.currentTarget.blueprint;
|
||||||
|
if (
|
||||||
|
!(await showConfirmationDialog(this, {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.overview.confirm_delete_header"
|
||||||
|
),
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.config.blueprint.overview.confirm_delete_text"
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await deleteBlueprint(this.hass, blueprint.domain, blueprint.path);
|
||||||
|
fireEvent(this, "reload-blueprints");
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return haStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-blueprint-overview": HaBlueprintOverview;
|
||||||
|
}
|
||||||
|
}
|
76
src/panels/config/blueprint/ha-config-blueprint.ts
Normal file
76
src/panels/config/blueprint/ha-config-blueprint.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { customElement, property, PropertyValues } from "lit-element";
|
||||||
|
import {
|
||||||
|
HassRouterPage,
|
||||||
|
RouterOptions,
|
||||||
|
} from "../../../layouts/hass-router-page";
|
||||||
|
import "./ha-blueprint-overview";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { Blueprints, fetchBlueprints } from "../../../data/blueprint";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// for fire event
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"reload-blueprints": undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("ha-config-blueprint")
|
||||||
|
class HaConfigBlueprint extends HassRouterPage {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public narrow!: boolean;
|
||||||
|
|
||||||
|
@property() public isWide!: boolean;
|
||||||
|
|
||||||
|
@property() public showAdvanced!: boolean;
|
||||||
|
|
||||||
|
@property() public blueprints: Blueprints = {};
|
||||||
|
|
||||||
|
protected routerOptions: RouterOptions = {
|
||||||
|
defaultPage: "dashboard",
|
||||||
|
routes: {
|
||||||
|
dashboard: {
|
||||||
|
tag: "ha-blueprint-overview",
|
||||||
|
cache: true,
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
tag: "ha-blueprint-editor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
private async _getBlueprints() {
|
||||||
|
this.blueprints = await fetchBlueprints(this.hass, "automation");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this.addEventListener("reload-blueprints", () => {
|
||||||
|
this._getBlueprints();
|
||||||
|
});
|
||||||
|
this._getBlueprints();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updatePageEl(pageEl, changedProps: PropertyValues) {
|
||||||
|
pageEl.hass = this.hass;
|
||||||
|
pageEl.narrow = this.narrow;
|
||||||
|
pageEl.isWide = this.isWide;
|
||||||
|
pageEl.route = this.routeTail;
|
||||||
|
pageEl.showAdvanced = this.showAdvanced;
|
||||||
|
pageEl.blueprints = this.blueprints;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(!changedProps || changedProps.has("route")) &&
|
||||||
|
this._currentPage === "edit"
|
||||||
|
) {
|
||||||
|
const blueprintId = this.routeTail.path.substr(1);
|
||||||
|
pageEl.blueprintId = blueprintId === "new" ? null : blueprintId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-config-blueprint": HaConfigBlueprint;
|
||||||
|
}
|
||||||
|
}
|
17
src/panels/config/blueprint/show-dialog-import-blueprint.ts
Normal file
17
src/panels/config/blueprint/show-dialog-import-blueprint.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
export const loadImportBlueprintDialog = () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "add-blueprint-dialog" */ "./dialog-import-blueprint"
|
||||||
|
);
|
||||||
|
|
||||||
|
export const showAddBlueprintDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
dialogParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "ha-dialog-import-blueprint",
|
||||||
|
dialogImport: loadImportBlueprintDialog,
|
||||||
|
dialogParams,
|
||||||
|
});
|
||||||
|
};
|
@ -33,6 +33,7 @@ import {
|
|||||||
mdiMathLog,
|
mdiMathLog,
|
||||||
mdiPencil,
|
mdiPencil,
|
||||||
mdiNfcVariant,
|
mdiNfcVariant,
|
||||||
|
mdiPaletteSwatch,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -74,6 +75,12 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
automation: [
|
automation: [
|
||||||
|
{
|
||||||
|
component: "blueprint",
|
||||||
|
path: "/config/blueprint",
|
||||||
|
translationKey: "ui.panel.config.blueprint.caption",
|
||||||
|
iconPath: mdiPaletteSwatch,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
component: "automation",
|
component: "automation",
|
||||||
path: "/config/automation",
|
path: "/config/automation",
|
||||||
@ -92,6 +99,8 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
|||||||
translationKey: "ui.panel.config.script.caption",
|
translationKey: "ui.panel.config.script.caption",
|
||||||
iconPath: mdiScriptText,
|
iconPath: mdiScriptText,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
helpers: [
|
||||||
{
|
{
|
||||||
component: "helpers",
|
component: "helpers",
|
||||||
path: "/config/helpers",
|
path: "/config/helpers",
|
||||||
@ -206,6 +215,13 @@ class HaPanelConfig extends HassRouterPage {
|
|||||||
/* webpackChunkName: "panel-config-automation" */ "./automation/ha-config-automation"
|
/* webpackChunkName: "panel-config-automation" */ "./automation/ha-config-automation"
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
blueprint: {
|
||||||
|
tag: "ha-config-blueprint",
|
||||||
|
load: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "panel-config-blueprint" */ "./blueprint/ha-config-blueprint"
|
||||||
|
),
|
||||||
|
},
|
||||||
tags: {
|
tags: {
|
||||||
tag: "ha-config-tags",
|
tag: "ha-config-tags",
|
||||||
load: () =>
|
load: () =>
|
||||||
|
@ -339,6 +339,11 @@
|
|||||||
"add_user": "Add user",
|
"add_user": "Add user",
|
||||||
"remove_user": "Remove user"
|
"remove_user": "Remove user"
|
||||||
},
|
},
|
||||||
|
"blueprint-picker": {
|
||||||
|
"select_blueprint": "Select a Blueprint",
|
||||||
|
"add_user": "Add user",
|
||||||
|
"remove_user": "Remove user"
|
||||||
|
},
|
||||||
"device-picker": {
|
"device-picker": {
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"toggle": "Toggle",
|
"toggle": "Toggle",
|
||||||
@ -1110,6 +1115,19 @@
|
|||||||
"name": "Name"
|
"name": "Name"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dialog_new": {
|
||||||
|
"header": "Create a new automation",
|
||||||
|
"how": "How do you want to create your new automation?",
|
||||||
|
|
||||||
|
"blueprint": { "use_blueprint": "Use a blueprint" },
|
||||||
|
"thingtalk": {
|
||||||
|
"header": "Describe the automation you want to create",
|
||||||
|
"intro": "And we will try to create it for you. For example: Turn the lights off when I leave.",
|
||||||
|
"input_label": "What should this automation do?",
|
||||||
|
"create": "Create"
|
||||||
|
},
|
||||||
|
"start_empty": "Start with an empty automation"
|
||||||
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
"enable_disable": "Enable/Disable automation",
|
"enable_disable": "Enable/Disable automation",
|
||||||
"introduction": "Use automations to bring your home alive.",
|
"introduction": "Use automations to bring your home alive.",
|
||||||
@ -1125,6 +1143,14 @@
|
|||||||
"label": "Description",
|
"label": "Description",
|
||||||
"placeholder": "Optional description"
|
"placeholder": "Optional description"
|
||||||
},
|
},
|
||||||
|
"blueprint": {
|
||||||
|
"header": "Blueprint",
|
||||||
|
"blueprint_to_use": "Blueprint to use",
|
||||||
|
"no_blueprints": "You don't have any blueprints",
|
||||||
|
"manage_blueprints": "Manage Blueprints",
|
||||||
|
"inputs": "Inputs",
|
||||||
|
"no_inputs": "This blueprint doesn't have any inputs."
|
||||||
|
},
|
||||||
"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.",
|
"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.",
|
||||||
@ -1414,6 +1440,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"blueprint": {
|
||||||
|
"caption": "Blueprints",
|
||||||
|
"description": "Manage blueprints",
|
||||||
|
"overview": {
|
||||||
|
"header": "Blueprint Editor",
|
||||||
|
"introduction": "The blueprint editor allows you to create and edit blueprints.",
|
||||||
|
"learn_more": "Learn more about blueprints",
|
||||||
|
"headers": {
|
||||||
|
"name": "Name"
|
||||||
|
},
|
||||||
|
"confirm_delete_header": "Delete this Blueprint?",
|
||||||
|
"confirm_delete_text": "Are you sure you want to delete this Blueprint"
|
||||||
|
},
|
||||||
|
"add": {
|
||||||
|
"header": "Add new blueprint",
|
||||||
|
"import_header": "Import {name} ({domain})",
|
||||||
|
"import_introduction": "You can import Blueprints of other users from Github and the community forums. Enter the url of the Blueprint below.",
|
||||||
|
"url": "Url of the blueprint",
|
||||||
|
"importing": "Importing blueprint...",
|
||||||
|
"import_btn": "Import blueprint",
|
||||||
|
"saving": "Saving blueprint...",
|
||||||
|
"save_btn": "Save blueprint",
|
||||||
|
"error_no_url": "Please enter the url of the blueprint."
|
||||||
|
}
|
||||||
|
},
|
||||||
"script": {
|
"script": {
|
||||||
"caption": "Scripts",
|
"caption": "Scripts",
|
||||||
"description": "Manage scripts",
|
"description": "Manage scripts",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user