From 9b28c7cf694be0ef3f76ece3ac4d852451897965 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Tue, 21 May 2024 10:01:51 -0700 Subject: [PATCH] Script editor updates (match automation editor) (#20791) * Show descriptions in script editor * Script editor updates (match automation editor) * review feedback --- .../dialog-automation-mode.ts | 2 +- .../show-dialog-automation-mode.ts | 11 +- .../dialog-automation-rename.ts | 2 +- .../show-dialog-automation-rename.ts | 11 +- .../config/automation/ha-automation-editor.ts | 171 +++-- src/panels/config/script/ha-script-editor.ts | 659 +++++++----------- src/translations/en.json | 2 + 7 files changed, 370 insertions(+), 488 deletions(-) diff --git a/src/panels/config/automation/automation-mode-dialog/dialog-automation-mode.ts b/src/panels/config/automation/automation-mode-dialog/dialog-automation-mode.ts index 54175de1083c..ba624d072183 100644 --- a/src/panels/config/automation/automation-mode-dialog/dialog-automation-mode.ts +++ b/src/panels/config/automation/automation-mode-dialog/dialog-automation-mode.ts @@ -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, diff --git a/src/panels/config/automation/automation-mode-dialog/show-dialog-automation-mode.ts b/src/panels/config/automation/automation-mode-dialog/show-dialog-automation-mode.ts index 3847ec252d71..0d25fea5d2f3 100644 --- a/src/panels/config/automation/automation-mode-dialog/show-dialog-automation-mode.ts +++ b/src/panels/config/automation/automation-mode-dialog/show-dialog-automation-mode.ts @@ -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", diff --git a/src/panels/config/automation/automation-rename-dialog/dialog-automation-rename.ts b/src/panels/config/automation/automation-rename-dialog/dialog-automation-rename.ts index f39223cfad50..7d869fd5b9ef 100644 --- a/src/panels/config/automation/automation-rename-dialog/dialog-automation-rename.ts +++ b/src/panels/config/automation/automation-rename-dialog/dialog-automation-rename.ts @@ -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, diff --git a/src/panels/config/automation/automation-rename-dialog/show-dialog-automation-rename.ts b/src/panels/config/automation/automation-rename-dialog/show-dialog-automation-rename.ts index cf0fd4dd365c..9c0b46435654 100644 --- a/src/panels/config/automation/automation-rename-dialog/show-dialog-automation-rename.ts +++ b/src/panels/config/automation/automation-rename-dialog/show-dialog-automation-rename.ts @@ -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", diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index 11571368c4ff..22793380104e 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -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` ${this._config?.id && !this.narrow ? html` @@ -171,7 +174,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { - ${stateObj && this._config && this.narrow + ${stateObj && this.narrow ? html` - - ${this._config && !("use_blueprint" in this._config) + ${!useBlueprint ? html` ` - : ""} + : nothing} - - ${this._config - ? html` -
+ ${this._errors || stateObj?.state === UNAVAILABLE + ? html` - ${this._errors || stateObj?.state === UNAVAILABLE - ? html` - ${this._errors || this._validationErrors} - ${stateObj?.state === UNAVAILABLE - ? html`` - : nothing} - ` - : ""} - ${this._mode === "gui" - ? "use_blueprint" in this._config + ${this._errors || this._validationErrors} + ${stateObj?.state === UNAVAILABLE + ? html`` + : nothing} + ` + : ""} + ${this._mode === "gui" + ? html` +
+ ${useBlueprint ? html` - ` - : this._mode === "yaml" - ? html` ${this._readOnly - ? html` - ${this.hass.localize( - "ui.panel.config.automation.editor.read_only" - )} - - ${this.hass.localize( - "ui.panel.config.automation.editor.migrate" - )} - - ` - : ""} - ${stateObj?.state === "off" - ? html` - - ${this.hass.localize( - "ui.panel.config.automation.editor.disabled" - )} - - ${this.hass.localize( - "ui.panel.config.automation.editor.enable" - )} - - - ` - : ""} - ` + `} +
+ ` + : this._mode === "yaml" + ? html` ${this._readOnly + ? html` + ${this.hass.localize( + "ui.panel.config.automation.editor.read_only" + )} + + ${this.hass.localize( + "ui.panel.config.automation.editor.migrate" + )} + + ` : nothing} -
- ` - : ""} + ${stateObj?.state === "off" + ? html` + + ${this.hass.localize( + "ui.panel.config.automation.editor.disabled" + )} + + ${this.hass.localize( + "ui.panel.config.automation.editor.enable" + )} + + + ` + : ""} + ` + : nothing} + { 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(); diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index 6b56d815b98f..0d8d3d0841ba 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -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` ${this.scriptId && !this.narrow ? html` @@ -213,7 +130,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { .path=${mdiDotsVertical} > - - + - ${this.hass.localize("ui.panel.config.script.picker.run_script")} - + - ${!useBlueprint && !("fields" in this._config) - ? html` - - ${this.hass.localize( - "ui.panel.config.script.editor.field.add_fields" - )} - - - ` - : nothing} ${this.scriptId && this.narrow ? html`
- + ${this.hass.localize( "ui.panel.config.script.editor.show_trace" )} @@ -258,41 +162,57 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { slot="graphic" .path=${mdiTransitConnection} > - + ` - : ""} - -
  • - - - ${this.hass.localize("ui.panel.config.automation.editor.edit_ui")} - ${this._mode === "gui" - ? html` + : nothing} + ${!useBlueprint && !("fields" in this._config) + ? html` + + ${this.hass.localize( + "ui.panel.config.script.editor.field.add_fields" + )} - ` - : ``} - - - ${this.hass.localize("ui.panel.config.automation.editor.edit_yaml")} - ${this._mode === "yaml" - ? html` + + ` + : nothing} + + + ${this.hass.localize("ui.panel.config.script.editor.rename")} + + + ${!useBlueprint + ? html` + + ${this.hass.localize( + "ui.panel.config.script.editor.change_mode" + )} - ` - : ``} - - -
  • + + ` + : nothing} - - + + +
  • + + + ${this.hass.localize("ui.panel.config.automation.editor.edit_ui")} + ${this._mode === "gui" + ? html` ` + : ``} + + + ${this.hass.localize("ui.panel.config.automation.editor.edit_yaml")} + ${this._mode === "yaml" + ? html`` + : ``} + + +
  • - - +
    ${this._errors || stateObj?.state === UNAVAILABLE - ? html` - - ${this._errors || this._validationErrors} - - ` - : ""} - ${this._readOnly - ? html` - ${this.hass.localize("ui.panel.config.script.editor.read_only")} - - ${this.hass.localize("ui.panel.config.script.editor.migrate")} - + ? html` + ${this._errors || this._validationErrors} + ${stateObj?.state === UNAVAILABLE + ? html`` + : nothing} ` : ""} ${this._mode === "gui" @@ -357,71 +298,63 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { rtl: computeRTL(this.hass), })} > - ${this._config + ${useBlueprint ? html` -
    - -
    - -
    -
    -
    - - ${useBlueprint - ? html` - - ` - : html` - - `} + ` - : ""} + : html` + + `}
    ` : this._mode === "yaml" - ? html` ` + ? html` ${this._readOnly + ? html` + ${this.hass.localize( + "ui.panel.config.script.editor.read_only" + )} + + ${this.hass.localize( + "ui.panel.config.script.editor.migrate" + )} + + ` + : nothing} + ` : nothing} @@ -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>, - 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 _computeHelperCallback = ( - schema: SchemaUnion> - ): string | undefined | TemplateResult => { - if (schema.name === "mode") { - return html` - ${this.hass.localize( - "ui.panel.config.script.editor.modes.learn_more" - )} - `; + 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]; } - return undefined; - }; + return config; + } - private async _showInfo() { - if (!this.scriptId) { - return; - } - const entity = this.entityRegistry.find( - (entry) => entry.unique_id === 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(); + } ); - if (!entity) { - return; - } - fireEvent(this, "hass-more-info", { entityId: entity.entity_id }); } - private async _showTrace() { - if (this.scriptId) { - const result = await this.confirmUnsavedChanged(); - if (result) { - navigate(`/config/script/trace/${this.scriptId}`); - } - } + 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 = { - 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 { + 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 { + 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 { 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); } diff --git a/src/translations/en.json b/src/translations/en.json index 2369de00137d..50db6feda5e7 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -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",