diff --git a/.eslintrc.json b/.eslintrc.json index 9cfa58084a..73d6cea999 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -84,7 +84,8 @@ "@typescript-eslint/no-unused-vars": 0, "@typescript-eslint/explicit-function-return-type": 0, "@typescript-eslint/explicit-module-boundary-types": 0, - "@typescript-eslint/no-shadow": ["error"] + "@typescript-eslint/no-shadow": ["error"], + "lit/attribute-value-entities": 0 }, "plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"], "processor": "disable/disable" diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index b24c5c227c..dfaeecd570 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -99,7 +99,7 @@ export class HaEntityPicker extends LitElement { @property({ type: Boolean }) private _opened = false; - @query("vaadin-combo-box-light", true) private _comboBox!: HTMLElement; + @query("vaadin-combo-box-light", true) private comboBox!: HTMLElement; public open() { this.updateComplete.then(() => { @@ -208,7 +208,7 @@ export class HaEntityPicker extends LitElement { this.entityFilter, this.includeDeviceClasses ); - (this._comboBox as any).filteredItems = this._states; + (this.comboBox as any).filteredItems = this._states; this._initedStates = true; } } @@ -296,7 +296,7 @@ export class HaEntityPicker extends LitElement { private _filterChanged(ev: CustomEvent): void { const filterString = ev.detail.value.toLowerCase(); - (this._comboBox as any).filteredItems = this._states.filter( + (this.comboBox as any).filteredItems = this._states.filter( (state) => state.entity_id.toLowerCase().includes(filterString) || computeStateName(state).toLowerCase().includes(filterString) diff --git a/src/components/ha-button-related-filter-menu.ts b/src/components/ha-button-related-filter-menu.ts index fa2c580735..1e4cde248d 100644 --- a/src/components/ha-button-related-filter-menu.ts +++ b/src/components/ha-button-related-filter-menu.ts @@ -18,6 +18,9 @@ import type { HomeAssistant } from "../types"; import "./ha-svg-icon"; import "./ha-area-picker"; import "./device/ha-device-picker"; +import "./entity/ha-entity-picker"; +import { computeStateName } from "../common/entity/compute_state_name"; +import { computeDeviceName } from "../data/device_registry"; declare global { // for fire event @@ -33,6 +36,7 @@ declare global { interface FilterValue { area?: string; device?: string; + entity?: string; } @customElement("ha-button-related-filter-menu") @@ -47,6 +51,14 @@ export class HaRelatedFilterButtonMenu extends LitElement { @property({ attribute: false }) public value?: FilterValue; + /** + * Show no entities of these domains. + * @type {Array} + * @attr exclude-domains + */ + @property({ type: Array, attribute: "exclude-domains" }) + public excludeDomains?: string[]; + @internalProperty() private _open = false; protected render(): TemplateResult { @@ -78,6 +90,15 @@ export class HaRelatedFilterButtonMenu extends LitElement { .value=${this.value?.device} @value-changed=${this._devicePicked} > + `; } @@ -93,6 +114,25 @@ export class HaRelatedFilterButtonMenu extends LitElement { this._open = false; } + private async _entityPicked(ev: CustomEvent) { + const entityId = ev.detail.value; + if (!entityId) { + fireEvent(this, "related-changed", { value: undefined }); + return; + } + const filter = this.hass.localize( + "ui.components.related-filter-menu.filtered_by_entity", + "entity_name", + computeStateName((ev.currentTarget as any).comboBox.selectedItem) + ); + const items = await findRelated(this.hass, "entity", entityId); + fireEvent(this, "related-changed", { + value: { entity: entityId }, + filter, + items, + }); + } + private async _devicePicked(ev: CustomEvent) { const deviceId = ev.detail.value; if (!deviceId) { @@ -102,7 +142,10 @@ export class HaRelatedFilterButtonMenu extends LitElement { const filter = this.hass.localize( "ui.components.related-filter-menu.filtered_by_device", "device_name", - (ev.currentTarget as any).comboBox.selectedItem.name + computeDeviceName( + (ev.currentTarget as any).comboBox.selectedItem, + this.hass + ) ); const items = await findRelated(this.hass, "device", deviceId); @@ -142,7 +185,8 @@ export class HaRelatedFilterButtonMenu extends LitElement { position: static; } ha-area-picker, - ha-device-picker { + ha-device-picker, + ha-entity-picker { display: block; width: 300px; padding: 4px 16px; diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index 12e870be15..5f879b843b 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -261,6 +261,7 @@ class HaAutomationPicker extends LitElement { .narrow=${this.narrow} .hass=${this.hass} .value=${this._filterValue} + exclude-domains='["automation"]' @related-changed=${this._relatedFilterChanged} > diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts index 4b18f9e79f..177d7da864 100644 --- a/src/panels/config/scene/ha-scene-dashboard.ts +++ b/src/panels/config/scene/ha-scene-dashboard.ts @@ -58,6 +58,9 @@ class HaSceneDashboard extends LitElement { private _scenes = memoizeOne( (scenes: SceneEntity[], filteredScenes?: string[] | null) => { + if (filteredScenes === null) { + return []; + } return (filteredScenes ? scenes.filter((scene) => filteredScenes!.includes(scene.entity_id)) : scenes @@ -183,6 +186,7 @@ class HaSceneDashboard extends LitElement { .narrow=${this.narrow} .hass=${this.hass} .value=${this._filterValue} + exclude-domains='["scene"]' @related-changed=${this._relatedFilterChanged} > diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts index cb352e7f33..b60e594ab5 100644 --- a/src/panels/config/script/ha-script-picker.ts +++ b/src/panels/config/script/ha-script-picker.ts @@ -56,6 +56,9 @@ class HaScriptPicker extends LitElement { private _scripts = memoizeOne( (scripts: HassEntity[], filteredScripts?: string[] | null) => { + if (filteredScripts === null) { + return []; + } return (filteredScripts ? scripts.filter((script) => filteredScripts!.includes(script.entity_id) @@ -193,6 +196,7 @@ class HaScriptPicker extends LitElement { .narrow=${this.narrow} .hass=${this.hass} .value=${this._filterValue} + exclude-domains='["script"]' @related-changed=${this._relatedFilterChanged} > diff --git a/src/translations/en.json b/src/translations/en.json index 1d2d8b3303..3315f926f1 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -399,8 +399,10 @@ } }, "related-filter-menu": { + "filter_by_entity": "Filter by entity", "filter_by_device": "Filter by device", "filter_by_area": "Filter by area", + "filtered_by_entity": "entity: {entity_name}", "filtered_by_device": "device: {device_name}", "filtered_by_area": "area: {area_name}" },