mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 19:26:36 +00:00
Add search to device and entity filters (#20341)
This commit is contained in:
parent
5b86b1277f
commit
1e2c1d1464
@ -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;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user