From 3b425c3e140f5b1752fb4a2752fcc4d44e32b51b Mon Sep 17 00:00:00 2001 From: Nikolay Vasilchuk <Anonym.tsk@gmail.com> Date: Thu, 11 Oct 2018 12:46:16 +0300 Subject: [PATCH] Logbook: filter by entity and period (#1728) * Filter logbook by entity_id * Filter logbook by period * Filter logbook styles * CI Fix * Review * Review * CI Fix --- src/panels/logbook/ha-logbook-data.js | 86 ++++++++++++++++------ src/panels/logbook/ha-logbook.js | 16 +++++ src/panels/logbook/ha-panel-logbook.js | 99 +++++++++++++++++++++++--- 3 files changed, 167 insertions(+), 34 deletions(-) diff --git a/src/panels/logbook/ha-logbook-data.js b/src/panels/logbook/ha-logbook-data.js index c4188951c1..996e11bc74 100644 --- a/src/panels/logbook/ha-logbook-data.js +++ b/src/panels/logbook/ha-logbook-data.js @@ -1,6 +1,7 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js'; -var DATE_CACHE = {}; +const DATA_CACHE = {}; +const ALL_ENTITIES = '*'; class HaLogbookData extends PolymerElement { static get properties() { @@ -12,7 +13,17 @@ class HaLogbookData extends PolymerElement { filterDate: { type: String, - observer: 'filterDateChanged', + observer: 'filterDataChanged', + }, + + filterPeriod: { + type: Number, + observer: 'filterDataChanged', + }, + + filterEntity: { + type: String, + observer: 'filterDataChanged', }, isLoading: { @@ -33,41 +44,70 @@ class HaLogbookData extends PolymerElement { hassChanged(newHass, oldHass) { if (!oldHass && this.filterDate) { - this.filterDateChanged(this.filterDate); + this.updateData(); } } - filterDateChanged(filterDate) { + filterDataChanged(newValue, oldValue) { + if (oldValue !== undefined) { + this.updateData(); + } + } + + updateData() { if (!this.hass) return; this._setIsLoading(true); - this.getDate(filterDate).then(function (logbookEntries) { - this._setEntries(logbookEntries); - this._setIsLoading(false); - }.bind(this)); + this.getDate(this.filterDate, this.filterPeriod, this.filterEntity) + .then((logbookEntries) => { + this._setEntries(logbookEntries); + this._setIsLoading(false); + }); } - getDate(date) { - if (!DATE_CACHE[date]) { - DATE_CACHE[date] = this.hass.callApi('GET', 'logbook/' + date).then( - function (logbookEntries) { - logbookEntries.reverse(); - return logbookEntries; - }, - function () { - DATE_CACHE[date] = false; - return null; - } - ); + getDate(date, period, entityId) { + if (!entityId) entityId = ALL_ENTITIES; + + if (!DATA_CACHE[period]) DATA_CACHE[period] = []; + if (!DATA_CACHE[period][date]) DATA_CACHE[period][date] = []; + + if (DATA_CACHE[period][date][entityId]) { + return DATA_CACHE[period][date][entityId]; } - return DATE_CACHE[date]; + if (entityId !== ALL_ENTITIES && DATA_CACHE[period][date][ALL_ENTITIES]) { + return DATA_CACHE[period][date][ALL_ENTITIES].then(function (entities) { + return entities.filter(function (entity) { + return entity.entity_id === entityId; + }); + }); + } + + DATA_CACHE[period][date][entityId] = this._getFromServer(date, period, entityId); + return DATA_CACHE[period][date][entityId]; + } + + _getFromServer(date, period, entityId) { + let url = 'logbook/' + date + '?period=' + period; + if (entityId !== ALL_ENTITIES) { + url += '&entity=' + entityId; + } + + return this.hass.callApi('GET', url).then( + function (logbookEntries) { + logbookEntries.reverse(); + return logbookEntries; + }, + function () { + return null; + } + ); } refreshLogbook() { - DATE_CACHE[this.filterDate] = null; - this.filterDateChanged(this.filterDate); + DATA_CACHE[this.filterPeriod][this.filterDate] = []; + this.updateData(); } } diff --git a/src/panels/logbook/ha-logbook.js b/src/panels/logbook/ha-logbook.js index 387056f61c..d2a600140b 100644 --- a/src/panels/logbook/ha-logbook.js +++ b/src/panels/logbook/ha-logbook.js @@ -5,6 +5,7 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import formatTime from '../../common/datetime/format_time.js'; +import formatDate from '../../common/datetime/format_date.js'; import EventsMixin from '../../mixins/events-mixin.js'; import domainIcon from '../../common/entity/domain_icon.js'; @@ -50,6 +51,10 @@ class HaLogbook extends EventsMixin(PolymerElement) { </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> @@ -85,6 +90,17 @@ class HaLogbook extends EventsMixin(PolymerElement) { return formatTime(new Date(date), this.language); } + _formatDate(date) { + return formatDate(new Date(date), this.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 && current.substr(0, 10) !== previous.substr(0, 10); + } + _computeIcon(domain) { return domainIcon(domain); } diff --git a/src/panels/logbook/ha-panel-logbook.js b/src/panels/logbook/ha-panel-logbook.js index cab422b0ea..9220ebdf38 100644 --- a/src/panels/logbook/ha-panel-logbook.js +++ b/src/panels/logbook/ha-panel-logbook.js @@ -9,6 +9,7 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import '@vaadin/vaadin-date-picker/vaadin-date-picker.js'; import '../../components/ha-menu-button.js'; +import '../../components/entity/ha-entity-picker.js'; import '../../resources/ha-date-picker-style.js'; import '../../resources/ha-style.js'; @@ -31,16 +32,36 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) { paper-spinner { position: absolute; - top: 15px; - left: 186px; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + } + + .wrap { + margin-bottom: 24px; } vaadin-date-picker { --vaadin-date-picker-clear-icon: { display: none; } - margin-bottom: 24px; max-width: 200px; + margin-right: 16px; + } + + paper-dropdown-menu { + max-width: 100px; + margin-right: 16px; + } + + paper-item { + cursor: pointer; + } + + ha-entity-picker { + display: inline-block; + width: 100%; + max-width: 400px; } [hidden] { @@ -53,6 +74,8 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) { is-loading='{{isLoading}}' entries='{{entries}}' filter-date='[[_computeFilterDate(_currentDate)]]' + filter-period='[[_computeFilterDays(_periodIndex)]]' + filter-entity='[[entityId]]' ></ha-logbook-data> <app-header-layout has-scrolling-region> @@ -75,14 +98,38 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) { alt="[[localize('ui.common.loading')]]" ></paper-spinner> - <vaadin-date-picker - id='picker' - value='{{_currentDate}}' - label="[[localize('ui.panel.logbook.showing_entries')]]" - disabled='[[isLoading]]' - required - ></vaadin-date-picker> - + <div class="flex layout horizontal wrap"> + <vaadin-date-picker + id='picker' + value='{{_currentDate}}' + label="[[localize('ui.panel.logbook.showing_entries')]]" + disabled='[[isLoading]]' + required + ></vaadin-date-picker> + + <paper-dropdown-menu + label-float + label="[[localize('ui.panel.logbook.period')]]" + disabled='[[isLoading]]' + > + <paper-listbox + slot="dropdown-content" + selected="{{_periodIndex}}" + > + <paper-item>[[localize('ui.duration.day', 'count', 1)]]</paper-item> + <paper-item>[[localize('ui.duration.day', 'count', 3)]]</paper-item> + <paper-item>[[localize('ui.duration.week', 'count', 1)]]</paper-item> + </paper-listbox> + </paper-dropdown-menu> + + <ha-entity-picker + hass="[[hass]]" + value="{{_entityId}}" + label="[[localize('ui.components.entity.entity-picker.entity')]]" + disabled='[[isLoading]]' + on-change='_entityPicked' + ></ha-entity-picker> + </div> <ha-logbook hass='[[hass]]' entries="[[entries]]" hidden$='[[isLoading]]'></ha-logbook> </div> @@ -116,6 +163,22 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) { } }, + _periodIndex: { + type: Number, + value: 0, + }, + + _entityId: { + type: String, + value: '', + }, + + entityId: { + type: String, + value: '', + readOnly: true, + }, + isLoading: { type: Boolean, }, @@ -145,6 +208,20 @@ class HaPanelLogbook extends LocalizeMixin(PolymerElement) { return new Date(parts[0], parts[1], parts[2]).toISOString(); } + _computeFilterDays(periodIndex) { + switch (periodIndex) { + case 1: + return 3; + case 2: + return 7; + default: return 1; + } + } + + _entityPicked(ev) { + this._setEntityId(ev.target.value); + } + refreshLogbook() { this.shadowRoot.querySelector('ha-logbook-data').refreshLogbook(); }