mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-07 16:37:48 +00:00
Fix area and device id filtering
Add add and remove all buttons next to refresh button Index devices and entities on updates for more efficient querying
This commit is contained in:
parent
b633067e5c
commit
ba7351a676
@ -186,6 +186,7 @@ class StateHistoryCharts extends LitElement {
|
|||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-height: var(--history-max-height);
|
max-height: var(--history-max-height);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { mdiRefresh } from "@mdi/js";
|
import { mdiCollapseAll, mdiExpandAll, mdiRefresh } from "@mdi/js";
|
||||||
import "@polymer/app-layout/app-header/app-header";
|
import "@polymer/app-layout/app-header/app-header";
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
import {
|
import {
|
||||||
@ -34,6 +34,10 @@ import {
|
|||||||
EntityRegistryEntry,
|
EntityRegistryEntry,
|
||||||
subscribeEntityRegistry,
|
subscribeEntityRegistry,
|
||||||
} from "../../data/entity_registry";
|
} from "../../data/entity_registry";
|
||||||
|
import {
|
||||||
|
DeviceRegistryEntry,
|
||||||
|
subscribeDeviceRegistry,
|
||||||
|
} from "../../data/device_registry";
|
||||||
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
||||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
@ -57,9 +61,23 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _ranges?: DateRangePickerRanges;
|
@state() private _ranges?: DateRangePickerRanges;
|
||||||
|
|
||||||
@state() private _entities?: EntityRegistryEntry[];
|
@state() private _devices?: { [deviceId: string]: DeviceRegistryEntry };
|
||||||
|
|
||||||
@state() private _stateEntities?: EntityRegistryEntry[];
|
@state() private _entities?: { [entityId: string]: EntityRegistryEntry };
|
||||||
|
|
||||||
|
@state() private _stateEntities?: { [entityId: string]: EntityRegistryEntry };
|
||||||
|
|
||||||
|
@state() private _deviceIdToEntities?: {
|
||||||
|
[deviceId: string]: EntityRegistryEntry[];
|
||||||
|
};
|
||||||
|
|
||||||
|
@state() private _areaIdToEntities?: {
|
||||||
|
[areaId: string]: EntityRegistryEntry[];
|
||||||
|
};
|
||||||
|
|
||||||
|
@state() private _areaIdToDevices?: {
|
||||||
|
[areaId: string]: DeviceRegistryEntry[];
|
||||||
|
};
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super();
|
super();
|
||||||
@ -76,7 +94,52 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
public hassSubscribe(): UnsubscribeFunc[] {
|
public hassSubscribe(): UnsubscribeFunc[] {
|
||||||
return [
|
return [
|
||||||
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||||
this._entities = entities;
|
this._entities = entities.reduce((accumulator, current) => {
|
||||||
|
accumulator[current.entity_id] = current;
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
this._deviceIdToEntities = entities.reduce((accumulator, current) => {
|
||||||
|
if (current.device_id === undefined || current.device_id === null) {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
let found = accumulator[current.device_id];
|
||||||
|
if (found === undefined) {
|
||||||
|
found = [];
|
||||||
|
accumulator[current.device_id] = found;
|
||||||
|
}
|
||||||
|
found.push(current);
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
this._areaIdToEntities = entities.reduce((accumulator, current) => {
|
||||||
|
if (current.area_id === undefined || current.area_id === null) {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
let found = accumulator[current.area_id];
|
||||||
|
if (found === undefined) {
|
||||||
|
found = [];
|
||||||
|
accumulator[current.area_id] = found;
|
||||||
|
}
|
||||||
|
found.push(current);
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
}),
|
||||||
|
subscribeDeviceRegistry(this.hass.connection!, (devices) => {
|
||||||
|
this._devices = devices.reduce((accumulator, current) => {
|
||||||
|
accumulator[current.id] = current;
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
this._areaIdToDevices = devices.reduce((accumulator, current) => {
|
||||||
|
if (current.area_id === undefined || current.area_id === null) {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
let found = accumulator[current.area_id];
|
||||||
|
if (found === undefined) {
|
||||||
|
found = [];
|
||||||
|
accumulator[current.area_id] = found;
|
||||||
|
}
|
||||||
|
found.push(current);
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -91,6 +154,18 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
></ha-menu-button>
|
></ha-menu-button>
|
||||||
<div main-title>${this.hass.localize("panel.history")}</div>
|
<div main-title>${this.hass.localize("panel.history")}</div>
|
||||||
|
<ha-icon-button
|
||||||
|
@click=${this._showAll}
|
||||||
|
.disabled=${this._isLoading}
|
||||||
|
.path=${mdiExpandAll}
|
||||||
|
.label=${"Show All"}
|
||||||
|
></ha-icon-button>
|
||||||
|
<ha-icon-button
|
||||||
|
@click=${this._removeAll}
|
||||||
|
.disabled=${this._isLoading}
|
||||||
|
.path=${mdiCollapseAll}
|
||||||
|
.label=${"Clear All"}
|
||||||
|
></ha-icon-button>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
@click=${this._refreshHistory}
|
@click=${this._refreshHistory}
|
||||||
.disabled=${this._isLoading}
|
.disabled=${this._isLoading}
|
||||||
@ -125,6 +200,8 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
alt=${this.hass.localize("ui.common.loading")}
|
alt=${this.hass.localize("ui.common.loading")}
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
</div>`
|
</div>`
|
||||||
|
: this._targetPickerValue === undefined
|
||||||
|
? html`<div class="info">No selection made</div>`
|
||||||
: html`
|
: html`
|
||||||
<state-history-charts
|
<state-history-charts
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -135,24 +212,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
</state-history-charts>
|
</state-history-charts>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
${this._isLoading
|
|
||||||
? html`<div class="progress-wrapper">
|
|
||||||
<ha-circular-progress
|
|
||||||
active
|
|
||||||
alt=${this.hass.localize("ui.common.loading")}
|
|
||||||
></ha-circular-progress>
|
|
||||||
</div>`
|
|
||||||
: html`
|
|
||||||
<state-history-charts
|
|
||||||
virtualize
|
|
||||||
.hass=${this.hass}
|
|
||||||
.historyData=${this._stateHistory}
|
|
||||||
.endTime=${this._endDate}
|
|
||||||
.narrow=${this.narrow}
|
|
||||||
no-single
|
|
||||||
>
|
|
||||||
</state-history-charts>
|
|
||||||
`}
|
|
||||||
</ha-app-layout>
|
</ha-app-layout>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -211,15 +270,13 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
this.rtl = computeRTL(this.hass);
|
this.rtl = computeRTL(this.hass);
|
||||||
}
|
}
|
||||||
if (this._entities) {
|
if (this._entities) {
|
||||||
const stateEntities: EntityRegistryEntry[] = [];
|
const stateEntities: { [entityId: string]: EntityRegistryEntry } = {};
|
||||||
const regEntityIds = new Set(
|
const regEntityIds = new Set(Object.keys(this._entities));
|
||||||
this._entities.map((entity) => entity.entity_id)
|
|
||||||
);
|
|
||||||
for (const entityId of Object.keys(this.hass.states)) {
|
for (const entityId of Object.keys(this.hass.states)) {
|
||||||
if (regEntityIds.has(entityId)) {
|
if (regEntityIds.has(entityId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
stateEntities.push({
|
stateEntities[entityId] = {
|
||||||
name: computeStateName(this.hass.states[entityId]),
|
name: computeStateName(this.hass.states[entityId]),
|
||||||
entity_id: entityId,
|
entity_id: entityId,
|
||||||
platform: computeDomain(entityId),
|
platform: computeDomain(entityId),
|
||||||
@ -230,13 +287,23 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
device_id: null,
|
device_id: null,
|
||||||
icon: null,
|
icon: null,
|
||||||
entity_category: null,
|
entity_category: null,
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
this._stateEntities = stateEntities;
|
this._stateEntities = stateEntities;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _showAll() {
|
||||||
|
this._targetPickerValue = { entity_id: Object.keys(this._entities ?? {}) };
|
||||||
|
this._getHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _removeAll() {
|
||||||
|
this._targetPickerValue = undefined;
|
||||||
|
this._getHistory();
|
||||||
|
}
|
||||||
|
|
||||||
private _refreshHistory() {
|
private _refreshHistory() {
|
||||||
this._getHistory();
|
this._getHistory();
|
||||||
}
|
}
|
||||||
@ -261,50 +328,75 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
this._isLoading = false;
|
this._isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _filterEntity(entity: EntityRegistryEntry): boolean {
|
|
||||||
const { area_id, device_id, entity_id } = this._targetPickerValue;
|
|
||||||
if (area_id !== undefined) {
|
|
||||||
if (typeof area_id === "string" && area_id === entity.area_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Array.isArray(area_id) && area_id.includes(entity.area_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (device_id !== undefined) {
|
|
||||||
if (typeof device_id === "string" && device_id === entity.device_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Array.isArray(device_id) && device_id.includes(entity.device_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (entity_id !== undefined) {
|
|
||||||
if (typeof entity_id === "string" && entity_id === entity.entity_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Array.isArray(entity_id) && entity_id.includes(entity.entity_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getEntityIds(): string[] {
|
private _getEntityIds(): string[] {
|
||||||
if (
|
if (
|
||||||
this._targetPickerValue === undefined ||
|
this._targetPickerValue === undefined ||
|
||||||
this._entities === undefined ||
|
this._entities === undefined ||
|
||||||
this._stateEntities === undefined
|
this._stateEntities === undefined ||
|
||||||
|
this._devices === undefined ||
|
||||||
|
this._deviceIdToEntities === undefined ||
|
||||||
|
this._areaIdToEntities === undefined ||
|
||||||
|
this._areaIdToDevices === undefined
|
||||||
) {
|
) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const entityIds = this._entities
|
const entityIds = new Set<string>();
|
||||||
.filter((entity) => this._filterEntity(entity))
|
let {
|
||||||
.map((entity) => entity.entity_id);
|
area_id: searchingAreaId,
|
||||||
const stateEntityIds = this._stateEntities
|
device_id: searchingDeviceId,
|
||||||
.filter((entity) => this._filterEntity(entity))
|
entity_id: searchingEntityId,
|
||||||
.map((entity) => entity.entity_id);
|
} = this._targetPickerValue;
|
||||||
return [...entityIds, ...stateEntityIds];
|
if (searchingAreaId !== undefined) {
|
||||||
|
if (typeof searchingAreaId === "string") {
|
||||||
|
searchingAreaId = [searchingAreaId];
|
||||||
|
}
|
||||||
|
for (const singleSearchingAreaId of searchingAreaId) {
|
||||||
|
const foundEntities = this._areaIdToEntities[singleSearchingAreaId];
|
||||||
|
if (foundEntities !== undefined) {
|
||||||
|
for (const foundEntity of foundEntities) {
|
||||||
|
entityIds.add(foundEntity.entity_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const foundDevices = this._areaIdToDevices[singleSearchingAreaId];
|
||||||
|
if (foundDevices !== undefined) {
|
||||||
|
for (const foundDevice of foundDevices) {
|
||||||
|
const foundDeviceEntities =
|
||||||
|
this._deviceIdToEntities[foundDevice.id];
|
||||||
|
for (const foundDeviceEntity of foundDeviceEntities) {
|
||||||
|
if (
|
||||||
|
foundDeviceEntity.area_id === undefined ||
|
||||||
|
foundDeviceEntity.area_id === null ||
|
||||||
|
foundDeviceEntity.area_id === singleSearchingAreaId
|
||||||
|
) {
|
||||||
|
entityIds.add(foundDeviceEntity.entity_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (searchingDeviceId !== undefined) {
|
||||||
|
if (typeof searchingDeviceId === "string") {
|
||||||
|
searchingDeviceId = [searchingDeviceId];
|
||||||
|
}
|
||||||
|
for (const singleSearchingDeviceId of searchingDeviceId) {
|
||||||
|
const foundEntities = this._deviceIdToEntities[singleSearchingDeviceId];
|
||||||
|
if (foundEntities !== undefined) {
|
||||||
|
for (const foundEntity of foundEntities) {
|
||||||
|
entityIds.add(foundEntity.entity_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (searchingEntityId !== undefined) {
|
||||||
|
if (typeof searchingEntityId === "string") {
|
||||||
|
searchingEntityId = [searchingEntityId];
|
||||||
|
}
|
||||||
|
for (const singleSearchingEntityId of searchingEntityId) {
|
||||||
|
entityIds.add(singleSearchingEntityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...entityIds];
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dateRangeChanged(ev) {
|
private _dateRangeChanged(ev) {
|
||||||
@ -389,7 +481,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-start;
|
||||||
padding: 8px 16px 0;
|
padding: 8px 16px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,6 +489,12 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
text-align: center;
|
||||||
|
line-height: 60px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
ha-date-range-picker {
|
ha-date-range-picker {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
margin-inline-end: 16px;
|
margin-inline-end: 16px;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user