Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/common/util/throttle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const throttle = <T extends any[]>(
) => {
let timeout: number | undefined;
let previous = 0;
return (...args: T): void => {
const throttledFunc = (...args: T): void => {
const later = () => {
previous = leading === false ? 0 : Date.now();
timeout = undefined;
Expand All @@ -35,4 +35,10 @@ export const throttle = <T extends any[]>(
timeout = window.setTimeout(later, remaining);
}
};
throttledFunc.cancel = () => {
clearTimeout(timeout);
timeout = undefined;
previous = 0;
};
return throttledFunc;
};
2 changes: 1 addition & 1 deletion src/components/entity/ha-entity-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface HassEntityWithCachedName extends HassEntity {
friendly_name: string;
}

export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
export type HaEntityPickerEntityFilterFunc = (entity: HassEntity) => boolean;

// eslint-disable-next-line lit/prefer-static-styles
const rowRenderer: ComboBoxLitRenderer<HassEntityWithCachedName> = (item) =>
Expand Down
6 changes: 3 additions & 3 deletions src/components/trace/ha-trace-logbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { customElement, property } from "lit/decorators";
import { LogbookEntry } from "../../data/logbook";
import { HomeAssistant } from "../../types";
import "./hat-logbook-note";
import "../../panels/logbook/ha-logbook";
import "../../panels/logbook/ha-logbook-renderer";
import { TraceExtended } from "../../data/trace";

@customElement("ha-trace-logbook")
Expand All @@ -19,12 +19,12 @@ export class HaTraceLogbook extends LitElement {
protected render(): TemplateResult {
return this.logbookEntries.length
? html`
<ha-logbook
<ha-logbook-renderer
relative-time
.hass=${this.hass}
.entries=${this.logbookEntries}
.narrow=${this.narrow}
></ha-logbook>
></ha-logbook-renderer>
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
`
: html`<div class="padded-box">
Expand Down
6 changes: 3 additions & 3 deletions src/components/trace/ha-trace-path-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
getDataFromPath,
TraceExtended,
} from "../../data/trace";
import "../../panels/logbook/ha-logbook";
import "../../panels/logbook/ha-logbook-renderer";
import { traceTabStyles } from "./trace-tab-styles";
import { HomeAssistant } from "../../types";
import type { NodeInfo } from "./hat-script-graph";
Expand Down Expand Up @@ -224,12 +224,12 @@ export class HaTracePathDetails extends LitElement {

return entries.length
? html`
<ha-logbook
<ha-logbook-renderer
relative-time
.hass=${this.hass}
.entries=${entries}
.narrow=${this.narrow}
></ha-logbook>
></ha-logbook-renderer>
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
`
: html`<div class="padded-box">
Expand Down
194 changes: 24 additions & 170 deletions src/dialogs/more-info/ha-more-info-logbook.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,23 @@
import { startOfYesterday } from "date-fns";
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { fireEvent } from "../../common/dom/fire_event";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { throttle } from "../../common/util/throttle";
import "../../components/ha-circular-progress";
import { getLogbookData, LogbookEntry } from "../../data/logbook";
import { loadTraceContexts, TraceContexts } from "../../data/trace";
import { fetchUsers } from "../../data/user";
import "../../panels/logbook/ha-logbook";
import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types";
import type { HomeAssistant } from "../../types";

@customElement("ha-more-info-logbook")
export class MoreInfoLogbook extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;

@property() public entityId!: string;

@state() private _logbookEntries?: LogbookEntry[];

@state() private _traceContexts?: TraceContexts;

@state() private _userIdToName = {};

private _lastLogbookDate?: Date;

private _fetchUserPromise?: Promise<void>;

private _error?: string;

private _showMoreHref = "";

private _throttleGetLogbookEntries = throttle(() => {
this._getLogBookData();
}, 10000);
private _time = { recent: 86400 };

protected render(): TemplateResult {
if (!this.entityId) {
if (!isComponentLoaded(this.hass, "logbook") || !this.entityId) {
return html``;
}
const stateObj = this.hass.states[this.entityId];
Expand All @@ -48,164 +27,43 @@ export class MoreInfoLogbook extends LitElement {
}

return html`
${isComponentLoaded(this.hass, "logbook")
? this._error
? html`<div class="no-entries">
${`${this.hass.localize(
"ui.components.logbook.retrieval_error"
)}: ${this._error}`}
</div>`
: !this._logbookEntries
? html`
<ha-circular-progress
active
alt=${this.hass.localize("ui.common.loading")}
></ha-circular-progress>
`
: this._logbookEntries.length
? html`
<div class="header">
<div class="title">
${this.hass.localize("ui.dialogs.more_info_control.logbook")}
</div>
<a href=${this._showMoreHref} @click=${this._close}
>${this.hass.localize(
"ui.dialogs.more_info_control.show_more"
)}</a
>
</div>
<ha-logbook
narrow
no-icon
no-name
relative-time
.hass=${this.hass}
.entries=${this._logbookEntries}
.traceContexts=${this._traceContexts}
.userIdToName=${this._userIdToName}
></ha-logbook>
`
: html`<div class="no-entries">
${this.hass.localize("ui.components.logbook.entries_not_found")}
</div>`
: ""}
<div class="header">
<div class="title">
${this.hass.localize("ui.dialogs.more_info_control.logbook")}
</div>
<a href=${this._showMoreHref} @click=${this._close}
>${this.hass.localize("ui.dialogs.more_info_control.show_more")}</a
>
</div>
<ha-logbook
.hass=${this.hass}
.time=${this._time}
.entityId=${this.entityId}
narrow
no-icon
no-name
relative-time
></ha-logbook>
`;
}

protected firstUpdated(): void {
this._fetchUserPromise = this._fetchUserNames();
}

protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);

if (changedProps.has("entityId")) {
this._lastLogbookDate = undefined;
this._logbookEntries = undefined;

if (!this.entityId) {
return;
}
protected willUpdate(changedProps: PropertyValues): void {
super.willUpdate(changedProps);

if (changedProps.has("entityId") && this.entityId) {
this._showMoreHref = `/logbook?entity_id=${
this.entityId
}&start_date=${startOfYesterday().toISOString()}`;

this._throttleGetLogbookEntries();
return;
}

if (!this.entityId || !changedProps.has("hass")) {
return;
}

const oldHass = changedProps.get("hass") as HomeAssistant | undefined;

if (
oldHass &&
this.hass.states[this.entityId] !== oldHass?.states[this.entityId]
) {
// wait for commit of data (we only account for the default setting of 1 sec)
setTimeout(this._throttleGetLogbookEntries, 1000);
}
}

private async _getLogBookData() {
if (!isComponentLoaded(this.hass, "logbook")) {
return;
}
const lastDate =
this._lastLogbookDate ||
new Date(new Date().getTime() - 24 * 60 * 60 * 1000);
const now = new Date();
let newEntries;
let traceContexts;

try {
[newEntries, traceContexts] = await Promise.all([
getLogbookData(
this.hass,
lastDate.toISOString(),
now.toISOString(),
this.entityId
),
this.hass.user?.is_admin ? loadTraceContexts(this.hass) : {},
this._fetchUserPromise,
]);
} catch (err: any) {
this._error = err.message;
}

this._logbookEntries = this._logbookEntries
? [...newEntries, ...this._logbookEntries]
: newEntries;
this._lastLogbookDate = now;
this._traceContexts = traceContexts;
}

private async _fetchUserNames() {
const userIdToName = {};

// Start loading users
const userProm = this.hass.user?.is_admin && fetchUsers(this.hass);

// Process persons
Object.values(this.hass.states).forEach((entity) => {
if (
entity.attributes.user_id &&
computeStateDomain(entity) === "person"
) {
this._userIdToName[entity.attributes.user_id] =
entity.attributes.friendly_name;
}
});

// Process users
if (userProm) {
const users = await userProm;
for (const user of users) {
if (!(user.id in userIdToName)) {
userIdToName[user.id] = user.name;
}
}
}

this._userIdToName = userIdToName;
}

private _close(): void {
setTimeout(() => fireEvent(this, "closed"), 500);
}

static get styles() {
return [
haStyle,
css`
.no-entries {
text-align: center;
padding: 16px;
color: var(--secondary-text-color);
}
ha-logbook {
--logbook-max-height: 250px;
}
Expand All @@ -214,10 +72,6 @@ export class MoreInfoLogbook extends LitElement {
--logbook-max-height: unset;
}
}
ha-circular-progress {
display: flex;
justify-content: center;
}
.header {
display: flex;
flex-direction: row;
Expand Down
Loading