mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Add filter for domains to entity settings (#20605)
This commit is contained in:
parent
87bcd3e471
commit
4c9c52d27d
@ -69,7 +69,7 @@ export class HaFilterDevices extends LitElement {
|
|||||||
@value-changed=${this._handleSearchChange}
|
@value-changed=${this._handleSearchChange}
|
||||||
>
|
>
|
||||||
</search-input-outlined>
|
</search-input-outlined>
|
||||||
<mwc-list class="ha-scrollbar">
|
<mwc-list class="ha-scrollbar" multi>
|
||||||
<lit-virtualizer
|
<lit-virtualizer
|
||||||
.items=${this._devices(
|
.items=${this._devices(
|
||||||
this.hass.devices,
|
this.hass.devices,
|
||||||
|
198
src/components/ha-filter-domains.ts
Normal file
198
src/components/ha-filter-domains.ts
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import { mdiFilterVariantRemove } from "@mdi/js";
|
||||||
|
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { repeat } from "lit/directives/repeat";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { stringCompare } from "../common/string/compare";
|
||||||
|
import { domainToName } from "../data/integration";
|
||||||
|
import { haStyleScrollbar } from "../resources/styles";
|
||||||
|
import type { HomeAssistant } from "../types";
|
||||||
|
import "./ha-domain-icon";
|
||||||
|
import "./search-input-outlined";
|
||||||
|
import { computeDomain } from "../common/entity/compute_domain";
|
||||||
|
|
||||||
|
@customElement("ha-filter-domains")
|
||||||
|
export class HaFilterDomains extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public value?: string[];
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean, reflect: true }) public expanded = false;
|
||||||
|
|
||||||
|
@state() private _shouldRender = false;
|
||||||
|
|
||||||
|
@state() private _filter?: string;
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`
|
||||||
|
<ha-expansion-panel
|
||||||
|
leftChevron
|
||||||
|
.expanded=${this.expanded}
|
||||||
|
@expanded-will-change=${this._expandedWillChange}
|
||||||
|
@expanded-changed=${this._expandedChanged}
|
||||||
|
>
|
||||||
|
<div slot="header" class="header">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.entities.picker.headers.domain"
|
||||||
|
)}
|
||||||
|
${this.value?.length
|
||||||
|
? html`<div class="badge">${this.value?.length}</div>
|
||||||
|
<ha-icon-button
|
||||||
|
.path=${mdiFilterVariantRemove}
|
||||||
|
@click=${this._clearFilter}
|
||||||
|
></ha-icon-button>`
|
||||||
|
: nothing}
|
||||||
|
</div>
|
||||||
|
${this._shouldRender
|
||||||
|
? html`<search-input-outlined
|
||||||
|
.hass=${this.hass}
|
||||||
|
.filter=${this._filter}
|
||||||
|
@value-changed=${this._handleSearchChange}
|
||||||
|
>
|
||||||
|
</search-input-outlined>
|
||||||
|
<mwc-list
|
||||||
|
class="ha-scrollbar"
|
||||||
|
@click=${this._handleItemClick}
|
||||||
|
multi
|
||||||
|
>
|
||||||
|
${repeat(
|
||||||
|
this._domains(this.hass.states, this._filter),
|
||||||
|
(i) => i,
|
||||||
|
(domain) =>
|
||||||
|
html`<ha-check-list-item
|
||||||
|
.value=${domain}
|
||||||
|
.selected=${(this.value || []).includes(domain)}
|
||||||
|
graphic="icon"
|
||||||
|
>
|
||||||
|
<ha-domain-icon
|
||||||
|
slot="graphic"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.domain=${domain}
|
||||||
|
brandFallback
|
||||||
|
></ha-domain-icon>
|
||||||
|
${domainToName(this.hass.localize, domain)}
|
||||||
|
</ha-check-list-item>`
|
||||||
|
)}
|
||||||
|
</mwc-list> `
|
||||||
|
: nothing}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _domains = memoizeOne((states, filter) => {
|
||||||
|
const domains = new Set<string>();
|
||||||
|
Object.keys(states).forEach((entityId) => {
|
||||||
|
domains.add(computeDomain(entityId));
|
||||||
|
});
|
||||||
|
return Array.from(domains)
|
||||||
|
.filter((domain) => !filter || domain.toLowerCase().includes(filter))
|
||||||
|
.sort((a, b) => stringCompare(a, b, this.hass.locale.language));
|
||||||
|
});
|
||||||
|
|
||||||
|
protected updated(changed) {
|
||||||
|
if (changed.has("expanded") && this.expanded) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.expanded) return;
|
||||||
|
this.renderRoot.querySelector("mwc-list")!.style.height =
|
||||||
|
`${this.clientHeight - 49 - 32}px`; // 32px is the height of the search input
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _expandedWillChange(ev) {
|
||||||
|
this._shouldRender = ev.detail.expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _expandedChanged(ev) {
|
||||||
|
this.expanded = ev.detail.expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleItemClick(ev) {
|
||||||
|
const listItem = ev.target.closest("ha-check-list-item");
|
||||||
|
const value = listItem?.value;
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.value?.includes(value)) {
|
||||||
|
this.value = this.value?.filter((val) => val !== value);
|
||||||
|
} else {
|
||||||
|
this.value = [...(this.value || []), value];
|
||||||
|
}
|
||||||
|
|
||||||
|
listItem.selected = this.value.includes(value);
|
||||||
|
|
||||||
|
fireEvent(this, "data-table-filter-changed", {
|
||||||
|
value: this.value,
|
||||||
|
items: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _clearFilter(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.value = undefined;
|
||||||
|
fireEvent(this, "data-table-filter-changed", {
|
||||||
|
value: undefined,
|
||||||
|
items: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleSearchChange(ev: CustomEvent) {
|
||||||
|
this._filter = ev.detail.value.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyleScrollbar,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
border-bottom: 1px solid var(--divider-color);
|
||||||
|
}
|
||||||
|
:host([expanded]) {
|
||||||
|
flex: 1;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
ha-expansion-panel {
|
||||||
|
--ha-card-border-radius: 0;
|
||||||
|
--expansion-panel-content-padding: 0;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.header ha-icon-button {
|
||||||
|
margin-inline-start: auto;
|
||||||
|
margin-inline-end: 8px;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-inline-start: 8px;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
min-width: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 11px;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
line-height: 16px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0px 2px;
|
||||||
|
color: var(--text-primary-color);
|
||||||
|
}
|
||||||
|
search-input-outlined {
|
||||||
|
display: block;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-filter-domains": HaFilterDomains;
|
||||||
|
}
|
||||||
|
}
|
@ -71,7 +71,7 @@ export class HaFilterEntities extends LitElement {
|
|||||||
@value-changed=${this._handleSearchChange}
|
@value-changed=${this._handleSearchChange}
|
||||||
>
|
>
|
||||||
</search-input-outlined>
|
</search-input-outlined>
|
||||||
<mwc-list class="ha-scrollbar">
|
<mwc-list class="ha-scrollbar" multi>
|
||||||
<lit-virtualizer
|
<lit-virtualizer
|
||||||
.items=${this._entities(
|
.items=${this._entities(
|
||||||
this.hass.states,
|
this.hass.states,
|
||||||
|
@ -55,7 +55,11 @@ export class HaFilterIntegrations extends LitElement {
|
|||||||
@value-changed=${this._handleSearchChange}
|
@value-changed=${this._handleSearchChange}
|
||||||
>
|
>
|
||||||
</search-input-outlined>
|
</search-input-outlined>
|
||||||
<mwc-list class="ha-scrollbar" @click=${this._handleItemClick}>
|
<mwc-list
|
||||||
|
class="ha-scrollbar"
|
||||||
|
@click=${this._handleItemClick}
|
||||||
|
multi
|
||||||
|
>
|
||||||
${repeat(
|
${repeat(
|
||||||
this._integrations(this._manifests, this._filter, this.value),
|
this._integrations(this._manifests, this._filter, this.value),
|
||||||
(i) => i.domain,
|
(i) => i.domain,
|
||||||
|
@ -53,6 +53,7 @@ import "../../../components/ha-alert";
|
|||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-check-list-item";
|
import "../../../components/ha-check-list-item";
|
||||||
import "../../../components/ha-filter-devices";
|
import "../../../components/ha-filter-devices";
|
||||||
|
import "../../../components/ha-filter-domains";
|
||||||
import "../../../components/ha-filter-floor-areas";
|
import "../../../components/ha-filter-floor-areas";
|
||||||
import "../../../components/ha-filter-integrations";
|
import "../../../components/ha-filter-integrations";
|
||||||
import "../../../components/ha-filter-labels";
|
import "../../../components/ha-filter-labels";
|
||||||
@ -443,6 +444,10 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
|||||||
entryIds.includes(entity.config_entry_id))
|
entryIds.includes(entity.config_entry_id))
|
||||||
);
|
);
|
||||||
filter.value!.forEach((domain) => filteredDomains.add(domain));
|
filter.value!.forEach((domain) => filteredDomains.add(domain));
|
||||||
|
} else if (key === "ha-filter-domains" && filter.value?.length) {
|
||||||
|
filteredEntities = filteredEntities.filter((entity) =>
|
||||||
|
filter.value?.includes(computeDomain(entity.entity_id))
|
||||||
|
);
|
||||||
} else if (key === "ha-filter-labels" && filter.value?.length) {
|
} else if (key === "ha-filter-labels" && filter.value?.length) {
|
||||||
filteredEntities = filteredEntities.filter((entity) =>
|
filteredEntities = filteredEntities.filter((entity) =>
|
||||||
entity.labels.some((lbl) => filter.value!.includes(lbl))
|
entity.labels.some((lbl) => filter.value!.includes(lbl))
|
||||||
@ -782,6 +787,15 @@ ${
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
@expanded-changed=${this._filterExpanded}
|
@expanded-changed=${this._filterExpanded}
|
||||||
></ha-filter-devices>
|
></ha-filter-devices>
|
||||||
|
<ha-filter-domains
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._filters["ha-filter-domains"]?.value}
|
||||||
|
@data-table-filter-changed=${this._filterChanged}
|
||||||
|
slot="filter-pane"
|
||||||
|
.expanded=${this._expandedFilter === "ha-filter-domains"}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
@expanded-changed=${this._filterExpanded}
|
||||||
|
></ha-filter-domains>
|
||||||
<ha-filter-integrations
|
<ha-filter-integrations
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.value=${this._filters["ha-filter-integrations"]?.value}
|
.value=${this._filters["ha-filter-integrations"]?.value}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user