diff --git a/src/components/ha-filter-devices.ts b/src/components/ha-filter-devices.ts index 4b9f2bebc443..de5f5d9c7850 100644 --- a/src/components/ha-filter-devices.ts +++ b/src/components/ha-filter-devices.ts @@ -13,10 +13,11 @@ import { stringCompare } from "../common/string/compare"; import { computeDeviceName } from "../data/device_registry"; import { findRelated, RelatedResult } from "../data/search"; import { haStyleScrollbar } from "../resources/styles"; +import { loadVirtualizer } from "../resources/virtualizer"; import type { HomeAssistant } from "../types"; -import "./ha-expansion-panel"; import "./ha-check-list-item"; -import { loadVirtualizer } from "../resources/virtualizer"; +import "./ha-expansion-panel"; +import "./search-input-outlined"; @customElement("ha-filter-devices") export class HaFilterDevices extends LitElement { @@ -32,6 +33,8 @@ export class HaFilterDevices extends LitElement { @state() private _shouldRender = false; + @state() private _filter?: string; + public willUpdate(properties: PropertyValues) { super.willUpdate(properties); @@ -55,15 +58,25 @@ export class HaFilterDevices extends LitElement { : nothing} ${this._shouldRender - ? html` - - - ` + + + + + ` : nothing} `; @@ -72,12 +85,14 @@ export class HaFilterDevices extends LitElement { private _keyFunction = (device) => device?.id; private _renderItem = (device) => - html` - ${computeDeviceName(device, this.hass)} - `; + !device + ? nothing + : html` + ${computeDeviceName(device, this.hass)} + `; private _handleItemClick(ev) { const listItem = ev.target.closest("ha-check-list-item"); @@ -99,7 +114,7 @@ export class HaFilterDevices extends LitElement { setTimeout(() => { if (!this.expanded) return; this.renderRoot.querySelector("mwc-list")!.style.height = - `${this.clientHeight - 49}px`; + `${this.clientHeight - 49 - 32}px`; // 32px is the height of the search input }, 300); } } @@ -112,16 +127,28 @@ export class HaFilterDevices extends LitElement { this.expanded = ev.detail.expanded; } - private _devices = memoizeOne((devices: HomeAssistant["devices"], _value) => { - const values = Object.values(devices); - return values.sort((a, b) => - stringCompare( - a.name_by_user || a.name || "", - b.name_by_user || b.name || "", - this.hass.locale.language - ) - ); - }); + private _handleSearchChange(ev: CustomEvent) { + this._filter = ev.detail.value.toLowerCase(); + } + + private _devices = memoizeOne( + (devices: HomeAssistant["devices"], filter: string, _value) => { + const values = Object.values(devices); + return values + .filter( + (device) => + !filter || + computeDeviceName(device, this.hass).toLowerCase().includes(filter) + ) + .sort((a, b) => + stringCompare( + computeDeviceName(a, this.hass), + computeDeviceName(b, this.hass), + this.hass.locale.language + ) + ); + } + ); private async _findRelated() { const relatedPromises: Promise[] = []; @@ -197,6 +224,10 @@ export class HaFilterDevices extends LitElement { ha-check-list-item { width: 100%; } + search-input-outlined { + display: block; + padding: 0 8px; + } `, ]; } diff --git a/src/components/ha-filter-entities.ts b/src/components/ha-filter-entities.ts index 2cffd9945612..15d9b2f39154 100644 --- a/src/components/ha-filter-entities.ts +++ b/src/components/ha-filter-entities.ts @@ -14,10 +14,11 @@ import { computeStateName } from "../common/entity/compute_state_name"; import { stringCompare } from "../common/string/compare"; import { findRelated, RelatedResult } from "../data/search"; import { haStyleScrollbar } from "../resources/styles"; +import { loadVirtualizer } from "../resources/virtualizer"; import type { HomeAssistant } from "../types"; -import "./ha-state-icon"; import "./ha-check-list-item"; -import { loadVirtualizer } from "../resources/virtualizer"; +import "./ha-state-icon"; +import "./search-input-outlined"; @customElement("ha-filter-entities") export class HaFilterEntities extends LitElement { @@ -33,6 +34,8 @@ export class HaFilterEntities extends LitElement { @state() private _shouldRender = false; + @state() private _filter?: string; + public willUpdate(properties: PropertyValues) { super.willUpdate(properties); @@ -57,11 +60,18 @@ export class HaFilterEntities extends LitElement { ${this._shouldRender ? html` + + { if (!this.expanded) return; this.renderRoot.querySelector("mwc-list")!.style.height = - `${this.clientHeight - 49}px`; + `${this.clientHeight - 49 - 32}px`; // 32px is the height of the search input }, 300); } } @@ -89,18 +99,20 @@ export class HaFilterEntities extends LitElement { private _keyFunction = (entity) => entity?.entity_id; private _renderItem = (entity) => - html` - - ${computeStateName(entity)} - `; + !entity + ? nothing + : html` + + ${computeStateName(entity)} + `; private _handleItemClick(ev) { const listItem = ev.target.closest("ha-check-list-item"); @@ -125,12 +137,27 @@ export class HaFilterEntities extends LitElement { this.expanded = ev.detail.expanded; } + private _handleSearchChange(ev: CustomEvent) { + this._filter = ev.detail.value.toLowerCase(); + } + private _entities = memoizeOne( - (states: HomeAssistant["states"], type: this["type"], _value) => { + ( + states: HomeAssistant["states"], + type: this["type"], + filter: string, + _value + ) => { const values = Object.values(states); return values .filter( - (entityState) => !type || computeStateDomain(entityState) !== type + (entityState) => + (!type || computeStateDomain(entityState) !== type) && + (!filter || + entityState.entity_id.toLowerCase().includes(filter) || + entityState.attributes.friendly_name + ?.toLowerCase() + .includes(filter)) ) .sort((a, b) => stringCompare( @@ -216,6 +243,10 @@ export class HaFilterEntities extends LitElement { --mdc-list-item-graphic-margin: 16px; width: 100%; } + search-input-outlined { + display: block; + padding: 0 8px; + } `, ]; }