@@ -154,6 +156,7 @@ class HaDeviceCard extends EventsMixin(LocalizeMixin(PolymerElement)) {
type: Boolean,
reflectToAttribute: true,
},
+ hideSettings: { type: Boolean, value: false },
_childDevices: {
type: Array,
computed: "_computeChildDevices(device, devices)",
diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts
index 1c249c39ea..6998abdd73 100644
--- a/src/panels/config/ha-panel-config.ts
+++ b/src/panels/config/ha-panel-config.ts
@@ -48,6 +48,11 @@ class HaPanelConfig extends HassRouterPage {
load: () =>
import(/* webpackChunkName: "panel-config-core" */ "./core/ha-config-core"),
},
+ devices: {
+ tag: "ha-config-devices",
+ load: () =>
+ import(/* webpackChunkName: "panel-config-devices" */ "./devices/ha-config-devices"),
+ },
server_control: {
tag: "ha-config-server-control",
load: () =>
diff --git a/src/panels/config/integrations/config-entry/ha-config-entry-page.ts b/src/panels/config/integrations/config-entry/ha-config-entry-page.ts
index 979a10887d..2235fcc5aa 100644
--- a/src/panels/config/integrations/config-entry/ha-config-entry-page.ts
+++ b/src/panels/config/integrations/config-entry/ha-config-entry-page.ts
@@ -5,7 +5,7 @@ import "../../../../layouts/hass-error-screen";
import "../../../../components/entity/state-badge";
import { compare } from "../../../../common/string/compare";
-import "./ha-device-card";
+import "../../devices/ha-device-card";
import "./ha-ce-entities-card";
import { showOptionsFlowDialog } from "../../../../dialogs/config-flow/show-dialog-options-flow";
import { property, LitElement, CSSResult, css, html } from "lit-element";
@@ -106,6 +106,7 @@ class HaConfigEntryPage extends LitElement {
icon="hass:delete"
@click=${this._removeEntry}
>
+
${configEntryDevices.length === 0 && noDeviceEntities.length === 0
? html`
diff --git a/src/panels/config/integrations/ha-config-entries-dashboard.js b/src/panels/config/integrations/ha-config-entries-dashboard.js
deleted file mode 100644
index 48e4ff6022..0000000000
--- a/src/panels/config/integrations/ha-config-entries-dashboard.js
+++ /dev/null
@@ -1,235 +0,0 @@
-import "@polymer/iron-flex-layout/iron-flex-layout-classes";
-import "@polymer/paper-tooltip/paper-tooltip";
-import "@material/mwc-button";
-import "@polymer/iron-icon/iron-icon";
-import "@polymer/paper-item/paper-item";
-import "@polymer/paper-item/paper-item-body";
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "../../../components/ha-card";
-import "../../../components/ha-fab";
-import "../../../components/entity/ha-state-icon";
-import "../../../layouts/hass-subpage";
-import "../../../resources/ha-style";
-import "../../../components/ha-icon-next";
-
-import { computeRTL } from "../../../common/util/compute_rtl";
-import "../ha-config-section";
-import { EventsMixin } from "../../../mixins/events-mixin";
-import LocalizeMixin from "../../../mixins/localize-mixin";
-import computeStateName from "../../../common/entity/compute_state_name";
-import {
- loadConfigFlowDialog,
- showConfigFlowDialog,
-} from "../../../dialogs/config-flow/show-dialog-config-flow";
-import { localizeConfigFlowTitle } from "../../../data/config_flow";
-
-/*
- * @appliesMixin LocalizeMixin
- * @appliesMixin EventsMixin
- */
-class HaConfigManagerDashboard extends LocalizeMixin(
- EventsMixin(PolymerElement)
-) {
- static get template() {
- return html`
-
-
-
-
-
- [[localize('ui.panel.config.integrations.discovered')]]
-
-
-
-
- [[_computeActiveFlowTitle(localize, item)]]
-
-
[[localize('ui.panel.config.integrations.configure')]]
-
-
-
-
-
-
-
- [[localize('ui.panel.config.integrations.configured')]]
-
-
-
-
- [[localize('ui.panel.config.integrations.none')]]
-
-
-
-
-
-
-
-
- [[_computeIntegrationTitle(localize, item.domain)]]:
- [[item.title]]
-
-
-
-
-
- [[_computeStateName(item)]]
-
-
-
-
-
-
-
-
-
-
-
-
-
- `;
- }
-
- 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,
-
- rtl: {
- type: Boolean,
- reflectToAttribute: true,
- computed: "_computeRTL(hass)",
- },
- };
- }
-
- connectedCallback() {
- super.connectedCallback();
- loadConfigFlowDialog();
- }
-
- _createFlow() {
- showConfigFlowDialog(this, {
- dialogClosedCallback: () => this.fire("hass-reload-entries"),
- });
- }
-
- _continueFlow(ev) {
- showConfigFlowDialog(this, {
- continueFlowId: ev.model.item.flow_id,
- dialogClosedCallback: () => this.fire("hass-reload-entries"),
- });
- }
-
- _computeIntegrationTitle(localize, integration) {
- return localize(`component.${integration}.config.title`);
- }
-
- _computeActiveFlowTitle(localize, flow) {
- return localizeConfigFlowTitle(localize, flow);
- }
-
- _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);
- }
-
- _computeRTL(hass) {
- return computeRTL(hass);
- }
-}
-
-customElements.define("ha-config-entries-dashboard", HaConfigManagerDashboard);
diff --git a/src/panels/config/integrations/ha-config-entries-dashboard.ts b/src/panels/config/integrations/ha-config-entries-dashboard.ts
new file mode 100644
index 0000000000..7b3cd73673
--- /dev/null
+++ b/src/panels/config/integrations/ha-config-entries-dashboard.ts
@@ -0,0 +1,237 @@
+import "@polymer/iron-flex-layout/iron-flex-layout-classes";
+import "@polymer/paper-tooltip/paper-tooltip";
+import "@material/mwc-button";
+import "@polymer/iron-icon/iron-icon";
+import "@polymer/paper-item/paper-item";
+import "@polymer/paper-item/paper-item-body";
+
+import { HassEntity } from "home-assistant-js-websocket";
+
+import "../../../components/ha-card";
+import "../../../components/ha-icon-next";
+import "../../../components/ha-fab";
+import "../../../components/entity/ha-state-icon";
+import "../../../layouts/hass-subpage";
+import "../../../resources/ha-style";
+import "../../../components/ha-icon";
+
+import { computeRTL } from "../../../common/util/compute_rtl";
+import "../ha-config-section";
+
+import computeStateName from "../../../common/entity/compute_state_name";
+import {
+ loadConfigFlowDialog,
+ showConfigFlowDialog,
+} from "../../../dialogs/config-flow/show-dialog-config-flow";
+import { localizeConfigFlowTitle } from "../../../data/config_flow";
+import {
+ LitElement,
+ TemplateResult,
+ html,
+ property,
+ customElement,
+ css,
+ CSSResult,
+} from "lit-element";
+import { HomeAssistant } from "../../../types";
+import { ConfigEntry } from "../../../data/config_entries";
+import { fireEvent } from "../../../common/dom/fire_event";
+import { EntityRegistryEntry } from "../../../data/entity_registry";
+
+@customElement("ha-config-entries-dashboard")
+export class HaConfigManagerDashboard extends LitElement {
+ @property() public hass!: HomeAssistant;
+
+ @property() public isWide = false;
+
+ @property() private entries = [];
+
+ /**
+ * Entity Registry entries.
+ */
+ @property() private entities: EntityRegistryEntry[] = [];
+
+ /**
+ * Current flows that are in progress and have not been started by a user.
+ * For example, can be discovered devices that require more config.
+ */
+ @property() private progress = [];
+
+ public connectedCallback() {
+ super.connectedCallback();
+ loadConfigFlowDialog();
+ }
+
+ protected render(): TemplateResult {
+ return html`
+
+ ${this.progress.length
+ ? html`
+
+ ${this.hass.localize(
+ "ui.panel.config.integrations.discovered"
+ )}
+
+ ${this.progress.map(
+ (flow) => html`
+
+
+ ${localizeConfigFlowTitle(this.hass.localize, flow)}
+
+
${this.hass.localize(
+ "ui.panel.config.integrations.configure"
+ )}
+
+ `
+ )}
+
+
+ `
+ : ""}
+
+
+ ${this.hass.localize(
+ "ui.panel.config.integrations.configured"
+ )}
+
+ ${this.entities.length
+ ? this.entries.map(
+ (item: any, idx) => html`
+
+
+
+
+ ${this.hass.localize(
+ `component.${item.domain}.config.title`
+ )}:
+ ${item.title}
+
+
+ ${this._getEntities(item).map(
+ (entity) => html`
+
+
+ ${computeStateName(entity)}
+
+ `
+ )}
+
+
+
+
+
+ `
+ )
+ : html`
+
+
+
+ ${this.hass.localize(
+ "ui.panel.config.integrations.none"
+ )}
+
+
+
+ `}
+
+
+
+
+
+ `;
+ }
+
+ private _createFlow() {
+ showConfigFlowDialog(this, {
+ dialogClosedCallback: () => fireEvent(this, "hass-reload-entries"),
+ });
+ }
+
+ private _continueFlow(ev) {
+ showConfigFlowDialog(this, {
+ continueFlowId: ev.model.item.flow_id,
+ dialogClosedCallback: () => fireEvent(this, "hass-reload-entries"),
+ });
+ }
+
+ private _getEntities(configEntry: ConfigEntry): HassEntity[] {
+ if (!this.entities) {
+ return [];
+ }
+ const states: HassEntity[] = [];
+ this.entities.forEach((entity) => {
+ if (
+ entity.config_entry_id === configEntry.entry_id &&
+ entity.entity_id in this.hass.states
+ ) {
+ states.push(this.hass.states[entity.entity_id]);
+ }
+ });
+ return states;
+ }
+ static get styles(): CSSResult {
+ return css`
+ ha-card {
+ overflow: hidden;
+ }
+ mwc-button {
+ top: 3px;
+ margin-right: -0.57em;
+ }
+ .config-entry-row {
+ display: flex;
+ padding: 0 16px;
+ }
+ ha-icon {
+ cursor: pointer;
+ margin: 8px;
+ }
+ .configured a {
+ color: var(--primary-text-color);
+ text-decoration: none;
+ }
+ ha-fab {
+ position: fixed;
+ bottom: 16px;
+ right: 16px;
+ z-index: 1;
+ }
+
+ ha-fab[is-wide] {
+ bottom: 24px;
+ right: 24px;
+ }
+
+ ha-fab[rtl] {
+ right: auto;
+ left: 16px;
+ }
+
+ ha-fab[rtl][is-wide] {
+ bottom: 24px;
+ right: auto;
+ left: 24px;
+ }
+ `;
+ }
+}
diff --git a/src/translations/en.json b/src/translations/en.json
index c4db454d5b..9ef2dd6626 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -889,6 +889,10 @@
"description_not_login": "Not logged in",
"description_features": "Control away from home, integrate with Alexa and Google Assistant."
},
+ "devices": {
+ "caption": "Devices",
+ "description": "Manage connected devices"
+ },
"entity_registry": {
"caption": "Entity Registry",
"description": "Overview of all known entities.",
@@ -920,7 +924,7 @@
},
"integrations": {
"caption": "Integrations",
- "description": "Manage connected devices and services",
+ "description": "Manage and setup integrations",
"discovered": "Discovered",
"configured": "Configured",
"new": "Set up a new integration",