ha-frontend-cdce8p/src/layouts/partial-panel-resolver.js
Paulus Schoutsen c3d67133c2
Improve custom panel support (#1236)
* Add custom panel

* Lint

* Add reference to docs

* Use panel.config
2018-06-01 10:06:28 -04:00

225 lines
6.0 KiB
JavaScript

import '@polymer/app-route/app-route.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import './hass-loading-screen.js';
import { importHref } from '../resources/html-import/import-href';
import dynamicContentUpdater from '../common/dom/dynamic_content_updater.js';
import NavigateMixin from '../mixins/navigate-mixin.js';
const loaded = {};
function ensureLoaded(panel) {
if (panel in loaded) return loaded[panel];
let imported;
// Name each panel we support here, that way Webpack knows about it.
switch (panel) {
case 'config':
imported = import(/* webpackChunkName: "panel-config" */ '../panels/config/ha-panel-config.js');
break;
case 'custom':
imported = import(/* webpackChunkName: "panel-custom" */ '../panels/custom/ha-panel-custom.js');
break;
case 'dev-event':
imported = import(/* webpackChunkName: "panel-dev-event" */ '../panels/dev-event/ha-panel-dev-event.js');
break;
case 'dev-info':
imported = import(/* webpackChunkName: "panel-dev-info" */ '../panels/dev-info/ha-panel-dev-info.js');
break;
case 'dev-mqtt':
imported = import(/* webpackChunkName: "panel-dev-mqtt" */ '../panels/dev-mqtt/ha-panel-dev-mqtt.js');
break;
case 'dev-service':
imported = import(/* webpackChunkName: "panel-dev-service" */ '../panels/dev-service/ha-panel-dev-service.js');
break;
case 'dev-state':
imported = import(/* webpackChunkName: "panel-dev-state" */ '../panels/dev-state/ha-panel-dev-state.js');
break;
case 'dev-template':
imported = import(/* webpackChunkName: "panel-dev-template" */ '../panels/dev-template/ha-panel-dev-template.js');
break;
case 'hassio':
imported = import(/* webpackChunkName: "panel-hassio" */ '../panels/hassio/ha-panel-hassio.js');
break;
case 'history':
imported = import(/* webpackChunkName: "panel-history" */ '../panels/history/ha-panel-history.js');
break;
case 'iframe':
imported = import(/* webpackChunkName: "panel-iframe" */ '../panels/iframe/ha-panel-iframe.js');
break;
case 'kiosk':
imported = import(/* webpackChunkName: "panel-kiosk" */ '../panels/kiosk/ha-panel-kiosk.js');
break;
case 'logbook':
imported = import(/* webpackChunkName: "panel-logbook" */ '../panels/logbook/ha-panel-logbook.js');
break;
case 'mailbox':
imported = import(/* webpackChunkName: "panel-mailbox" */ '../panels/mailbox/ha-panel-mailbox.js');
break;
case 'map':
imported = import(/* webpackChunkName: "panel-map" */ '../panels/map/ha-panel-map.js');
break;
case 'shopping-list':
imported = import(/* webpackChunkName: "panel-shopping-list" */ '../panels/shopping-list/ha-panel-shopping-list.js');
break;
default:
imported = null;
}
if (imported != null) {
loaded[panel] = imported;
}
return imported;
}
/*
* @appliesMixin NavigateMixin
*/
class PartialPanelResolver extends NavigateMixin(PolymerElement) {
static get template() {
return html`
<style>
[hidden] {
display: none !important;
}
</style>
<app-route route="{{route}}" pattern="/:panel" data="{{routeData}}" tail="{{routeTail}}"></app-route>
<template is="dom-if" if="[[!resolved]]">
<hass-loading-screen narrow="[[narrow]]" show-menu="[[showMenu]]"></hass-loading-screen>
</template>
<span id="panel" hidden\$="[[!resolved]]"></span>
`;
}
static get properties() {
return {
hass: {
type: Object,
observer: 'updateAttributes',
},
narrow: {
type: Boolean,
value: false,
observer: 'updateAttributes',
},
showMenu: {
type: Boolean,
value: false,
observer: 'updateAttributes',
},
route: Object,
routeData: Object,
routeTail: {
type: Object,
observer: 'updateAttributes',
},
resolved: {
type: Boolean,
value: false,
},
panel: {
type: Object,
computed: 'computeCurrentPanel(hass)',
observer: 'panelChanged',
},
};
}
panelChanged(panel) {
if (!panel) {
if (this.$.panel.lastChild) {
this.$.panel.removeChild(this.$.panel.lastChild);
}
return;
}
this.resolved = false;
let loadingProm;
if (panel.url) {
loadingProm = new Promise((resolve, reject) => importHref(panel.url, resolve, reject));
} else {
loadingProm = ensureLoaded(panel.component_name);
}
if (loadingProm === null) {
this.panelLoadError(panel);
return;
}
loadingProm.then(
() => {
dynamicContentUpdater(this.$.panel, 'ha-panel-' + panel.component_name, {
hass: this.hass,
narrow: this.narrow,
showMenu: this.showMenu,
route: this.routeTail,
panel: panel,
});
this.resolved = true;
},
(err) => {
/* eslint-disable-next-line */
console.error('Error loading panel', err);
// a single retry of importHref in the error callback fixes a webkit refresh issue
if (!this.retrySetPanelForWebkit(panel)) {
this.panelLoadError(panel);
}
},
);
}
panelLoadError(panel) {
alert(`I don't know how to resolve panel ${panel.component_name}`);
this.navigate('/states');
}
retrySetPanelForWebkit(panel) {
if (this._retryingPanelChanged) {
return false;
}
this._retryingPanelChanged = true;
return this.panelChanged(panel);
}
updateAttributes() {
var customEl = dom(this.$.panel).lastChild;
if (!customEl) return;
customEl.hass = this.hass;
customEl.narrow = this.narrow;
customEl.showMenu = this.showMenu;
customEl.route = this.routeTail;
}
computeCurrentPanel(hass) {
return hass.config.panels[hass.panelUrl];
}
}
customElements.define('partial-panel-resolver', PartialPanelResolver);