From 76daa2bb7fa0676399d2ec40055deba0db23de9a Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 25 Jun 2024 20:01:10 +0200 Subject: [PATCH] Add support for sections in filters (#21157) --- src/components/ha-service-control.ts | 208 ++++++++++++++++----------- 1 file changed, 126 insertions(+), 82 deletions(-) diff --git a/src/components/ha-service-control.ts b/src/components/ha-service-control.ts index 83df104f54aa..47ee86539306 100644 --- a/src/components/ha-service-control.ts +++ b/src/components/ha-service-control.ts @@ -65,6 +65,8 @@ interface ExtHassService extends Omit { Omit & { key: string; selector?: Selector; + fields?: Record>; + collapsed?: boolean; } >; hasSelector: string[]; @@ -247,20 +249,7 @@ export class HaServiceControl extends LitElement { } ); - private _filterFields = memoizeOne( - (serviceData: ExtHassService | undefined, value: this["value"]) => - serviceData?.fields?.filter( - (field) => - !field.filter || - this._filterField(serviceData.target, field.filter, value) - ) - ); - - private _filterField( - target: ExtHassService["target"], - filter: ExtHassService["fields"][number]["filter"], - value: this["value"] - ) { + private _getTargetedEntities = memoizeOne((target, value) => { const targetSelector = target ? { target } : { target: {} }; const targetEntities = ensureArray( @@ -330,6 +319,13 @@ export class HaServiceControl extends LitElement { ); }); } + return targetEntities; + }); + + private _filterField( + filter: ExtHassService["fields"][number]["filter"], + targetEntities: string[] + ) { if (!targetEntities.length) { return false; } @@ -391,7 +387,10 @@ export class HaServiceControl extends LitElement { serviceData?.fields.some((field) => showOptionalToggle(field)) ); - const filteredFields = this._filterFields(serviceData, this._value); + const targetEntities = this._getTargetedEntities( + serviceData?.target, + this._value + ); const domain = this._value?.service ? computeDomain(this._value.service) @@ -485,75 +484,115 @@ export class HaServiceControl extends LitElement { .defaultValue=${this._value?.data} @value-changed=${this._dataChanged} >` - : filteredFields?.map((dataField) => { - const selector = dataField?.selector ?? { text: undefined }; - const type = Object.keys(selector)[0]; - const enhancedSelector = ["action", "condition", "trigger"].includes( - type - ) - ? { - [type]: { - ...selector[type], - path: [dataField.key], - }, - } - : selector; - - const showOptional = showOptionalToggle(dataField); - - return dataField.selector && - (!dataField.advanced || - this.showAdvanced || - (this._value?.data && - this._value.data[dataField.key] !== undefined)) - ? html` - ${!showOptional - ? hasOptional - ? html`
` - : "" - : html``} - ${this.hass.localize( - `component.${domain}.services.${serviceName}.fields.${dataField.key}.name` - ) || - dataField.name || - dataField.key} - ${this.hass.localize( - `component.${domain}.services.${serviceName}.fields.${dataField.key}.description` - ) || dataField?.description} - -
` - : ""; - })} `; + : serviceData?.fields.map((dataField) => + dataField.fields + ? html` + ${Object.entries(dataField.fields).map(([key, field]) => + this._renderField( + { key, ...field }, + hasOptional, + domain, + serviceName, + targetEntities + ) + )} + ` + : this._renderField( + dataField, + hasOptional, + domain, + serviceName, + targetEntities + ) + )} `; } + private _renderField = ( + dataField: ExtHassService["fields"][number], + hasOptional: boolean, + domain: string | undefined, + serviceName: string | undefined, + targetEntities: string[] + ) => { + if ( + dataField.filter && + !this._filterField(dataField.filter, targetEntities) + ) { + return nothing; + } + + const selector = dataField?.selector ?? { text: undefined }; + const type = Object.keys(selector)[0]; + const enhancedSelector = ["action", "condition", "trigger"].includes(type) + ? { + [type]: { + ...selector[type], + path: [dataField.key], + }, + } + : selector; + + const showOptional = showOptionalToggle(dataField); + + return dataField.selector && + (!dataField.advanced || + this.showAdvanced || + (this._value?.data && this._value.data[dataField.key] !== undefined)) + ? html` + ${!showOptional + ? hasOptional + ? html`
` + : "" + : html``} + ${this.hass.localize( + `component.${domain}.services.${serviceName}.fields.${dataField.key}.name` + ) || + dataField.name || + dataField.key} + ${this.hass.localize( + `component.${domain}.services.${serviceName}.fields.${dataField.key}.description` + ) || dataField?.description} + +
` + : ""; + }; + private _localizeValueCallback = (key: string) => { if (!this._value?.service) { return ""; @@ -839,6 +878,11 @@ export class HaServiceControl extends LitElement { .description p { direction: ltr; } + ha-expansion-panel { + --ha-card-border-radius: 0; + --expansion-panel-summary-padding: 0 16px; + --expansion-panel-content-padding: 0; + } `; } }