Add search to device and entity filters (#20341)

This commit is contained in:
Bram Kragten 2024-04-02 21:46:21 +02:00 committed by GitHub
parent 5b86b1277f
commit 1e2c1d1464
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 108 additions and 46 deletions

View File

@ -13,10 +13,11 @@ import { stringCompare } from "../common/string/compare";
import { computeDeviceName } from "../data/device_registry"; import { computeDeviceName } from "../data/device_registry";
import { findRelated, RelatedResult } from "../data/search"; import { findRelated, RelatedResult } from "../data/search";
import { haStyleScrollbar } from "../resources/styles"; import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-expansion-panel";
import "./ha-check-list-item";
import { loadVirtualizer } from "../resources/virtualizer"; import { loadVirtualizer } from "../resources/virtualizer";
import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-expansion-panel";
import "./search-input-outlined";
@customElement("ha-filter-devices") @customElement("ha-filter-devices")
export class HaFilterDevices extends LitElement { export class HaFilterDevices extends LitElement {
@ -32,6 +33,8 @@ export class HaFilterDevices extends LitElement {
@state() private _shouldRender = false; @state() private _shouldRender = false;
@state() private _filter?: string;
public willUpdate(properties: PropertyValues) { public willUpdate(properties: PropertyValues) {
super.willUpdate(properties); super.willUpdate(properties);
@ -55,9 +58,19 @@ export class HaFilterDevices extends LitElement {
: nothing} : nothing}
</div> </div>
${this._shouldRender ${this._shouldRender
? html`<mwc-list class="ha-scrollbar"> ? html`<search-input-outlined
.hass=${this.hass}
.filter=${this._filter}
@value-changed=${this._handleSearchChange}
>
</search-input-outlined>
<mwc-list class="ha-scrollbar">
<lit-virtualizer <lit-virtualizer
.items=${this._devices(this.hass.devices, this.value)} .items=${this._devices(
this.hass.devices,
this._filter || "",
this.value
)}
.keyFunction=${this._keyFunction} .keyFunction=${this._keyFunction}
.renderItem=${this._renderItem} .renderItem=${this._renderItem}
@click=${this._handleItemClick} @click=${this._handleItemClick}
@ -72,7 +85,9 @@ export class HaFilterDevices extends LitElement {
private _keyFunction = (device) => device?.id; private _keyFunction = (device) => device?.id;
private _renderItem = (device) => private _renderItem = (device) =>
html`<ha-check-list-item !device
? nothing
: html`<ha-check-list-item
.value=${device.id} .value=${device.id}
.selected=${this.value?.includes(device.id)} .selected=${this.value?.includes(device.id)}
> >
@ -99,7 +114,7 @@ export class HaFilterDevices extends LitElement {
setTimeout(() => { setTimeout(() => {
if (!this.expanded) return; if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height = 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); }, 300);
} }
} }
@ -112,16 +127,28 @@ export class HaFilterDevices extends LitElement {
this.expanded = ev.detail.expanded; this.expanded = ev.detail.expanded;
} }
private _devices = memoizeOne((devices: HomeAssistant["devices"], _value) => { private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value.toLowerCase();
}
private _devices = memoizeOne(
(devices: HomeAssistant["devices"], filter: string, _value) => {
const values = Object.values(devices); const values = Object.values(devices);
return values.sort((a, b) => return values
.filter(
(device) =>
!filter ||
computeDeviceName(device, this.hass).toLowerCase().includes(filter)
)
.sort((a, b) =>
stringCompare( stringCompare(
a.name_by_user || a.name || "", computeDeviceName(a, this.hass),
b.name_by_user || b.name || "", computeDeviceName(b, this.hass),
this.hass.locale.language this.hass.locale.language
) )
); );
}); }
);
private async _findRelated() { private async _findRelated() {
const relatedPromises: Promise<RelatedResult>[] = []; const relatedPromises: Promise<RelatedResult>[] = [];
@ -197,6 +224,10 @@ export class HaFilterDevices extends LitElement {
ha-check-list-item { ha-check-list-item {
width: 100%; width: 100%;
} }
search-input-outlined {
display: block;
padding: 0 8px;
}
`, `,
]; ];
} }

View File

@ -14,10 +14,11 @@ import { computeStateName } from "../common/entity/compute_state_name";
import { stringCompare } from "../common/string/compare"; import { stringCompare } from "../common/string/compare";
import { findRelated, RelatedResult } from "../data/search"; import { findRelated, RelatedResult } from "../data/search";
import { haStyleScrollbar } from "../resources/styles"; import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-state-icon";
import "./ha-check-list-item";
import { loadVirtualizer } from "../resources/virtualizer"; import { loadVirtualizer } from "../resources/virtualizer";
import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-state-icon";
import "./search-input-outlined";
@customElement("ha-filter-entities") @customElement("ha-filter-entities")
export class HaFilterEntities extends LitElement { export class HaFilterEntities extends LitElement {
@ -33,6 +34,8 @@ export class HaFilterEntities extends LitElement {
@state() private _shouldRender = false; @state() private _shouldRender = false;
@state() private _filter?: string;
public willUpdate(properties: PropertyValues) { public willUpdate(properties: PropertyValues) {
super.willUpdate(properties); super.willUpdate(properties);
@ -57,11 +60,18 @@ export class HaFilterEntities extends LitElement {
</div> </div>
${this._shouldRender ${this._shouldRender
? html` ? html`
<search-input-outlined
.hass=${this.hass}
.filter=${this._filter}
@value-changed=${this._handleSearchChange}
>
</search-input-outlined>
<mwc-list class="ha-scrollbar"> <mwc-list class="ha-scrollbar">
<lit-virtualizer <lit-virtualizer
.items=${this._entities( .items=${this._entities(
this.hass.states, this.hass.states,
this.type, this.type,
this._filter || "",
this.value this.value
)} )}
.keyFunction=${this._keyFunction} .keyFunction=${this._keyFunction}
@ -81,7 +91,7 @@ export class HaFilterEntities extends LitElement {
setTimeout(() => { setTimeout(() => {
if (!this.expanded) return; if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height = 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); }, 300);
} }
} }
@ -89,7 +99,9 @@ export class HaFilterEntities extends LitElement {
private _keyFunction = (entity) => entity?.entity_id; private _keyFunction = (entity) => entity?.entity_id;
private _renderItem = (entity) => private _renderItem = (entity) =>
html`<ha-check-list-item !entity
? nothing
: html`<ha-check-list-item
.value=${entity.entity_id} .value=${entity.entity_id}
.selected=${this.value?.includes(entity.entity_id)} .selected=${this.value?.includes(entity.entity_id)}
graphic="icon" graphic="icon"
@ -125,12 +137,27 @@ export class HaFilterEntities extends LitElement {
this.expanded = ev.detail.expanded; this.expanded = ev.detail.expanded;
} }
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value.toLowerCase();
}
private _entities = memoizeOne( private _entities = memoizeOne(
(states: HomeAssistant["states"], type: this["type"], _value) => { (
states: HomeAssistant["states"],
type: this["type"],
filter: string,
_value
) => {
const values = Object.values(states); const values = Object.values(states);
return values return values
.filter( .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) => .sort((a, b) =>
stringCompare( stringCompare(
@ -216,6 +243,10 @@ export class HaFilterEntities extends LitElement {
--mdc-list-item-graphic-margin: 16px; --mdc-list-item-graphic-margin: 16px;
width: 100%; width: 100%;
} }
search-input-outlined {
display: block;
padding: 0 8px;
}
`, `,
]; ];
} }