diff --git a/src/data/automation.ts b/src/data/automation.ts index 19aae9e594..a4fbcf4f47 100644 --- a/src/data/automation.ts +++ b/src/data/automation.ts @@ -65,6 +65,7 @@ export interface BaseTrigger { platform: string; id?: string; variables?: Record; + enabled?: boolean; } export interface StateTrigger extends BaseTrigger { @@ -178,6 +179,7 @@ export type Trigger = interface BaseCondition { condition: string; alias?: string; + enabled?: boolean; } export interface LogicalCondition extends BaseCondition { diff --git a/src/data/device_automation.ts b/src/data/device_automation.ts index 9a6685e8bd..9458452675 100644 --- a/src/data/device_automation.ts +++ b/src/data/device_automation.ts @@ -11,6 +11,7 @@ export interface DeviceAutomation { type?: string; subtype?: string; event?: string; + enabled?: boolean; metadata?: { secondary: boolean }; } diff --git a/src/data/script.ts b/src/data/script.ts index 3966651a4a..a28369a289 100644 --- a/src/data/script.ts +++ b/src/data/script.ts @@ -13,6 +13,7 @@ import { literal, is, Describe, + boolean, } from "superstruct"; import { computeObjectId } from "../common/entity/compute_object_id"; import { navigate } from "../common/navigate"; @@ -25,6 +26,7 @@ export const MODES_MAX = ["queued", "parallel"]; export const baseActionStruct = object({ alias: optional(string()), + enabled: optional(boolean()), }); const targetStruct = object({ @@ -88,15 +90,18 @@ export interface BlueprintScriptConfig extends ManualScriptConfig { use_blueprint: { path: string; input?: BlueprintInput }; } -export interface EventAction { +interface BaseAction { alias?: string; + enabled?: boolean; +} + +export interface EventAction extends BaseAction { event: string; event_data?: Record; event_data_template?: Record; } -export interface ServiceAction { - alias?: string; +export interface ServiceAction extends BaseAction { service?: string; service_template?: string; entity_id?: string; @@ -104,55 +109,48 @@ export interface ServiceAction { data?: Record; } -export interface DeviceAction { - alias?: string; +export interface DeviceAction extends BaseAction { type: string; device_id: string; domain: string; entity_id: string; } -export interface DelayActionParts { +export interface DelayActionParts extends BaseAction { milliseconds?: number; seconds?: number; minutes?: number; hours?: number; days?: number; } -export interface DelayAction { - alias?: string; +export interface DelayAction extends BaseAction { delay: number | Partial | string; } -export interface ServiceSceneAction { - alias?: string; +export interface ServiceSceneAction extends BaseAction { service: "scene.turn_on"; target?: { entity_id?: string }; entity_id?: string; metadata: Record; } -export interface LegacySceneAction { - alias?: string; +export interface LegacySceneAction extends BaseAction { scene: string; } export type SceneAction = ServiceSceneAction | LegacySceneAction; -export interface WaitAction { - alias?: string; +export interface WaitAction extends BaseAction { wait_template: string; timeout?: number; continue_on_timeout?: boolean; } -export interface WaitForTriggerAction { - alias?: string; +export interface WaitForTriggerAction extends BaseAction { wait_for_trigger: Trigger | Trigger[]; timeout?: number; continue_on_timeout?: boolean; } -export interface PlayMediaAction { - alias?: string; +export interface PlayMediaAction extends BaseAction { service: "media_player.play_media"; target?: { entity_id?: string }; entity_id?: string; @@ -160,13 +158,11 @@ export interface PlayMediaAction { metadata: Record; } -export interface RepeatAction { - alias?: string; +export interface RepeatAction extends BaseAction { repeat: CountRepeat | WhileRepeat | UntilRepeat; } -interface BaseRepeat { - alias?: string; +interface BaseRepeat extends BaseAction { sequence: Action | Action[]; } @@ -182,38 +178,32 @@ export interface UntilRepeat extends BaseRepeat { until: Condition[]; } -export interface ChooseActionChoice { - alias?: string; +export interface ChooseActionChoice extends BaseAction { conditions: string | Condition[]; sequence: Action | Action[]; } -export interface ChooseAction { - alias?: string; +export interface ChooseAction extends BaseAction { choose: ChooseActionChoice | ChooseActionChoice[] | null; default?: Action | Action[]; } -export interface IfAction { - alias?: string; +export interface IfAction extends BaseAction { if: string | Condition[]; then: Action | Action[]; else?: Action | Action[]; } -export interface VariablesAction { - alias?: string; +export interface VariablesAction extends BaseAction { variables: Record; } -export interface StopAction { - alias?: string; +export interface StopAction extends BaseAction { stop: string; error?: boolean; } -interface UnknownAction { - alias?: string; +interface UnknownAction extends BaseAction { [key: string]: unknown; } diff --git a/src/panels/config/automation/action/ha-automation-action-row.ts b/src/panels/config/automation/action/ha-automation-action-row.ts index 2b45d064f9..126468e545 100644 --- a/src/panels/config/automation/action/ha-automation-action-row.ts +++ b/src/panels/config/automation/action/ha-automation-action-row.ts @@ -160,62 +160,82 @@ export default class HaAutomationActionRow extends LitElement { return html` -
-
- ${this.index !== 0 - ? html` - - ` - : ""} - ${this.index !== this.totalActions - 1 - ? html` - - ` - : ""} - - - - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.run_action" - )} - - - ${yamlMode - ? this.hass.localize( - "ui.panel.config.automation.editor.edit_ui" - ) - : this.hass.localize( - "ui.panel.config.automation.editor.edit_yaml" - )} - - - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.duplicate" - )} - - - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.delete" - )} - - -
+ ${this.action.enabled === false + ? html`
+ ${this.hass.localize( + "ui.panel.config.automation.editor.actions.disabled" + )} +
` + : ""} +
+ ${this.index !== 0 + ? html` + + ` + : ""} + ${this.index !== this.totalActions - 1 + ? html` + + ` + : ""} + + + + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.run_action" + )} + + + ${yamlMode + ? this.hass.localize( + "ui.panel.config.automation.editor.edit_ui" + ) + : this.hass.localize( + "ui.panel.config.automation.editor.edit_yaml" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.duplicate" + )} + + + ${this.action.enabled === false + ? this.hass.localize( + "ui.panel.config.automation.editor.actions.enable" + ) + : this.hass.localize( + "ui.panel.config.automation.editor.actions.disable" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.delete" + )} + + +
+
${this._warnings ? html` -
-
- + ${this.condition.enabled === false + ? html`
${this.hass.localize( - "ui.panel.config.automation.editor.conditions.test" + "ui.panel.config.automation.editor.actions.disabled" )} - - - - - - ${this._yamlMode - ? this.hass.localize( - "ui.panel.config.automation.editor.edit_ui" - ) - : this.hass.localize( - "ui.panel.config.automation.editor.edit_yaml" - )} - - - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.duplicate" - )} - - - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.delete" - )} - - -
+
` + : ""} +
+ + ${this.hass.localize( + "ui.panel.config.automation.editor.conditions.test" + )} + + + + + + ${this._yamlMode + ? this.hass.localize( + "ui.panel.config.automation.editor.edit_ui" + ) + : this.hass.localize( + "ui.panel.config.automation.editor.edit_yaml" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.duplicate" + )} + + + ${this.condition.enabled === false + ? this.hass.localize( + "ui.panel.config.automation.editor.actions.enable" + ) + : this.hass.localize( + "ui.panel.config.automation.editor.actions.disable" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.delete" + )} + + +
+
${this._warnings ? html`; private _processedTypes = memoizeOne( @@ -126,40 +128,60 @@ export default class HaAutomationTriggerRow extends LitElement { return html` -
-
- - - - ${this.hass.localize( - "ui.panel.config.automation.editor.triggers.edit_id" - )} - - - ${yamlMode - ? this.hass.localize( - "ui.panel.config.automation.editor.edit_ui" - ) - : this.hass.localize( - "ui.panel.config.automation.editor.edit_yaml" - )} - - - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.duplicate" - )} - - - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.delete" - )} - - -
+ ${this.trigger.enabled === false + ? html`
+ ${this.hass.localize( + "ui.panel.config.automation.editor.actions.disabled" + )} +
` + : ""} +
+ + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.edit_id" + )} + + + ${yamlMode + ? this.hass.localize( + "ui.panel.config.automation.editor.edit_ui" + ) + : this.hass.localize( + "ui.panel.config.automation.editor.edit_yaml" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.duplicate" + )} + + + ${this.trigger.enabled === false + ? this.hass.localize( + "ui.panel.config.automation.editor.actions.enable" + ) + : this.hass.localize( + "ui.panel.config.automation.editor.actions.disable" + )} + + + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.delete" + )} + + +
+
${this._warnings ? html` - ${showId ? html` ): void { super.updated(changedProps); if (changedProps.has("trigger")) { this._subscribeTrigger(); @@ -347,6 +368,9 @@ export default class HaAutomationTriggerRow extends LitElement { fireEvent(this, "duplicate"); break; case 3: + this._onDisable(); + break; + case 4: this._onDelete(); break; } @@ -365,6 +389,15 @@ export default class HaAutomationTriggerRow extends LitElement { }); } + private _onDisable() { + const enabled = !(this.trigger.enabled ?? true); + const value = { ...this.trigger, enabled }; + fireEvent(this, "value-changed", { value }); + if (this._yamlMode) { + this._yamlEditor?.setValue(value); + } + } + private _typeChanged(ev: CustomEvent) { const type = (ev.target as HaSelect).value; @@ -439,10 +472,27 @@ export default class HaAutomationTriggerRow extends LitElement { return [ haStyle, css` + .disabled { + opacity: 0.5; + pointer-events: none; + } + .card-content { + padding-top: 16px; + margin-top: 0; + } + .disabled-bar { + background: var(--divider-color, #e0e0e0); + text-align: center; + border-top-right-radius: var(--ha-card-border-radius); + border-top-left-radius: var(--ha-card-border-radius); + } .card-menu { float: right; z-index: 3; + margin: 4px; --mdc-theme-text-primary-on-background: var(--primary-text-color); + display: flex; + align-items: center; } :host-context([style*="direction: rtl;"]) .card-menu { float: left; diff --git a/src/translations/en.json b/src/translations/en.json index 5230ec1ecb..84f7b9f664 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1675,7 +1675,7 @@ "introduction": "The automation editor allows you to create and edit automations. Please follow the link below to read the instructions to make sure that you have configured Home Assistant correctly.", "learn_more": "Learn more about automations", "pick_automation": "Pick automation to edit", - "no_automations": "We couldn’t find any automations", + "no_automations": "We couldn't find any automations", "add_automation": "Create automation", "only_editable": "Only automations in automations.yaml are editable.", "dev_only_editable": "Only automations that have a unique ID assigned are debuggable.", @@ -1961,6 +1961,9 @@ "run_action_error": "Error running action", "run_action_success": "Action run successfully", "duplicate": "[%key:ui::panel::config::automation::editor::triggers::duplicate%]", + "enable": "Enable", + "disable": "Disable", + "disabled": "Disabled", "delete": "[%key:ui::panel::mailbox::delete_button%]", "delete_confirm": "[%key:ui::panel::config::automation::editor::triggers::delete_confirm%]", "unsupported_action": "No visual editor support for action: {action}",