mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-24 13:27:22 +00:00
Merge overview into integrations (#1672)
* Merge overview into integrations * Lint
This commit is contained in:
parent
67d09e8b3d
commit
7e0ff14f28
@ -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>
|
||||
|
||||
|
197
src/panels/config/config-entries/ha-config-entries-dashboard.js
Normal file
197
src/panels/config/config-entries/ha-config-entries-dashboard.js
Normal 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);
|
@ -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);
|
||||
|
107
src/panels/config/config-entries/ha-config-entry-page.js
Normal file
107
src/panels/config/config-entries/ha-config-entry-page.js
Normal 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);
|
||||
|
@ -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);
|
@ -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
|
||||
|
@ -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>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -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);
|
Loading…
x
Reference in New Issue
Block a user