diff --git a/gallery/src/pages/components/ha-form.ts b/gallery/src/pages/components/ha-form.ts index cab77bacfc..fb2cec39af 100644 --- a/gallery/src/pages/components/ha-form.ts +++ b/gallery/src/pages/components/ha-form.ts @@ -139,6 +139,7 @@ const SCHEMAS: { { name: "Attribute", selector: { attribute: { entity_id: "" } }, + context: { filter_entity: "entity" }, }, { name: "Device", selector: { device: {} } }, { name: "Duration", selector: { duration: {} } }, diff --git a/src/components/ha-form/ha-form.ts b/src/components/ha-form/ha-form.ts index e1e87d86f9..f3db63e2c1 100644 --- a/src/components/ha-form/ha-form.ts +++ b/src/components/ha-form/ha-form.ts @@ -106,6 +106,7 @@ export class HaForm extends LitElement implements HaFormElement { .disabled=${this.disabled} .helper=${this._computeHelper(item)} .required=${item.required || false} + .context=${this._generateContext(item)} >` : dynamicElement(`ha-form-${item.type}`, { schema: item, @@ -115,6 +116,7 @@ export class HaForm extends LitElement implements HaFormElement { hass: this.hass, computeLabel: this.computeLabel, computeHelper: this.computeHelper, + context: this._generateContext(item), })} `; })} @@ -122,6 +124,20 @@ export class HaForm extends LitElement implements HaFormElement { `; } + private _generateContext( + schema: HaFormSchema + ): Record | undefined { + if (!schema.context) { + return undefined; + } + + const context = {}; + for (const [context_key, data_key] of Object.entries(schema.context)) { + context[context_key] = this.data[data_key]; + } + return context; + } + protected createRenderRoot() { const root = super.createRenderRoot(); // attach it as soon as possible to make sure we fetch all events. diff --git a/src/components/ha-form/types.ts b/src/components/ha-form/types.ts index 2c3a9912d4..d8e380cca4 100644 --- a/src/components/ha-form/types.ts +++ b/src/components/ha-form/types.ts @@ -24,6 +24,7 @@ export interface HaFormBaseSchema { // This value will be set initially when form is loaded suggested_value?: HaFormData; }; + context?: Record; } export interface HaFormGridSchema extends HaFormBaseSchema { diff --git a/src/components/ha-selector/ha-selector-attribute.ts b/src/components/ha-selector/ha-selector-attribute.ts index 5739089061..a75f9bb5ec 100644 --- a/src/components/ha-selector/ha-selector-attribute.ts +++ b/src/components/ha-selector/ha-selector-attribute.ts @@ -1,9 +1,10 @@ import "../entity/ha-entity-attribute-picker"; -import { html, LitElement } from "lit"; +import { html, LitElement, PropertyValues } from "lit"; import { customElement, property } from "lit/decorators"; import { AttributeSelector } from "../../data/selector"; import { SubscribeMixin } from "../../mixins/subscribe-mixin"; import { HomeAssistant } from "../../types"; +import { fireEvent } from "../../common/dom/fire_event"; @customElement("ha-selector-attribute") export class HaSelectorAttribute extends SubscribeMixin(LitElement) { @@ -17,11 +18,16 @@ export class HaSelectorAttribute extends SubscribeMixin(LitElement) { @property({ type: Boolean }) public disabled = false; + @property() public context?: { + filter_entity?: string; + }; + protected render() { return html` `; } + + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if ( + // No need to filter value if no value + !this.value || + // Only adjust value if we used the context + this.selector.attribute.entity_id || + // Only check if context has changed + !changedProps.has("context") + ) { + return; + } + + const oldContext = changedProps.get("context") as this["context"]; + + if ( + !this.context || + oldContext?.filter_entity === this.context.filter_entity + ) { + return; + } + + // Validate that that the attribute is still valid for this entity, else unselect. + let invalid = false; + if (this.context.filter_entity) { + const stateObj = this.hass.states[this.context.filter_entity]; + + if (!(stateObj && this.value in stateObj.attributes)) { + invalid = true; + } + } else { + invalid = this.value !== undefined; + } + + if (invalid) { + fireEvent(this, "value-changed", { + value: undefined, + }); + } + } } declare global { diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts index 4aa268ee23..74ad6cf623 100644 --- a/src/components/ha-selector/ha-selector.ts +++ b/src/components/ha-selector/ha-selector.ts @@ -42,6 +42,8 @@ export class HaSelector extends LitElement { @property({ type: Boolean }) public required = true; + @property() public context?: Record; + public focus() { this.shadowRoot?.getElementById("selector")?.focus(); } @@ -61,6 +63,7 @@ export class HaSelector extends LitElement { disabled: this.disabled, required: this.required, helper: this.helper, + context: this.context, id: "selector", })} `; diff --git a/src/data/selector.ts b/src/data/selector.ts index d4d83c6ccb..8d8c062b08 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -31,7 +31,7 @@ export interface EntitySelector { export interface AttributeSelector { attribute: { - entity_id: string; + entity_id?: string; }; }