mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-09 10:26:35 +00:00
parent
23b55484c3
commit
253c8f358b
@ -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 { ensureArray } from "../common/array/ensure-array";
|
||||||
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||||
import { supportsFeature } from "../common/entity/supports-feature";
|
import { supportsFeature } from "../common/entity/supports-feature";
|
||||||
@ -871,3 +874,65 @@ export const computeCreateDomains = (
|
|||||||
|
|
||||||
return [...new Set(createDomains)];
|
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);
|
||||||
|
};
|
||||||
|
@ -50,12 +50,7 @@ import {
|
|||||||
} from "../../data/history";
|
} from "../../data/history";
|
||||||
import type { Statistics } from "../../data/recorder";
|
import type { Statistics } from "../../data/recorder";
|
||||||
import { fetchStatistics } from "../../data/recorder";
|
import { fetchStatistics } from "../../data/recorder";
|
||||||
import {
|
import { resolveEntityIDs } from "../../data/selector";
|
||||||
expandAreaTarget,
|
|
||||||
expandDeviceTarget,
|
|
||||||
expandFloorTarget,
|
|
||||||
expandLabelTarget,
|
|
||||||
} from "../../data/selector";
|
|
||||||
import { getSensorNumericDeviceClasses } from "../../data/sensor";
|
import { getSensorNumericDeviceClasses } from "../../data/sensor";
|
||||||
import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
|
import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
|
||||||
import { haStyle } from "../../resources/styles";
|
import { haStyle } from "../../resources/styles";
|
||||||
@ -543,66 +538,8 @@ class HaPanelHistory extends LitElement {
|
|||||||
entities: HomeAssistant["entities"],
|
entities: HomeAssistant["entities"],
|
||||||
devices: HomeAssistant["devices"],
|
devices: HomeAssistant["devices"],
|
||||||
areas: HomeAssistant["areas"]
|
areas: HomeAssistant["areas"]
|
||||||
): string[] => {
|
): string[] =>
|
||||||
if (!targetPickerValue) {
|
resolveEntityIDs(this.hass, targetPickerValue, entities, devices, areas)
|
||||||
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);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
private _dateRangeChanged(ev) {
|
private _dateRangeChanged(ev) {
|
||||||
|
@ -2,6 +2,8 @@ import { mdiRefresh } from "@mdi/js";
|
|||||||
import type { PropertyValues } from "lit";
|
import type { PropertyValues } from "lit";
|
||||||
import { css, html, LitElement } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
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 { navigate } from "../../common/navigate";
|
||||||
import { constructUrlCurrentPath } from "../../common/url/construct-url";
|
import { constructUrlCurrentPath } from "../../common/url/construct-url";
|
||||||
import {
|
import {
|
||||||
@ -15,10 +17,14 @@ import "../../components/ha-icon-button";
|
|||||||
import "../../components/ha-icon-button-arrow-prev";
|
import "../../components/ha-icon-button-arrow-prev";
|
||||||
import "../../components/ha-menu-button";
|
import "../../components/ha-menu-button";
|
||||||
import "../../components/ha-top-app-bar-fixed";
|
import "../../components/ha-top-app-bar-fixed";
|
||||||
|
import "../../components/ha-target-picker";
|
||||||
import { filterLogbookCompatibleEntities } from "../../data/logbook";
|
import { filterLogbookCompatibleEntities } from "../../data/logbook";
|
||||||
import { haStyle } from "../../resources/styles";
|
import { haStyle } from "../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import "./ha-logbook";
|
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")
|
@customElement("ha-panel-logbook")
|
||||||
export class HaPanelLogbook extends LitElement {
|
export class HaPanelLogbook extends LitElement {
|
||||||
@ -33,6 +39,13 @@ export class HaPanelLogbook extends LitElement {
|
|||||||
@state()
|
@state()
|
||||||
private _showBack?: boolean;
|
private _showBack?: boolean;
|
||||||
|
|
||||||
|
@storage({
|
||||||
|
key: "logbookPickedValue",
|
||||||
|
state: true,
|
||||||
|
subscribe: false,
|
||||||
|
})
|
||||||
|
private _targetPickerValue: HassServiceTarget = {};
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -82,21 +95,19 @@ export class HaPanelLogbook extends LitElement {
|
|||||||
@change=${this._dateRangeChanged}
|
@change=${this._dateRangeChanged}
|
||||||
></ha-date-range-picker>
|
></ha-date-range-picker>
|
||||||
|
|
||||||
<ha-entity-picker
|
<ha-target-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.value=${this._entityIds ? this._entityIds[0] : undefined}
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.components.entity.entity-picker.entity"
|
|
||||||
)}
|
|
||||||
.entityFilter=${filterLogbookCompatibleEntities}
|
.entityFilter=${filterLogbookCompatibleEntities}
|
||||||
@change=${this._entityPicked}
|
.value=${this._targetPickerValue}
|
||||||
></ha-entity-picker>
|
addOnTop
|
||||||
|
@value-changed=${this._targetsChanged}
|
||||||
|
></ha-target-picker>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ha-logbook
|
<ha-logbook
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.time=${this._time}
|
.time=${this._time}
|
||||||
.entityIds=${this._entityIds}
|
.entityIds=${this._getEntityIds()}
|
||||||
virtualize
|
virtualize
|
||||||
></ha-logbook>
|
></ha-logbook>
|
||||||
</ha-top-app-bar-fixed>
|
</ha-top-app-bar-fixed>
|
||||||
@ -140,32 +151,62 @@ export class HaPanelLogbook extends LitElement {
|
|||||||
this._applyURLParams();
|
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() {
|
private _applyURLParams() {
|
||||||
const searchParams = new URLSearchParams(location.search);
|
const searchParams = extractSearchParamsObject();
|
||||||
|
const entityIds = searchParams.entity_id;
|
||||||
if (searchParams.has("entity_id")) {
|
const deviceIds = searchParams.device_id;
|
||||||
const entityIdsRaw = searchParams.get("entity_id");
|
const areaIds = searchParams.area_id;
|
||||||
|
const floorIds = searchParams.floor_id;
|
||||||
if (!entityIdsRaw) {
|
const labelsIds = searchParams.label_id;
|
||||||
this._entityIds = undefined;
|
if (entityIds || deviceIds || areaIds || floorIds || labelsIds) {
|
||||||
} else {
|
this._targetPickerValue = {};
|
||||||
const entityIds = entityIdsRaw.split(",").sort();
|
}
|
||||||
|
if (entityIds) {
|
||||||
// Check if different
|
const splitIds = entityIds.split(",");
|
||||||
if (
|
this._targetPickerValue!.entity_id = splitIds;
|
||||||
!this._entityIds ||
|
}
|
||||||
entityIds.length !== this._entityIds.length ||
|
if (deviceIds) {
|
||||||
!this._entityIds.every((val, idx) => val === entityIds[idx])
|
const splitIds = deviceIds.split(",");
|
||||||
) {
|
this._targetPickerValue!.device_id = splitIds;
|
||||||
this._entityIds = entityIds;
|
}
|
||||||
}
|
if (areaIds) {
|
||||||
}
|
const splitIds = areaIds.split(",");
|
||||||
} else {
|
this._targetPickerValue!.area_id = splitIds;
|
||||||
this._entityIds = undefined;
|
}
|
||||||
|
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 startDateStr = searchParams.start_date;
|
||||||
const endDateStr = searchParams.get("end_date");
|
const endDateStr = searchParams.end_date;
|
||||||
|
|
||||||
if (startDateStr || endDateStr) {
|
if (startDateStr || endDateStr) {
|
||||||
const startDate = startDateStr
|
const startDate = startDateStr
|
||||||
@ -195,27 +236,48 @@ export class HaPanelLogbook extends LitElement {
|
|||||||
endDate.setDate(endDate.getDate() + 1);
|
endDate.setDate(endDate.getDate() + 1);
|
||||||
endDate.setMilliseconds(endDate.getMilliseconds() - 1);
|
endDate.setMilliseconds(endDate.getMilliseconds() - 1);
|
||||||
}
|
}
|
||||||
this._updatePath({
|
this._time = {
|
||||||
start_date: startDate.toISOString(),
|
range: [startDate, endDate],
|
||||||
end_date: endDate.toISOString(),
|
};
|
||||||
});
|
this._updatePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _entityPicked(ev) {
|
private _targetsChanged(ev) {
|
||||||
this._updatePath({
|
this._targetPickerValue = ev.detail.value || {};
|
||||||
entity_id: ev.target.value || undefined,
|
this._updatePath();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updatePath(update: Record<string, string | undefined>) {
|
private _updatePath() {
|
||||||
const params = extractSearchParamsObject();
|
const params: Record<string, string> = {};
|
||||||
for (const [key, value] of Object.entries(update)) {
|
|
||||||
if (value === undefined) {
|
if (this._targetPickerValue.entity_id) {
|
||||||
delete params[key];
|
params.entity_id = ensureArray(this._targetPickerValue.entity_id).join(
|
||||||
} else {
|
","
|
||||||
params[key] = value;
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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 });
|
navigate(`/logbook?${createSearchParam(params)}`, { replace: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user