mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-21 16:26:43 +00:00
Virtualize logbook (#4450)
* Virtualize logbook * Clean * Update ha-logbook.ts
This commit is contained in:
parent
adce40de56
commit
58ad949bc8
@ -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
7
src/data/logbook.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export interface LogbookEntry {
|
||||
when: string;
|
||||
name: string;
|
||||
message: string;
|
||||
entity_id?: string;
|
||||
domain: string;
|
||||
}
|
@ -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);
|
156
src/panels/logbook/ha-logbook.ts
Normal file
156
src/panels/logbook/ha-logbook.ts
Normal 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);
|
@ -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: {
|
||||
|
23
yarn.lock
23
yarn.lock
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user