mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 10:16:46 +00:00
Lazy load more info content, split logbook and history (#6936)
This commit is contained in:
parent
8a998369d6
commit
99d0a0a6fd
@ -2,8 +2,8 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|||||||
/* eslint-plugin-disable lit */
|
/* eslint-plugin-disable lit */
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/dialogs/more-info/more-info-content";
|
|
||||||
import "../../../src/state-summary/state-card-content";
|
import "../../../src/state-summary/state-card-content";
|
||||||
|
import "./more-info-content";
|
||||||
|
|
||||||
class DemoMoreInfo extends PolymerElement {
|
class DemoMoreInfo extends PolymerElement {
|
||||||
static get template() {
|
static get template() {
|
||||||
|
73
gallery/src/components/more-info-content.ts
Normal file
73
gallery/src/components/more-info-content.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { property, PropertyValues, UpdatingElement } from "lit-element";
|
||||||
|
import dynamicContentUpdater from "../../../src/common/dom/dynamic_content_updater";
|
||||||
|
import { stateMoreInfoType } from "../../../src/common/entity/state_more_info_type";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-alarm_control_panel";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-automation";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-camera";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-climate";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-configurator";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-counter";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-cover";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-default";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-fan";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-group";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-humidifier";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-input_datetime";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-light";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-lock";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-media_player";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-person";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-script";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-sun";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-timer";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-vacuum";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-water_heater";
|
||||||
|
import "../../../src/dialogs/more-info/controls/more-info-weather";
|
||||||
|
import { HomeAssistant } from "../../../src/types";
|
||||||
|
|
||||||
|
class MoreInfoContent extends UpdatingElement {
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public stateObj?: HassEntity;
|
||||||
|
|
||||||
|
private _detachedChild?: ChildNode;
|
||||||
|
|
||||||
|
protected firstUpdated(): void {
|
||||||
|
this.style.position = "relative";
|
||||||
|
this.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not a lit element, but an updating element, so we implement update
|
||||||
|
protected update(changedProps: PropertyValues): void {
|
||||||
|
super.update(changedProps);
|
||||||
|
const stateObj = this.stateObj;
|
||||||
|
const hass = this.hass;
|
||||||
|
|
||||||
|
if (!stateObj || !hass) {
|
||||||
|
if (this.lastChild) {
|
||||||
|
this._detachedChild = this.lastChild;
|
||||||
|
// Detach child to prevent it from doing work.
|
||||||
|
this.removeChild(this.lastChild);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._detachedChild) {
|
||||||
|
this.appendChild(this._detachedChild);
|
||||||
|
this._detachedChild = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moreInfoType =
|
||||||
|
stateObj.attributes && "custom_ui_more_info" in stateObj.attributes
|
||||||
|
? stateObj.attributes.custom_ui_more_info
|
||||||
|
: "more-info-" + stateMoreInfoType(stateObj);
|
||||||
|
|
||||||
|
dynamicContentUpdater(this, moreInfoType.toUpperCase(), {
|
||||||
|
hass,
|
||||||
|
stateObj,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("more-info-content", MoreInfoContent);
|
@ -3,10 +3,10 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { SUPPORT_BRIGHTNESS } from "../../../src/data/light";
|
import { SUPPORT_BRIGHTNESS } from "../../../src/data/light";
|
||||||
import "../../../src/dialogs/more-info/more-info-content";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-more-infos";
|
import "../components/demo-more-infos";
|
||||||
|
import "../components/more-info-content";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "bed_light", "on", {
|
getEntity("light", "bed_light", "on", {
|
||||||
|
@ -44,7 +44,6 @@ export const DOMAINS_WITH_MORE_INFO = [
|
|||||||
"script",
|
"script",
|
||||||
"sun",
|
"sun",
|
||||||
"timer",
|
"timer",
|
||||||
"updater",
|
|
||||||
"vacuum",
|
"vacuum",
|
||||||
"water_heater",
|
"water_heater",
|
||||||
"weather",
|
"weather",
|
||||||
|
50
src/common/util/throttle.ts
Normal file
50
src/common/util/throttle.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// From: underscore.js https://github.com/jashkenas/underscore/blob/master/underscore.js
|
||||||
|
|
||||||
|
// Returns a function, that, when invoked, will only be triggered at most once
|
||||||
|
// during a given window of time. Normally, the throttled function will run
|
||||||
|
// as much as it can, without ever going more than once per `wait` duration;
|
||||||
|
// but if you'd like to disable the execution on the leading edge, pass
|
||||||
|
// `false for leading`. To disable execution on the trailing edge, ditto.
|
||||||
|
export const throttle = <T extends Function>(
|
||||||
|
func: T,
|
||||||
|
wait: number,
|
||||||
|
leading = true,
|
||||||
|
trailing = true
|
||||||
|
): T => {
|
||||||
|
let timeout: number | undefined;
|
||||||
|
let previous = 0;
|
||||||
|
let context: any;
|
||||||
|
let args: any;
|
||||||
|
const later = () => {
|
||||||
|
previous = leading === false ? 0 : Date.now();
|
||||||
|
timeout = undefined;
|
||||||
|
func.apply(context, args);
|
||||||
|
if (!timeout) {
|
||||||
|
context = null;
|
||||||
|
args = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// @ts-ignore
|
||||||
|
return function (...argmnts) {
|
||||||
|
// @ts-ignore
|
||||||
|
// @typescript-eslint/no-this-alias
|
||||||
|
context = this;
|
||||||
|
args = argmnts;
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
if (!previous && leading === false) {
|
||||||
|
previous = now;
|
||||||
|
}
|
||||||
|
const remaining = wait - (now - previous);
|
||||||
|
if (remaining <= 0 || remaining > wait) {
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = undefined;
|
||||||
|
}
|
||||||
|
previous = now;
|
||||||
|
func.apply(context, args);
|
||||||
|
} else if (!timeout && trailing !== false) {
|
||||||
|
timeout = window.setTimeout(later, remaining);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
@ -13,10 +13,15 @@ import {
|
|||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { cache } from "lit-html/directives/cache";
|
import { cache } from "lit-html/directives/cache";
|
||||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||||
import { DOMAINS_MORE_INFO_NO_HISTORY } from "../../common/const";
|
import {
|
||||||
|
DOMAINS_MORE_INFO_NO_HISTORY,
|
||||||
|
DOMAINS_WITH_MORE_INFO,
|
||||||
|
} from "../../common/const";
|
||||||
|
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||||
|
import { stateMoreInfoType } from "../../common/entity/state_more_info_type";
|
||||||
import { navigate } from "../../common/navigate";
|
import { navigate } from "../../common/navigate";
|
||||||
import "../../components/ha-dialog";
|
import "../../components/ha-dialog";
|
||||||
import "../../components/ha-header-bar";
|
import "../../components/ha-header-bar";
|
||||||
@ -30,21 +35,38 @@ import "../../state-summary/state-card-content";
|
|||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import { showConfirmationDialog } from "../generic/show-dialog-box";
|
import { showConfirmationDialog } from "../generic/show-dialog-box";
|
||||||
import "./ha-more-info-history";
|
import "./ha-more-info-history";
|
||||||
import "./more-info-content";
|
import "./ha-more-info-logbook";
|
||||||
|
|
||||||
const DOMAINS_NO_INFO = ["camera", "configurator"];
|
const DOMAINS_NO_INFO = ["camera", "configurator"];
|
||||||
const CONTROL_DOMAINS = [
|
|
||||||
"light",
|
|
||||||
"media_player",
|
|
||||||
"vacuum",
|
|
||||||
"alarm_control_panel",
|
|
||||||
"climate",
|
|
||||||
"humidifier",
|
|
||||||
"weather",
|
|
||||||
];
|
|
||||||
const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"];
|
const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"];
|
||||||
const EDITABLE_DOMAINS = ["script"];
|
const EDITABLE_DOMAINS = ["script"];
|
||||||
|
|
||||||
|
const MORE_INFO_CONTROL_IMPORT = {
|
||||||
|
alarm_control_panel: () => import("./controls/more-info-alarm_control_panel"),
|
||||||
|
automation: () => import("./controls/more-info-automation"),
|
||||||
|
camera: () => import("./controls/more-info-camera"),
|
||||||
|
climate: () => import("./controls/more-info-climate"),
|
||||||
|
configurator: () => import("./controls/more-info-configurator"),
|
||||||
|
counter: () => import("./controls/more-info-counter"),
|
||||||
|
cover: () => import("./controls/more-info-cover"),
|
||||||
|
fan: () => import("./controls/more-info-fan"),
|
||||||
|
group: () => import("./controls/more-info-group"),
|
||||||
|
humidifier: () => import("./controls/more-info-humidifier"),
|
||||||
|
input_datetime: () => import("./controls/more-info-input_datetime"),
|
||||||
|
light: () => import("./controls/more-info-light"),
|
||||||
|
lock: () => import("./controls/more-info-lock"),
|
||||||
|
media_player: () => import("./controls/more-info-media_player"),
|
||||||
|
person: () => import("./controls/more-info-person"),
|
||||||
|
script: () => import("./controls/more-info-script"),
|
||||||
|
sun: () => import("./controls/more-info-sun"),
|
||||||
|
timer: () => import("./controls/more-info-timer"),
|
||||||
|
vacuum: () => import("./controls/more-info-vacuum"),
|
||||||
|
water_heater: () => import("./controls/more-info-water_heater"),
|
||||||
|
weather: () => import("./controls/more-info-weather"),
|
||||||
|
hidden: () => {},
|
||||||
|
default: () => import("./controls/more-info-default"),
|
||||||
|
};
|
||||||
|
|
||||||
export interface MoreInfoDialogParams {
|
export interface MoreInfoDialogParams {
|
||||||
entityId: string | null;
|
entityId: string | null;
|
||||||
}
|
}
|
||||||
@ -57,6 +79,8 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
|
|
||||||
@internalProperty() private _entityId?: string | null;
|
@internalProperty() private _entityId?: string | null;
|
||||||
|
|
||||||
|
@internalProperty() private _moreInfoType?: string;
|
||||||
|
|
||||||
@internalProperty() private _currTabIndex = 0;
|
@internalProperty() private _currTabIndex = 0;
|
||||||
|
|
||||||
public showDialog(params: MoreInfoDialogParams) {
|
public showDialog(params: MoreInfoDialogParams) {
|
||||||
@ -73,6 +97,23 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected updated(changedProperties) {
|
||||||
|
if (!this.hass || !this._entityId || !changedProperties.has("_entityId")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const stateObj = this.hass.states[this._entityId];
|
||||||
|
if (!stateObj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stateObj.attributes && "custom_ui_more_info" in stateObj.attributes) {
|
||||||
|
this._moreInfoType = stateObj.attributes.custom_ui_more_info;
|
||||||
|
} else {
|
||||||
|
const type = stateMoreInfoType(stateObj);
|
||||||
|
this._moreInfoType = `more-info-${type}`;
|
||||||
|
MORE_INFO_CONTROL_IMPORT[type]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this._entityId) {
|
if (!this._entityId) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -137,7 +178,7 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-header-bar>
|
</ha-header-bar>
|
||||||
${CONTROL_DOMAINS.includes(domain) &&
|
${DOMAINS_WITH_MORE_INFO.includes(domain) &&
|
||||||
this._computeShowHistoryComponent(entityId)
|
this._computeShowHistoryComponent(entityId)
|
||||||
? html`
|
? html`
|
||||||
<mwc-tab-bar
|
<mwc-tab-bar
|
||||||
@ -171,17 +212,23 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
></state-card-content>
|
></state-card-content>
|
||||||
`}
|
`}
|
||||||
<more-info-content
|
${DOMAINS_WITH_MORE_INFO.includes(domain) ||
|
||||||
.stateObj=${stateObj}
|
|
||||||
.hass=${this.hass}
|
|
||||||
></more-info-content>
|
|
||||||
${CONTROL_DOMAINS.includes(domain) ||
|
|
||||||
!this._computeShowHistoryComponent(entityId)
|
!this._computeShowHistoryComponent(entityId)
|
||||||
? ""
|
? ""
|
||||||
: html`<ha-more-info-history
|
: html`<ha-more-info-history
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.entityId=${this._entityId}
|
.entityId=${this._entityId}
|
||||||
></ha-more-info-history>`}
|
></ha-more-info-history>
|
||||||
|
<ha-more-info-logbook
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entityId=${this._entityId}
|
||||||
|
></ha-more-info-logbook>`}
|
||||||
|
${this._moreInfoType
|
||||||
|
? dynamicElement(this._moreInfoType, {
|
||||||
|
hass: this.hass,
|
||||||
|
stateObj,
|
||||||
|
})
|
||||||
|
: ""}
|
||||||
${stateObj.attributes.restored
|
${stateObj.attributes.restored
|
||||||
? html`
|
? html`
|
||||||
<p>
|
<p>
|
||||||
@ -210,6 +257,10 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.entityId=${this._entityId}
|
.entityId=${this._entityId}
|
||||||
></ha-more-info-history>
|
></ha-more-info-history>
|
||||||
|
<ha-more-info-logbook
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entityId=${this._entityId}
|
||||||
|
></ha-more-info-logbook>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,14 +9,11 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
import { throttle } from "../../common/util/throttle";
|
||||||
import "../../components/ha-circular-progress";
|
|
||||||
import "../../components/state-history-charts";
|
import "../../components/state-history-charts";
|
||||||
import { getRecentWithCache } from "../../data/cached-history";
|
import { getRecentWithCache } from "../../data/cached-history";
|
||||||
import { HistoryResult } from "../../data/history";
|
import { HistoryResult } from "../../data/history";
|
||||||
import { getLogbookData, LogbookEntry } from "../../data/logbook";
|
import { haStyle } from "../../resources/styles";
|
||||||
import "../../panels/logbook/ha-logbook";
|
|
||||||
import { haStyle, haStyleScrollbar } from "../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
@customElement("ha-more-info-history")
|
@customElement("ha-more-info-history")
|
||||||
@ -27,21 +24,14 @@ export class MoreInfoHistory extends LitElement {
|
|||||||
|
|
||||||
@internalProperty() private _stateHistory?: HistoryResult;
|
@internalProperty() private _stateHistory?: HistoryResult;
|
||||||
|
|
||||||
@internalProperty() private _entries?: LogbookEntry[];
|
private _throttleGetStateHistory = throttle(() => {
|
||||||
|
this._getStateHistory();
|
||||||
@internalProperty() private _persons = {};
|
}, 10000);
|
||||||
|
|
||||||
private _historyRefreshInterval?: number;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.entityId) {
|
if (!this.entityId) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
const stateObj = this.hass.states[this.entityId];
|
|
||||||
|
|
||||||
if (!stateObj) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`${isComponentLoaded(this.hass, "history")
|
return html`${isComponentLoaded(this.hass, "history")
|
||||||
? html`<state-history-charts
|
? html`<state-history-charts
|
||||||
@ -50,54 +40,35 @@ export class MoreInfoHistory extends LitElement {
|
|||||||
.historyData=${this._stateHistory}
|
.historyData=${this._stateHistory}
|
||||||
.isLoadingData=${!this._stateHistory}
|
.isLoadingData=${!this._stateHistory}
|
||||||
></state-history-charts>`
|
></state-history-charts>`
|
||||||
: ""}
|
|
||||||
${isComponentLoaded(this.hass, "logbook")
|
|
||||||
? !this._entries
|
|
||||||
? html`
|
|
||||||
<ha-circular-progress
|
|
||||||
active
|
|
||||||
alt=${this.hass.localize("ui.common.loading")}
|
|
||||||
></ha-circular-progress>
|
|
||||||
`
|
|
||||||
: this._entries.length
|
|
||||||
? html`
|
|
||||||
<ha-logbook
|
|
||||||
class="ha-scrollbar"
|
|
||||||
narrow
|
|
||||||
no-icon
|
|
||||||
no-name
|
|
||||||
.hass=${this.hass}
|
|
||||||
.entries=${this._entries}
|
|
||||||
.userIdToName=${this._persons}
|
|
||||||
></ha-logbook>
|
|
||||||
`
|
|
||||||
: html`<div class="no-entries">
|
|
||||||
${this.hass.localize("ui.components.logbook.entries_not_found")}
|
|
||||||
</div>`
|
|
||||||
: ""} `;
|
: ""} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(): void {
|
|
||||||
this._fetchPersonNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues): void {
|
protected updated(changedProps: PropertyValues): void {
|
||||||
super.updated(changedProps);
|
super.updated(changedProps);
|
||||||
if (!this.entityId) {
|
|
||||||
clearInterval(this._historyRefreshInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changedProps.has("entityId")) {
|
if (changedProps.has("entityId")) {
|
||||||
this._stateHistory = undefined;
|
this._stateHistory = undefined;
|
||||||
this._entries = undefined;
|
|
||||||
|
|
||||||
this._getStateHistory();
|
if (!this.entityId) {
|
||||||
this._getLogBookData();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
clearInterval(this._historyRefreshInterval);
|
this._throttleGetStateHistory();
|
||||||
this._historyRefreshInterval = window.setInterval(() => {
|
return;
|
||||||
this._getStateHistory();
|
}
|
||||||
}, 60 * 1000);
|
|
||||||
|
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._throttleGetStateHistory, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,55 +89,14 @@ export class MoreInfoHistory extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getLogBookData() {
|
|
||||||
if (!isComponentLoaded(this.hass, "logbook")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const yesterday = new Date(new Date().getTime() - 24 * 60 * 60 * 1000);
|
|
||||||
const now = new Date();
|
|
||||||
this._entries = await getLogbookData(
|
|
||||||
this.hass,
|
|
||||||
yesterday.toISOString(),
|
|
||||||
now.toISOString(),
|
|
||||||
this.entityId,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _fetchPersonNames() {
|
|
||||||
Object.values(this.hass.states).forEach((entity) => {
|
|
||||||
if (
|
|
||||||
entity.attributes.user_id &&
|
|
||||||
computeStateDomain(entity) === "person"
|
|
||||||
) {
|
|
||||||
this._persons[entity.attributes.user_id] =
|
|
||||||
entity.attributes.friendly_name;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
haStyleScrollbar,
|
|
||||||
css`
|
css`
|
||||||
state-history-charts {
|
state-history-charts {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
.no-entries {
|
|
||||||
text-align: center;
|
|
||||||
padding: 16px;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
ha-logbook {
|
|
||||||
max-height: 250px;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
ha-circular-progress {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
171
src/dialogs/more-info/ha-more-info-logbook.ts
Normal file
171
src/dialogs/more-info/ha-more-info-logbook.ts
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import {
|
||||||
|
css,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||||
|
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||||
|
import { throttle } from "../../common/util/throttle";
|
||||||
|
import "../../components/ha-circular-progress";
|
||||||
|
import "../../components/state-history-charts";
|
||||||
|
import { getLogbookData, LogbookEntry } from "../../data/logbook";
|
||||||
|
import "../../panels/logbook/ha-logbook";
|
||||||
|
import { haStyle, haStyleScrollbar } from "../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
|
@customElement("ha-more-info-logbook")
|
||||||
|
export class MoreInfoLogbook extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public entityId!: string;
|
||||||
|
|
||||||
|
@internalProperty() private _logbookEntries?: LogbookEntry[];
|
||||||
|
|
||||||
|
@internalProperty() private _persons = {};
|
||||||
|
|
||||||
|
private _lastLogbookDate?: Date;
|
||||||
|
|
||||||
|
private _throttleGetLogbookEntries = throttle(() => {
|
||||||
|
this._getLogBookData();
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.entityId) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
const stateObj = this.hass.states[this.entityId];
|
||||||
|
|
||||||
|
if (!stateObj) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
${isComponentLoaded(this.hass, "logbook")
|
||||||
|
? !this._logbookEntries
|
||||||
|
? html`
|
||||||
|
<ha-circular-progress
|
||||||
|
active
|
||||||
|
alt=${this.hass.localize("ui.common.loading")}
|
||||||
|
></ha-circular-progress>
|
||||||
|
`
|
||||||
|
: this._logbookEntries.length
|
||||||
|
? html`
|
||||||
|
<ha-logbook
|
||||||
|
class="ha-scrollbar"
|
||||||
|
narrow
|
||||||
|
no-icon
|
||||||
|
no-name
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entries=${this._logbookEntries}
|
||||||
|
.userIdToName=${this._persons}
|
||||||
|
></ha-logbook>
|
||||||
|
`
|
||||||
|
: html`<div class="no-entries">
|
||||||
|
${this.hass.localize("ui.components.logbook.entries_not_found")}
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(): void {
|
||||||
|
this._fetchPersonNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues): void {
|
||||||
|
super.updated(changedProps);
|
||||||
|
|
||||||
|
if (changedProps.has("entityId")) {
|
||||||
|
this._lastLogbookDate = undefined;
|
||||||
|
this._logbookEntries = undefined;
|
||||||
|
|
||||||
|
if (!this.entityId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
const newEntries = await getLogbookData(
|
||||||
|
this.hass,
|
||||||
|
lastDate.toISOString(),
|
||||||
|
now.toISOString(),
|
||||||
|
this.entityId,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
this._logbookEntries = this._logbookEntries
|
||||||
|
? [...newEntries, ...this._logbookEntries]
|
||||||
|
: newEntries;
|
||||||
|
this._lastLogbookDate = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchPersonNames() {
|
||||||
|
Object.values(this.hass.states).forEach((entity) => {
|
||||||
|
if (
|
||||||
|
entity.attributes.user_id &&
|
||||||
|
computeStateDomain(entity) === "person"
|
||||||
|
) {
|
||||||
|
this._persons[entity.attributes.user_id] =
|
||||||
|
entity.attributes.friendly_name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
haStyleScrollbar,
|
||||||
|
css`
|
||||||
|
.no-entries {
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
ha-logbook {
|
||||||
|
max-height: 250px;
|
||||||
|
overflow: auto;
|
||||||
|
display: block;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
ha-circular-progress {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-more-info-logbook": MoreInfoLogbook;
|
||||||
|
}
|
||||||
|
}
|
@ -1,73 +0,0 @@
|
|||||||
import { HassEntity } from "home-assistant-js-websocket";
|
|
||||||
import { property, PropertyValues, UpdatingElement } from "lit-element";
|
|
||||||
import dynamicContentUpdater from "../../common/dom/dynamic_content_updater";
|
|
||||||
import { stateMoreInfoType } from "../../common/entity/state_more_info_type";
|
|
||||||
import { HomeAssistant } from "../../types";
|
|
||||||
import "./controls/more-info-alarm_control_panel";
|
|
||||||
import "./controls/more-info-automation";
|
|
||||||
import "./controls/more-info-camera";
|
|
||||||
import "./controls/more-info-climate";
|
|
||||||
import "./controls/more-info-configurator";
|
|
||||||
import "./controls/more-info-counter";
|
|
||||||
import "./controls/more-info-cover";
|
|
||||||
import "./controls/more-info-default";
|
|
||||||
import "./controls/more-info-fan";
|
|
||||||
import "./controls/more-info-group";
|
|
||||||
import "./controls/more-info-humidifier";
|
|
||||||
import "./controls/more-info-input_datetime";
|
|
||||||
import "./controls/more-info-light";
|
|
||||||
import "./controls/more-info-lock";
|
|
||||||
import "./controls/more-info-media_player";
|
|
||||||
import "./controls/more-info-person";
|
|
||||||
import "./controls/more-info-script";
|
|
||||||
import "./controls/more-info-sun";
|
|
||||||
import "./controls/more-info-timer";
|
|
||||||
import "./controls/more-info-vacuum";
|
|
||||||
import "./controls/more-info-water_heater";
|
|
||||||
import "./controls/more-info-weather";
|
|
||||||
|
|
||||||
class MoreInfoContent extends UpdatingElement {
|
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@property() public stateObj?: HassEntity;
|
|
||||||
|
|
||||||
private _detachedChild?: ChildNode;
|
|
||||||
|
|
||||||
protected firstUpdated(): void {
|
|
||||||
this.style.position = "relative";
|
|
||||||
this.style.display = "block";
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is not a lit element, but an updating element, so we implement update
|
|
||||||
protected update(changedProps: PropertyValues): void {
|
|
||||||
super.update(changedProps);
|
|
||||||
const stateObj = this.stateObj;
|
|
||||||
const hass = this.hass;
|
|
||||||
|
|
||||||
if (!stateObj || !hass) {
|
|
||||||
if (this.lastChild) {
|
|
||||||
this._detachedChild = this.lastChild;
|
|
||||||
// Detach child to prevent it from doing work.
|
|
||||||
this.removeChild(this.lastChild);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._detachedChild) {
|
|
||||||
this.appendChild(this._detachedChild);
|
|
||||||
this._detachedChild = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const moreInfoType =
|
|
||||||
stateObj.attributes && "custom_ui_more_info" in stateObj.attributes
|
|
||||||
? stateObj.attributes.custom_ui_more_info
|
|
||||||
: "more-info-" + stateMoreInfoType(stateObj);
|
|
||||||
|
|
||||||
dynamicContentUpdater(this, moreInfoType.toUpperCase(), {
|
|
||||||
hass,
|
|
||||||
stateObj,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("more-info-content", MoreInfoContent);
|
|
Loading…
x
Reference in New Issue
Block a user