From d466ab63bd029f259f237497bbfefe24e86c2e88 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 26 Mar 2026 15:58:22 +0100 Subject: [PATCH] Add target error badge if target is missing (#30352) * Add target error badge if target is missing * Don't show for newly added items --- .../action/ha-automation-action-row.ts | 30 ++++++++++---- .../automation/action/ha-automation-action.ts | 1 + .../condition/ha-automation-condition-row.ts | 33 +++++++++++----- .../condition/ha-automation-condition.ts | 1 + .../target/ha-automation-row-targets.ts | 35 +++++++++++------ .../trigger/ha-automation-trigger-row.ts | 39 ++++++++++++++----- .../trigger/ha-automation-trigger.ts | 1 + 7 files changed, 103 insertions(+), 37 deletions(-) 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 8582b1dbf4..b3637dbea6 100644 --- a/src/panels/config/automation/action/ha-automation-action-row.ts +++ b/src/panels/config/automation/action/ha-automation-action-row.ts @@ -185,6 +185,8 @@ export default class HaAutomationActionRow extends LitElement { @state() private _collapsed = true; + @state() private _isNew = false; + @state() private _warnings?: string[]; @query("ha-automation-action-editor") @@ -237,12 +239,13 @@ export default class HaAutomationActionRow extends LitElement { private _renderRow() { const type = getAutomationActionType(this.action); - const target = - type === "service" && "target" in this.action - ? (this.action as ServiceAction).target - : type === "device_id" && (this.action as DeviceAction).device_id - ? { device_id: (this.action as DeviceAction).device_id } - : undefined; + const actionHasTarget = type === "service" && "target" in this.action; + + const target = actionHasTarget + ? (this.action as ServiceAction).target + : type === "device_id" && (this.action as DeviceAction).device_id + ? { device_id: (this.action as DeviceAction).device_id } + : undefined; return html` ${type === "service" && "action" in this.action && this.action.action @@ -265,7 +268,9 @@ export default class HaAutomationActionRow extends LitElement { ${capitalizeFirstLetter( describeAction(this.hass, this._entityReg, this.action) )} - ${target ? this._renderTargets(target) : nothing} + ${target !== undefined || (actionHasTarget && !this._isNew) + ? this._renderTargets(target, actionHasTarget && !this._isNew) + : nothing} ${type !== "condition" && (this.action as NonConditionAction).continue_on_error === true ? html` + (target?: HassServiceTarget, targetRequired = false) => html`` ); @@ -812,6 +818,10 @@ export default class HaAutomationActionRow extends LitElement { this.openSidebar(); } + public markAsNew(): void { + this._isNew = true; + } + public openSidebar(action?: Action): void { const sidebarAction = action ?? this.action; const actionType = getAutomationActionType(sidebarAction); @@ -822,6 +832,7 @@ export default class HaAutomationActionRow extends LitElement { }, close: (focus?: boolean) => { this._selected = false; + this._isNew = false; fireEvent(this, "close-sidebar"); if (focus) { this.focus(); @@ -901,6 +912,9 @@ export default class HaAutomationActionRow extends LitElement { ); private _toggleCollapse() { + if (!this._collapsed) { + this._isNew = false; + } this._collapsed = !this._collapsed; } diff --git a/src/panels/config/automation/action/ha-automation-action.ts b/src/panels/config/automation/action/ha-automation-action.ts index d33825c0e7..a5bd5d4f5c 100644 --- a/src/panels/config/automation/action/ha-automation-action.ts +++ b/src/panels/config/automation/action/ha-automation-action.ts @@ -161,6 +161,7 @@ export default class HaAutomationAction extends AutomationSortableListMixin @@ -464,10 +470,11 @@ export default class HaAutomationConditionRow extends LitElement { } private _renderTargets = memoizeOne( - (target?: HassServiceTarget) => + (target?: HassServiceTarget, targetRequired = false) => html`` ); @@ -743,6 +750,10 @@ export default class HaAutomationConditionRow extends LitElement { this.openSidebar(); } + public markAsNew(): void { + this._isNew = true; + } + public openSidebar(condition?: Condition): void { const sidebarCondition = condition || this.condition; fireEvent(this, "open-sidebar", { @@ -751,6 +762,7 @@ export default class HaAutomationConditionRow extends LitElement { }, close: (focus?: boolean) => { this._selected = false; + this._isNew = false; fireEvent(this, "close-sidebar"); if (focus) { this.focus(); @@ -806,6 +818,9 @@ export default class HaAutomationConditionRow extends LitElement { ); private _toggleCollapse() { + if (!this._collapsed) { + this._isNew = false; + } this._collapsed = !this._collapsed; } diff --git a/src/panels/config/automation/condition/ha-automation-condition.ts b/src/panels/config/automation/condition/ha-automation-condition.ts index a598f81687..371ca3f960 100644 --- a/src/panels/config/automation/condition/ha-automation-condition.ts +++ b/src/panels/config/automation/condition/ha-automation-condition.ts @@ -169,6 +169,7 @@ export default class HaAutomationCondition extends AutomationSortableListMixin -
- ${this.localize( - "ui.panel.config.automation.editor.target_summary.no_target" - )} -
- `; + return this._renderTargetBadge( + this.targetRequired + ? html`` + : nothing, + this.localize( + "ui.panel.config.automation.editor.target_summary.no_target" + ), + false, + this.targetRequired + ); } const totalLength = Object.values(this.target || {}).reduce( (acc, val) => acc + ensureArray(val).length, @@ -154,9 +162,10 @@ export class HaAutomationRowTargets extends LitElement { private _renderTargetBadge( icon: TemplateResult | typeof nothing, label: string, - alert = false + warning = false, + error = false ) { - return html`
+ return html`
${icon}
${label}
`; @@ -230,10 +239,14 @@ export class HaAutomationRowTargets extends LitElement { overflow: hidden; height: 32px; } - .target.alert { + .target.warning { background: var(--ha-color-fill-warning-normal-resting); color: var(--ha-color-on-warning-normal); } + .target.error { + background: var(--ha-color-fill-danger-normal-resting); + color: var(--ha-color-on-danger-normal); + } .target .label { overflow: hidden; text-overflow: ellipsis; diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts index 8bce976357..abd1bf167d 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts @@ -145,6 +145,8 @@ export default class HaAutomationTriggerRow extends LitElement { @state() private _selected = false; + @state() private _isNew = false; + @state() private _warnings?: string[]; @property({ attribute: false }) @@ -197,14 +199,16 @@ export default class HaAutomationTriggerRow extends LitElement { const yamlMode = this._yamlMode || !supported; - const target = + const descriptionHasTarget = type === "platform" && "target" in - this.triggerDescriptions[(this.trigger as PlatformTrigger).trigger] - ? (this.trigger as PlatformTrigger).target - : type === "device" && (this.trigger as DeviceTrigger).device_id - ? { device_id: (this.trigger as DeviceTrigger).device_id } - : undefined; + this.triggerDescriptions[(this.trigger as PlatformTrigger).trigger]; + + const target = descriptionHasTarget + ? (this.trigger as PlatformTrigger).target + : type === "device" && (this.trigger as DeviceTrigger).device_id + ? { device_id: (this.trigger as DeviceTrigger).device_id } + : undefined; return html` ${type === "list" @@ -220,7 +224,9 @@ export default class HaAutomationTriggerRow extends LitElement { >`}

${describeTrigger(this.trigger, this.hass, this._entityReg)} - ${target ? this._renderTargets(target) : nothing} + ${target !== undefined || (descriptionHasTarget && !this._isNew) + ? this._renderTargets(target, descriptionHasTarget && !this._isNew) + : nothing}

@@ -446,7 +452,10 @@ export default class HaAutomationTriggerRow extends LitElement { : nothing}${this._renderRow()}` : html` - + ${this._renderRow()} `} @@ -467,10 +476,11 @@ export default class HaAutomationTriggerRow extends LitElement { } private _renderTargets = memoizeOne( - (target?: HassServiceTarget) => + (target?: HassServiceTarget, targetRequired = false) => html`` ); @@ -576,6 +586,16 @@ export default class HaAutomationTriggerRow extends LitElement { this.openSidebar(); } + public markAsNew(): void { + this._isNew = true; + } + + private _expansionPanelChanged(ev: CustomEvent) { + if (!ev.detail.expanded) { + this._isNew = false; + } + } + public openSidebar(trigger?: Trigger): void { trigger = trigger || this.trigger; fireEvent(this, "open-sidebar", { @@ -584,6 +604,7 @@ export default class HaAutomationTriggerRow extends LitElement { }, close: (focus?: boolean) => { this._selected = false; + this._isNew = false; fireEvent(this, "close-sidebar"); if (focus) { this.focus(); diff --git a/src/panels/config/automation/trigger/ha-automation-trigger.ts b/src/panels/config/automation/trigger/ha-automation-trigger.ts index 3b7fe00ec7..c0139d3dcb 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger.ts @@ -252,6 +252,7 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin