Scriptomation yaml editor (#7273)

This commit is contained in:
Thomas Lovén 2020-10-12 11:26:16 +02:00 committed by GitHub
parent 557d6d37a1
commit 44166f76d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 602 additions and 352 deletions

View File

@ -105,6 +105,10 @@ export class HaYamlEditor extends LitElement {
fireEvent(this, "value-changed", { value: parsed, isValid } as any); fireEvent(this, "value-changed", { value: parsed, isValid } as any);
} }
get yaml() {
return this._editor?.value;
}
} }
declare global { declare global {

View File

@ -1,5 +1,6 @@
import "@material/mwc-fab"; import "@material/mwc-fab";
import { import {
mdiCheck,
mdiContentDuplicate, mdiContentDuplicate,
mdiContentSave, mdiContentSave,
mdiDelete, mdiDelete,
@ -21,6 +22,7 @@ import {
property, property,
PropertyValues, PropertyValues,
TemplateResult, TemplateResult,
query,
} from "lit-element"; } from "lit-element";
import { classMap } from "lit-html/directives/class-map"; import { classMap } from "lit-html/directives/class-map";
import { navigate } from "../../../common/navigate"; import { navigate } from "../../../common/navigate";
@ -28,6 +30,8 @@ import "../../../components/ha-button-menu";
import "../../../components/ha-card"; import "../../../components/ha-card";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import "../../../components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
import { import {
AutomationConfig, AutomationConfig,
AutomationEntity, AutomationEntity,
@ -89,6 +93,10 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
@internalProperty() private _entityId?: string; @internalProperty() private _entityId?: string;
@internalProperty() private _mode: "gui" | "yaml" = "gui";
@query("ha-yaml-editor", true) private _editor?: HaYamlEditor;
protected render(): TemplateResult { protected render(): TemplateResult {
const stateObj = this._entityId const stateObj = this._entityId
? this.hass.states[this._entityId] ? this.hass.states[this._entityId]
@ -105,6 +113,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
corner="BOTTOM_START" corner="BOTTOM_START"
slot="toolbar-icon" slot="toolbar-icon"
@action=${this._handleMenuAction} @action=${this._handleMenuAction}
activatable
> >
<mwc-icon-button <mwc-icon-button
slot="trigger" slot="trigger"
@ -113,6 +122,39 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
><ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon> ><ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button> </mwc-icon-button>
<mwc-list-item
aria-label=${this.hass.localize(
"ui.panel.config.automation.editor.edit_ui"
)}
graphic="icon"
?activated=${this._mode === "gui"}
>
${this.hass.localize("ui.panel.config.automation.editor.edit_ui")}
${this._mode === "gui"
? html`<ha-svg-icon
slot="graphic"
.path=${mdiCheck}
></ha-svg-icon>`
: ``}
</mwc-list-item>
<mwc-list-item
aria-label=${this.hass.localize(
"ui.panel.config.automation.editor.edit_yaml"
)}
graphic="icon"
?activated=${this._mode === "yaml"}
>
${this.hass.localize("ui.panel.config.automation.editor.edit_yaml")}
${this._mode === "yaml"
? html`<ha-svg-icon
slot="graphic"
.path=${mdiCheck}
></ha-svg-icon>`
: ``}
</mwc-list-item>
<li divider role="separator"></li>
<mwc-list-item <mwc-list-item
.disabled=${!this.automationId} .disabled=${!this.automationId}
aria-label=${this.hass.localize( aria-label=${this.hass.localize(
@ -152,215 +194,270 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
${this._errors ${this._errors
? html` <div class="errors">${this._errors}</div> ` ? html` <div class="errors">${this._errors}</div> `
: ""} : ""}
<ha-config-section .isWide=${this.isWide}> ${this._mode === "gui"
${!this.narrow ? html`
? html` <span slot="header">${this._config.alias}</span> ` <ha-config-section .isWide=${this.isWide}>
: ""} ${!this.narrow
<span slot="introduction"> ? html`
${this.hass.localize( <span slot="header">${this._config.alias}</span>
"ui.panel.config.automation.editor.introduction" `
)} : ""}
</span> <span slot="introduction">
<ha-card> ${this.hass.localize(
<div class="card-content"> "ui.panel.config.automation.editor.introduction"
<paper-input )}
.label=${this.hass.localize( </span>
"ui.panel.config.automation.editor.alias" <ha-card>
)} <div class="card-content">
name="alias" <paper-input
.value=${this._config.alias} .label=${this.hass.localize(
@value-changed=${this._valueChanged} "ui.panel.config.automation.editor.alias"
> )}
</paper-input> name="alias"
<paper-textarea .value=${this._config.alias}
.label=${this.hass.localize( @value-changed=${this._valueChanged}
"ui.panel.config.automation.editor.description.label" >
)} </paper-input>
.placeholder=${this.hass.localize( <paper-textarea
"ui.panel.config.automation.editor.description.placeholder" .label=${this.hass.localize(
)} "ui.panel.config.automation.editor.description.label"
name="description" )}
.value=${this._config.description} .placeholder=${this.hass.localize(
@value-changed=${this._valueChanged} "ui.panel.config.automation.editor.description.placeholder"
></paper-textarea> )}
<p> name="description"
${this.hass.localize( .value=${this._config.description}
"ui.panel.config.automation.editor.modes.description", @value-changed=${this._valueChanged}
"documentation_link", ></paper-textarea>
html`<a <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( href="${documentationUrl(
this.hass, this.hass,
"/integrations/automation/#automation-modes" "/docs/automation/trigger/"
)}" )}"
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
>${this.hass.localize( >
"ui.panel.config.automation.editor.modes.documentation" ${this.hass.localize(
)}</a "ui.panel.config.automation.editor.triggers.learn_more"
>`
)}
</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" </a>
name="max" </span>
.value=${this._config.max || "10"} <ha-automation-trigger
@value-changed=${this._valueChanged} .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"
> >
</paper-input>` ${this.hass.localize(
: html``} "ui.panel.config.automation.editor.conditions.learn_more"
</div> )}
${stateObj </a>
? html` </span>
<div <ha-automation-condition
class="card-actions layout horizontal justified center" .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"
> >
<div class="layout horizontal center"> ${this.hass.localize(
<ha-entity-toggle "ui.panel.config.automation.editor.actions.learn_more"
.hass=${this.hass} )}
.stateObj=${stateObj} </a>
></ha-entity-toggle> </span>
<ha-automation-action
.actions=${this._config.action}
@value-changed=${this._actionChanged}
.hass=${this.hass}
></ha-automation-action>
</ha-config-section>
`
: this._mode === "yaml"
? html`
<ha-config-section .isWide=${false}>
${!this.narrow
? html`
<span slot="header">${this._config.alias}</span>
`
: ``}
<ha-card>
<div class="card-content">
<ha-yaml-editor
.defaultValue=${this._preprocessYaml()}
@value-changed=${this._yamlChanged}
></ha-yaml-editor>
<mwc-button @click=${this._copyYaml}>
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.automation.editor.enable_disable" "ui.panel.config.automation.editor.copy_to_clipboard"
)}
</div>
<mwc-button
@click=${this._excuteAutomation}
.stateObj=${stateObj}
>
${this.hass.localize(
"ui.card.automation.trigger"
)} )}
</mwc-button> </mwc-button>
</div> </div>
` ${stateObj
: ""} ? html`
</ha-card> <div
</ha-config-section> class="card-actions layout horizontal justified center"
>
<ha-config-section .isWide=${this.isWide}> <div class="layout horizontal center">
<span slot="header"> <ha-entity-toggle
${this.hass.localize( .hass=${this.hass}
"ui.panel.config.automation.editor.triggers.header" .stateObj=${stateObj}
)} ></ha-entity-toggle>
</span> ${this.hass.localize(
<span slot="introduction"> "ui.panel.config.automation.editor.enable_disable"
<p> )}
${this.hass.localize( </div>
"ui.panel.config.automation.editor.triggers.introduction" <mwc-button
)} @click=${this._excuteAutomation}
</p> .stateObj=${stateObj}
<a >
href="${documentationUrl( ${this.hass.localize(
this.hass, "ui.card.automation.trigger"
"/docs/automation/trigger/" )}
)}" </mwc-button>
target="_blank" </div>
rel="noreferrer" `
> : ""}
${this.hass.localize( </ha-card>
"ui.panel.config.automation.editor.triggers.learn_more" <ha-config-section> </ha-config-section
)} ></ha-config-section>
</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>
</div> </div>
` `
: ""} : ""}
@ -512,6 +609,33 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
triggerAutomation(this.hass, (ev.target as any).stateObj.entity_id); triggerAutomation(this.hass, (ev.target as any).stateObj.entity_id);
} }
private _preprocessYaml() {
const cleanConfig = this._config;
if (!cleanConfig) {
return {};
}
delete cleanConfig.id;
return cleanConfig;
}
private async _copyYaml() {
if (this._editor?.yaml) {
navigator.clipboard.writeText(this._editor.yaml);
}
}
private _yamlChanged(ev: CustomEvent) {
ev.stopPropagation();
if (!ev.detail.isValid) {
return;
}
this._config = ev.detail.value;
this._errors = undefined;
this._dirty = true;
}
private _backTapped(): void { private _backTapped(): void {
if (this._dirty) { if (this._dirty) {
showConfirmationDialog(this, { showConfirmationDialog(this, {
@ -571,9 +695,15 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) { private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
switch (ev.detail.index) { switch (ev.detail.index) {
case 0: case 0:
this._duplicate(); this._mode = "gui";
break; break;
case 1: case 1:
this._mode = "yaml";
break;
case 2:
this._duplicate();
break;
case 3:
this._deleteConfirm(); this._deleteConfirm();
break; break;
} }

View File

@ -1,5 +1,5 @@
import "@material/mwc-fab"; import "@material/mwc-fab";
import { mdiContentSave, mdiDelete, mdiDotsVertical } from "@mdi/js"; import { mdiCheck, mdiContentSave, mdiDelete, mdiDotsVertical } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
@ -15,6 +15,7 @@ import {
property, property,
PropertyValues, PropertyValues,
TemplateResult, TemplateResult,
query,
} from "lit-element"; } from "lit-element";
import { classMap } from "lit-html/directives/class-map"; import { classMap } from "lit-html/directives/class-map";
import { computeObjectId } from "../../../common/entity/compute_object_id"; import { computeObjectId } from "../../../common/entity/compute_object_id";
@ -26,6 +27,8 @@ import "../../../components/ha-card";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import "../../../components/ha-icon-input"; import "../../../components/ha-icon-input";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import "../../../components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
import { import {
Action, Action,
deleteScript, deleteScript,
@ -68,6 +71,10 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@internalProperty() private _errors?: string; @internalProperty() private _errors?: string;
@internalProperty() private _mode: "gui" | "yaml" = "gui";
@query("ha-yaml-editor", true) private _editor?: HaYamlEditor;
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<hass-tabs-subpage <hass-tabs-subpage
@ -81,6 +88,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
corner="BOTTOM_START" corner="BOTTOM_START"
slot="toolbar-icon" slot="toolbar-icon"
@action=${this._handleMenuAction} @action=${this._handleMenuAction}
activatable
> >
<mwc-icon-button <mwc-icon-button
slot="trigger" slot="trigger"
@ -89,17 +97,48 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
><ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon> ><ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button> </mwc-icon-button>
<mwc-list-item
aria-label=${this.hass.localize(
"ui.panel.config.automation.editor.edit_ui"
)}
graphic="icon"
?activated=${this._mode === "gui"}
>
${this.hass.localize("ui.panel.config.automation.editor.edit_ui")}
${this._mode === "gui"
? html`<ha-svg-icon
slot="graphic"
.path=${mdiCheck}
></ha-svg-icon>`
: ``}
</mwc-list-item>
<mwc-list-item
aria-label=${this.hass.localize(
"ui.panel.config.automation.editor.edit_yaml"
)}
graphic="icon"
?activated=${this._mode === "yaml"}
>
${this.hass.localize("ui.panel.config.automation.editor.edit_yaml")}
${this._mode === "yaml"
? html`<ha-svg-icon
slot="graphic"
.path=${mdiCheck}
></ha-svg-icon>`
: ``}
</mwc-list-item>
<li divider role="separator"></li>
<mwc-list-item <mwc-list-item
.disabled=${!this.scriptEntityId} .disabled=${!this.scriptEntityId}
aria-label=${this.hass.localize( aria-label=${this.hass.localize(
"ui.panel.config.automation.picker.delete_automation" "ui.panel.config.script.editor.delete_script"
)} )}
class=${classMap({ warning: this.scriptEntityId })} class=${classMap({ warning: this.scriptEntityId })}
graphic="icon" graphic="icon"
> >
${this.hass.localize( ${this.hass.localize("ui.panel.config.script.editor.delete_script")}
"ui.panel.config.automation.picker.delete_automation"
)}
<ha-svg-icon slot="graphic" .path=${mdiDelete}></ha-svg-icon> <ha-svg-icon slot="graphic" .path=${mdiDelete}></ha-svg-icon>
</mwc-list-item> </mwc-list-item>
</ha-button-menu> </ha-button-menu>
@ -110,164 +149,214 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
${this._errors ${this._errors
? html` <div class="errors">${this._errors}</div> ` ? html` <div class="errors">${this._errors}</div> `
: ""} : ""}
<div ${this._mode === "gui"
class="${classMap({ ? html`
rtl: computeRTL(this.hass), <div
})}" class=${classMap({
> rtl: computeRTL(this.hass),
${this._config })}
? html` >
<ha-config-section .isWide=${this.isWide}> ${this._config
${!this.narrow ? html`
? html` <span slot="header">${this._config.alias}</span> ` <ha-config-section .isWide=${this.isWide}>
: ""} ${!this.narrow
<span slot="introduction"> ? html`
${this.hass.localize( <span slot="header">${this._config.alias}</span>
"ui.panel.config.script.editor.introduction" `
)} : ""}
</span> <span slot="introduction">
<ha-card> ${this.hass.localize(
<div class="card-content"> "ui.panel.config.script.editor.introduction"
<paper-input )}
.label=${this.hass.localize( </span>
"ui.panel.config.script.editor.alias" <ha-card>
)} <div class="card-content">
name="alias" <paper-input
.value=${this._config.alias} .label=${this.hass.localize(
@value-changed=${this._valueChanged} "ui.panel.config.script.editor.alias"
@change=${this._aliasChanged} )}
> name="alias"
</paper-input> .value=${this._config.alias}
<ha-icon-input @value-changed=${this._valueChanged}
.label=${this.hass.localize( @change=${this._aliasChanged}
"ui.panel.config.script.editor.icon" >
)} </paper-input>
.name=${"icon"} <ha-icon-input
.value=${this._config.icon} .label=${this.hass.localize(
@value-changed=${this._valueChanged} "ui.panel.config.script.editor.icon"
> )}
</ha-icon-input> .name=${"icon"}
${!this.scriptEntityId .value=${this._config.icon}
? html` <paper-input @value-changed=${this._valueChanged}
.label=${this.hass.localize( >
"ui.panel.config.script.editor.id" </ha-icon-input>
${!this.scriptEntityId
? html`<paper-input
.label=${this.hass.localize(
"ui.panel.config.script.editor.id"
)}
.errorMessage=${this.hass.localize(
"ui.panel.config.script.editor.id_already_exists"
)}
.invalid=${this._idError}
.value=${this._entityId}
@value-changed=${this._idChanged}
>
</paper-input>`
: ""}
<p>
${this.hass.localize(
"ui.panel.config.script.editor.modes.description",
"documentation_link",
html`<a
href="${documentationUrl(
this.hass,
"/integrations/script/#script-modes"
)}"
target="_blank"
rel="noreferrer"
>${this.hass.localize(
"ui.panel.config.script.editor.modes.documentation"
)}</a
>`
)}
</p>
<paper-dropdown-menu-light
.label=${this.hass.localize(
"ui.panel.config.script.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.script.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.script.editor.max.${this._config.mode}`
)}
type="number"
name="max"
.value=${this._config.max || "10"}
@value-changed=${this._valueChanged}
>
</paper-input>`
: html``}
</div>
${this.scriptEntityId
? html`
<div
class="card-actions layout horizontal justified center"
>
<span></span>
<mwc-button
@click=${this._runScript}
title="${this.hass.localize(
"ui.panel.config.script.picker.activate_script"
)}"
?disabled=${this._dirty}
>
${this.hass.localize(
"ui.card.script.execute"
)}
</mwc-button>
</div>
`
: ``}
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.script.editor.sequence"
)}
</span>
<span slot="introduction">
<p>
${this.hass.localize(
"ui.panel.config.script.editor.sequence_sentence"
)} )}
.errorMessage=${this.hass.localize( </p>
"ui.panel.config.script.editor.id_already_exists" <a
)}
.invalid=${this._idError}
.value=${this._entityId}
@value-changed=${this._idChanged}
>
</paper-input>`
: ""}
<p>
${this.hass.localize(
"ui.panel.config.script.editor.modes.description",
"documentation_link",
html`<a
href="${documentationUrl( href="${documentationUrl(
this.hass, this.hass,
"/integrations/script/#script-modes" "/docs/scripts/"
)}" )}"
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
>${this.hass.localize( >
"ui.panel.config.script.editor.modes.documentation" ${this.hass.localize(
)}</a "ui.panel.config.script.editor.link_available_actions"
>`
)}
</p>
<paper-dropdown-menu-light
.label=${this.hass.localize(
"ui.panel.config.script.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.script.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.script.editor.max.${this._config.mode}`
)} )}
type="number" </a>
name="max" </span>
.value=${this._config.max || "10"} <ha-automation-action
@value-changed=${this._valueChanged} .actions=${this._config.sequence}
> @value-changed=${this._sequenceChanged}
</paper-input>` .hass=${this.hass}
: html``} ></ha-automation-action>
</div> </ha-config-section>
${this.scriptEntityId `
? html` : ""}
<div </div>
class="card-actions layout horizontal justified center" `
> : this._mode === "yaml"
<span></span> ? html`
<mwc-button <ha-config-section .isWide=${false}>
@click=${this._runScript} ${!this.narrow
title="${this.hass.localize( ? html`<span slot="header">${this._config?.alias}</span>`
"ui.panel.config.script.picker.activate_script" : ``}
)}" <ha-card>
?disabled=${this._dirty} <div class="card-content">
> <ha-yaml-editor
${this.hass.localize("ui.card.script.execute")} .defaultValue=${this._preprocessYaml()}
</mwc-button> @value-changed=${this._yamlChanged}
</div> ></ha-yaml-editor>
` <mwc-button @click=${this._copyYaml}>
: ``}
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.script.editor.sequence"
)}
</span>
<span slot="introduction">
<p>
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.script.editor.sequence_sentence" "ui.panel.config.automation.editor.copy_to_clipboard"
)} )}
</p> </mwc-button>
<a </div>
href="${documentationUrl(this.hass, "/docs/scripts/")}" ${this.scriptEntityId
target="_blank" ? html`
rel="noreferrer" <div
> class="card-actions layout horizontal justified center"
${this.hass.localize( >
"ui.panel.config.script.editor.link_available_actions" <span></span>
)} <mwc-button
</a> @click=${this._runScript}
</span> title="${this.hass.localize(
<ha-automation-action "ui.panel.config.script.picker.activate_script"
.actions=${this._config.sequence} )}"
@value-changed=${this._sequenceChanged} ?disabled=${this._dirty}
.hass=${this.hass} >
></ha-automation-action> ${this.hass.localize("ui.card.script.execute")}
</ha-config-section> </mwc-button>
` </div>
: ""} `
</div> : ``}
</ha-card>
</ha-config-section>
`
: ``}
</div> </div>
<mwc-fab <mwc-fab
slot="fab" slot="fab"
@ -419,6 +508,26 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
this._dirty = true; this._dirty = true;
} }
private _preprocessYaml() {
return this._config;
}
private async _copyYaml() {
if (this._editor?.yaml) {
navigator.clipboard.writeText(this._editor.yaml);
}
}
private _yamlChanged(ev: CustomEvent) {
ev.stopPropagation();
if (!ev.detail.isValid) {
return;
}
this._config = ev.detail.value;
this._errors = undefined;
this._dirty = true;
}
private _backTapped(): void { private _backTapped(): void {
if (this._dirty) { if (this._dirty) {
showConfirmationDialog(this, { showConfirmationDialog(this, {
@ -451,6 +560,12 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) { private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
switch (ev.detail.index) { switch (ev.detail.index) {
case 0: case 0:
this._mode = "gui";
break;
case 1:
this._mode = "yaml";
break;
case 2:
this._deleteConfirm(); this._deleteConfirm();
break; break;
} }

View File

@ -1064,6 +1064,7 @@
}, },
"edit_yaml": "Edit as YAML", "edit_yaml": "Edit as YAML",
"edit_ui": "Edit with UI", "edit_ui": "Edit with UI",
"copy_to_clipboard": "Copy to Clipboard",
"triggers": { "triggers": {
"name": "Trigger", "name": "Trigger",
"header": "Triggers", "header": "Triggers",