Virtualize logbook (#4450)

* Virtualize logbook

* Clean

* Update ha-logbook.ts
This commit is contained in:
Bram Kragten 2020-01-12 13:00:26 +01:00 committed by GitHub
parent adce40de56
commit 58ad949bc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 213 additions and 142 deletions

View File

@ -89,6 +89,7 @@
"leaflet": "^1.4.0",
"lit-element": "^2.2.1",
"lit-html": "^1.1.0",
"lit-virtualizer": "^0.4.2",
"marked": "^0.6.1",
"mdn-polyfills": "^5.16.0",
"memoize-one": "^5.0.2",

7
src/data/logbook.ts Normal file
View File

@ -0,0 +1,7 @@
export interface LogbookEntry {
when: string;
name: string;
message: string;
entity_id?: string;
domain: string;
}

View File

@ -1,137 +0,0 @@
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
import "@polymer/iron-icon/iron-icon";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import formatTime from "../../common/datetime/format_time";
import formatDate from "../../common/datetime/format_date";
import { EventsMixin } from "../../mixins/events-mixin";
import LocalizeMixin from "../../mixins/localize-mixin";
import { domainIcon } from "../../common/entity/domain_icon";
import { computeRTL } from "../../common/util/compute_rtl";
/*
* @appliesMixin EventsMixin
*/
class HaLogbook extends LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<style include="iron-flex"></style>
<style>
:host {
display: block;
}
:host([rtl]) {
direction: ltr;
}
.entry {
@apply --paper-font-body1;
line-height: 2em;
}
.time {
width: 55px;
font-size: 0.8em;
color: var(--secondary-text-color);
}
:host([rtl]) .date {
direction: rtl;
}
iron-icon {
margin: 0 8px 0 16px;
color: var(--primary-text-color);
}
.message {
color: var(--primary-text-color);
}
a {
color: var(--primary-color);
}
</style>
<template is="dom-if" if="[[!entries.length]]">
[[localize('ui.panel.logbook.entries_not_found')]]
</template>
<template is="dom-repeat" items="[[entries]]">
<template is="dom-if" if="{{_needHeader(entries.*, index)}}">
<h4 class="date">[[_formatDate(item.when)]]</h4>
</template>
<div class="horizontal layout entry">
<div class="time">[[_formatTime(item.when)]]</div>
<iron-icon icon="[[_computeIcon(item.domain)]]"></iron-icon>
<div class="message" flex="">
<template is="dom-if" if="[[!item.entity_id]]">
<span class="name">[[item.name]]</span>
</template>
<template is="dom-if" if="[[item.entity_id]]">
<a href="#" on-click="entityClicked" class="name"
>[[item.name]]</a
>
</template>
<span> </span> <span>[[item.message]]</span>
</div>
</div>
</template>
`;
}
static get properties() {
return {
hass: {
type: Object,
},
entries: {
type: Array,
value: [],
},
rtl: {
type: Boolean,
reflectToAttribute: true,
computed: "_computeRTL(hass)",
},
};
}
_formatTime(date) {
return formatTime(new Date(date), this.hass.language);
}
_formatDate(date) {
return formatDate(new Date(date), this.hass.language);
}
_needHeader(change, index) {
if (!index) return true;
const current = this.get("when", change.base[index]);
const previous = this.get("when", change.base[index - 1]);
return (
current &&
previous &&
new Date(current).toDateString() !== new Date(previous).toDateString()
);
}
_computeIcon(domain) {
return domainIcon(domain);
}
_computeRTL(hass) {
return computeRTL(hass);
}
entityClicked(ev) {
ev.preventDefault();
this.fire("hass-more-info", { entityId: ev.model.item.entity_id });
}
}
customElements.define("ha-logbook", HaLogbook);

View File

@ -0,0 +1,156 @@
import "@polymer/iron-icon/iron-icon";
import formatTime from "../../common/datetime/format_time";
import formatDate from "../../common/datetime/format_date";
import { domainIcon } from "../../common/entity/domain_icon";
import { computeRTL } from "../../common/util/compute_rtl";
import {
LitElement,
html,
property,
TemplateResult,
CSSResult,
css,
PropertyValues,
} from "lit-element";
import { HomeAssistant } from "../../types";
import { fireEvent } from "../../common/dom/fire_event";
import "lit-virtualizer";
import { LogbookEntry } from "../../data/logbook";
class HaLogbook extends LitElement {
@property() public hass!: HomeAssistant;
@property() public entries: LogbookEntry[] = [];
@property({ attribute: "rtl", type: Boolean, reflect: true })
// @ts-ignore
private _rtl = false;
protected updated(changedProps: PropertyValues) {
super.updated(changedProps);
if (!changedProps.has("hass")) {
return;
}
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
if (oldHass && oldHass.language !== this.hass.language) {
this._rtl = computeRTL(this.hass);
}
}
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this._rtl = computeRTL(this.hass);
}
protected render(): TemplateResult | void {
if (!this.entries?.length) {
return html`
${this.hass.localize("ui.panel.logbook.entries_not_found")}
`;
}
return html`
<lit-virtualizer
.items=${this.entries}
.renderItem=${(item: LogbookEntry, index: number) =>
this._renderLogbookItem(item, index)}
style="height: 100%;"
></lit-virtualizer>
`;
}
private _renderLogbookItem(
item: LogbookEntry,
index: number
): TemplateResult {
const previous = this.entries[index - 1];
return html`
<div>
${index === 0 ||
(item?.when &&
previous?.when &&
new Date(item.when).toDateString() !==
new Date(previous.when).toDateString())
? html`
<h4 class="date">
${formatDate(new Date(item.when), this.hass.language)}
</h4>
`
: html``}
<div class="entry">
<div class="time">
${formatTime(new Date(item.when), this.hass.language)}
</div>
<iron-icon .icon="${domainIcon(item.domain)}"></iron-icon>
<div class="message">
${!item.entity_id
? html`
<span class="name">${item.name}</span>
`
: html`
<a
href="#"
@click=${this._entityClicked}
.entityId=${item.entity_id}
class="name"
>
${item.name}
</a>
`}
<span>${item.message}</span>
</div>
</div>
</div>
`;
}
private _entityClicked(ev: Event) {
ev.preventDefault();
fireEvent(this, "hass-more-info", {
entityId: (ev.target as any).entityId,
});
}
static get styles(): CSSResult {
return css`
:host {
display: block;
height: 100%;
}
:host([rtl]) {
direction: ltr;
}
.entry {
display: flex;
line-height: 2em;
}
.time {
width: 55px;
font-size: 0.8em;
color: var(--secondary-text-color);
}
:host([rtl]) .date {
direction: rtl;
}
iron-icon {
margin: 0 8px 0 16px;
color: var(--primary-text-color);
}
.message {
color: var(--primary-text-color);
}
a {
color: var(--primary-color);
}
`;
}
}
customElements.define("ha-logbook", HaLogbook);

View File

@ -28,7 +28,15 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) {
return html`
<style include="ha-style">
.content {
padding: 0 16px 16px;
padding: 0 16px 0 16px;
}
ha-logbook {
height: calc(100vh - 136px);
}
:host([narrow]) ha-logbook {
height: calc(100vh - 198px);
}
paper-spinner {
@ -42,6 +50,15 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) {
margin-bottom: 24px;
}
.filters {
display: flex;
align-items: center;
}
:host([narrow]) .filters {
flex-wrap: wrap;
}
vaadin-date-picker {
max-width: 200px;
margin-right: 16px;
@ -65,10 +82,15 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) {
ha-entity-picker {
display: inline-block;
width: 100%;
flex-grow: 1;
max-width: 400px;
}
:host([narrow]) ha-entity-picker {
max-width: none;
width: 100%;
}
[hidden] {
display: none !important;
}
@ -106,7 +128,7 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) {
alt="[[localize('ui.common.loading')]]"
></paper-spinner>
<div class="flex layout horizontal wrap">
<div class="filters">
<vaadin-date-picker
id="picker"
value="{{_currentDate}}"
@ -158,7 +180,8 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) {
static get properties() {
return {
hass: Object,
narrow: Boolean,
narrow: { type: Boolean, reflectToAttribute: true },
// ISO8601 formatted date string
_currentDate: {

View File

@ -6246,6 +6246,11 @@ etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
event-target-shim@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
eventemitter3@3.1.0, eventemitter3@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
@ -8751,7 +8756,7 @@ listr@^0.14.2:
p-map "^2.0.0"
rxjs "^6.3.3"
lit-element@^2.2.1:
lit-element@^2.0.0, lit-element@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-2.2.1.tgz#79c94d8cfdc2d73b245656e37991bd1e4811d96f"
integrity sha512-ipDcgQ1EpW6Va2Z6dWm79jYdimVepO5GL0eYkZrFvdr0OD/1N260Q9DH+K5HXHFrRoC7dOg+ZpED2XE0TgGdXw==
@ -8763,6 +8768,17 @@ lit-html@^1.0.0, lit-html@^1.1.0, lit-html@^1.1.2:
resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.1.2.tgz#2e3560a7075210243649c888ad738eaf0daa8374"
integrity sha512-FFlUMKHKi+qG1x1iHNZ1hrtc/zHmfYTyrSvs3/wBTvaNtpZjOZGWzU7efGYVpgp6KvWeKF6ql9/KsCq6Z/mEDA==
lit-virtualizer@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/lit-virtualizer/-/lit-virtualizer-0.4.2.tgz#8c66e26c0e50cd8e3fc7f2dfeab932967b40050a"
integrity sha512-aytx/Qym8h7eIh3u17oT2FfgmhOixnk4IuJAOMIbA6E8szkbpnKUDSLDWlN9ihQyCb0eijV213P+4mlekOWKxA==
dependencies:
event-target-shim "^5.0.1"
lit-element "^2.0.0"
lit-html "^1.0.0"
resize-observer-polyfill "^1.5.1"
tslib "^1.10.0"
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@ -11622,6 +11638,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
resolve-cwd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"