diff --git a/src/components/ha-icon-overflow-menu.ts b/src/components/ha-icon-overflow-menu.ts
index 4f81550e30..6ff579c2a8 100644
--- a/src/components/ha-icon-overflow-menu.ts
+++ b/src/components/ha-icon-overflow-menu.ts
@@ -3,6 +3,8 @@ import { mdiDotsVertical } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
+import { classMap } from "lit/directives/class-map";
+import { haStyle } from "../resources/styles";
import { HomeAssistant } from "../types";
import "./ha-button-menu";
import "./ha-icon-button";
@@ -16,6 +18,7 @@ export interface IconOverflowMenuItem {
disabled?: boolean;
tooltip?: string;
onClick: CallableFunction;
+ warning?: boolean;
}
@customElement("ha-icon-overflow-menu")
@@ -49,9 +52,13 @@ export class HaIconOverflowMenu extends LitElement {
graphic="icon"
.disabled=${item.disabled}
@click=${item.action}
+ class=${classMap({ warning: Boolean(item.warning) })}
>
-
+
${item.label}
@@ -81,7 +88,8 @@ export class HaIconOverflowMenu extends LitElement {
`;
}
- protected _handleIconOverflowMenuOpened() {
+ protected _handleIconOverflowMenuOpened(e) {
+ e.stopPropagation();
// If this component is used inside a data table, the z-index of the row
// needs to be increased. Otherwise the ha-button-menu would be displayed
// underneath the next row in the table.
@@ -99,12 +107,15 @@ export class HaIconOverflowMenu extends LitElement {
}
static get styles() {
- return css`
- :host {
- display: flex;
- justify-content: flex-end;
- }
- `;
+ return [
+ haStyle,
+ css`
+ :host {
+ display: flex;
+ justify-content: flex-end;
+ }
+ `,
+ ];
}
}
diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts
index aba85d255b..7ee6e86dda 100644
--- a/src/panels/config/automation/ha-automation-picker.ts
+++ b/src/panels/config/automation/ha-automation-picker.ts
@@ -1,4 +1,16 @@
-import { mdiHelpCircle, mdiInformationOutline, mdiPlus } from "@mdi/js";
+import {
+ mdiCancel,
+ mdiContentDuplicate,
+ mdiDelete,
+ mdiHelpCircle,
+ mdiInformationOutline,
+ mdiPlay,
+ mdiPlayCircleOutline,
+ mdiPlus,
+ mdiStopCircleOutline,
+ mdiTransitConnection,
+} from "@mdi/js";
+import "@polymer/paper-tooltip/paper-tooltip";
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
@@ -13,11 +25,22 @@ import type {
RowClickedEvent,
} from "../../../components/data-table/ha-data-table";
import "../../../components/ha-button-related-filter-menu";
+import "../../../components/ha-chip";
import "../../../components/ha-fab";
import "../../../components/ha-icon-button";
+import "../../../components/ha-icon-overflow-menu";
import "../../../components/ha-svg-icon";
-import type { AutomationEntity } from "../../../data/automation";
-import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
+import {
+ AutomationEntity,
+ deleteAutomation,
+ getAutomationConfig,
+ showAutomationEditor,
+ triggerAutomationActions,
+} from "../../../data/automation";
+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";
@@ -63,6 +86,7 @@ class HaAutomationPicker extends LitElement {
...automation,
name: computeStateName(automation),
last_triggered: automation.attributes.last_triggered || undefined,
+ disabled: automation.state === "off",
}));
}
);
@@ -123,22 +147,105 @@ class HaAutomationPicker extends LitElement {
},
};
}
+
+ columns.disabled = this.narrow
+ ? {
+ title: "",
+ template: (disabled: boolean) =>
+ disabled
+ ? html`
+
+ ${this.hass.localize(
+ "ui.panel.config.automation.picker.disabled"
+ )}
+
+
+ `
+ : "",
+ }
+ : {
+ width: "20%",
+ title: "",
+ template: (disabled: boolean) =>
+ disabled
+ ? html`
+
+ ${this.hass.localize(
+ "ui.panel.config.automation.picker.disabled"
+ )}
+
+ `
+ : "",
+ };
+
columns.actions = {
title: "",
- label: this.hass.localize(
- "ui.panel.config.automation.picker.headers.actions"
- ),
- type: "icon-button",
- template: (_info, automation: any) => html`
-
- `,
+ width: this.narrow ? undefined : "10%",
+ type: "overflow-menu",
+ template: (_: string, automation: any) =>
+ html`
+ this._showInfo(automation),
+ },
+ {
+ path: mdiPlay,
+ label: this.hass.localize(
+ "ui.panel.config.automation.editor.run"
+ ),
+ action: () => this._runActions(automation),
+ },
+ {
+ path: mdiTransitConnection,
+ label: this.hass.localize(
+ "ui.panel.config.automation.editor.show_trace"
+ ),
+ action: () => this._showTrace(automation),
+ },
+ {
+ path: mdiContentDuplicate,
+ label: this.hass.localize(
+ "ui.panel.config.automation.picker.duplicate"
+ ),
+ action: () => this.duplicate(automation),
+ },
+ {
+ path:
+ automation.state === "off"
+ ? mdiPlayCircleOutline
+ : mdiStopCircleOutline,
+ label:
+ automation.state === "off"
+ ? this.hass.localize(
+ "ui.panel.config.automation.editor.enable"
+ )
+ : this.hass.localize(
+ "ui.panel.config.automation.editor.disable"
+ ),
+ action: () => this._toggle(automation),
+ },
+ {
+ label: this.hass.localize(
+ "ui.panel.config.automation.picker.delete"
+ ),
+ path: mdiDelete,
+ action: () => this._deleteConfirm(automation),
+ warning: true,
+ },
+ ]}
+ >
+
+ `,
};
return columns;
}
@@ -210,12 +317,52 @@ class HaAutomationPicker extends LitElement {
this._filterValue = undefined;
}
- private _showInfo(ev) {
- ev.stopPropagation();
- const automation = ev.currentTarget.automation;
+ private _showInfo(automation: any) {
fireEvent(this, "hass-more-info", { entityId: automation.entity_id });
}
+ private _runActions(automation: any) {
+ triggerAutomationActions(this.hass, automation.entity_id);
+ }
+
+ private _showTrace(automation: any) {
+ navigate(`/config/automation/trace/${automation.attributes.id}`);
+ }
+
+ private async _toggle(automation): Promise {
+ const service = automation.state === "off" ? "turn_on" : "turn_off";
+ await this.hass.callService("automation", service, {
+ entity_id: automation.entity_id,
+ });
+ }
+
+ private async _deleteConfirm(automation) {
+ showConfirmationDialog(this, {
+ text: this.hass.localize(
+ "ui.panel.config.automation.picker.delete_confirm"
+ ),
+ confirmText: this.hass!.localize("ui.common.delete"),
+ dismissText: this.hass!.localize("ui.common.cancel"),
+ confirm: () => this._delete(automation),
+ });
+ }
+
+ private async _delete(automation) {
+ await deleteAutomation(this.hass, automation.attributes.id);
+ }
+
+ private async duplicate(automation) {
+ const config = await getAutomationConfig(
+ this.hass,
+ automation.attributes.id
+ );
+ showAutomationEditor({
+ ...config,
+ id: undefined,
+ alias: undefined,
+ });
+ }
+
private _showHelp() {
showAlertDialog(this, {
title: this.hass.localize("ui.panel.config.automation.caption"),
diff --git a/src/translations/en.json b/src/translations/en.json
index 920ec90499..e38adf3c96 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -1793,6 +1793,7 @@
"delete": "Delete",
"delete_confirm": "Are you sure you want to delete this automation?",
"duplicate": "Duplicate",
+ "disabled": "Disabled",
"headers": {
"toggle": "Enable/disable",
"name": "Name",
@@ -1822,6 +1823,7 @@
"run": "[%key:ui::panel::config::automation::editor::actions::run%]",
"rename": "[%key:ui::panel::config::automation::editor::triggers::rename%]",
"show_trace": "Traces",
+ "show_info": "Information",
"introduction": "Use automations to bring your home to life.",
"default_name": "New Automation",
"missing_name": "Cannot save automation without a name",