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