mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-25 22:07:20 +00:00
Pass device ID to logbook if available (#12728)
This commit is contained in:
parent
1f105b6c15
commit
bfeb90780f
@ -56,17 +56,28 @@ export const getLogbookData = async (
|
||||
hass: HomeAssistant,
|
||||
startDate: string,
|
||||
endDate: string,
|
||||
entityId?: string
|
||||
entityIds?: string[],
|
||||
deviceIds?: string[]
|
||||
): Promise<LogbookEntry[]> => {
|
||||
const localize = await hass.loadBackendTranslation("device_class");
|
||||
return addLogbookMessage(
|
||||
hass,
|
||||
localize,
|
||||
await getLogbookDataCache(hass, startDate, endDate, entityId)
|
||||
// bypass cache if we have a device ID
|
||||
deviceIds?.length
|
||||
? await getLogbookDataFromServer(
|
||||
hass,
|
||||
startDate,
|
||||
endDate,
|
||||
entityIds,
|
||||
undefined,
|
||||
deviceIds
|
||||
)
|
||||
: await getLogbookDataCache(hass, startDate, endDate, entityIds)
|
||||
);
|
||||
};
|
||||
|
||||
export const addLogbookMessage = (
|
||||
const addLogbookMessage = (
|
||||
hass: HomeAssistant,
|
||||
localize: LocalizeFunc,
|
||||
logbookData: LogbookEntry[]
|
||||
@ -86,60 +97,73 @@ export const addLogbookMessage = (
|
||||
return logbookData;
|
||||
};
|
||||
|
||||
export const getLogbookDataCache = async (
|
||||
const getLogbookDataCache = async (
|
||||
hass: HomeAssistant,
|
||||
startDate: string,
|
||||
endDate: string,
|
||||
entityId?: string
|
||||
entityId?: string[]
|
||||
) => {
|
||||
const ALL_ENTITIES = "*";
|
||||
|
||||
if (!entityId) {
|
||||
entityId = ALL_ENTITIES;
|
||||
}
|
||||
|
||||
const entityIdKey = entityId ? entityId.toString() : ALL_ENTITIES;
|
||||
const cacheKey = `${startDate}${endDate}`;
|
||||
|
||||
if (!DATA_CACHE[cacheKey]) {
|
||||
DATA_CACHE[cacheKey] = {};
|
||||
}
|
||||
|
||||
if (entityId in DATA_CACHE[cacheKey]) {
|
||||
return DATA_CACHE[cacheKey][entityId];
|
||||
if (entityIdKey in DATA_CACHE[cacheKey]) {
|
||||
return DATA_CACHE[cacheKey][entityIdKey];
|
||||
}
|
||||
|
||||
if (entityId !== ALL_ENTITIES && DATA_CACHE[cacheKey][ALL_ENTITIES]) {
|
||||
if (entityId && DATA_CACHE[cacheKey][ALL_ENTITIES]) {
|
||||
const entities = await DATA_CACHE[cacheKey][ALL_ENTITIES];
|
||||
return entities.filter((entity) => entity.entity_id === entityId);
|
||||
return entities.filter(
|
||||
(entity) => entity.entity_id && entityId.includes(entity.entity_id)
|
||||
);
|
||||
}
|
||||
|
||||
DATA_CACHE[cacheKey][entityId] = getLogbookDataFromServer(
|
||||
DATA_CACHE[cacheKey][entityIdKey] = getLogbookDataFromServer(
|
||||
hass,
|
||||
startDate,
|
||||
endDate,
|
||||
entityId !== ALL_ENTITIES ? entityId : undefined
|
||||
).then((entries) => entries.reverse());
|
||||
return DATA_CACHE[cacheKey][entityId];
|
||||
entityId
|
||||
);
|
||||
return DATA_CACHE[cacheKey][entityIdKey];
|
||||
};
|
||||
|
||||
export const getLogbookDataFromServer = (
|
||||
const getLogbookDataFromServer = (
|
||||
hass: HomeAssistant,
|
||||
startDate: string,
|
||||
endDate?: string,
|
||||
entityId?: string,
|
||||
contextId?: string
|
||||
) => {
|
||||
let params: any = {
|
||||
entityIds?: string[],
|
||||
contextId?: string,
|
||||
deviceIds?: string[]
|
||||
): Promise<LogbookEntry[]> => {
|
||||
// If all specified filters are empty lists, we can return an empty list.
|
||||
if (
|
||||
(entityIds || deviceIds) &&
|
||||
(!entityIds || entityIds.length === 0) &&
|
||||
(!deviceIds || deviceIds.length === 0)
|
||||
) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
const params: any = {
|
||||
type: "logbook/get_events",
|
||||
start_time: startDate,
|
||||
};
|
||||
if (endDate) {
|
||||
params = { ...params, end_time: endDate };
|
||||
params.end_time = endDate;
|
||||
}
|
||||
if (entityId) {
|
||||
params = { ...params, entity_ids: entityId.split(",") };
|
||||
} else if (contextId) {
|
||||
params = { ...params, context_id: contextId };
|
||||
if (entityIds?.length) {
|
||||
params.entity_ids = entityIds;
|
||||
}
|
||||
if (deviceIds?.length) {
|
||||
params.device_ids = deviceIds;
|
||||
}
|
||||
if (contextId) {
|
||||
params.context_id = contextId;
|
||||
}
|
||||
return hass.callWS<LogbookEntry[]>(params);
|
||||
};
|
||||
@ -148,7 +172,7 @@ export const clearLogbookCache = (startDate: string, endDate: string) => {
|
||||
DATA_CACHE[`${startDate}${endDate}`] = {};
|
||||
};
|
||||
|
||||
export const getLogbookMessage = (
|
||||
const getLogbookMessage = (
|
||||
hass: HomeAssistant,
|
||||
localize: LocalizeFunc,
|
||||
state: string,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { startOfYesterday } from "date-fns/esm";
|
||||
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import "../../panels/logbook/ha-logbook";
|
||||
@ -16,6 +17,8 @@ export class MoreInfoLogbook extends LitElement {
|
||||
|
||||
private _time = { recent: 86400 };
|
||||
|
||||
private _entityIdAsList = memoizeOne((entityId: string) => [entityId]);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!isComponentLoaded(this.hass, "logbook") || !this.entityId) {
|
||||
return html``;
|
||||
@ -38,7 +41,7 @@ export class MoreInfoLogbook extends LitElement {
|
||||
<ha-logbook
|
||||
.hass=${this.hass}
|
||||
.time=${this._time}
|
||||
.entityId=${this.entityId}
|
||||
.entityIds=${this._entityIdAsList(this.entityId)}
|
||||
narrow
|
||||
no-icon
|
||||
no-name
|
||||
|
@ -2,7 +2,10 @@ import "@material/mwc-button";
|
||||
import { mdiImagePlus, mdiPencil } from "@mdi/js";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import { HassEntity } from "home-assistant-js-websocket/dist/types";
|
||||
import {
|
||||
HassEntity,
|
||||
UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket/dist/types";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
@ -20,6 +23,7 @@ import "../../logbook/ha-logbook";
|
||||
import {
|
||||
AreaRegistryEntry,
|
||||
deleteAreaRegistryEntry,
|
||||
subscribeAreaRegistry,
|
||||
updateAreaRegistryEntry,
|
||||
} from "../../../data/area_registry";
|
||||
import { AutomationEntity } from "../../../data/automation";
|
||||
@ -27,11 +31,13 @@ import {
|
||||
computeDeviceName,
|
||||
DeviceRegistryEntry,
|
||||
sortDeviceRegistryByName,
|
||||
subscribeDeviceRegistry,
|
||||
} from "../../../data/device_registry";
|
||||
import {
|
||||
computeEntityRegistryName,
|
||||
EntityRegistryEntry,
|
||||
sortEntityRegistryByName,
|
||||
subscribeEntityRegistry,
|
||||
} from "../../../data/entity_registry";
|
||||
import { SceneEntity } from "../../../data/scene";
|
||||
import { ScriptEntity } from "../../../data/script";
|
||||
@ -45,6 +51,7 @@ import {
|
||||
loadAreaRegistryDetailDialog,
|
||||
showAreaRegistryDetailDialog,
|
||||
} from "./show-dialog-area-registry-detail";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
|
||||
declare type NameAndEntity<EntityType extends HassEntity> = {
|
||||
name: string;
|
||||
@ -52,17 +59,11 @@ declare type NameAndEntity<EntityType extends HassEntity> = {
|
||||
};
|
||||
|
||||
@customElement("ha-config-area-page")
|
||||
class HaConfigAreaPage extends LitElement {
|
||||
class HaConfigAreaPage extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public areaId!: string;
|
||||
|
||||
@property() public areas!: AreaRegistryEntry[];
|
||||
|
||||
@property() public devices!: DeviceRegistryEntry[];
|
||||
|
||||
@property() public entities!: EntityRegistryEntry[];
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
|
||||
|
||||
@property() public isWide!: boolean;
|
||||
@ -71,6 +72,12 @@ class HaConfigAreaPage extends LitElement {
|
||||
|
||||
@property() public route!: Route;
|
||||
|
||||
@state() public _areas!: AreaRegistryEntry[];
|
||||
|
||||
@state() public _devices!: DeviceRegistryEntry[];
|
||||
|
||||
@state() public _entities!: EntityRegistryEntry[];
|
||||
|
||||
@state() private _related?: RelatedResult;
|
||||
|
||||
private _logbookTime = { recent: 86400 };
|
||||
@ -89,7 +96,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
registryDevices: DeviceRegistryEntry[],
|
||||
registryEntities: EntityRegistryEntry[]
|
||||
) => {
|
||||
const devices = new Map();
|
||||
const devices = new Map<string, DeviceRegistryEntry>();
|
||||
|
||||
for (const device of registryDevices) {
|
||||
if (device.area_id === areaId) {
|
||||
@ -105,7 +112,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
if (entity.area_id === areaId) {
|
||||
entities.push(entity);
|
||||
}
|
||||
} else if (devices.has(entity.device_id)) {
|
||||
} else if (entity.device_id && devices.has(entity.device_id)) {
|
||||
indirectEntities.push(entity);
|
||||
}
|
||||
}
|
||||
@ -118,6 +125,10 @@ class HaConfigAreaPage extends LitElement {
|
||||
}
|
||||
);
|
||||
|
||||
private _allDeviceIds = memoizeOne((devices: DeviceRegistryEntry[]) =>
|
||||
devices.map((device) => device.id)
|
||||
);
|
||||
|
||||
private _allEntities = memoizeOne(
|
||||
(memberships: {
|
||||
entities: EntityRegistryEntry[];
|
||||
@ -140,8 +151,26 @@ class HaConfigAreaPage extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
|
||||
return [
|
||||
subscribeAreaRegistry(this.hass.connection, (areas) => {
|
||||
this._areas = areas;
|
||||
}),
|
||||
subscribeDeviceRegistry(this.hass.connection, (entries) => {
|
||||
this._devices = entries;
|
||||
}),
|
||||
subscribeEntityRegistry(this.hass.connection, (entries) => {
|
||||
this._entities = entries;
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const area = this._area(this.areaId, this.areas);
|
||||
if (!this._areas || !this._devices || !this._entities) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const area = this._area(this.areaId, this._areas);
|
||||
|
||||
if (!area) {
|
||||
return html`
|
||||
@ -154,8 +183,8 @@ class HaConfigAreaPage extends LitElement {
|
||||
|
||||
const memberships = this._memberships(
|
||||
this.areaId,
|
||||
this.devices,
|
||||
this.entities
|
||||
this._devices,
|
||||
this._entities
|
||||
);
|
||||
const { devices, entities } = memberships;
|
||||
|
||||
@ -465,6 +494,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
.hass=${this.hass}
|
||||
.time=${this._logbookTime}
|
||||
.entityIds=${this._allEntities(memberships)}
|
||||
.deviceIds=${this._allDeviceIds(memberships.devices)}
|
||||
virtualize
|
||||
narrow
|
||||
no-icon
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { mdiHelpCircle, mdiPlus } from "@mdi/js";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import "../../../components/ha-fab";
|
||||
@ -9,12 +10,20 @@ import "../../../components/ha-svg-icon";
|
||||
import {
|
||||
AreaRegistryEntry,
|
||||
createAreaRegistryEntry,
|
||||
subscribeAreaRegistry,
|
||||
} from "../../../data/area_registry";
|
||||
import type { DeviceRegistryEntry } from "../../../data/device_registry";
|
||||
import type { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||
import {
|
||||
DeviceRegistryEntry,
|
||||
subscribeDeviceRegistry,
|
||||
} from "../../../data/device_registry";
|
||||
import {
|
||||
EntityRegistryEntry,
|
||||
subscribeEntityRegistry,
|
||||
} from "../../../data/entity_registry";
|
||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import "../../../layouts/hass-loading-screen";
|
||||
import "../../../layouts/hass-tabs-subpage";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { HomeAssistant, Route } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
@ -24,7 +33,7 @@ import {
|
||||
} from "./show-dialog-area-registry-detail";
|
||||
|
||||
@customElement("ha-config-areas-dashboard")
|
||||
export class HaConfigAreasDashboard extends LitElement {
|
||||
export class HaConfigAreasDashboard extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public isWide?: boolean;
|
||||
@ -33,13 +42,13 @@ export class HaConfigAreasDashboard extends LitElement {
|
||||
|
||||
@property() public route!: Route;
|
||||
|
||||
@property() public areas!: AreaRegistryEntry[];
|
||||
@state() private _areas!: AreaRegistryEntry[];
|
||||
|
||||
@property() public devices!: DeviceRegistryEntry[];
|
||||
@state() private _devices!: DeviceRegistryEntry[];
|
||||
|
||||
@property() public entities!: EntityRegistryEntry[];
|
||||
@state() private _entities!: EntityRegistryEntry[];
|
||||
|
||||
private _areas = memoizeOne(
|
||||
private _processAreas = memoizeOne(
|
||||
(
|
||||
areas: AreaRegistryEntry[],
|
||||
devices: DeviceRegistryEntry[],
|
||||
@ -75,6 +84,20 @@ export class HaConfigAreasDashboard extends LitElement {
|
||||
})
|
||||
);
|
||||
|
||||
protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
|
||||
return [
|
||||
subscribeAreaRegistry(this.hass.connection, (areas) => {
|
||||
this._areas = areas;
|
||||
}),
|
||||
subscribeDeviceRegistry(this.hass.connection, (entries) => {
|
||||
this._devices = entries;
|
||||
}),
|
||||
subscribeEntityRegistry(this.hass.connection, (entries) => {
|
||||
this._entities = entries;
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
@ -92,56 +115,62 @@ export class HaConfigAreasDashboard extends LitElement {
|
||||
@click=${this._showHelp}
|
||||
></ha-icon-button>
|
||||
<div class="container">
|
||||
${this._areas(this.areas, this.devices, this.entities).map(
|
||||
(area) =>
|
||||
html`<a href=${`/config/areas/area/${area.area_id}`}
|
||||
><ha-card outlined>
|
||||
<div
|
||||
style=${styleMap({
|
||||
backgroundImage: area.picture
|
||||
? `url(${area.picture})`
|
||||
: undefined,
|
||||
})}
|
||||
class="picture ${!area.picture ? "placeholder" : ""}"
|
||||
></div>
|
||||
<h1 class="card-header">${area.name}</h1>
|
||||
<div class="card-content">
|
||||
<div>
|
||||
${area.devices
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.devices",
|
||||
"count",
|
||||
area.devices
|
||||
)}${area.services ? "," : ""}
|
||||
`
|
||||
: ""}
|
||||
${area.services
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.services",
|
||||
"count",
|
||||
area.services
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
${(area.devices || area.services) && area.entities
|
||||
? this.hass.localize("ui.common.and")
|
||||
: ""}
|
||||
${area.entities
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.entities",
|
||||
"count",
|
||||
area.entities
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
</ha-card></a
|
||||
>`
|
||||
)}
|
||||
${!this._areas || !this._devices || !this._entities
|
||||
? ""
|
||||
: this._processAreas(
|
||||
this._areas,
|
||||
this._devices,
|
||||
this._entities
|
||||
).map(
|
||||
(area) =>
|
||||
html`<a href=${`/config/areas/area/${area.area_id}`}
|
||||
><ha-card outlined>
|
||||
<div
|
||||
style=${styleMap({
|
||||
backgroundImage: area.picture
|
||||
? `url(${area.picture})`
|
||||
: undefined,
|
||||
})}
|
||||
class="picture ${!area.picture ? "placeholder" : ""}"
|
||||
></div>
|
||||
<h1 class="card-header">${area.name}</h1>
|
||||
<div class="card-content">
|
||||
<div>
|
||||
${area.devices
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.devices",
|
||||
"count",
|
||||
area.devices
|
||||
)}${area.services ? "," : ""}
|
||||
`
|
||||
: ""}
|
||||
${area.services
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.services",
|
||||
"count",
|
||||
area.services
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
${(area.devices || area.services) && area.entities
|
||||
? this.hass.localize("ui.common.and")
|
||||
: ""}
|
||||
${area.entities
|
||||
? html`
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.entities",
|
||||
"count",
|
||||
area.entities
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
</ha-card></a
|
||||
>`
|
||||
)}
|
||||
</div>
|
||||
<ha-fab
|
||||
slot="fab"
|
||||
|
@ -1,20 +1,4 @@
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { stringCompare } from "../../../common/string/compare";
|
||||
import {
|
||||
AreaRegistryEntry,
|
||||
subscribeAreaRegistry,
|
||||
} from "../../../data/area_registry";
|
||||
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
|
||||
import {
|
||||
DeviceRegistryEntry,
|
||||
subscribeDeviceRegistry,
|
||||
} from "../../../data/device_registry";
|
||||
import {
|
||||
EntityRegistryEntry,
|
||||
subscribeEntityRegistry,
|
||||
} from "../../../data/entity_registry";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import {
|
||||
HassRouterPage,
|
||||
RouterOptions,
|
||||
@ -46,44 +30,6 @@ class HaConfigAreas extends HassRouterPage {
|
||||
},
|
||||
};
|
||||
|
||||
@state() private _configEntries: ConfigEntry[] = [];
|
||||
|
||||
@state()
|
||||
private _deviceRegistryEntries: DeviceRegistryEntry[] = [];
|
||||
|
||||
@state()
|
||||
private _entityRegistryEntries: EntityRegistryEntry[] = [];
|
||||
|
||||
@state() private _areas: AreaRegistryEntry[] = [];
|
||||
|
||||
private _unsubs?: UnsubscribeFunc[];
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
if (this._unsubs) {
|
||||
while (this._unsubs.length) {
|
||||
this._unsubs.pop()!();
|
||||
}
|
||||
this._unsubs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (!this._unsubs && changedProps.has("hass")) {
|
||||
this._loadData();
|
||||
}
|
||||
}
|
||||
|
||||
protected updatePageEl(pageEl) {
|
||||
pageEl.hass = this.hass;
|
||||
|
||||
@ -91,37 +37,11 @@ class HaConfigAreas extends HassRouterPage {
|
||||
pageEl.areaId = this.routeTail.path.substr(1);
|
||||
}
|
||||
|
||||
pageEl.entries = this._configEntries;
|
||||
pageEl.devices = this._deviceRegistryEntries;
|
||||
pageEl.entities = this._entityRegistryEntries;
|
||||
pageEl.areas = this._areas;
|
||||
pageEl.narrow = this.narrow;
|
||||
pageEl.isWide = this.isWide;
|
||||
pageEl.showAdvanced = this.showAdvanced;
|
||||
pageEl.route = this.routeTail;
|
||||
}
|
||||
|
||||
private _loadData() {
|
||||
getConfigEntries(this.hass).then((configEntries) => {
|
||||
this._configEntries = configEntries.sort((conf1, conf2) =>
|
||||
stringCompare(conf1.title, conf2.title)
|
||||
);
|
||||
});
|
||||
if (this._unsubs) {
|
||||
return;
|
||||
}
|
||||
this._unsubs = [
|
||||
subscribeAreaRegistry(this.hass.connection, (areas) => {
|
||||
this._areas = areas;
|
||||
}),
|
||||
subscribeDeviceRegistry(this.hass.connection, (entries) => {
|
||||
this._deviceRegistryEntries = entries;
|
||||
}),
|
||||
subscribeEntityRegistry(this.hass.connection, (entries) => {
|
||||
this._entityRegistryEntries = entries;
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -134,6 +134,8 @@ export class HaConfigDevicePage extends LitElement {
|
||||
)
|
||||
);
|
||||
|
||||
private _deviceIdInList = memoizeOne((deviceId: string) => [deviceId]);
|
||||
|
||||
private _entityIds = memoizeOne(
|
||||
(entries: EntityRegistryStateEntry[]): string[] =>
|
||||
entries.map((entry) => entry.entity_id)
|
||||
@ -592,7 +594,8 @@ export class HaConfigDevicePage extends LitElement {
|
||||
<ha-logbook
|
||||
.hass=${this.hass}
|
||||
.time=${this._logbookTime}
|
||||
.entityId=${this._entityIds(entities)}
|
||||
.entityIds=${this._entityIds(entities)}
|
||||
.deviceIds=${this._deviceIdInList(this.deviceId)}
|
||||
virtualize
|
||||
narrow
|
||||
no-icon
|
||||
|
@ -21,7 +21,9 @@ export class HaLogbook extends LitElement {
|
||||
|
||||
@property() public time!: { range: [Date, Date] } | { recent: number };
|
||||
|
||||
@property() public entityId?: string | string[];
|
||||
@property() public entityIds?: string[];
|
||||
|
||||
@property() public deviceIds?: string[];
|
||||
|
||||
@property({ type: Boolean, attribute: "narrow" })
|
||||
public narrow = false;
|
||||
@ -120,23 +122,47 @@ export class HaLogbook extends LitElement {
|
||||
|
||||
this._lastLogbookDate = undefined;
|
||||
this._logbookEntries = undefined;
|
||||
this._error = undefined;
|
||||
this._throttleGetLogbookEntries();
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (changedProps.has("time") || changedProps.has("entityId")) {
|
||||
let changed = changedProps.has("time");
|
||||
|
||||
for (const key of ["entityIds", "deviceIds"]) {
|
||||
if (!changedProps.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const oldValue = changedProps.get(key) as string[] | undefined;
|
||||
const curValue = this[key] as string[] | undefined;
|
||||
|
||||
if (
|
||||
!oldValue ||
|
||||
!curValue ||
|
||||
oldValue.length !== curValue.length ||
|
||||
!oldValue.every((val) => curValue.includes(val))
|
||||
) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this.refresh(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._filterAlwaysEmptyResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only need to fetch again if we track recent entries for an entity
|
||||
if (
|
||||
!("recent" in this.time) ||
|
||||
!changedProps.has("hass") ||
|
||||
!this.entityId
|
||||
!this.entityIds
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@ -146,7 +172,7 @@ export class HaLogbook extends LitElement {
|
||||
// Refresh data if we know the entity has changed.
|
||||
if (
|
||||
!oldHass ||
|
||||
ensureArray(this.entityId).some(
|
||||
ensureArray(this.entityIds).some(
|
||||
(entityId) => this.hass.states[entityId] !== oldHass?.states[entityId]
|
||||
)
|
||||
) {
|
||||
@ -155,9 +181,34 @@ export class HaLogbook extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private get _filterAlwaysEmptyResults(): boolean {
|
||||
const entityIds = ensureArray(this.entityIds);
|
||||
const deviceIds = ensureArray(this.deviceIds);
|
||||
|
||||
// If all specified filters are empty lists, we can return an empty list.
|
||||
return (
|
||||
(entityIds || deviceIds) &&
|
||||
(!entityIds || entityIds.length === 0) &&
|
||||
(!deviceIds || deviceIds.length === 0)
|
||||
);
|
||||
}
|
||||
|
||||
private async _getLogBookData() {
|
||||
this._renderId += 1;
|
||||
const renderId = this._renderId;
|
||||
this._error = undefined;
|
||||
|
||||
if (this._filterAlwaysEmptyResults) {
|
||||
this._logbookEntries = [];
|
||||
this._lastLogbookDate = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateUsers();
|
||||
if (this.hass.user?.is_admin) {
|
||||
this._updateTraceContexts();
|
||||
}
|
||||
|
||||
let startTime: Date;
|
||||
let endTime: Date;
|
||||
let appendData = false;
|
||||
@ -173,34 +224,21 @@ export class HaLogbook extends LitElement {
|
||||
endTime = new Date();
|
||||
}
|
||||
|
||||
const entityIdFilter = this.entityId
|
||||
? ensureArray(this.entityId)
|
||||
: undefined;
|
||||
|
||||
let newEntries: LogbookEntry[];
|
||||
|
||||
if (entityIdFilter?.length === 0) {
|
||||
// filtering by 0 entities, means we never can have any results
|
||||
newEntries = [];
|
||||
} else {
|
||||
this._updateUsers();
|
||||
if (this.hass.user?.is_admin) {
|
||||
this._updateTraceContexts();
|
||||
}
|
||||
|
||||
try {
|
||||
newEntries = await getLogbookData(
|
||||
this.hass,
|
||||
startTime.toISOString(),
|
||||
endTime.toISOString(),
|
||||
entityIdFilter ? entityIdFilter.toString() : undefined
|
||||
);
|
||||
} catch (err: any) {
|
||||
if (renderId === this._renderId) {
|
||||
this._error = err.message;
|
||||
}
|
||||
return;
|
||||
try {
|
||||
newEntries = await getLogbookData(
|
||||
this.hass,
|
||||
startTime.toISOString(),
|
||||
endTime.toISOString(),
|
||||
ensureArray(this.entityIds),
|
||||
ensureArray(this.deviceIds)
|
||||
);
|
||||
} catch (err: any) {
|
||||
if (renderId === this._renderId) {
|
||||
this._error = err.message;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// New render happening.
|
||||
@ -208,6 +246,10 @@ export class HaLogbook extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
// Put newest ones on top. Reverse works in-place so
|
||||
// make a copy first.
|
||||
newEntries = [...newEntries].reverse();
|
||||
|
||||
this._logbookEntries =
|
||||
appendData && this._logbookEntries
|
||||
? newEntries.concat(...this._logbookEntries)
|
||||
|
@ -38,7 +38,7 @@ export class HaPanelLogbook extends LitElement {
|
||||
|
||||
@state() _time: { range: [Date, Date] };
|
||||
|
||||
@state() _entityId = "";
|
||||
@state() _entityIds?: string[];
|
||||
|
||||
@property({ reflect: true, type: Boolean }) rtl = false;
|
||||
|
||||
@ -85,7 +85,7 @@ export class HaPanelLogbook extends LitElement {
|
||||
|
||||
<ha-entity-picker
|
||||
.hass=${this.hass}
|
||||
.value=${this._entityId}
|
||||
.value=${this._entityIds ? this._entityIds[0] : undefined}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.entity.entity-picker.entity"
|
||||
)}
|
||||
@ -97,7 +97,7 @@ export class HaPanelLogbook extends LitElement {
|
||||
<ha-logbook
|
||||
.hass=${this.hass}
|
||||
.time=${this._time}
|
||||
.entityId=${this._entityId}
|
||||
.entityIds=${this._entityIds}
|
||||
virtualize
|
||||
></ha-logbook>
|
||||
</ha-app-layout>
|
||||
@ -157,15 +157,30 @@ export class HaPanelLogbook extends LitElement {
|
||||
this.rtl = computeRTL(this.hass);
|
||||
}
|
||||
}
|
||||
|
||||
this._applyURLParams();
|
||||
}
|
||||
|
||||
private _applyURLParams() {
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
|
||||
if (searchParams.has("entity_id")) {
|
||||
this._entityId = searchParams.get("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 startDateStr = searchParams.get("start_date");
|
||||
@ -199,19 +214,19 @@ export class HaPanelLogbook extends LitElement {
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
endDate.setMilliseconds(endDate.getMilliseconds() - 1);
|
||||
}
|
||||
this._time = { range: [startDate, endDate] };
|
||||
this._updatePath({
|
||||
start_date: this._time.range[0].toISOString(),
|
||||
end_date: this._time.range[1].toISOString(),
|
||||
start_date: startDate.toISOString(),
|
||||
end_date: endDate.toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
private _entityPicked(ev) {
|
||||
this._entityId = ev.target.value;
|
||||
this._updatePath({ entity_id: this._entityId });
|
||||
this._updatePath({
|
||||
entity_id: ev.target.value || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
private _updatePath(update: Record<string, string>) {
|
||||
private _updatePath(update: Record<string, string | undefined>) {
|
||||
const params = extractSearchParamsObject();
|
||||
for (const [key, value] of Object.entries(update)) {
|
||||
if (value === undefined) {
|
||||
|
@ -120,7 +120,7 @@ export class HuiLogbookCard extends LitElement implements LovelaceCard {
|
||||
<ha-logbook
|
||||
.hass=${this.hass}
|
||||
.time=${this._time}
|
||||
.entityId=${this._entityId}
|
||||
.entityIds=${this._entityId}
|
||||
narrow
|
||||
relative-time
|
||||
virtualize
|
||||
|
Loading…
x
Reference in New Issue
Block a user