mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-24 13:27:22 +00:00
Add basic overview page (#1668)
* Add basic overview page * Add empty state * Show hub devices * Add more info to config entries page * Lint
This commit is contained in:
parent
650d2d7a47
commit
c593e2789c
10
src/common/string/compare.js
Normal file
10
src/common/string/compare.js
Normal file
@ -0,0 +1,10 @@
|
||||
export default (a, b) => {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
if (a > b) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
@ -129,7 +129,7 @@ class HaSidebar extends LocalizeMixin(PolymerElement) {
|
||||
</app-toolbar>
|
||||
|
||||
<paper-listbox attr-for-selected="data-panel" selected="[[hass.panelUrl]]">
|
||||
<a href='[[_computeUrl(defaultPage)]]' data-panel$="[[defaultPage]]">
|
||||
<a href='[[_computeUrl(defaultPage)]]' data-panel$="[[defaultPage]]" tabindex="-1">
|
||||
<paper-icon-item>
|
||||
<ha-icon slot="item-icon" icon="hass:apps"></ha-icon>
|
||||
<span class="item-text">[[localize('panel.states')]]</span>
|
||||
@ -137,7 +137,7 @@ class HaSidebar extends LocalizeMixin(PolymerElement) {
|
||||
</a>
|
||||
|
||||
<template is="dom-repeat" items="[[panels]]">
|
||||
<a href='[[_computeUrl(item.url_path)]]' data-panel$='[[item.url_path]]'>
|
||||
<a href='[[_computeUrl(item.url_path)]]' data-panel$='[[item.url_path]]' tabindex="-1">
|
||||
<paper-icon-item>
|
||||
<ha-icon slot="item-icon" icon="[[item.icon]]"></ha-icon>
|
||||
<span class="item-text">[[_computePanelName(localize, item)]]</span>
|
||||
@ -159,14 +159,14 @@ class HaSidebar extends LocalizeMixin(PolymerElement) {
|
||||
<div class="subheader">[[localize('ui.sidebar.developer_tools')]]</div>
|
||||
|
||||
<div class="dev-tools layout horizontal justified">
|
||||
<a href="/dev-service">
|
||||
<a href="/dev-service" tabindex="-1">
|
||||
<paper-icon-button
|
||||
icon="hass:remote"
|
||||
alt="[[localize('panel.dev-services')]]"
|
||||
title="[[localize('panel.dev-services')]]"
|
||||
></paper-icon-button>
|
||||
</a>
|
||||
<a href="/dev-state">
|
||||
<a href="/dev-state" tabindex="-1">
|
||||
<paper-icon-button
|
||||
icon="hass:code-tags"
|
||||
alt="[[localize('panel.dev-states')]]"
|
||||
@ -174,7 +174,7 @@ class HaSidebar extends LocalizeMixin(PolymerElement) {
|
||||
|
||||
></paper-icon-button>
|
||||
</a>
|
||||
<a href="/dev-event">
|
||||
<a href="/dev-event" tabindex="-1">
|
||||
<paper-icon-button
|
||||
icon="hass:radio-tower"
|
||||
alt="[[localize('panel.dev-events')]]"
|
||||
@ -182,7 +182,7 @@ class HaSidebar extends LocalizeMixin(PolymerElement) {
|
||||
|
||||
></paper-icon-button>
|
||||
</a>
|
||||
<a href="/dev-template">
|
||||
<a href="/dev-template" tabindex="-1">
|
||||
<paper-icon-button
|
||||
icon="hass:file-xml"
|
||||
alt="[[localize('panel.dev-templates')]]"
|
||||
@ -191,7 +191,7 @@ class HaSidebar extends LocalizeMixin(PolymerElement) {
|
||||
></paper-icon-button>
|
||||
</a>
|
||||
<template is="dom-if" if="[[_mqttLoaded(hass)]]">
|
||||
<a href="/dev-mqtt">
|
||||
<a href="/dev-mqtt" tabindex="-1">
|
||||
<paper-icon-button
|
||||
icon="hass:altimeter"
|
||||
alt="[[localize('panel.dev-mqtt')]]"
|
||||
@ -200,7 +200,7 @@ class HaSidebar extends LocalizeMixin(PolymerElement) {
|
||||
></paper-icon-button>
|
||||
</a>
|
||||
</template>
|
||||
<a href="/dev-info">
|
||||
<a href="/dev-info" tabindex="-1">
|
||||
<paper-icon-button
|
||||
icon="hass:information-outline"
|
||||
alt="[[localize('panel.dev-info')]]"
|
||||
|
@ -41,6 +41,9 @@ class HaConfigManager extends
|
||||
display: flex;
|
||||
padding: 0 16px;
|
||||
}
|
||||
ha-state-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<hass-subpage header="Integrations">
|
||||
@ -78,7 +81,7 @@ class HaConfigManager extends
|
||||
<div secondary>
|
||||
<template is='dom-repeat' items='[[_computeConfigEntryEntities(hass, item, _entities)]]'>
|
||||
<span>
|
||||
<ha-state-icon state-obj='[[item]]'></ha-state-icon>
|
||||
<ha-state-icon state-obj='[[item]]' on-click='_handleMoreInfo'></ha-state-icon>
|
||||
<paper-tooltip position="bottom">[[_computeStateName(item)]]</paper-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
@ -227,6 +230,10 @@ class HaConfigManager extends
|
||||
_computeStateName(stateObj) {
|
||||
return computeStateName(stateObj);
|
||||
}
|
||||
|
||||
_handleMoreInfo(ev) {
|
||||
this.fire('hass-more-info', { entityId: ev.model.item.entity_id });
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-config-entries', HaConfigManager);
|
||||
|
@ -1,54 +0,0 @@
|
||||
import '@polymer/iron-icon/iron-icon.js';
|
||||
import '@polymer/paper-card/paper-card.js';
|
||||
import '@polymer/paper-item/paper-item-body.js';
|
||||
import '@polymer/paper-item/paper-item.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import NavigateMixin from '../../../mixins/navigate-mixin.js';
|
||||
|
||||
/*
|
||||
* @appliesMixin NavigateMixin
|
||||
*/
|
||||
class HaConfigCloudMenu extends NavigateMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex">
|
||||
paper-card {
|
||||
display: block;
|
||||
}
|
||||
paper-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<paper-card>
|
||||
<paper-item on-click="_navigate">
|
||||
<paper-item-body two-line="">
|
||||
Home Assistant Cloud
|
||||
<template is="dom-if" if="[[account]]">
|
||||
<div secondary="">Logged in as [[account.email]]</div>
|
||||
</template>
|
||||
<template is="dom-if" if="[[!account]]">
|
||||
<div secondary="">Connect with Google Home and Amazon Alexa</div>
|
||||
</template>
|
||||
</paper-item-body>
|
||||
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||
</paper-item>
|
||||
</paper-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
isWide: Boolean,
|
||||
account: Object,
|
||||
};
|
||||
}
|
||||
|
||||
_navigate() {
|
||||
this.navigate('/config/cloud');
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-config-cloud-menu', HaConfigCloudMenu);
|
@ -1,30 +1,39 @@
|
||||
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
|
||||
import '@polymer/app-layout/app-header/app-header.js';
|
||||
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
|
||||
import '@polymer/iron-icon/iron-icon.js';
|
||||
import '@polymer/paper-card/paper-card.js';
|
||||
import '@polymer/paper-item/paper-item-body.js';
|
||||
import '@polymer/paper-item/paper-item.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import '../../../components/ha-menu-button.js';
|
||||
|
||||
import '../ha-config-section.js';
|
||||
import './ha-config-cloud-menu.js';
|
||||
import './ha-config-entries-menu.js';
|
||||
import './ha-config-users-menu.js';
|
||||
import './ha-config-navigation.js';
|
||||
|
||||
import isComponentLoaded from '../../../common/config/is_component_loaded.js';
|
||||
import LocalizeMixin from '../../../mixins/localize-mixin.js';
|
||||
import NavigateMixin from '../../../mixins/navigate-mixin.js';
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class HaConfigDashboard extends LocalizeMixin(PolymerElement) {
|
||||
class HaConfigDashboard extends NavigateMixin(LocalizeMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex ha-style">
|
||||
.content {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
paper-card {
|
||||
display: block;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
<app-header-layout has-scrolling-region="">
|
||||
@ -41,16 +50,57 @@ class HaConfigDashboard extends LocalizeMixin(PolymerElement) {
|
||||
<span slot="introduction">[[localize('ui.panel.config.introduction')]]</span>
|
||||
|
||||
<template is="dom-if" if="[[computeIsLoaded(hass, 'cloud')]]">
|
||||
<ha-config-cloud-menu hass="[[hass]]" account="[[account]]"></ha-config-cloud-menu>
|
||||
<paper-card>
|
||||
<a href='/config/cloud' tabindex="-1">
|
||||
<paper-item on-click="_navigate">
|
||||
<paper-item-body two-line="">
|
||||
Home Assistant Cloud
|
||||
<template is="dom-if" if="[[account]]">
|
||||
<div secondary="">Logged in as [[account.email]]</div>
|
||||
</template>
|
||||
<template is="dom-if" if="[[!account]]">
|
||||
<div secondary="">Not logged in</div>
|
||||
</template>
|
||||
</paper-item-body>
|
||||
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||
</paper-item>
|
||||
</paper-card>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<template is="dom-if" if="[[computeIsLoaded(hass, 'config.config_entries')]]">
|
||||
<ha-config-entries-menu hass="[[hass]]"></ha-config-entries-menu>
|
||||
</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>
|
||||
|
||||
<template is="dom-if" if="[[hass.user.is_owner]]">
|
||||
<ha-config-users-menu hass="[[hass]]"></ha-config-users-menu>
|
||||
</template>
|
||||
<a href='/config/integrations' tabindex="-1">
|
||||
<paper-item>
|
||||
<paper-item-body two-line>
|
||||
Integrations
|
||||
<div secondary>Manage connected devices and services</div>
|
||||
</paper-item-body>
|
||||
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||
</paper-item>
|
||||
</a>
|
||||
|
||||
<a href='/config/users' tabindex="-1">
|
||||
<paper-item>
|
||||
<paper-item-body two-line>
|
||||
[[localize('ui.panel.config.users.caption')]]
|
||||
<div secondary>
|
||||
[[localize('ui.panel.config.users.description')]]
|
||||
</div>
|
||||
</paper-item-body>
|
||||
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||
</paper-item>
|
||||
</a>
|
||||
</paper-card>
|
||||
|
||||
<ha-config-navigation hass="[[hass]]"></ha-config-navigation>
|
||||
</ha-config-section>
|
||||
|
@ -1,49 +0,0 @@
|
||||
import '@polymer/iron-icon/iron-icon.js';
|
||||
import '@polymer/paper-card/paper-card.js';
|
||||
import '@polymer/paper-item/paper-item-body.js';
|
||||
import '@polymer/paper-item/paper-item.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import NavigateMixin from '../../../mixins/navigate-mixin.js';
|
||||
|
||||
/*
|
||||
* @appliesMixin NavigateMixin
|
||||
*/
|
||||
class HaConfigEntriesMenu extends NavigateMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex">
|
||||
paper-card {
|
||||
display: block;
|
||||
}
|
||||
paper-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<paper-card>
|
||||
<paper-item on-click="_navigate">
|
||||
<paper-item-body two-line="">
|
||||
Integrations
|
||||
<div secondary="">Manage connected devices and services</div>
|
||||
</paper-item-body>
|
||||
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||
</paper-item>
|
||||
</paper-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
isWide: Boolean,
|
||||
account: Object,
|
||||
};
|
||||
}
|
||||
|
||||
_navigate() {
|
||||
this.navigate('/config/integrations');
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-config-entries-menu', HaConfigEntriesMenu);
|
@ -1,48 +0,0 @@
|
||||
import '@polymer/iron-icon/iron-icon.js';
|
||||
import '@polymer/paper-card/paper-card.js';
|
||||
import '@polymer/paper-item/paper-item-body.js';
|
||||
import '@polymer/paper-item/paper-item.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import LocalizeMixin from '../../../mixins/localize-mixin.js';
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class HaConfigUsersMenu extends LocalizeMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex">
|
||||
paper-card {
|
||||
display: block;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
</style>
|
||||
<paper-card>
|
||||
<a href='/config/users'>
|
||||
<paper-item>
|
||||
<paper-item-body two-line>
|
||||
[[localize('ui.panel.config.users.caption')]]
|
||||
<div secondary>
|
||||
[[localize('ui.panel.config.users.description')]]
|
||||
</div>
|
||||
</paper-item-body>
|
||||
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||
</paper-item>
|
||||
</a>
|
||||
</paper-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-config-users-menu', HaConfigUsersMenu);
|
@ -5,19 +5,20 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import '../../layouts/hass-error-screen.js';
|
||||
|
||||
import './automation/ha-config-automation.js';
|
||||
import './cloud/ha-config-cloud.js';
|
||||
import './config-entries/ha-config-entries.js';
|
||||
import './core/ha-config-core.js';
|
||||
import './customize/ha-config-customize.js';
|
||||
import './dashboard/ha-config-dashboard.js';
|
||||
import './script/ha-config-script.js';
|
||||
import './users/ha-config-users.js';
|
||||
import './zwave/ha-config-zwave.js';
|
||||
|
||||
import isComponentLoaded from '../../common/config/is_component_loaded.js';
|
||||
import NavigateMixin from '../../mixins/navigate-mixin.js';
|
||||
|
||||
import(/* webpackChunkName: "panel-config-automation" */ './automation/ha-config-automation.js');
|
||||
import(/* webpackChunkName: "panel-config-cloud" */ './cloud/ha-config-cloud.js');
|
||||
import(/* webpackChunkName: "panel-config-config" */ './config-entries/ha-config-entries.js');
|
||||
import(/* webpackChunkName: "panel-config-core" */ './core/ha-config-core.js');
|
||||
import(/* webpackChunkName: "panel-config-customize" */ './customize/ha-config-customize.js');
|
||||
import(/* webpackChunkName: "panel-config-dashboard" */ './dashboard/ha-config-dashboard.js');
|
||||
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
|
||||
*/
|
||||
@ -113,6 +114,14 @@ 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>
|
||||
`;
|
||||
}
|
||||
|
||||
|
178
src/panels/config/overview/ha-config-overview.js
Normal file
178
src/panels/config/overview/ha-config-overview.js
Normal file
@ -0,0 +1,178 @@
|
||||
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);
|
144
src/panels/config/overview/ha-overview-device-row.js
Normal file
144
src/panels/config/overview/ha-overview-device-row.js
Normal file
@ -0,0 +1,144 @@
|
||||
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 EventsMixin from '../../../mixins/events-mixin.js';
|
||||
import computeStateName from '../../../common/entity/compute_state_name.js';
|
||||
import '../../../components/entity/state-badge.js';
|
||||
import compare from '../../../common/string/compare.js';
|
||||
|
||||
function computeEntityName(hass, entity) {
|
||||
if (entity.name) return entity.name;
|
||||
const state = hass.states[entity.entity_id];
|
||||
return state ? computeStateName(state) : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
*/
|
||||
class HaDeviceRow extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.device-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.device {
|
||||
width: 30%;
|
||||
}
|
||||
.device .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
.device .model,
|
||||
.device .manuf {
|
||||
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;
|
||||
cursor: pointer;
|
||||
}
|
||||
.entity-row .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'>
|
||||
</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>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
device: Object,
|
||||
devices: Array,
|
||||
entities: Array,
|
||||
hass: Object,
|
||||
_childDevices: {
|
||||
type: Array,
|
||||
computed: '_computeChildDevices(device, devices)',
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_computeChildDevices(device, devices) {
|
||||
return devices
|
||||
.filter(dev => dev.hub_device_id === device.id)
|
||||
.sort((dev1, dev2) => compare(dev1.name, dev2.name));
|
||||
}
|
||||
|
||||
_computeDeviceEntities(hass, device, entities) {
|
||||
return entities
|
||||
.filter(entity => entity.device_id === device.id)
|
||||
.sort((ent1, ent2) => compare(
|
||||
computeEntityName(hass, ent1) || `zzz${ent1.entity_id}`,
|
||||
computeEntityName(hass, ent2) || `zzz${ent2.entity_id}`
|
||||
));
|
||||
}
|
||||
|
||||
_computeStateObj(entity, hass) {
|
||||
return hass.states[entity.entity_id];
|
||||
}
|
||||
|
||||
_computeEntityName(entity, hass) {
|
||||
return computeEntityName(hass, entity) || '(entity unavailable)';
|
||||
}
|
||||
|
||||
_computeDeviceName(devices, deviceId) {
|
||||
const device = devices.find(dev => dev.id === deviceId);
|
||||
return device ? device.name : '(device unavailable)';
|
||||
}
|
||||
|
||||
_openMoreInfo(ev) {
|
||||
this.fire('hass-more-info', { entityId: ev.model.entity.entity_id });
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-overview-device-row', HaDeviceRow);
|
Loading…
x
Reference in New Issue
Block a user