mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-09 10:26:35 +00:00
Get persistent_notifications for lovelace from websocket. (#1649)
* Get persistent_notifications for lovelace from websocket. * Only fetch notifications on event. * Use collection for notifications.
This commit is contained in:
parent
443e083a79
commit
5187f3b84f
@ -8,6 +8,7 @@ import '../components/ha-markdown.js';
|
|||||||
|
|
||||||
import computeStateName from '../common/entity/compute_state_name.js';
|
import computeStateName from '../common/entity/compute_state_name.js';
|
||||||
import LocalizeMixin from '../mixins/localize-mixin.js';
|
import LocalizeMixin from '../mixins/localize-mixin.js';
|
||||||
|
import computeObjectId from '../common/entity/compute_object_id';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @appliesMixin LocalizeMixin
|
* @appliesMixin LocalizeMixin
|
||||||
@ -65,7 +66,9 @@ class HaPersistentNotificationCard extends LocalizeMixin(PolymerElement) {
|
|||||||
|
|
||||||
dismissTap(ev) {
|
dismissTap(ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.hass.callApi('DELETE', 'states/' + this.stateObj.entity_id);
|
this.hass.callService('persistent_notification', 'dismiss', {
|
||||||
|
notification_id: computeObjectId(this.stateObj.entity_id)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define('ha-persistent_notification-card', HaPersistentNotificationCard);
|
customElements.define('ha-persistent_notification-card', HaPersistentNotificationCard);
|
||||||
|
20
src/data/ws-notifications.js
Normal file
20
src/data/ws-notifications.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { createCollection } from 'home-assistant-js-websocket';
|
||||||
|
|
||||||
|
const fetchNotifications = conn => conn.sendMessagePromise({
|
||||||
|
type: 'persistent_notification/get'
|
||||||
|
});
|
||||||
|
|
||||||
|
const subscribeUpdates = (conn, store) =>
|
||||||
|
conn.subscribeEvents(
|
||||||
|
() => fetchNotifications(conn).then(ntf => store.setState(ntf, true)),
|
||||||
|
'persistent_notifications_updated'
|
||||||
|
);
|
||||||
|
|
||||||
|
export const subscribeNotifications = (conn, onChange) =>
|
||||||
|
createCollection(
|
||||||
|
'_ntf',
|
||||||
|
fetchNotifications,
|
||||||
|
subscribeUpdates,
|
||||||
|
conn,
|
||||||
|
onChange
|
||||||
|
);
|
@ -1,12 +1,7 @@
|
|||||||
import computeDomain from '../../../common/entity/compute_domain.js';
|
import computeDomain from '../../../common/entity/compute_domain.js';
|
||||||
|
|
||||||
const NOTIFICATION_DOMAINS = [
|
|
||||||
'configurator',
|
|
||||||
'persistent_notification'
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function computeNotifications(states) {
|
export default function computeNotifications(states) {
|
||||||
return Object.keys(states)
|
return Object.keys(states)
|
||||||
.filter(entityId => NOTIFICATION_DOMAINS.includes(computeDomain(entityId)))
|
.filter(entityId => computeDomain(entityId) === 'configurator')
|
||||||
.map(entityId => states[entityId]);
|
.map(entityId => states[entityId]);
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,13 @@ export class HuiConfiguratorNotificationItem extends EventsMixin(LocalizeMixin(P
|
|||||||
<hui-notification-item-template>
|
<hui-notification-item-template>
|
||||||
<span slot="header">[[localize('domain.configurator')]]</span>
|
<span slot="header">[[localize('domain.configurator')]]</span>
|
||||||
|
|
||||||
<div>[[_getMessage(stateObj)]]</div>
|
<div>[[_getMessage(notification)]]</div>
|
||||||
|
|
||||||
<paper-button
|
<paper-button
|
||||||
slot="actions"
|
slot="actions"
|
||||||
class="primary"
|
class="primary"
|
||||||
on-click="_handleClick"
|
on-click="_handleClick"
|
||||||
>[[_localizeState(stateObj.state)]]</paper-button>
|
>[[_localizeState(notification.state)]]</paper-button>
|
||||||
</hui-notification-item-template>
|
</hui-notification-item-template>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -33,20 +33,20 @@ export class HuiConfiguratorNotificationItem extends EventsMixin(LocalizeMixin(P
|
|||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
hass: Object,
|
hass: Object,
|
||||||
stateObj: Object
|
notification: Object
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleClick() {
|
_handleClick() {
|
||||||
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
|
this.fire('hass-more-info', { entityId: this.notification.entity_id });
|
||||||
}
|
}
|
||||||
|
|
||||||
_localizeState(state) {
|
_localizeState(state) {
|
||||||
return this.localize(`state.configurator.${state}`);
|
return this.localize(`state.configurator.${state}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
_getMessage(stateObj) {
|
_getMessage(notification) {
|
||||||
const friendlyName = stateObj.attributes.friendly_name;
|
const friendlyName = notification.attributes.friendly_name;
|
||||||
return this.localize('ui.notification_drawer.click_to_configure', 'entity', friendlyName);
|
return this.localize('ui.notification_drawer.click_to_configure', 'entity', friendlyName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|||||||
|
|
||||||
import './hui-notification-item.js';
|
import './hui-notification-item.js';
|
||||||
|
|
||||||
import computeNotifications from '../../common/compute-notifications.js';
|
|
||||||
|
|
||||||
import EventsMixin from '../../../../mixins/events-mixin.js';
|
import EventsMixin from '../../../../mixins/events-mixin.js';
|
||||||
import LocalizeMixin from '../../../../mixins/localize-mixin.js';
|
import LocalizeMixin from '../../../../mixins/localize-mixin.js';
|
||||||
|
|
||||||
@ -105,16 +103,16 @@ export class HuiNotificationDrawer extends EventsMixin(LocalizeMixin(PolymerElem
|
|||||||
<paper-icon-button icon="hass:chevron-right" on-click="_closeDrawer"></paper-icon-button>
|
<paper-icon-button icon="hass:chevron-right" on-click="_closeDrawer"></paper-icon-button>
|
||||||
</app-toolbar>
|
</app-toolbar>
|
||||||
<div class="notifications">
|
<div class="notifications">
|
||||||
<template is="dom-if" if="[[!_empty(_entities)]]">
|
<template is="dom-if" if="[[!_empty(notifications)]]">
|
||||||
<dom-repeat items="[[_entities]]">
|
<dom-repeat items="[[notifications]]">
|
||||||
<template>
|
<template>
|
||||||
<div class="notification">
|
<div class="notification">
|
||||||
<hui-notification-item hass="[[hass]]" state-obj="[[item]]"></hui-notification-item>
|
<hui-notification-item hass="[[hass]]" notification="[[item]]"></hui-notification-item>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-repeat>
|
</dom-repeat>
|
||||||
</template>
|
</template>
|
||||||
<template is="dom-if" if="[[_empty(_entities)]]">
|
<template is="dom-if" if="[[_empty(notifications)]]">
|
||||||
<div class="empty">[[localize('ui.notification_drawer.empty')]]<div>
|
<div class="empty">[[localize('ui.notification_drawer.empty')]]<div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@ -125,10 +123,6 @@ export class HuiNotificationDrawer extends EventsMixin(LocalizeMixin(PolymerElem
|
|||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
hass: Object,
|
hass: Object,
|
||||||
_entities: {
|
|
||||||
type: Array,
|
|
||||||
computed: '_getEntities(hass.states, hidden)'
|
|
||||||
},
|
|
||||||
narrow: {
|
narrow: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
reflectToAttribute: true
|
reflectToAttribute: true
|
||||||
@ -142,21 +136,21 @@ export class HuiNotificationDrawer extends EventsMixin(LocalizeMixin(PolymerElem
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
value: true,
|
value: true,
|
||||||
reflectToAttribute: true
|
reflectToAttribute: true
|
||||||
|
},
|
||||||
|
notifications: {
|
||||||
|
type: Array,
|
||||||
|
value: []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_getEntities(states, hidden) {
|
|
||||||
return (states && !hidden) ? computeNotifications(states) : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
_closeDrawer(ev) {
|
_closeDrawer(ev) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
this.open = false;
|
this.open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_empty(entities) {
|
_empty(notifications) {
|
||||||
return entities.length === 0;
|
return notifications.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_openChanged(open) {
|
_openChanged(open) {
|
||||||
|
@ -8,25 +8,27 @@ export class HuiNotificationItem extends PolymerElement {
|
|||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
hass: Object,
|
hass: Object,
|
||||||
stateObj: {
|
notification: {
|
||||||
type: Object,
|
type: Object,
|
||||||
observer: '_stateChanged'
|
observer: '_stateChanged'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_stateChanged(stateObj) {
|
_stateChanged(notification) {
|
||||||
if (this.lastChild) {
|
if (this.lastChild) {
|
||||||
this.removeChild(this.lastChild);
|
this.removeChild(this.lastChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stateObj) return;
|
if (!notification) return;
|
||||||
|
|
||||||
const domain = computeDomain(stateObj.entity_id);
|
const domain = notification.entity_id
|
||||||
|
? computeDomain(notification.entity_id)
|
||||||
|
: 'persistent_notification';
|
||||||
const tag = `hui-${domain}-notification-item`;
|
const tag = `hui-${domain}-notification-item`;
|
||||||
const el = document.createElement(tag);
|
const el = document.createElement(tag);
|
||||||
el.hass = this.hass;
|
el.hass = this.hass;
|
||||||
el.stateObj = stateObj;
|
el.notification = notification;
|
||||||
this.appendChild(el);
|
this.appendChild(el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@ import '@polymer/app-layout/app-toolbar/app-toolbar.js';
|
|||||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||||
|
|
||||||
import computeNotifications from '../../common/compute-notifications.js';
|
|
||||||
|
|
||||||
import EventsMixin from '../../../../mixins/events-mixin.js';
|
import EventsMixin from '../../../../mixins/events-mixin.js';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -36,16 +34,19 @@ export class HuiNotificationsButton extends EventsMixin(PolymerElement) {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<paper-icon-button icon="hass:bell" on-click="_clicked"></paper-icon-button>
|
<paper-icon-button icon="hass:bell" on-click="_clicked"></paper-icon-button>
|
||||||
<span class="indicator" hidden$="[[!_hasNotifications(hass.states)]]"></span>
|
<span class="indicator" hidden$="[[!_hasNotifications(notifications)]]"></span>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
hass: Object,
|
|
||||||
notificationsOpen: {
|
notificationsOpen: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
notify: true
|
notify: true
|
||||||
|
},
|
||||||
|
notifications: {
|
||||||
|
type: Array,
|
||||||
|
value: []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -54,8 +55,8 @@ export class HuiNotificationsButton extends EventsMixin(PolymerElement) {
|
|||||||
this.notificationsOpen = true;
|
this.notificationsOpen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasNotifications(states) {
|
_hasNotifications(notifications) {
|
||||||
return computeNotifications(states).length > 0;
|
return notifications.length > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define('hui-notifications-button', HuiNotificationsButton);
|
customElements.define('hui-notifications-button', HuiNotificationsButton);
|
||||||
|
@ -4,8 +4,6 @@ import '@polymer/paper-icon-button/paper-icon-button.js';
|
|||||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||||
|
|
||||||
import computeStateName from '../../../../common/entity/compute_state_name.js';
|
|
||||||
|
|
||||||
import '../../../../components/ha-markdown.js';
|
import '../../../../components/ha-markdown.js';
|
||||||
import './hui-notification-item-template.js';
|
import './hui-notification-item-template.js';
|
||||||
|
|
||||||
@ -18,13 +16,13 @@ export class HuiPersistentNotificationItem extends LocalizeMixin(PolymerElement)
|
|||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<hui-notification-item-template>
|
<hui-notification-item-template>
|
||||||
<span slot="header">[[_computeTitle(stateObj)]]</span>
|
<span slot="header">[[_computeTitle(notification)]]</span>
|
||||||
|
|
||||||
<ha-markdown content="[[stateObj.attributes.message]]"></ha-markdown>
|
<ha-markdown content="[[notification.message]]"></ha-markdown>
|
||||||
|
|
||||||
<paper-button
|
<paper-button
|
||||||
slot="actions"
|
slot="actions"
|
||||||
class="primary"
|
class="primary"
|
||||||
on-click="_handleDismiss"
|
on-click="_handleDismiss"
|
||||||
>[[localize('ui.card.persistent_notification.dismiss')]]</paper-button>
|
>[[localize('ui.card.persistent_notification.dismiss')]]</paper-button>
|
||||||
</hui-notification-item-template>
|
</hui-notification-item-template>
|
||||||
@ -34,16 +32,18 @@ export class HuiPersistentNotificationItem extends LocalizeMixin(PolymerElement)
|
|||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
hass: Object,
|
hass: Object,
|
||||||
stateObj: Object
|
notification: Object
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleDismiss() {
|
_handleDismiss() {
|
||||||
this.hass.callApi('DELETE', `states/${this.stateObj.entity_id}`);
|
this.hass.callService('persistent_notification', 'dismiss', {
|
||||||
|
notification_id: this.notification.notification_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_computeTitle(stateObj) {
|
_computeTitle(notification) {
|
||||||
return (stateObj.attributes.title || computeStateName(stateObj));
|
return notification.title || notification.notification_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define(
|
customElements.define(
|
||||||
|
@ -22,6 +22,7 @@ import '../../layouts/ha-app-layout.js';
|
|||||||
import '../../components/ha-start-voice-button.js';
|
import '../../components/ha-start-voice-button.js';
|
||||||
import '../../components/ha-icon.js';
|
import '../../components/ha-icon.js';
|
||||||
import { loadModule, loadCSS, loadJS } from '../../common/dom/load_resource.js';
|
import { loadModule, loadCSS, loadJS } from '../../common/dom/load_resource.js';
|
||||||
|
import { subscribeNotifications } from '../../data/ws-notifications';
|
||||||
import './components/notifications/hui-notification-drawer.js';
|
import './components/notifications/hui-notification-drawer.js';
|
||||||
import './components/notifications/hui-notifications-button.js';
|
import './components/notifications/hui-notifications-button.js';
|
||||||
import './hui-unused-entities.js';
|
import './hui-unused-entities.js';
|
||||||
@ -29,6 +30,7 @@ import './hui-view.js';
|
|||||||
import debounce from '../../common/util/debounce.js';
|
import debounce from '../../common/util/debounce.js';
|
||||||
|
|
||||||
import createCardElement from './common/create-card-element.js';
|
import createCardElement from './common/create-card-element.js';
|
||||||
|
import computeNotifications from './common/compute-notifications';
|
||||||
|
|
||||||
// CSS and JS should only be imported once. Modules and HTML are safe.
|
// CSS and JS should only be imported once. Modules and HTML are safe.
|
||||||
const CSS_CACHE = {};
|
const CSS_CACHE = {};
|
||||||
@ -76,6 +78,7 @@ class HUIRoot extends NavigateMixin(EventsMixin(PolymerElement)) {
|
|||||||
<app-route route="[[route]]" pattern="/:view" data="{{routeData}}"></app-route>
|
<app-route route="[[route]]" pattern="/:view" data="{{routeData}}"></app-route>
|
||||||
<hui-notification-drawer
|
<hui-notification-drawer
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
|
notifications="[[_notifications]]"
|
||||||
open="{{notificationsOpen}}"
|
open="{{notificationsOpen}}"
|
||||||
narrow="[[narrow]]"
|
narrow="[[narrow]]"
|
||||||
></hui-notification-drawer>
|
></hui-notification-drawer>
|
||||||
@ -87,6 +90,7 @@ class HUIRoot extends NavigateMixin(EventsMixin(PolymerElement)) {
|
|||||||
<hui-notifications-button
|
<hui-notifications-button
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
notifications-open="{{notificationsOpen}}"
|
notifications-open="{{notificationsOpen}}"
|
||||||
|
notifications="[[_notifications]]"
|
||||||
></hui-notifications-button>
|
></hui-notifications-button>
|
||||||
<ha-start-voice-button hass="[[hass]]"></ha-start-voice-button>
|
<ha-start-voice-button hass="[[hass]]"></ha-start-voice-button>
|
||||||
<paper-menu-button
|
<paper-menu-button
|
||||||
@ -156,6 +160,16 @@ class HUIRoot extends NavigateMixin(EventsMixin(PolymerElement)) {
|
|||||||
value: false,
|
value: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_persistentNotifications: {
|
||||||
|
type: Array,
|
||||||
|
value: []
|
||||||
|
},
|
||||||
|
|
||||||
|
_notifications: {
|
||||||
|
type: Array,
|
||||||
|
computed: '_updateNotifications(hass.states, _persistentNotifications)'
|
||||||
|
},
|
||||||
|
|
||||||
routeData: Object,
|
routeData: Object,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -165,6 +179,27 @@ class HUIRoot extends NavigateMixin(EventsMixin(PolymerElement)) {
|
|||||||
this._debouncedConfigChanged = debounce(() => this._selectView(this._curView), 100);
|
this._debouncedConfigChanged = debounce(() => this._selectView(this._curView), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this._unsubNotifications = subscribeNotifications(this.hass.connection, (notifications) => {
|
||||||
|
this._persistentNotifications = notifications;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
if (typeof this._unsubNotifications === 'function') {
|
||||||
|
this._unsubNotifications();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateNotifications(states, persistent) {
|
||||||
|
if (!states) return persistent;
|
||||||
|
|
||||||
|
const configurator = computeNotifications(states);
|
||||||
|
return persistent.concat(configurator);
|
||||||
|
}
|
||||||
|
|
||||||
_routeChanged(route) {
|
_routeChanged(route) {
|
||||||
const views = this.config && this.config.views;
|
const views = this.config && this.config.views;
|
||||||
if (route.path === '' && route.prefix === '/lovelace' && views) {
|
if (route.path === '' && route.prefix === '/lovelace' && views) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user