diff --git a/src/data/script.ts b/src/data/script.ts index 9685af17dd..1f925cffe3 100644 --- a/src/data/script.ts +++ b/src/data/script.ts @@ -301,6 +301,9 @@ export const deleteScript = (hass: HomeAssistant, objectId: string) => let inititialScriptEditorData: Partial | undefined; +export const getScriptConfig = (hass: HomeAssistant, objectId: string) => + hass.callApi("GET", `config/script/config/${objectId}`); + export const showScriptEditor = (data?: Partial) => { inititialScriptEditorData = data; navigate("/config/script/edit/new"); diff --git a/src/layouts/hass-tabs-subpage-data-table.ts b/src/layouts/hass-tabs-subpage-data-table.ts index 27d2c8cde3..81227b26a8 100644 --- a/src/layouts/hass-tabs-subpage-data-table.ts +++ b/src/layouts/hass-tabs-subpage-data-table.ts @@ -375,3 +375,9 @@ export class HaTabsSubpageDataTable extends LitElement { `; } } + +declare global { + interface HTMLElementTagNameMap { + "hass-tabs-subpage-data-table": HaTabsSubpageDataTable; + } +} diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index 44a333f885..f7803ef429 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -40,9 +40,9 @@ import type { HaYamlEditor } from "../../../components/ha-yaml-editor"; import { Action, deleteScript, + getScriptConfig, getScriptEditorInitData, isMaxMode, - ManualScriptConfig, MODES, MODES_MAX, ScriptConfig, @@ -427,37 +427,32 @@ 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.scriptEntityId) ) { - this.hass - .callApi( - "GET", - `config/script/config/${computeObjectId(this.scriptEntityId)}` - ) - .then( - (config) => { - // 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]; - } - this._dirty = false; - this._config = config; - }, - (resp) => { - 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 - ) - ); - history.back(); + getScriptConfig(this.hass, computeObjectId(this.scriptEntityId)).then( + (config) => { + // 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]; } - ); + this._dirty = false; + this._config = config; + }, + (resp) => { + 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 + ) + ); + history.back(); + } + ); } if ( diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts index ab828534bd..217a86359e 100644 --- a/src/panels/config/script/ha-script-picker.ts +++ b/src/panels/config/script/ha-script-picker.ts @@ -1,10 +1,11 @@ import { + mdiContentDuplicate, + mdiDelete, mdiHelpCircle, - mdiHistory, mdiInformationOutline, - mdiPencil, mdiPlay, mdiPlus, + mdiTransitConnection, } from "@mdi/js"; import { HassEntity } from "home-assistant-js-websocket"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; @@ -12,6 +13,7 @@ import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { formatDateTime } from "../../../common/datetime/format_date_time"; import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event"; +import { computeObjectId } from "../../../common/entity/compute_object_id"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { navigate } from "../../../common/navigate"; import { computeRTL } from "../../../common/util/compute_rtl"; @@ -22,9 +24,18 @@ import { import "../../../components/ha-button-related-filter-menu"; import "../../../components/ha-fab"; import "../../../components/ha-icon-button"; +import "../../../components/ha-icon-overflow-menu"; import "../../../components/ha-svg-icon"; -import { triggerScript } from "../../../data/script"; -import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; +import { + deleteScript, + getScriptConfig, + showScriptEditor, + triggerScript, +} from "../../../data/script"; +import { + showAlertDialog, + showConfirmationDialog, +} from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/hass-tabs-subpage-data-table"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; @@ -71,22 +82,6 @@ class HaScriptPicker extends LitElement { private _columns = memoizeOne((narrow, _locale): DataTableColumnContainer => { const columns: DataTableColumnContainer = { - activate: { - title: "", - label: this.hass.localize("ui.panel.config.script.picker.run_script"), - type: "icon-button", - template: (_toggle, script) => - html` - - `, - }, icon: { title: "", label: this.hass.localize( @@ -121,7 +116,7 @@ class HaScriptPicker extends LitElement { if (!narrow) { columns.last_triggered = { sortable: true, - width: "20%", + width: "40%", title: this.hass.localize("ui.card.automation.last_triggered"), template: (last_triggered) => html` ${last_triggered @@ -130,51 +125,57 @@ class HaScriptPicker extends LitElement { `, }; } - columns.info = { + + columns.actions = { title: "", - label: this.hass.localize("ui.panel.config.script.picker.show_info"), - type: "icon-button", - template: (_info, script) => html` - - `, - }; - columns.trace = { - title: "", - label: this.hass.localize("ui.panel.config.script.picker.dev_script"), - type: "icon-button", - template: (_info, script: any) => html` - - - - `, - }; - columns.edit = { - title: "", - label: this.hass.localize("ui.panel.config.script.picker.edit_script"), - type: "icon-button", - template: (_info, script: any) => html` - - - - `, + width: this.narrow ? undefined : "10%", + type: "overflow-menu", + template: (_: string, script: any) => + html` + this._showInfo(script), + }, + { + path: mdiPlay, + label: this.hass.localize("ui.panel.config.script.picker.run"), + action: () => this._runScript(script), + }, + { + path: mdiTransitConnection, + label: this.hass.localize( + "ui.panel.config.script.picker.show_trace" + ), + action: () => this._showTrace(script), + }, + { + path: mdiContentDuplicate, + label: this.hass.localize( + "ui.panel.config.script.picker.duplicate" + ), + action: () => this._duplicate(script), + }, + { + label: this.hass.localize( + "ui.panel.config.script.picker.delete" + ), + path: mdiDelete, + action: () => this._deleteConfirm(script), + warning: true, + }, + ]} + > + + `, }; + return columns; }); @@ -251,9 +252,7 @@ class HaScriptPicker extends LitElement { navigate(`/config/script/edit/${ev.detail.id}`); } - private _runScript = async (ev) => { - ev.stopPropagation(); - const script = ev.currentTarget.script as HassEntity; + private _runScript = async (script: any) => { await triggerScript(this.hass, script.entity_id); showToast(this, { message: this.hass.localize( @@ -264,10 +263,12 @@ class HaScriptPicker extends LitElement { }); }; - private _showInfo(ev) { - ev.stopPropagation(); - const entityId = ev.currentTarget.script.entity_id; - fireEvent(this, "hass-more-info", { entityId }); + private _showInfo(script: any) { + fireEvent(this, "hass-more-info", { entityId: script.entity_id }); + } + + private _showTrace(script: any) { + navigate(`/config/script/trace/${script.entity_id}`); } private _showHelp() { @@ -288,6 +289,32 @@ class HaScriptPicker extends LitElement { }); } + private async _duplicate(script: any) { + const config = await getScriptConfig( + this.hass, + computeObjectId(script.entity_id) + ); + showScriptEditor({ + ...config, + alias: `${config?.alias} (${this.hass.localize( + "ui.panel.config.script.picker.duplicate" + )})`, + }); + } + + private async _deleteConfirm(script: any) { + showConfirmationDialog(this, { + text: this.hass.localize("ui.panel.config.script.editor.delete_confirm"), + confirmText: this.hass!.localize("ui.common.delete"), + dismissText: this.hass!.localize("ui.common.cancel"), + confirm: () => this._delete(script), + }); + } + + private async _delete(script: any) { + await deleteScript(this.hass, computeObjectId(script.entity_id)); + } + static get styles(): CSSResultGroup { return [ haStyle, diff --git a/src/translations/en.json b/src/translations/en.json index 2e05baaf2b..d269d9a34e 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2269,10 +2269,10 @@ "learn_more": "Learn more about scripts", "no_scripts": "We couldn't find any scripts", "add_script": "Add script", - "show_info": "Show info about script", "run_script": "Run script", - "edit_script": "Edit script", - "dev_script": "Debug script", + "run": "[%key:ui::panel::config::automation::editor::run%]", + "show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]", + "show_info": "[%key:ui::panel::config::automation::editor::show_info%]", "headers": { "name": "Name", "state": "State"