diff --git a/src/layouts/hass-subpage.js b/src/layouts/hass-subpage.js
index eedde86637..ca225ad2a5 100644
--- a/src/layouts/hass-subpage.js
+++ b/src/layouts/hass-subpage.js
@@ -14,6 +14,7 @@ class HassSubpage extends PolymerElement {
[[header]]
+
diff --git a/src/panels/config/config-entries/ha-config-entries-dashboard.js b/src/panels/config/config-entries/ha-config-entries-dashboard.js
new file mode 100644
index 0000000000..dbce3667b3
--- /dev/null
+++ b/src/panels/config/config-entries/ha-config-entries-dashboard.js
@@ -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`
+
+
+
+
+
+ Discovered
+
+
+
+
+ [[_computeIntegrationTitle(localize, item.handler)]]
+
+
Configure
+
+
+
+
+
+
+
+ Configured
+
+
+
+
+ Nothing configured yet
+
+
+
+
+
+
+
+ [[_computeIntegrationTitle(localize, item.domain)]]: [[item.title]]
+
+
+
+
+ [[_computeStateName(item)]]
+
+
+
+
+
+
+
+
+
+
+
+
+ Set up a new integration
+
+
+
+
+ [[_computeIntegrationTitle(localize, item)]]
+
+
Configure
+
+
+
+
+
+`;
+ }
+
+ 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);
diff --git a/src/panels/config/config-entries/ha-config-entries.js b/src/panels/config/config-entries/ha-config-entries.js
index aa9d5eddfe..aef873ccae 100644
--- a/src/panels/config/config-entries/ha-config-entries.js
+++ b/src/panels/config/config-entries/ha-config-entries.js
@@ -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`
-
+
-
-
-
- Discovered
-
-
-
-
- [[_computeIntegrationTitle(localize, item.handler)]]
-
-
Configure
-
-
-
-
-
-
-
- Configured
-
-
-
-
- Nothing configured yet
-
-
-
-
-
-
- [[_computeIntegrationTitle(localize, item.domain)]]: [[item.title]]
- [[item.state]] – added by [[item.source]]
-
-
-
-
- [[_computeStateName(item)]]
-
-
-
-
-
Remove
-
-
-
-
-
-
- Set up a new integration
-
-
-
-
- [[_computeIntegrationTitle(localize, item)]]
-
-
Configure
-
-
-
-
-
+
+
+
+
+
+
`;
}
@@ -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);
diff --git a/src/panels/config/config-entries/ha-config-entry-page.js b/src/panels/config/config-entries/ha-config-entry-page.js
new file mode 100644
index 0000000000..1df8e85508
--- /dev/null
+++ b/src/panels/config/config-entries/ha-config-entry-page.js
@@ -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`
+
+
+
+
+
+
+
+
+
+`;
+ }
+
+ 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);
+
diff --git a/src/panels/config/overview/ha-overview-device-row.js b/src/panels/config/config-entries/ha-device-card.js
similarity index 61%
rename from src/panels/config/overview/ha-overview-device-row.js
rename to src/panels/config/config-entries/ha-device-card.js
index 781a3dccc1..c8fa7d74d4 100644
--- a/src/panels/config/overview/ha-overview-device-row.js
+++ b/src/panels/config/config-entries/ha-device-card.js
@@ -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`
-
-
-
-
[[device.name]]
-
[[device.model]]
-
by [[device.manufacturer]]
-
-
-
-
-
-
-
-
[[_computeEntityName(entity, hass)]]
-
[[entity.entity_id]]
-
-
+
+
+
+
+
[[device.model]]
+
by [[device.manufacturer]]
+
+
+
+ Connected via
+ [[_computeDeviceName(devices, device.hub_device_id)]]
+
-
-
-
+
+
+
+
+
+ [[_computeEntityName(entity, hass)]]
+ [[entity.entity_id]]
+
+
-
+
+
`;
}
@@ -141,4 +132,4 @@ class HaDeviceRow extends EventsMixin(PolymerElement) {
}
}
-customElements.define('ha-overview-device-row', HaDeviceRow);
+customElements.define('ha-device-card', HaDeviceCard);
diff --git a/src/panels/config/dashboard/ha-config-dashboard.js b/src/panels/config/dashboard/ha-config-dashboard.js
index c28461c0cb..d62c303277 100644
--- a/src/panels/config/dashboard/ha-config-dashboard.js
+++ b/src/panels/config/dashboard/ha-config-dashboard.js
@@ -69,17 +69,7 @@ class HaConfigDashboard extends NavigateMixin(LocalizeMixin(PolymerElement)) {
-
-
-
- Overview
- Find out how your config, devices and entities relate
-
-
-
-
-
-
+
Integrations
diff --git a/src/panels/config/ha-panel-config.js b/src/panels/config/ha-panel-config.js
index f0ead6f540..4a3ea75b74 100644
--- a/src/panels/config/ha-panel-config.js
+++ b/src/panels/config/ha-panel-config.js
@@ -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) {
-
-
-
-
`;
}
diff --git a/src/panels/config/overview/ha-config-overview.js b/src/panels/config/overview/ha-config-overview.js
deleted file mode 100644
index 7e7beafbde..0000000000
--- a/src/panels/config/overview/ha-config-overview.js
+++ /dev/null
@@ -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`
-
-
-
-
-
-
- No integrations found.
Configure an integration
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
- }
-
- 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);