diff --git a/src/data/selector.ts b/src/data/selector.ts index c72dacc4f1..5623ecc268 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -1,4 +1,7 @@ -import type { HassEntity } from "home-assistant-js-websocket"; +import type { + HassEntity, + HassServiceTarget, +} from "home-assistant-js-websocket"; import { ensureArray } from "../common/array/ensure-array"; import { computeStateDomain } from "../common/entity/compute_state_domain"; import { supportsFeature } from "../common/entity/supports-feature"; @@ -871,3 +874,65 @@ export const computeCreateDomains = ( return [...new Set(createDomains)]; }; + +export const resolveEntityIDs = ( + hass: HomeAssistant, + targetPickerValue: HassServiceTarget, + entities: HomeAssistant["entities"], + devices: HomeAssistant["devices"], + areas: HomeAssistant["areas"] +): string[] => { + if (!targetPickerValue) { + return []; + } + + const targetSelector = { target: {} }; + const targetEntities = new Set(ensureArray(targetPickerValue.entity_id)); + const targetDevices = new Set(ensureArray(targetPickerValue.device_id)); + const targetAreas = new Set(ensureArray(targetPickerValue.area_id)); + const targetFloors = new Set(ensureArray(targetPickerValue.floor_id)); + const targetLabels = new Set(ensureArray(targetPickerValue.label_id)); + + targetLabels.forEach((labelId) => { + const expanded = expandLabelTarget( + hass, + labelId, + areas, + devices, + entities, + targetSelector + ); + expanded.devices.forEach((id) => targetDevices.add(id)); + expanded.entities.forEach((id) => targetEntities.add(id)); + expanded.areas.forEach((id) => targetAreas.add(id)); + }); + + targetFloors.forEach((floorId) => { + const expanded = expandFloorTarget(hass, floorId, areas, targetSelector); + expanded.areas.forEach((id) => targetAreas.add(id)); + }); + + targetAreas.forEach((areaId) => { + const expanded = expandAreaTarget( + hass, + areaId, + devices, + entities, + targetSelector + ); + expanded.devices.forEach((id) => targetDevices.add(id)); + expanded.entities.forEach((id) => targetEntities.add(id)); + }); + + targetDevices.forEach((deviceId) => { + const expanded = expandDeviceTarget( + hass, + deviceId, + entities, + targetSelector + ); + expanded.entities.forEach((id) => targetEntities.add(id)); + }); + + return Array.from(targetEntities); +}; diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts index c167c48da1..39ff903a0c 100644 --- a/src/panels/history/ha-panel-history.ts +++ b/src/panels/history/ha-panel-history.ts @@ -50,12 +50,7 @@ import { } from "../../data/history"; import type { Statistics } from "../../data/recorder"; import { fetchStatistics } from "../../data/recorder"; -import { - expandAreaTarget, - expandDeviceTarget, - expandFloorTarget, - expandLabelTarget, -} from "../../data/selector"; +import { resolveEntityIDs } from "../../data/selector"; import { getSensorNumericDeviceClasses } from "../../data/sensor"; import { showAlertDialog } from "../../dialogs/generic/show-dialog-box"; import { haStyle } from "../../resources/styles"; @@ -543,66 +538,8 @@ class HaPanelHistory extends LitElement { entities: HomeAssistant["entities"], devices: HomeAssistant["devices"], areas: HomeAssistant["areas"] - ): string[] => { - if (!targetPickerValue) { - return []; - } - - const targetSelector = { target: {} }; - const targetEntities = new Set(ensureArray(targetPickerValue.entity_id)); - const targetDevices = new Set(ensureArray(targetPickerValue.device_id)); - const targetAreas = new Set(ensureArray(targetPickerValue.area_id)); - const targetFloors = new Set(ensureArray(targetPickerValue.floor_id)); - const targetLabels = new Set(ensureArray(targetPickerValue.label_id)); - - targetLabels.forEach((labelId) => { - const expanded = expandLabelTarget( - this.hass, - labelId, - areas, - devices, - entities, - targetSelector - ); - expanded.devices.forEach((id) => targetDevices.add(id)); - expanded.entities.forEach((id) => targetEntities.add(id)); - expanded.areas.forEach((id) => targetAreas.add(id)); - }); - - targetFloors.forEach((floorId) => { - const expanded = expandFloorTarget( - this.hass, - floorId, - areas, - targetSelector - ); - expanded.areas.forEach((id) => targetAreas.add(id)); - }); - - targetAreas.forEach((areaId) => { - const expanded = expandAreaTarget( - this.hass, - areaId, - devices, - entities, - targetSelector - ); - expanded.devices.forEach((id) => targetDevices.add(id)); - expanded.entities.forEach((id) => targetEntities.add(id)); - }); - - targetDevices.forEach((deviceId) => { - const expanded = expandDeviceTarget( - this.hass, - deviceId, - entities, - targetSelector - ); - expanded.entities.forEach((id) => targetEntities.add(id)); - }); - - return Array.from(targetEntities); - } + ): string[] => + resolveEntityIDs(this.hass, targetPickerValue, entities, devices, areas) ); private _dateRangeChanged(ev) { diff --git a/src/panels/logbook/ha-panel-logbook.ts b/src/panels/logbook/ha-panel-logbook.ts index 54c9f9b022..a69adc24a6 100644 --- a/src/panels/logbook/ha-panel-logbook.ts +++ b/src/panels/logbook/ha-panel-logbook.ts @@ -2,6 +2,8 @@ import { mdiRefresh } from "@mdi/js"; import type { PropertyValues } from "lit"; import { css, html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators"; +import type { HassServiceTarget } from "home-assistant-js-websocket"; +import memoizeOne from "memoize-one"; import { navigate } from "../../common/navigate"; import { constructUrlCurrentPath } from "../../common/url/construct-url"; import { @@ -15,10 +17,14 @@ import "../../components/ha-icon-button"; import "../../components/ha-icon-button-arrow-prev"; import "../../components/ha-menu-button"; import "../../components/ha-top-app-bar-fixed"; +import "../../components/ha-target-picker"; import { filterLogbookCompatibleEntities } from "../../data/logbook"; import { haStyle } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; import "./ha-logbook"; +import { storage } from "../../common/decorators/storage"; +import { ensureArray } from "../../common/array/ensure-array"; +import { resolveEntityIDs } from "../../data/selector"; @customElement("ha-panel-logbook") export class HaPanelLogbook extends LitElement { @@ -33,6 +39,13 @@ export class HaPanelLogbook extends LitElement { @state() private _showBack?: boolean; + @storage({ + key: "logbookPickedValue", + state: true, + subscribe: false, + }) + private _targetPickerValue: HassServiceTarget = {}; + public constructor() { super(); @@ -82,21 +95,19 @@ export class HaPanelLogbook extends LitElement { @change=${this._dateRangeChanged} > - + .value=${this._targetPickerValue} + addOnTop + @value-changed=${this._targetsChanged} + > @@ -140,32 +151,62 @@ export class HaPanelLogbook extends LitElement { this._applyURLParams(); }; + private _getEntityIds(): string[] | undefined { + const entities = this.__getEntityIds( + this._targetPickerValue, + this.hass.entities, + this.hass.devices, + this.hass.areas + ); + if (entities.length === 0) { + return undefined; + } + return entities; + } + + private __getEntityIds = memoizeOne( + ( + targetPickerValue: HassServiceTarget, + entities: HomeAssistant["entities"], + devices: HomeAssistant["devices"], + areas: HomeAssistant["areas"] + ): string[] => + resolveEntityIDs(this.hass, targetPickerValue, entities, devices, areas) + ); + private _applyURLParams() { - const searchParams = new URLSearchParams(location.search); - - if (searchParams.has("entity_id")) { - const entityIdsRaw = searchParams.get("entity_id"); - - if (!entityIdsRaw) { - this._entityIds = undefined; - } else { - const entityIds = entityIdsRaw.split(",").sort(); - - // Check if different - if ( - !this._entityIds || - entityIds.length !== this._entityIds.length || - !this._entityIds.every((val, idx) => val === entityIds[idx]) - ) { - this._entityIds = entityIds; - } - } - } else { - this._entityIds = undefined; + const searchParams = extractSearchParamsObject(); + const entityIds = searchParams.entity_id; + const deviceIds = searchParams.device_id; + const areaIds = searchParams.area_id; + const floorIds = searchParams.floor_id; + const labelsIds = searchParams.label_id; + if (entityIds || deviceIds || areaIds || floorIds || labelsIds) { + this._targetPickerValue = {}; + } + if (entityIds) { + const splitIds = entityIds.split(","); + this._targetPickerValue!.entity_id = splitIds; + } + if (deviceIds) { + const splitIds = deviceIds.split(","); + this._targetPickerValue!.device_id = splitIds; + } + if (areaIds) { + const splitIds = areaIds.split(","); + this._targetPickerValue!.area_id = splitIds; + } + if (floorIds) { + const splitIds = floorIds.split(","); + this._targetPickerValue!.floor_id = splitIds; + } + if (labelsIds) { + const splitIds = labelsIds.split(","); + this._targetPickerValue!.label_id = splitIds; } - const startDateStr = searchParams.get("start_date"); - const endDateStr = searchParams.get("end_date"); + const startDateStr = searchParams.start_date; + const endDateStr = searchParams.end_date; if (startDateStr || endDateStr) { const startDate = startDateStr @@ -195,27 +236,48 @@ export class HaPanelLogbook extends LitElement { endDate.setDate(endDate.getDate() + 1); endDate.setMilliseconds(endDate.getMilliseconds() - 1); } - this._updatePath({ - start_date: startDate.toISOString(), - end_date: endDate.toISOString(), - }); + this._time = { + range: [startDate, endDate], + }; + this._updatePath(); } - private _entityPicked(ev) { - this._updatePath({ - entity_id: ev.target.value || undefined, - }); + private _targetsChanged(ev) { + this._targetPickerValue = ev.detail.value || {}; + this._updatePath(); } - private _updatePath(update: Record) { - const params = extractSearchParamsObject(); - for (const [key, value] of Object.entries(update)) { - if (value === undefined) { - delete params[key]; - } else { - params[key] = value; - } + private _updatePath() { + const params: Record = {}; + + if (this._targetPickerValue.entity_id) { + params.entity_id = ensureArray(this._targetPickerValue.entity_id).join( + "," + ); } + if (this._targetPickerValue.label_id) { + params.label_id = ensureArray(this._targetPickerValue.label_id).join(","); + } + if (this._targetPickerValue.floor_id) { + params.floor_id = ensureArray(this._targetPickerValue.floor_id).join(","); + } + if (this._targetPickerValue.area_id) { + params.area_id = ensureArray(this._targetPickerValue.area_id).join(","); + } + if (this._targetPickerValue.device_id) { + params.device_id = ensureArray(this._targetPickerValue.device_id).join( + "," + ); + } + + if (this._time.range[0]) { + params.start_date = this._time.range[0].toISOString(); + } + + if (this._time.range[1]) { + params.end_date = this._time.range[1].toISOString(); + } + navigate(`/logbook?${createSearchParam(params)}`, { replace: true }); }