mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 03:36:44 +00:00
Script editor updates (match automation editor) (#20791)
* Show descriptions in script editor * Script editor updates (match automation editor) * review feedback
This commit is contained in:
parent
d9bac06806
commit
9b28c7cf69
@ -138,7 +138,7 @@ class DialogAutomationMode extends LitElement implements HassDialog {
|
||||
}
|
||||
|
||||
private _save(): void {
|
||||
this._params.updateAutomation({
|
||||
this._params.updateConfig({
|
||||
...this._params.config,
|
||||
mode: this._newMode,
|
||||
max: this._newMax,
|
||||
|
@ -1,18 +1,25 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { AutomationConfig } from "../../../../data/automation";
|
||||
import type { ScriptConfig } from "../../../../data/script";
|
||||
|
||||
export const loadAutomationModeDialog = () =>
|
||||
import("./dialog-automation-mode");
|
||||
|
||||
export interface AutomationModeDialog {
|
||||
config: AutomationConfig;
|
||||
updateAutomation: (config: AutomationConfig) => void;
|
||||
updateConfig: (config: AutomationConfig) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export interface ScriptModeDialog {
|
||||
config: ScriptConfig;
|
||||
updateConfig: (config: ScriptConfig) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const showAutomationModeDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: AutomationModeDialog
|
||||
dialogParams: AutomationModeDialog | ScriptModeDialog
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "ha-dialog-automation-mode",
|
||||
|
@ -124,7 +124,7 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
||||
this._error = "Name is required";
|
||||
return;
|
||||
}
|
||||
this._params.updateAutomation({
|
||||
this._params.updateConfig({
|
||||
...this._params.config,
|
||||
alias: this._newName,
|
||||
description: this._newDescription,
|
||||
|
@ -1,18 +1,25 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { AutomationConfig } from "../../../../data/automation";
|
||||
import type { ScriptConfig } from "../../../../data/script";
|
||||
|
||||
export const loadAutomationRenameDialog = () =>
|
||||
import("./dialog-automation-rename");
|
||||
|
||||
export interface AutomationRenameDialog {
|
||||
config: AutomationConfig;
|
||||
updateAutomation: (config: AutomationConfig) => void;
|
||||
updateConfig: (config: AutomationConfig) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export interface ScriptRenameDialog {
|
||||
config: ScriptConfig;
|
||||
updateConfig: (config: ScriptConfig) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const showAutomationRenameDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: AutomationRenameDialog
|
||||
dialogParams: AutomationRenameDialog | ScriptRenameDialog
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "ha-dialog-automation-rename",
|
||||
|
@ -28,6 +28,7 @@ import { property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-fab";
|
||||
@ -117,22 +118,24 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
private _configSubscriptionsId = 1;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (!this._config) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const stateObj = this._entityId
|
||||
? this.hass.states[this._entityId]
|
||||
: undefined;
|
||||
|
||||
const useBlueprint = "use_blueprint" in this._config;
|
||||
return html`
|
||||
<hass-subpage
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.backCallback=${this._backTapped}
|
||||
.header=${!this._config
|
||||
? ""
|
||||
: this._config.alias ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.editor.default_name"
|
||||
)}
|
||||
.header=${this._config.alias ||
|
||||
this.hass.localize("ui.panel.config.automation.editor.default_name")}
|
||||
>
|
||||
${this._config?.id && !this.narrow
|
||||
? html`
|
||||
@ -171,7 +174,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPlay}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
|
||||
${stateObj && this._config && this.narrow
|
||||
${stateObj && this.narrow
|
||||
? html`<a
|
||||
href="/config/automation/trace/${encodeURIComponent(
|
||||
this._config.id!
|
||||
@ -187,7 +190,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</a>`
|
||||
: ""}
|
||||
: nothing}
|
||||
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@ -197,8 +200,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
${this.hass.localize("ui.panel.config.automation.editor.rename")}
|
||||
<ha-svg-icon slot="graphic" .path=${mdiRenameBox}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
|
||||
${this._config && !("use_blueprint" in this._config)
|
||||
${!useBlueprint
|
||||
? html`
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@ -214,7 +216,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
|
||||
<ha-list-item
|
||||
.disabled=${!this._readOnly && !this.automationId}
|
||||
@ -288,35 +290,38 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
</ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
|
||||
${this._config
|
||||
? html`
|
||||
<div
|
||||
class="content ${classMap({
|
||||
"yaml-mode": this._mode === "yaml",
|
||||
})}"
|
||||
@subscribe-automation-config=${this._subscribeAutomationConfig}
|
||||
<div
|
||||
class="content ${classMap({
|
||||
"yaml-mode": this._mode === "yaml",
|
||||
})}"
|
||||
@subscribe-automation-config=${this._subscribeAutomationConfig}
|
||||
>
|
||||
${this._errors || stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-alert
|
||||
alert-type="error"
|
||||
.title=${stateObj?.state === UNAVAILABLE
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.unavailable"
|
||||
)
|
||||
: undefined}
|
||||
>
|
||||
${this._errors || stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-alert
|
||||
alert-type="error"
|
||||
.title=${stateObj?.state === UNAVAILABLE
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.unavailable"
|
||||
)
|
||||
: undefined}
|
||||
>
|
||||
${this._errors || this._validationErrors}
|
||||
${stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiRobotConfused}
|
||||
></ha-svg-icon>`
|
||||
: nothing}
|
||||
</ha-alert>`
|
||||
: ""}
|
||||
${this._mode === "gui"
|
||||
? "use_blueprint" in this._config
|
||||
${this._errors || this._validationErrors}
|
||||
${stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiRobotConfused}
|
||||
></ha-svg-icon>`
|
||||
: nothing}
|
||||
</ha-alert>`
|
||||
: ""}
|
||||
${this._mode === "gui"
|
||||
? html`
|
||||
<div
|
||||
class=${classMap({
|
||||
rtl: computeRTL(this.hass),
|
||||
})}
|
||||
>
|
||||
${useBlueprint
|
||||
? html`
|
||||
<blueprint-automation-editor
|
||||
.hass=${this.hass}
|
||||
@ -340,51 +345,45 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
@value-changed=${this._valueChanged}
|
||||
@duplicate=${this._duplicate}
|
||||
></manual-automation-editor>
|
||||
`
|
||||
: this._mode === "yaml"
|
||||
? html` ${this._readOnly
|
||||
? html`<ha-alert alert-type="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.read_only"
|
||||
)}
|
||||
<mwc-button
|
||||
slot="action"
|
||||
@click=${this._duplicate}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.migrate"
|
||||
)}
|
||||
</mwc-button>
|
||||
</ha-alert>`
|
||||
: ""}
|
||||
${stateObj?.state === "off"
|
||||
? html`
|
||||
<ha-alert alert-type="info">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.disabled"
|
||||
)}
|
||||
<mwc-button
|
||||
slot="action"
|
||||
@click=${this._toggle}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.enable"
|
||||
)}
|
||||
</mwc-button>
|
||||
</ha-alert>
|
||||
`
|
||||
: ""}
|
||||
<ha-yaml-editor
|
||||
copyClipboard
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this._preprocessYaml()}
|
||||
.readOnly=${this._readOnly}
|
||||
@value-changed=${this._yamlChanged}
|
||||
></ha-yaml-editor>`
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
: this._mode === "yaml"
|
||||
? html` ${this._readOnly
|
||||
? html`<ha-alert alert-type="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.read_only"
|
||||
)}
|
||||
<mwc-button slot="action" @click=${this._duplicate}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.migrate"
|
||||
)}
|
||||
</mwc-button>
|
||||
</ha-alert>`
|
||||
: nothing}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${stateObj?.state === "off"
|
||||
? html`
|
||||
<ha-alert alert-type="info">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.disabled"
|
||||
)}
|
||||
<mwc-button slot="action" @click=${this._toggle}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.enable"
|
||||
)}
|
||||
</mwc-button>
|
||||
</ha-alert>
|
||||
`
|
||||
: ""}
|
||||
<ha-yaml-editor
|
||||
copyClipboard
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this._preprocessYaml()}
|
||||
.readOnly=${this._readOnly}
|
||||
@value-changed=${this._yamlChanged}
|
||||
></ha-yaml-editor>`
|
||||
: nothing}
|
||||
</div>
|
||||
<ha-fab
|
||||
slot="fab"
|
||||
class=${classMap({ dirty: this._dirty })}
|
||||
@ -689,7 +688,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
return new Promise((resolve) => {
|
||||
showAutomationRenameDialog(this, {
|
||||
config: this._config!,
|
||||
updateAutomation: (config) => {
|
||||
updateConfig: (config) => {
|
||||
this._config = config;
|
||||
this._dirty = true;
|
||||
this.requestUpdate();
|
||||
@ -704,7 +703,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
return new Promise((resolve) => {
|
||||
showAutomationModeDialog(this, {
|
||||
config: this._config!,
|
||||
updateAutomation: (config) => {
|
||||
updateConfig: (config) => {
|
||||
this._config = config;
|
||||
this._dirty = true;
|
||||
this.requestUpdate();
|
||||
|
@ -1,13 +1,16 @@
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import "@material/mwc-button";
|
||||
import {
|
||||
mdiCheck,
|
||||
mdiContentDuplicate,
|
||||
mdiContentSave,
|
||||
mdiDebugStepOver,
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiFormTextbox,
|
||||
mdiInformationOutline,
|
||||
mdiPlay,
|
||||
mdiRenameBox,
|
||||
mdiRobotConfused,
|
||||
mdiTransitConnection,
|
||||
} from "@mdi/js";
|
||||
import {
|
||||
@ -21,35 +24,28 @@ import {
|
||||
} from "lit";
|
||||
import { property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-fab";
|
||||
import type {
|
||||
HaFormDataContainer,
|
||||
SchemaUnion,
|
||||
} from "../../../components/ha-form/types";
|
||||
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-yaml-editor";
|
||||
import "../../../components/ha-list-item";
|
||||
import { validateConfig } from "../../../data/config";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||
import {
|
||||
MODES,
|
||||
MODES_MAX,
|
||||
ScriptConfig,
|
||||
deleteScript,
|
||||
fetchScriptFileConfig,
|
||||
getScriptEditorInitData,
|
||||
getScriptStateConfig,
|
||||
hasScriptFields,
|
||||
isMaxMode,
|
||||
showScriptEditor,
|
||||
triggerScript,
|
||||
} from "../../../data/script";
|
||||
@ -58,8 +54,9 @@ import "../../../layouts/hass-subpage";
|
||||
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { Entries, HomeAssistant, Route } from "../../../types";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
import { showToast } from "../../../util/toast";
|
||||
import { showAutomationModeDialog } from "../automation/automation-mode-dialog/show-dialog-automation-mode";
|
||||
import { showAutomationRenameDialog } from "../automation/automation-rename-dialog/show-dialog-automation-rename";
|
||||
import "./blueprint-script-editor";
|
||||
import "./manual-script-editor";
|
||||
import type { HaManualScriptEditor } from "./manual-script-editor";
|
||||
@ -72,24 +69,24 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
@property() public entityId: string | null = null;
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
|
||||
|
||||
@property({ type: Boolean }) public isWide = false;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
@state() private _config?: ScriptConfig;
|
||||
|
||||
@state() private _entityId?: string;
|
||||
|
||||
@state() private _idError = false;
|
||||
|
||||
@state() private _dirty = false;
|
||||
|
||||
@state() private _errors?: string;
|
||||
|
||||
@state() private _entityId?: string;
|
||||
|
||||
@state() private _mode: "gui" | "yaml" = "gui";
|
||||
|
||||
@state() private _readOnly = false;
|
||||
@ -99,72 +96,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
@state() private _validationErrors?: (string | TemplateResult)[];
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(
|
||||
hasID: boolean,
|
||||
useBluePrint?: boolean,
|
||||
currentMode?: (typeof MODES)[number]
|
||||
) =>
|
||||
[
|
||||
{
|
||||
name: "alias",
|
||||
selector: {
|
||||
text: {
|
||||
type: "text",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "icon",
|
||||
selector: {
|
||||
icon: {},
|
||||
},
|
||||
},
|
||||
...(!hasID
|
||||
? ([
|
||||
{
|
||||
name: "id",
|
||||
selector: {
|
||||
text: {
|
||||
prefix: "script.",
|
||||
},
|
||||
},
|
||||
},
|
||||
] as const)
|
||||
: []),
|
||||
...(!useBluePrint
|
||||
? ([
|
||||
{
|
||||
name: "mode",
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: MODES.map((mode) => ({
|
||||
label: this.hass.localize(
|
||||
`ui.panel.config.script.editor.modes.${mode}`
|
||||
),
|
||||
value: mode,
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
] as const)
|
||||
: []),
|
||||
...(currentMode && isMaxMode(currentMode)
|
||||
? ([
|
||||
{
|
||||
name: "max",
|
||||
required: true,
|
||||
selector: {
|
||||
number: { mode: "box", min: 1, max: Infinity },
|
||||
},
|
||||
},
|
||||
] as const)
|
||||
: []),
|
||||
] as const
|
||||
);
|
||||
|
||||
protected render() {
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (!this._config) {
|
||||
return nothing;
|
||||
}
|
||||
@ -174,28 +106,13 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
: undefined;
|
||||
|
||||
const useBlueprint = "use_blueprint" in this._config;
|
||||
|
||||
const schema = this._schema(
|
||||
!!this.scriptId,
|
||||
useBlueprint,
|
||||
this._config.mode
|
||||
);
|
||||
|
||||
const data = {
|
||||
...(!this._config.mode && !useBlueprint && { mode: MODES[0] }),
|
||||
icon: undefined,
|
||||
max: this._config.mode && isMaxMode(this._config.mode) ? 10 : undefined,
|
||||
...this._config,
|
||||
id: this._entityId,
|
||||
};
|
||||
|
||||
return html`
|
||||
<hass-subpage
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.backCallback=${this._backTapped}
|
||||
.header=${!this._config?.alias ? "" : this._config.alias}
|
||||
.header=${!this._config.alias ? "" : this._config.alias}
|
||||
>
|
||||
${this.scriptId && !this.narrow
|
||||
? html`
|
||||
@ -213,7 +130,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.disabled=${!this.scriptId}
|
||||
@click=${this._showInfo}
|
||||
@ -223,34 +140,21 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
slot="graphic"
|
||||
.path=${mdiInformationOutline}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.disabled=${!this.scriptId}
|
||||
@click=${this._runScript}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.script.picker.run_script")}
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPlay}></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
${!useBlueprint && !("fields" in this._config)
|
||||
? html`
|
||||
<mwc-list-item graphic="icon" @click=${this._addFields}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.field.add_fields"
|
||||
)}
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${mdiFormTextbox}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
`
|
||||
: nothing}
|
||||
${this.scriptId && this.narrow
|
||||
? html`
|
||||
<a href="/config/script/trace/${this.scriptId}">
|
||||
<mwc-list-item graphic="icon">
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.show_trace"
|
||||
)}
|
||||
@ -258,41 +162,57 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
slot="graphic"
|
||||
.path=${mdiTransitConnection}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
</a>
|
||||
`
|
||||
: ""}
|
||||
|
||||
<li divider role="separator"></li>
|
||||
|
||||
<mwc-list-item graphic="icon" @click=${this._switchUiMode}>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.edit_ui")}
|
||||
${this._mode === "gui"
|
||||
? html`
|
||||
: nothing}
|
||||
${!useBlueprint && !("fields" in this._config)
|
||||
? html`
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.disabled=${this._readOnly || this._mode === "yaml"}
|
||||
@click=${this._addFields}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.field.add_fields"
|
||||
)}
|
||||
<ha-svg-icon
|
||||
class="selected_menu_item"
|
||||
slot="graphic"
|
||||
.path=${mdiCheck}
|
||||
.path=${mdiFormTextbox}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: ``}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item graphic="icon" @click=${this._switchYamlMode}>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.edit_yaml")}
|
||||
${this._mode === "yaml"
|
||||
? html`
|
||||
</ha-list-item>
|
||||
`
|
||||
: nothing}
|
||||
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@click=${this._promptScriptAlias}
|
||||
.disabled=${!this.scriptId ||
|
||||
this._readOnly ||
|
||||
this._mode === "yaml"}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.script.editor.rename")}
|
||||
<ha-svg-icon slot="graphic" .path=${mdiRenameBox}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
${!useBlueprint
|
||||
? html`
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@click=${this._promptScriptMode}
|
||||
.disabled=${this._readOnly || this._mode === "yaml"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.change_mode"
|
||||
)}
|
||||
<ha-svg-icon
|
||||
class="selected_menu_item"
|
||||
slot="graphic"
|
||||
.path=${mdiCheck}
|
||||
.path=${mdiDebugStepOver}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: ``}
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
`
|
||||
: nothing}
|
||||
|
||||
<li divider role="separator"></li>
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
.disabled=${!this._readOnly && !this.scriptId}
|
||||
graphic="icon"
|
||||
@click=${this._duplicate}
|
||||
@ -306,9 +226,34 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
slot="graphic"
|
||||
.path=${mdiContentDuplicate}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
<mwc-list-item
|
||||
<li divider role="separator"></li>
|
||||
|
||||
<ha-list-item graphic="icon" @click=${this._switchUiMode}>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.edit_ui")}
|
||||
${this._mode === "gui"
|
||||
? html`<ha-svg-icon
|
||||
class="selected_menu_item"
|
||||
slot="graphic"
|
||||
.path=${mdiCheck}
|
||||
></ha-svg-icon> `
|
||||
: ``}
|
||||
</ha-list-item>
|
||||
<ha-list-item graphic="icon" @click=${this._switchYamlMode}>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.edit_yaml")}
|
||||
${this._mode === "yaml"
|
||||
? html`<ha-svg-icon
|
||||
class="selected_menu_item"
|
||||
slot="graphic"
|
||||
.path=${mdiCheck}
|
||||
></ha-svg-icon>`
|
||||
: ``}
|
||||
</ha-list-item>
|
||||
|
||||
<li divider role="separator"></li>
|
||||
|
||||
<ha-list-item
|
||||
.disabled=${this._readOnly || !this.scriptId}
|
||||
class=${classMap({ warning: Boolean(this.scriptId) })}
|
||||
graphic="icon"
|
||||
@ -321,7 +266,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
.path=${mdiDelete}
|
||||
>
|
||||
</ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
<div
|
||||
class="content ${classMap({
|
||||
@ -329,25 +274,21 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
})}"
|
||||
>
|
||||
${this._errors || stateObj?.state === UNAVAILABLE
|
||||
? html`
|
||||
<ha-alert
|
||||
alert-type="error"
|
||||
.title=${stateObj?.state === UNAVAILABLE
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.script.editor.unavailable"
|
||||
)
|
||||
: undefined}
|
||||
>
|
||||
${this._errors || this._validationErrors}
|
||||
</ha-alert>
|
||||
`
|
||||
: ""}
|
||||
${this._readOnly
|
||||
? html`<ha-alert alert-type="warning">
|
||||
${this.hass.localize("ui.panel.config.script.editor.read_only")}
|
||||
<mwc-button slot="action" @click=${this._duplicate}>
|
||||
${this.hass.localize("ui.panel.config.script.editor.migrate")}
|
||||
</mwc-button>
|
||||
? html`<ha-alert
|
||||
alert-type="error"
|
||||
.title=${stateObj?.state === UNAVAILABLE
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.script.editor.unavailable"
|
||||
)
|
||||
: undefined}
|
||||
>
|
||||
${this._errors || this._validationErrors}
|
||||
${stateObj?.state === UNAVAILABLE
|
||||
? html`<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiRobotConfused}
|
||||
></ha-svg-icon>`
|
||||
: nothing}
|
||||
</ha-alert>`
|
||||
: ""}
|
||||
${this._mode === "gui"
|
||||
@ -357,71 +298,63 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
rtl: computeRTL(this.hass),
|
||||
})}
|
||||
>
|
||||
${this._config
|
||||
${useBlueprint
|
||||
? html`
|
||||
<div class="config-container">
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<ha-form
|
||||
.schema=${schema}
|
||||
.data=${data}
|
||||
.hass=${this.hass}
|
||||
.disabled=${this._readOnly}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
.computeHelper=${this._computeHelperCallback}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>
|
||||
</div>
|
||||
</ha-card>
|
||||
</div>
|
||||
|
||||
${useBlueprint
|
||||
? html`
|
||||
<blueprint-script-editor
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.config=${this._config}
|
||||
.disabled=${this._readOnly}
|
||||
@duplicate=${this._duplicate}
|
||||
@value-changed=${this._configChanged}
|
||||
></blueprint-script-editor>
|
||||
`
|
||||
: html`
|
||||
<manual-script-editor
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.config=${this._config}
|
||||
.disabled=${this._readOnly}
|
||||
@duplicate=${this._duplicate}
|
||||
@value-changed=${this._configChanged}
|
||||
></manual-script-editor>
|
||||
`}
|
||||
<blueprint-script-editor
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.config=${this._config}
|
||||
.disabled=${this._readOnly}
|
||||
@value-changed=${this._valueChanged}
|
||||
@duplicate=${this._duplicate}
|
||||
></blueprint-script-editor>
|
||||
`
|
||||
: ""}
|
||||
: html`
|
||||
<manual-script-editor
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
.config=${this._config}
|
||||
.disabled=${this._readOnly}
|
||||
@value-changed=${this._valueChanged}
|
||||
@duplicate=${this._duplicate}
|
||||
></manual-script-editor>
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
: this._mode === "yaml"
|
||||
? html` <ha-yaml-editor
|
||||
copyClipboard
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this._preprocessYaml()}
|
||||
.readOnly=${this._readOnly}
|
||||
@value-changed=${this._yamlChanged}
|
||||
></ha-yaml-editor>`
|
||||
? html` ${this._readOnly
|
||||
? html`<ha-alert alert-type="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.read_only"
|
||||
)}
|
||||
<mwc-button slot="action" @click=${this._duplicate}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.migrate"
|
||||
)}
|
||||
</mwc-button>
|
||||
</ha-alert>`
|
||||
: nothing}
|
||||
<ha-yaml-editor
|
||||
copyClipboard
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this._preprocessYaml()}
|
||||
.readOnly=${this._readOnly}
|
||||
@value-changed=${this._yamlChanged}
|
||||
></ha-yaml-editor>`
|
||||
: nothing}
|
||||
</div>
|
||||
<ha-fab
|
||||
slot="fab"
|
||||
class=${classMap({
|
||||
dirty: this._dirty,
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.script.editor.save_script"
|
||||
)}
|
||||
extended
|
||||
@click=${this._saveScript}
|
||||
class=${classMap({
|
||||
dirty: this._dirty,
|
||||
})}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiContentSave}></ha-svg-icon>
|
||||
</ha-fab>
|
||||
@ -441,42 +374,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
// Only refresh config if we picked a new script. If same ID, don't fetch it.
|
||||
(!oldScript || oldScript !== this.scriptId)
|
||||
) {
|
||||
fetchScriptFileConfig(this.hass, this.scriptId).then(
|
||||
(config) => {
|
||||
this._dirty = false;
|
||||
this._readOnly = false;
|
||||
this._config = this._normalizeConfig(config);
|
||||
const entity = this.entityRegistry.find(
|
||||
(ent) =>
|
||||
ent.platform === "script" && ent.unique_id === this.scriptId
|
||||
);
|
||||
this._entityId = entity?.entity_id;
|
||||
this._checkValidation();
|
||||
},
|
||||
(resp) => {
|
||||
const entity = this.entityRegistry.find(
|
||||
(ent) =>
|
||||
ent.platform === "script" && ent.unique_id === this.scriptId
|
||||
);
|
||||
if (entity) {
|
||||
navigate(`/config/script/show/${entity.entity_id}`, {
|
||||
replace: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
alert(
|
||||
resp.status_code === 404
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.script.editor.load_error_not_editable"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.script.editor.load_error_unknown",
|
||||
{ err_no: resp.status_code || resp.code }
|
||||
)
|
||||
);
|
||||
history.back();
|
||||
}
|
||||
);
|
||||
this._loadConfig();
|
||||
}
|
||||
|
||||
if (changedProps.has("scriptId") && !this.scriptId && this.hass) {
|
||||
@ -493,6 +391,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
...initData,
|
||||
} as ScriptConfig;
|
||||
this._readOnly = false;
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
if (changedProps.has("entityId") && this.entityId) {
|
||||
@ -512,14 +411,13 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
private _normalizeConfig(config: ScriptConfig): ScriptConfig {
|
||||
// Normalize data: ensure sequence is a list
|
||||
// Happens when people copy paste their scripts into the config
|
||||
const value = config.sequence;
|
||||
if (value && !Array.isArray(value)) {
|
||||
config.sequence = [value];
|
||||
private _setEntityId(id?: string) {
|
||||
this._entityId = id;
|
||||
if (this.hass.states[`script.${this._entityId}`]) {
|
||||
this._idError = true;
|
||||
} else {
|
||||
this._idError = false;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
private async _checkValidation() {
|
||||
@ -546,69 +444,57 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
);
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>,
|
||||
data: HaFormDataContainer
|
||||
): string => {
|
||||
switch (schema.name) {
|
||||
case "mode":
|
||||
return this.hass.localize("ui.panel.config.script.editor.modes.label");
|
||||
case "max":
|
||||
// Mode must be one of max modes per schema definition above
|
||||
return this.hass.localize(
|
||||
`ui.panel.config.script.editor.max.${
|
||||
data.mode as (typeof MODES_MAX)[number]
|
||||
}`
|
||||
);
|
||||
default:
|
||||
return this.hass.localize(
|
||||
`ui.panel.config.script.editor.${schema.name}`
|
||||
);
|
||||
private _normalizeConfig(config: ScriptConfig): ScriptConfig {
|
||||
// Normalize data: ensure sequence is a list
|
||||
// Happens when people copy paste their scripts into the config
|
||||
const value = config.sequence;
|
||||
if (value && !Array.isArray(value)) {
|
||||
config.sequence = [value];
|
||||
}
|
||||
};
|
||||
|
||||
private _computeHelperCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
): string | undefined | TemplateResult => {
|
||||
if (schema.name === "mode") {
|
||||
return html`
|
||||
<a
|
||||
style="color: var(--secondary-text-color)"
|
||||
href=${documentationUrl(
|
||||
this.hass,
|
||||
"/integrations/script/#script-modes"
|
||||
)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.script.editor.modes.learn_more"
|
||||
)}</a
|
||||
>
|
||||
`;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
private async _showInfo() {
|
||||
if (!this.scriptId) {
|
||||
return;
|
||||
}
|
||||
const entity = this.entityRegistry.find(
|
||||
(entry) => entry.unique_id === this.scriptId
|
||||
);
|
||||
if (!entity) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "hass-more-info", { entityId: entity.entity_id });
|
||||
return config;
|
||||
}
|
||||
|
||||
private async _showTrace() {
|
||||
if (this.scriptId) {
|
||||
const result = await this.confirmUnsavedChanged();
|
||||
if (result) {
|
||||
navigate(`/config/script/trace/${this.scriptId}`);
|
||||
private async _loadConfig() {
|
||||
fetchScriptFileConfig(this.hass, this.scriptId!).then(
|
||||
(config) => {
|
||||
this._dirty = false;
|
||||
this._readOnly = false;
|
||||
this._config = this._normalizeConfig(config);
|
||||
const entity = this.entityRegistry.find(
|
||||
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
|
||||
);
|
||||
this._entityId = entity?.entity_id;
|
||||
this._checkValidation();
|
||||
},
|
||||
(resp) => {
|
||||
const entity = this.entityRegistry.find(
|
||||
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
|
||||
);
|
||||
if (entity) {
|
||||
navigate(`/config/script/show/${entity.entity_id}`, {
|
||||
replace: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
alert(
|
||||
resp.status_code === 404
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.script.editor.load_error_not_editable"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.script.editor.load_error_unknown",
|
||||
{ err_no: resp.status_code || resp.code }
|
||||
)
|
||||
);
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _valueChanged(ev) {
|
||||
this._config = ev.detail.value;
|
||||
this._errors = undefined;
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
private async _runScript(ev: CustomEvent) {
|
||||
@ -633,42 +519,39 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
const aliasSlugify = slugify(alias);
|
||||
let id = aliasSlugify;
|
||||
let i = 2;
|
||||
while (this.hass.states[`script.${id}`]) {
|
||||
while (this._idIsUsed(id)) {
|
||||
id = `${aliasSlugify}_${i}`;
|
||||
i++;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private _setEntityId(id?: string) {
|
||||
this._entityId = id;
|
||||
if (this.hass.states[`script.${this._entityId}`]) {
|
||||
this._idError = true;
|
||||
} else {
|
||||
this._idError = false;
|
||||
}
|
||||
private _idIsUsed(id: string): boolean {
|
||||
return (
|
||||
`script.${id}` in this.hass.states ||
|
||||
this.entityRegistry.some((ent) => ent.unique_id === id)
|
||||
);
|
||||
}
|
||||
|
||||
private updateEntityId(
|
||||
newId: string | undefined,
|
||||
newAlias: string | undefined
|
||||
) {
|
||||
const currentAlias = this._config?.alias ?? "";
|
||||
const currentEntityId = this._entityId ?? "";
|
||||
|
||||
if (newId !== this._entityId) {
|
||||
this._setEntityId(newId || undefined);
|
||||
private async _showInfo() {
|
||||
if (!this.scriptId) {
|
||||
return;
|
||||
}
|
||||
const entity = this.entityRegistry.find(
|
||||
(entry) => entry.unique_id === this.scriptId
|
||||
);
|
||||
if (!entity) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "hass-more-info", { entityId: entity.entity_id });
|
||||
}
|
||||
|
||||
const currentComputedEntity = this._computeEntityIdFromAlias(currentAlias);
|
||||
|
||||
if (currentComputedEntity === currentEntityId || !this._entityId) {
|
||||
const newComputedId = newAlias
|
||||
? this._computeEntityIdFromAlias(newAlias)
|
||||
: undefined;
|
||||
|
||||
this._setEntityId(newComputedId);
|
||||
private async _showTrace() {
|
||||
if (this.scriptId) {
|
||||
const result = await this.confirmUnsavedChanged();
|
||||
if (result) {
|
||||
navigate(`/config/script/trace/${this.scriptId}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -680,53 +563,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (this._readOnly) {
|
||||
return;
|
||||
}
|
||||
this._errors = undefined;
|
||||
const values = ev.detail.value as any;
|
||||
|
||||
let changed = false;
|
||||
const newValues: Omit<ScriptConfig, "sequence"> = {
|
||||
alias: values.alias ?? "",
|
||||
icon: values.icon,
|
||||
mode: values.mode,
|
||||
max: isMaxMode(values.mode) ? values.max : undefined,
|
||||
};
|
||||
|
||||
if (!this.scriptId) {
|
||||
this.updateEntityId(values.id, values.alias);
|
||||
}
|
||||
|
||||
for (const key of Object.keys(newValues)) {
|
||||
const value = newValues[key];
|
||||
|
||||
if (value === this._config![key]) {
|
||||
continue;
|
||||
}
|
||||
if (value === undefined) {
|
||||
const newConfig = { ...this._config! };
|
||||
delete newConfig![key];
|
||||
this._config = newConfig;
|
||||
} else {
|
||||
this._config = { ...this._config!, [key]: value };
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this._dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private _configChanged(ev) {
|
||||
this._config = ev.detail.value;
|
||||
this._errors = undefined;
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
private _preprocessYaml() {
|
||||
return this._config;
|
||||
}
|
||||
@ -795,9 +631,9 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
{ name: this._config?.alias }
|
||||
),
|
||||
confirmText: this.hass!.localize("ui.common.delete"),
|
||||
destructive: true,
|
||||
dismissText: this.hass!.localize("ui.common.cancel"),
|
||||
confirm: () => this._delete(),
|
||||
destructive: true,
|
||||
});
|
||||
}
|
||||
|
||||
@ -814,6 +650,36 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
this._mode = "yaml";
|
||||
}
|
||||
|
||||
private async _promptScriptAlias(): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
showAutomationRenameDialog(this, {
|
||||
config: this._config!,
|
||||
updateConfig: (config) => {
|
||||
this._config = config;
|
||||
this._dirty = true;
|
||||
this.requestUpdate();
|
||||
resolve(true);
|
||||
},
|
||||
onClose: () => resolve(false),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async _promptScriptMode(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
showAutomationModeDialog(this, {
|
||||
config: this._config!,
|
||||
updateConfig: (config) => {
|
||||
this._config = config;
|
||||
this._dirty = true;
|
||||
this.requestUpdate();
|
||||
resolve();
|
||||
},
|
||||
onClose: () => resolve(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async _saveScript(): Promise<void> {
|
||||
if (this._idError) {
|
||||
showToast(this, {
|
||||
@ -830,7 +696,16 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.scriptId) {
|
||||
const saved = await this._promptScriptAlias();
|
||||
if (!saved) {
|
||||
return;
|
||||
}
|
||||
const entityId = this._computeEntityIdFromAlias(this._config!.alias);
|
||||
this._setEntityId(entityId);
|
||||
}
|
||||
const id = this.scriptId || this._entityId || Date.now();
|
||||
|
||||
try {
|
||||
await this.hass!.callApi(
|
||||
"POST",
|
||||
@ -860,9 +735,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
ha-card {
|
||||
overflow: hidden;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@ -896,11 +768,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.yaml-mode ha-card {
|
||||
overflow: initial;
|
||||
--ha-card-border-radius: 0;
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
span[slot="introduction"] a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
@ -3622,6 +3622,8 @@
|
||||
"introduction": "Use scripts to run a sequence of actions.",
|
||||
"show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]",
|
||||
"show_info": "[%key:ui::panel::config::automation::editor::show_info%]",
|
||||
"rename": "[%key:ui::panel::config::automation::editor::triggers::rename%]",
|
||||
"change_mode": "[%key:ui::panel::config::automation::editor::change_mode%]",
|
||||
"read_only": "This script cannot be edited from the UI, because it is not stored in the ''scripts.yaml'' file.",
|
||||
"unavailable": "Script is unavailable",
|
||||
"migrate": "Migrate",
|
||||
|
Loading…
x
Reference in New Issue
Block a user