diff --git a/src/data/target.ts b/src/data/target.ts index 5114ecee53..52ab516b99 100644 --- a/src/data/target.ts +++ b/src/data/target.ts @@ -47,13 +47,34 @@ export interface ExtractFromTargetResultReferenced { export const extractFromTarget = async ( hass: HomeAssistant, - target: HassServiceTarget + target: HassServiceTarget, + expandGroup = false ) => hass.callWS({ type: "extract_from_target", target, + expand_group: expandGroup, }); +export const getResolvedTargetEntityCount = async ( + hass: HomeAssistant, + target?: HassServiceTarget +): Promise => { + if (!target) { + return undefined; + } + + try { + return (await extractFromTarget(hass, target, true)).referenced_entities + .length; + } catch (err) { + // eslint-disable-next-line no-console + console.error("Error resolving target entity count", err); + } + + return undefined; +}; + export const getTriggersForTarget = async ( callWS: HomeAssistant["callWS"], target: HassServiceTarget, diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-platform.ts b/src/panels/config/automation/condition/types/ha-automation-condition-platform.ts index b6b4d1f875..5f4b80830f 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-platform.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-platform.ts @@ -16,6 +16,7 @@ import { import type { IntegrationManifest } from "../../../../../data/integration"; import { fetchIntegrationManifest } from "../../../../../data/integration"; import type { TargetSelector } from "../../../../../data/selector"; +import { getResolvedTargetEntityCount } from "../../../../../data/target"; import type { HomeAssistant } from "../../../../../types"; import { documentationUrl } from "../../../../../util/documentation-url"; @@ -38,6 +39,8 @@ export class HaPlatformCondition extends LitElement { @state() private _manifest?: IntegrationManifest; + @state() private _resolvedTargetEntityCount?: number; + public static get defaultConfig(): PlatformCondition { return { condition: "" }; } @@ -107,6 +110,10 @@ export class HaPlatformCondition extends LitElement { }); } } + + if (oldValue?.target !== this.condition?.target) { + this._updateResolvedTargetEntityCount(this.condition?.target); + } } protected render() { @@ -214,51 +221,57 @@ export class HaPlatformCondition extends LitElement { const showOptional = showOptionalToggle(dataField); - return dataField.selector - ? html` - ${!showOptional - ? hasOptional - ? html`
` - : nothing - : html``} - ${this.hass.localize( - `component.${domain}.conditions.${conditionName}.fields.${fieldName}.name` - ) || conditionName} - ${this.hass.localize( - `component.${domain}.conditions.${conditionName}.fields.${fieldName}.description` - )} - + ${!showOptional + ? hasOptional + ? html`
` + : nothing + : html`
-
` - : nothing; + .checked=${this._checkedKeys.has(fieldName) || + (this.condition?.options && + this.condition.options[fieldName] !== undefined)} + .disabled=${this.disabled} + @change=${this._checkboxChanged} + slot="prefix" + >`} + ${this.hass.localize( + `component.${domain}.conditions.${conditionName}.fields.${fieldName}.name` + ) || conditionName} + ${this.hass.localize( + `component.${domain}.conditions.${conditionName}.fields.${fieldName}.description` + )} + + `; }; private _generateContext( @@ -395,6 +408,47 @@ export class HaPlatformCondition extends LitElement { } } + private _resolveTargetEntityCount = memoizeOne( + async (target: PlatformCondition["target"]) => + getResolvedTargetEntityCount(this.hass, target) + ); + + private async _updateResolvedTargetEntityCount( + target: PlatformCondition["target"] + ) { + this._resolvedTargetEntityCount = + await this._resolveTargetEntityCount(target); + + if ( + this._resolvedTargetEntityCount === 1 && + this.condition.options?.behavior !== undefined + ) { + const options = { ...this.condition.options }; + delete options.behavior; + + fireEvent(this, "value-changed", { + value: { + ...this.condition, + options, + }, + }); + } else if ( + this._resolvedTargetEntityCount !== undefined && + this._resolvedTargetEntityCount > 1 && + this.condition.options?.behavior === undefined + ) { + const behaviorDefault = this.description?.fields?.behavior?.default; + if (behaviorDefault !== undefined) { + fireEvent(this, "value-changed", { + value: { + ...this.condition, + options: { ...this.condition.options, behavior: behaviorDefault }, + }, + }); + } + } + } + static styles = css` :host { display: block; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-platform.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-platform.ts index 02289222b1..cfcc95dd10 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-platform.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-platform.ts @@ -11,6 +11,7 @@ import type { PlatformTrigger } from "../../../../../data/automation"; import type { IntegrationManifest } from "../../../../../data/integration"; import { fetchIntegrationManifest } from "../../../../../data/integration"; import type { TargetSelector } from "../../../../../data/selector"; +import { getResolvedTargetEntityCount } from "../../../../../data/target"; import { getTriggerDomain, getTriggerObjectId, @@ -48,6 +49,8 @@ export class HaPlatformTrigger extends LitElement { @state() private _manifest?: IntegrationManifest; + @state() private _resolvedTargetEntityCount?: number; + public static get defaultConfig(): PlatformTrigger { return { trigger: "" }; } @@ -143,6 +146,10 @@ export class HaPlatformTrigger extends LitElement { }); } } + + if (oldValue?.target !== this.trigger?.target) { + this._updateResolvedTargetEntityCount(this.trigger?.target); + } } protected render() { @@ -250,51 +257,58 @@ export class HaPlatformTrigger extends LitElement { const showOptional = showOptionalToggle(dataField); - return dataField.selector - ? html` - ${!showOptional - ? hasOptional - ? html`
` - : nothing - : html``} - ${this.hass.localize( - `component.${domain}.triggers.${triggerName}.fields.${fieldName}.name` - ) || triggerName} - ${this.hass.localize( - `component.${domain}.triggers.${triggerName}.fields.${fieldName}.description` - )} - + ${!showOptional + ? hasOptional + ? html`
` + : nothing + : html`
-
` - : nothing; + .checked=${this._checkedKeys.has(fieldName) || + (this.trigger?.options && + this.trigger.options[fieldName] !== undefined)} + .disabled=${this.disabled} + @change=${this._checkboxChanged} + slot="prefix" + >`} + ${this.hass.localize( + `component.${domain}.triggers.${triggerName}.fields.${fieldName}.name` + ) || triggerName} + ${this.hass.localize( + `component.${domain}.triggers.${triggerName}.fields.${fieldName}.description` + )} + + `; }; private _generateContext( @@ -431,6 +445,47 @@ export class HaPlatformTrigger extends LitElement { } } + private _resolveTargetEntityCount = memoizeOne( + async (target: PlatformTrigger["target"]) => + getResolvedTargetEntityCount(this.hass, target) + ); + + private async _updateResolvedTargetEntityCount( + target: PlatformTrigger["target"] + ) { + this._resolvedTargetEntityCount = + await this._resolveTargetEntityCount(target); + + if ( + this._resolvedTargetEntityCount === 1 && + this.trigger.options?.behavior !== undefined + ) { + const options = { ...this.trigger.options }; + delete options.behavior; + + fireEvent(this, "value-changed", { + value: { + ...this.trigger, + options, + }, + }); + } else if ( + this._resolvedTargetEntityCount !== undefined && + this._resolvedTargetEntityCount > 1 && + this.trigger.options?.behavior === undefined + ) { + const behaviorDefault = this.description?.fields?.behavior?.default; + if (behaviorDefault !== undefined) { + fireEvent(this, "value-changed", { + value: { + ...this.trigger, + options: { ...this.trigger.options, behavior: behaviorDefault }, + }, + }); + } + } + } + static styles = css` :host { display: block;