Merge overview into integrations (#1672)

* Merge overview into integrations

* Lint
This commit is contained in:
Paulus Schoutsen 2018-09-19 11:11:00 +02:00 committed by GitHub
parent 67d09e8b3d
commit 7e0ff14f28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 394 additions and 409 deletions

View File

@ -14,6 +14,7 @@ class HassSubpage extends PolymerElement {
<app-toolbar>
<paper-icon-button icon="hass:arrow-left" on-click="_backTapped"></paper-icon-button>
<div main-title="">[[header]]</div>
<slot name="toolbar-icon"></slot>
</app-toolbar>
</app-header>

View File

@ -0,0 +1,197 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import '@polymer/paper-tooltip/paper-tooltip.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/paper-item/paper-item.js';
import '@polymer/paper-item/paper-item-body.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../../components/entity/ha-state-icon.js';
import '../../../layouts/hass-subpage.js';
import '../../../resources/ha-style.js';
import '../ha-config-section.js';
import EventsMixin from '../../../mixins/events-mixin.js';
import LocalizeMixin from '../../../mixins/localize-mixin.js';
import computeStateName from '../../../common/entity/compute_state_name.js';
let registeredDialog = false;
/*
* @appliesMixin LocalizeMixin
* @appliesMixin EventsMixin
*/
class HaConfigManagerDashboard extends
LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<style include="iron-flex ha-style">
paper-button {
color: var(--primary-color);
font-weight: 500;
top: 3px;
margin-right: -.57em;
}
paper-card:last-child {
margin-top: 12px;
}
.config-entry-row {
display: flex;
padding: 0 16px;
}
ha-state-icon {
cursor: pointer;
}
a paper-item {
color: var(--primary-text-color);
}
</style>
<hass-subpage header="Integrations">
<template is="dom-if" if="[[progress.length]]">
<ha-config-section>
<span slot="header">Discovered</span>
<paper-card>
<template is="dom-repeat" items="[[progress]]">
<div class="config-entry-row">
<paper-item-body>
[[_computeIntegrationTitle(localize, item.handler)]]
</paper-item-body>
<paper-button on-click="_continueFlow">Configure</paper-button>
</div>
</template>
</paper-card>
</ha-config-section>
</template>
<ha-config-section>
<span slot="header">Configured</span>
<paper-card>
<template is="dom-if" if="[[!entries.length]]">
<div class="config-entry-row">
<paper-item-body two-line>
<div>Nothing configured yet</div>
</paper-item-body>
</div>
</template>
<template is="dom-repeat" items="[[entries]]">
<a href='/config/integrations/[[item.entry_id]]'>
<paper-item>
<paper-item-body two-line>
<div>[[_computeIntegrationTitle(localize, item.domain)]]: [[item.title]]</div>
<div secondary>
<template is='dom-repeat' items='[[_computeConfigEntryEntities(hass, item, entities)]]'>
<span>
<ha-state-icon state-obj='[[item]]' on-click='_handleMoreInfo'></ha-state-icon>
<paper-tooltip position="bottom">[[_computeStateName(item)]]</paper-tooltip>
</span>
</template>
</div>
</paper-item-body>
<iron-icon icon='hass:chevron-right'></iron-icon>
</paper-item>
</a>
</template>
</paper-card>
</ha-config-section>
<ha-config-section>
<span slot="header">Set up a new integration</span>
<paper-card>
<template is="dom-repeat" items="[[handlers]]">
<div class="config-entry-row">
<paper-item-body>
[[_computeIntegrationTitle(localize, item)]]
</paper-item-body>
<paper-button on-click="_createFlow">Configure</paper-button>
</div>
</template>
</paper-card>
</ha-config-section>
</hass-subpage>
`;
}
static get properties() {
return {
hass: Object,
isWide: Boolean,
/**
* Existing entries.
*/
entries: Array,
/**
* Entity Registry entries.
*/
entities: Array,
/**
* Current flows that are in progress and have not been started by a user.
* For example, can be discovered devices that require more config.
*/
progress: Array,
handlers: Array,
};
}
connectedCallback() {
super.connectedCallback();
if (!registeredDialog) {
registeredDialog = true;
this.fire('register-dialog', {
dialogShowEvent: 'show-config-flow',
dialogTag: 'ha-config-flow',
dialogImport: () => import('./ha-config-flow.js'),
});
}
}
_createFlow(ev) {
this.fire('show-config-flow', {
hass: this.hass,
newFlowForHandler: ev.model.item,
dialogClosedCallback: () => this.fire('hass-reload-entries'),
});
}
_continueFlow(ev) {
this.fire('show-config-flow', {
hass: this.hass,
continueFlowId: ev.model.item.flow_id,
dialogClosedCallback: () => this.fire('hass-reload-entries'),
});
}
_computeIntegrationTitle(localize, integration) {
return localize(`component.${integration}.config.title`);
}
_computeConfigEntryEntities(hass, configEntry, entities) {
if (!entities) {
return [];
}
const states = [];
entities.forEach((entity) => {
if (entity.config_entry_id === configEntry.entry_id && entity.entity_id in hass.states) {
states.push(hass.states[entity.entity_id]);
}
});
return states;
}
_computeStateName(stateObj) {
return computeStateName(stateObj);
}
_handleMoreInfo(ev) {
this.fire('hass-more-info', { entityId: ev.model.item.entity_id });
}
}
customElements.define('ha-config-entries-dashboard', HaConfigManagerDashboard);

View File

@ -1,112 +1,37 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import '@polymer/paper-tooltip/paper-tooltip.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-item/paper-item-body.js';
import '@polymer/app-route/app-route.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
import { timeOut } from '@polymer/polymer/lib/utils/async.js';
import '../../../components/entity/ha-state-icon.js';
import '../../../layouts/hass-subpage.js';
import '../../../resources/ha-style.js';
import './ha-config-entries-dashboard.js';
import './ha-config-entry-page.js';
import NavigateMixin from '../../../mixins/navigate-mixin.js';
import compare from '../../../common/string/compare.js';
import '../ha-config-section.js';
import EventsMixin from '../../../mixins/events-mixin.js';
import LocalizeMixin from '../../../mixins/localize-mixin.js';
import computeStateName from '../../../common/entity/compute_state_name.js';
let registeredDialog = false;
/*
* @appliesMixin LocalizeMixin
* @appliesMixin EventsMixin
*/
class HaConfigManager extends
LocalizeMixin(EventsMixin(PolymerElement)) {
class HaConfigEntries extends NavigateMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex ha-style">
paper-button {
color: var(--primary-color);
font-weight: 500;
top: 3px;
margin-right: -.57em;
}
paper-card:last-child {
margin-top: 12px;
}
.config-entry-row {
display: flex;
padding: 0 16px;
}
ha-state-icon {
cursor: pointer;
}
</style>
<app-route route="[[route]]" pattern="/integrations/:page" data="{{_routeData}}" tail="{{_routeTail}}"></app-route>
<hass-subpage header="Integrations">
<template is="dom-if" if="[[_progress.length]]">
<ha-config-section>
<span slot="header">Discovered</span>
<paper-card>
<template is="dom-repeat" items="[[_progress]]">
<div class="config-entry-row">
<paper-item-body>
[[_computeIntegrationTitle(localize, item.handler)]]
</paper-item-body>
<paper-button on-click="_continueFlow">Configure</paper-button>
</div>
</template>
</paper-card>
</ha-config-section>
</template>
<ha-config-section>
<span slot="header">Configured</span>
<paper-card>
<template is="dom-if" if="[[!_entries.length]]">
<div class="config-entry-row">
<paper-item-body two-line>
<div>Nothing configured yet</div>
</paper-item-body>
</div>
</template>
<template is="dom-repeat" items="[[_entries]]">
<div class="config-entry-row">
<paper-item-body three-line>
<div>[[_computeIntegrationTitle(localize, item.domain)]]: [[item.title]]</div>
<div secondary>[[item.state]] added by [[item.source]]</div>
<div secondary>
<template is='dom-repeat' items='[[_computeConfigEntryEntities(hass, item, _entities)]]'>
<span>
<ha-state-icon state-obj='[[item]]' on-click='_handleMoreInfo'></ha-state-icon>
<paper-tooltip position="bottom">[[_computeStateName(item)]]</paper-tooltip>
</span>
</template>
</div>
</paper-item-body>
<paper-button on-click="_removeEntry">Remove</paper-button>
</div>
</template>
</paper-card>
</ha-config-section>
<ha-config-section>
<span slot="header">Set up a new integration</span>
<paper-card>
<template is="dom-repeat" items="[[_handlers]]">
<div class="config-entry-row">
<paper-item-body>
[[_computeIntegrationTitle(localize, item)]]
</paper-item-body>
<paper-button on-click="_createFlow">Configure</paper-button>
</div>
</template>
</paper-card>
</ha-config-section>
</hass-subpage>
<template is='dom-if' if='[[_configEntry]]'>
<ha-config-entry-page
hass='[[hass]]'
config-entry='[[_configEntry]]'
entries='[[_entries]]'
entities='[[_entities]]'
devices='[[_devices]]'
></ha-config-entry-page>
</template>
<template is='dom-if' if='[[!_configEntry]]'>
<ha-config-entries-dashboard
hass='[[hass]]'
entries='[[_entries]]'
entities='[[_entities]]'
handlers='[[_handlers]]'
progress='[[_progress]]'
></ha-config-entries-dashboard>
</template>
`;
}
@ -114,6 +39,12 @@ class HaConfigManager extends
return {
hass: Object,
isWide: Boolean,
route: Object,
_configEntry: {
type: Object,
computed: '_computeConfigEntry(_routeData, _entries)',
},
/**
* Existing entries.
@ -125,6 +56,11 @@ class HaConfigManager extends
*/
_entities: Array,
/**
* Device Registry entries.
*/
_devices: Array,
/**
* Current flows that are in progress and have not been started by a user.
* For example, can be discovered devices that require more config.
@ -132,26 +68,22 @@ class HaConfigManager extends
_progress: Array,
_handlers: Array,
_routeData: Object,
_routeTail: Object,
};
}
ready() {
super.ready();
this._loadData();
this.addEventListener('hass-reload-entries', () => this._loadData());
}
connectedCallback() {
super.connectedCallback();
if (!registeredDialog) {
registeredDialog = true;
this.fire('register-dialog', {
dialogShowEvent: 'show-config-flow',
dialogTag: 'ha-config-flow',
dialogImport: () => import('./ha-config-flow.js'),
});
}
this.hass.connection.subscribeEvents(() => {
this._debouncer = Debouncer.debounce(
this._debouncer,
@ -166,39 +98,10 @@ class HaConfigManager extends
if (this._unsubEvents) this._unsubEvents();
}
_createFlow(ev) {
this.fire('show-config-flow', {
hass: this.hass,
newFlowForHandler: ev.model.item,
dialogClosedCallback: () => this._loadData(),
});
}
_continueFlow(ev) {
this.fire('show-config-flow', {
hass: this.hass,
continueFlowId: ev.model.item.flow_id,
dialogClosedCallback: () => this._loadData(),
});
}
_removeEntry(ev) {
if (!confirm('Are you sure you want to delete this integration?')) return;
const entryId = ev.model.item.entry_id;
this.hass.callApi('delete', `config/config_entries/entry/${entryId}`)
.then((result) => {
this._entries = this._entries.filter(entry => entry.entry_id !== entryId);
if (result.require_restart) {
alert('Restart Home Assistant to finish removing this integration');
}
});
}
_loadData() {
this.hass.callApi('get', 'config/config_entries/entry')
.then((entries) => { this._entries = entries; });
this.hass.callApi('get', 'config/config_entries/entry').then((entries) => {
this._entries = entries.sort((conf1, conf2) => compare(conf1.title, conf2.title));
});
this.hass.callApi('get', 'config/config_entries/flow')
.then((progress) => { this._progress = progress; });
@ -208,32 +111,14 @@ class HaConfigManager extends
this.hass.callWS({ type: 'config/entity_registry/list' })
.then((entities) => { this._entities = entities; });
this.hass.callWS({ type: 'config/device_registry/list' })
.then((devices) => { this._devices = devices; });
}
_computeIntegrationTitle(localize, integration) {
return localize(`component.${integration}.config.title`);
}
_computeConfigEntryEntities(hass, configEntry, entities) {
if (!entities) {
return [];
}
const states = [];
entities.forEach((entity) => {
if (entity.config_entry_id === configEntry.entry_id && entity.entity_id in hass.states) {
states.push(hass.states[entity.entity_id]);
}
});
return states;
}
_computeStateName(stateObj) {
return computeStateName(stateObj);
}
_handleMoreInfo(ev) {
this.fire('hass-more-info', { entityId: ev.model.item.entity_id });
_computeConfigEntry(routeData, entries) {
return !!entries && !!routeData && entries.find(ent => ent.entry_id === routeData.page);
}
}
customElements.define('ha-config-entries', HaConfigManager);
customElements.define('ha-config-entries', HaConfigEntries);

View File

@ -0,0 +1,107 @@
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../../layouts/hass-subpage.js';
import '../../../components/entity/state-badge.js';
import compare from '../../../common/string/compare.js';
import './ha-device-card.js';
import EventsMixin from '../../../mixins/events-mixin.js';
import NavigateMixin from '../../../mixins/navigate-mixin.js';
class HaConfigEntryPage extends NavigateMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<style>
.content {
display: flex;
flex-wrap: wrap;
padding: 4px;
justify-content: center;
}
ha-device-card {
flex: 1;
min-width: 300px;
max-width: 300px;
margin: 8px;
}
@media(max-width: 600px) {
ha-device-card {
max-width: 500px;
margin-left: auto;
margin-right: auto;
}
}
</style>
<hass-subpage header='[[configEntry.title]]'>
<paper-icon-button
slot='toolbar-icon'
icon='hass:delete'
on-click='_removeEntry'
></paper-icon-button>
<div class='content'>
<template is='dom-repeat' items='[[_computeConfigEntryDevices(configEntry, devices)]]' as='device'>
<ha-device-card
hass='[[hass]]'
devices='[[devices]]'
device='[[device]]'
entities='[[entities]]'
></ha-device-card>
</template>
</div>
</hass-subpage>
`;
}
static get properties() {
return {
hass: Object,
isWide: Boolean,
configEntry: {
type: Object,
value: null,
},
/**
* Existing entries.
*/
_entries: Array,
/**
* Entity Registry entries.
*/
_entities: Array,
};
}
_computeConfigEntryDevices(configEntry, devices) {
if (!devices) return [];
return devices.filter(device =>
device.config_entries.includes(configEntry.entry_id)).sort((dev1, dev2) =>
// Put hub devices first, then sort by name
(!!dev1.hub_device_id - !!dev2.hub_device_id) ||
compare(dev1.name, dev2.name));
}
_removeEntry() {
if (!confirm('Are you sure you want to delete this integration?')) return;
const entryId = this.configEntry.entry_id;
this.hass.callApi('delete', `config/config_entries/entry/${entryId}`)
.then((result) => {
this.fire('hass-reload-entries');
if (result.require_restart) {
alert('Restart Home Assistant to finish removing this integration');
}
this.navigate('/config/integrations/dashboard', true);
});
}
}
customElements.define('ha-config-entry-page', HaConfigEntryPage);

View File

@ -1,3 +1,5 @@
import '@polymer/paper-item/paper-icon-item.js';
import '@polymer/paper-item/paper-item-body.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
@ -18,12 +20,13 @@ function computeEntityName(hass, entity) {
/*
* @appliesMixin EventsMixin
*/
class HaDeviceRow extends EventsMixin(PolymerElement) {
class HaDeviceCard extends EventsMixin(PolymerElement) {
static get template() {
return html`
<style>
:host {
paper-card {
display: block;
padding-bottom: 8px;
}
.device-row {
display: flex;
@ -40,58 +43,46 @@ class HaDeviceRow extends EventsMixin(PolymerElement) {
.device .manuf {
color: var(--secondary-text-color);
}
.entity-rows {
padding-top: 12px;
margin-left: 8px;
.hub-info {
margin-top: 8px;
}
.entity-row {
margin: 8px 0;
display: flex;
flex-direction: row;
}
state-badge {
margin-right: 8px;
paper-icon-item {
cursor: pointer;
}
.entity-row .entity-id {
.manuf,
.entity-id {
color: var(--secondary-text-color);
}
ha-overview-device-row {
margin-left: 16px;
}
</style>
<div>
<div class='device-row'>
<div class='device'>
<div class='name'>[[device.name]]</div>
<div class='model'>[[device.model]]</div>
<div class='manuf'>by [[device.manufacturer]]</div>
</div>
<div class='entity-rows'>
<template is='dom-repeat' items='[[_computeDeviceEntities(hass, device, entities)]]' as='entity'>
<div class='entity-row'>
<state-badge
state-obj="[[_computeStateObj(entity, hass)]]"
on-click='_openMoreInfo'
></state-badge>
<div>
<div class='name'>[[_computeEntityName(entity, hass)]]</div>
<div class='entity-id'>[[entity.entity_id]]</div>
</div>
</div class='entity-row'>
<paper-card heading='[[device.name]]'>
<div class='card-content'>
<!-- <h1>[[configEntry.title]] ([[_computeIntegrationTitle(localize, configEntry.domain)]])</h1> -->
<div class='info'>
<div class='model'>[[device.model]]</div>
<div class='manuf'>by [[device.manufacturer]]</div>
</div>
<template is='dom-if' if='[[device.hub_device_id]]'>
<div class='hub-info'>
Connected via
<span class='hub'>[[_computeDeviceName(devices, device.hub_device_id)]]</span>
</div>
</template>
</div>
</div>
<template is='dom-repeat' items='[[_childDevices]]' as='device'>
<ha-overview-device-row
hass='[[hass]]'
devices='[[devices]]'
device='[[device]]'
entities='[[entities]]'
></ha-overview-device-row>
<template is='dom-repeat' items='[[_computeDeviceEntities(hass, device, entities)]]' as='entity'>
<paper-icon-item on-click='_openMoreInfo'>
<state-badge
state-obj="[[_computeStateObj(entity, hass)]]"
slot='item-icon'
></state-badge>
<paper-item-body>
<div class='name'>[[_computeEntityName(entity, hass)]]</div>
<div class='secondary entity-id'>[[entity.entity_id]]</div>
</paper-item-body>
</paper-icon-item>
</template>
</div>
</paper-card>
`;
}
@ -141,4 +132,4 @@ class HaDeviceRow extends EventsMixin(PolymerElement) {
}
}
customElements.define('ha-overview-device-row', HaDeviceRow);
customElements.define('ha-device-card', HaDeviceCard);

View File

@ -69,17 +69,7 @@ class HaConfigDashboard extends NavigateMixin(LocalizeMixin(PolymerElement)) {
</template>
<paper-card>
<a href='/config/overview' tabindex="-1">
<paper-item>
<paper-item-body two-line>
Overview
<div secondary>Find out how your config, devices and entities relate</div>
</paper-item-body>
<iron-icon icon="hass:chevron-right"></iron-icon>
</paper-item>
</a>
<a href='/config/integrations' tabindex="-1">
<a href='/config/integrations/dashboard' tabindex="-1">
<paper-item>
<paper-item-body two-line>
Integrations

View File

@ -17,7 +17,6 @@ import(/* webpackChunkName: "panel-config-dashboard" */ './dashboard/ha-config-d
import(/* webpackChunkName: "panel-config-script" */ './script/ha-config-script.js');
import(/* webpackChunkName: "panel-config-users" */ './users/ha-config-users.js');
import(/* webpackChunkName: "panel-config-zwave" */ './zwave/ha-config-zwave.js');
import(/* webpackChunkName: "panel-config-overview" */ './overview/ha-config-overview.js');
/*
* @appliesMixin NavigateMixin
@ -101,6 +100,7 @@ class HaPanelConfig extends NavigateMixin(PolymerElement) {
<template is="dom-if" if='[[_equals(_routeData.page, "integrations")]]' restamp>
<ha-config-entries
route='[[route]]'
page-name='integrations'
hass='[[hass]]'
is-wide='[[isWide]]'
@ -114,14 +114,6 @@ class HaPanelConfig extends NavigateMixin(PolymerElement) {
hass='[[hass]]'
></ha-config-users>
</template>
<template is="dom-if" if='[[_equals(_routeData.page, "overview")]]' restamp>
<ha-config-overview
page-name='overview'
route='[[route]]'
hass='[[hass]]'
></ha-config-overview>
</template>
`;
}

View File

@ -1,178 +0,0 @@
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../../layouts/hass-subpage.js';
import computeStateName from '../../../common/entity/compute_state_name.js';
import '../../../components/entity/state-badge.js';
import './ha-overview-device-row.js';
import compare from '../../../common/string/compare.js';
class HaConfigOverview extends PolymerElement {
static get template() {
return html`
<style>
a {
color: var(--primary-color);
}
paper-card {
display: block;
margin: 16px auto;
max-width: 500px;
}
li {
color: var(--primary-text-color);
}
.secondary {
color: var(--secondary-text-color);
}
.device-row {
display: flex;
flex-direction: row;
margin-bottom: 8px;
}
.device {
width: 30%;
}
.device .name {
font-weight: bold;
}
.device .model,
.device .manuf,
.device .hub {
color: var(--secondary-text-color);
}
.entity-rows {
padding-top: 12px;
margin-left: 8px;
}
.entity-row {
margin: 8px 0;
display: flex;
flex-direction: row;
}
state-badge {
margin-right: 8px;
}
.entity-row .entity-id {
color: var(--secondary-text-color);
}
</style>
<hass-subpage header="Overview">
<div class='content'>
<template is='dom-if' if='[[!_configs.length]]'>
<paper-card heading='No integrations'>
<div class='card-content'>
No integrations found. <a href='/config/integrations'>Configure an integration</a>
</div>
</paper-card>
</template>
<template is='dom-repeat' items='[[_configs]]' as='configEntry'>
<paper-card heading='[[configEntry.title]]'>
<div class='card-content'>
<!-- <h1>[[configEntry.title]] ([[_computeIntegrationTitle(localize, configEntry.domain)]])</h1> -->
<template is='dom-repeat' items='[[_computeConfigEntryDevices(configEntry, _devices)]]' as='device'>
<ha-overview-device-row
hass='[[hass]]'
devices='[[_devices]]'
device='[[device]]'
entities='[[_entities]]'
></ha-overview-device-row>
</template>
</div>
</paper-card>
</dom-repeat>
</div>
</hass-subpage>
`;
}
static get properties() {
return {
hass: Object,
isWide: Boolean,
_loading: {
type: Boolean,
computed: '_computeLoading(_configs, _devices, _entities)'
},
_configs: {
type: Array,
value: null,
},
_devices: {
type: Array,
value: null,
},
_entities: {
type: Array,
value: null,
}
};
}
ready() {
super.ready();
this._loadData();
}
connectedCallback() {
super.connectedCallback();
}
disconnectedCallback() {
super.disconnectedCallback();
}
_loadData() {
this.hass.callWS({ type: 'config/entity_registry/list' })
.then((entities) => { this._entities = entities; });
this.hass.callWS({ type: 'config/device_registry/list' })
.then((devices) => { this._devices = devices; });
this.hass.callApi('get', 'config/config_entries/entry')
.then((configs) => {
this._configs = configs.sort((conf1, conf2) => compare(conf1.title, conf2.title));
});
}
_computeLoading(configs, devices, entities) {
return configs && devices && entities;
}
_computeIntegrationTitle(localize, integration) {
return localize(`component.${integration}.config.title`);
}
_computeConfigEntryDevices(configEntry, devices) {
return devices.filter(device =>
device.config_entries.includes(configEntry.entry_id) &&
!device.hub_device_id).sort((dev1, dev2) => compare(dev1.name, dev2.name));
}
_computeDeviceEntities(device, entities) {
return entities.filter(entity => entity.device_id === device.id);
}
_computeStateObj(entity, hass) {
return hass.states[entity.entity_id];
}
_computeEntityName(entity, hass) {
const state = hass.states[entity.entity_id];
if (state) {
return computeStateName(state);
}
return `${entity.name || ''} (entity unavailable)`;
}
_computeDeviceName(devices, deviceId) {
const device = devices.find(dev => dev.id === deviceId);
return device ? device.name : '(device unavailable)';
}
}
customElements.define('ha-config-overview', HaConfigOverview);