From 4eb46bc2758fae6d16680399f47983759749a12b Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 12 Jun 2020 11:51:00 +0200 Subject: [PATCH] Move integration config panels to integrations (#6122) --- src/common/entity/valid_entity_id.ts | 2 +- src/components/data-table/ha-data-table.ts | 5 + src/components/ha-textarea.js | 46 -- .../dialog-zha-device-info.ts | 113 ---- .../show-dialog-zha-device-info.ts | 21 - .../ha-automation-action-wait_template.ts | 5 +- .../ha-automation-condition-numeric_state.ts | 6 +- .../types/ha-automation-condition-template.ts | 6 +- .../config/automation/ha-automation-editor.ts | 5 +- .../ha-automation-trigger-numeric_state.ts | 6 +- .../types/ha-automation-trigger-template.ts | 6 +- .../device-detail/ha-device-info-card.ts | 2 +- .../ha-device-actions-mqtt.ts} | 29 +- .../ha-device-actions-zha.ts | 128 ++++ .../ha-device-info-zha.ts | 93 +++ .../config/devices/ha-config-device-page.ts | 52 +- src/panels/config/ha-panel-config.ts | 18 +- .../integrations/ha-integration-card.ts | 32 +- .../integration-panels}/zha/functions.ts | 5 +- .../integration-panels}/zha/types.ts | 2 +- .../zha/zha-add-devices-page.ts | 186 +++--- .../zha/zha-add-group-page.ts | 18 +- .../zha/zha-cluster-attributes.ts | 16 +- .../zha/zha-cluster-commands.ts | 16 +- .../zha/zha-clusters-data-table.ts | 10 +- .../integration-panels}/zha/zha-clusters.ts | 22 +- .../zha/zha-config-dashboard-router.ts | 29 +- .../zha/zha-config-dashboard.ts | 132 ++++ .../zha/zha-device-binding.ts | 16 +- .../integration-panels/zha/zha-device-card.ts | 243 ++++++++ .../zha/zha-device-endpoint-data-table.ts | 43 +- .../zha/zha-group-binding.ts | 20 +- .../integration-panels}/zha/zha-group-page.ts | 70 ++- .../zha/zha-groups-dashboard.ts | 193 ++++++ .../zwave/ha-config-zwave.js | 30 +- .../integration-panels}/zwave/zwave-groups.js | 8 +- .../zwave/zwave-log-dialog.js | 6 +- .../integration-panels}/zwave/zwave-log.js | 12 +- .../zwave/zwave-network.ts | 20 +- .../zwave/zwave-node-config.ts | 10 +- .../zwave/zwave-node-protection.js | 6 +- .../zwave/zwave-usercodes.js | 6 +- .../integration-panels}/zwave/zwave-values.ts | 10 +- src/panels/config/zha/zha-config-dashboard.ts | 188 ------ src/panels/config/zha/zha-device-card.ts | 566 ------------------ src/panels/config/zha/zha-device-page.ts | 157 ----- src/panels/config/zha/zha-groups-dashboard.ts | 172 ------ .../config/zha/zha-groups-data-table.ts | 129 ---- src/panels/config/zha/zha-node.ts | 148 ----- src/state/hass-element.ts | 2 - src/state/zha-dialog-mixin.ts | 30 - src/translations/en.json | 18 +- 52 files changed, 1203 insertions(+), 1911 deletions(-) delete mode 100644 src/components/ha-textarea.js delete mode 100644 src/dialogs/zha-device-info-dialog/dialog-zha-device-info.ts delete mode 100644 src/dialogs/zha-device-info-dialog/show-dialog-zha-device-info.ts rename src/panels/config/devices/device-detail/{ha-device-card-mqtt.ts => integration-elements/ha-device-actions-mqtt.ts} (56%) create mode 100644 src/panels/config/devices/device-detail/integration-elements/ha-device-actions-zha.ts create mode 100644 src/panels/config/devices/device-detail/integration-elements/ha-device-info-zha.ts rename src/panels/config/{ => integrations/integration-panels}/zha/functions.ts (83%) rename src/panels/config/{ => integrations/integration-panels}/zha/types.ts (93%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-add-devices-page.ts (56%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-add-group-page.ts (91%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-cluster-attributes.ts (95%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-cluster-commands.ts (95%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-clusters-data-table.ts (88%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-clusters.ts (89%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-config-dashboard-router.ts (73%) create mode 100644 src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts rename src/panels/config/{ => integrations/integration-panels}/zha/zha-device-binding.ts (93%) create mode 100644 src/panels/config/integrations/integration-panels/zha/zha-device-card.ts rename src/panels/config/{ => integrations/integration-panels}/zha/zha-device-endpoint-data-table.ts (78%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-group-binding.ts (93%) rename src/panels/config/{ => integrations/integration-panels}/zha/zha-group-page.ts (87%) create mode 100644 src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts rename src/panels/config/{ => integrations/integration-panels}/zwave/ha-config-zwave.js (95%) rename src/panels/config/{ => integrations/integration-panels}/zwave/zwave-groups.js (97%) rename src/panels/config/{ => integrations/integration-panels}/zwave/zwave-log-dialog.js (91%) rename src/panels/config/{ => integrations/integration-panels}/zwave/zwave-log.js (92%) rename src/panels/config/{ => integrations/integration-panels}/zwave/zwave-network.ts (94%) rename src/panels/config/{ => integrations/integration-panels}/zwave/zwave-node-config.ts (97%) rename src/panels/config/{ => integrations/integration-panels}/zwave/zwave-node-protection.js (96%) rename src/panels/config/{ => integrations/integration-panels}/zwave/zwave-usercodes.js (97%) rename src/panels/config/{ => integrations/integration-panels}/zwave/zwave-values.ts (90%) delete mode 100644 src/panels/config/zha/zha-config-dashboard.ts delete mode 100644 src/panels/config/zha/zha-device-card.ts delete mode 100755 src/panels/config/zha/zha-device-page.ts delete mode 100644 src/panels/config/zha/zha-groups-dashboard.ts delete mode 100644 src/panels/config/zha/zha-groups-data-table.ts delete mode 100644 src/panels/config/zha/zha-node.ts delete mode 100644 src/state/zha-dialog-mixin.ts diff --git a/src/common/entity/valid_entity_id.ts b/src/common/entity/valid_entity_id.ts index 4e8e6770f2..c9c8d9acb9 100644 --- a/src/common/entity/valid_entity_id.ts +++ b/src/common/entity/valid_entity_id.ts @@ -6,7 +6,7 @@ export const isValidEntityId = (entityId: string) => export const createValidEntityId = (input: string) => input .toLowerCase() - .replace(/\s|'/g, "_") // replace spaces and quotes with underscore + .replace(/\s|'|\./g, "_") // replace spaces, points and quotes with underscore .replace(/\W/g, "") // remove not allowed chars .replace(/_{2,}/g, "_") // replace multiple underscores with 1 .replace(/_$/, ""); // remove underscores at the end diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index ce957a0ee4..c1150236ca 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -619,6 +619,11 @@ export class HaDataTable extends LitElement { text-transform: inherit; } + .mdc-data-table__cell a { + color: inherit; + text-decoration: none; + } + .mdc-data-table__cell--numeric { text-align: right; } diff --git a/src/components/ha-textarea.js b/src/components/ha-textarea.js deleted file mode 100644 index 36aa884120..0000000000 --- a/src/components/ha-textarea.js +++ /dev/null @@ -1,46 +0,0 @@ -/* -Wrapper for paper-textarea. - -paper-textarea crashes on iOS when created programmatically. This only impacts -our automation and script editors as they are using Preact. Polymer is using -template elements and does not have this issue. - -paper-textarea issue: https://github.com/PolymerElements/paper-input/issues/556 -WebKit issue: https://bugs.webkit.org/show_bug.cgi?id=174629 -*/ - -import "@polymer/paper-input/paper-textarea"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -class HaTextarea extends PolymerElement { - static get template() { - return html` - - - `; - } - - static get properties() { - return { - name: String, - label: String, - placeholder: String, - value: { - type: String, - notify: true, - }, - }; - } -} - -customElements.define("ha-textarea", HaTextarea); diff --git a/src/dialogs/zha-device-info-dialog/dialog-zha-device-info.ts b/src/dialogs/zha-device-info-dialog/dialog-zha-device-info.ts deleted file mode 100644 index d61c9a9102..0000000000 --- a/src/dialogs/zha-device-info-dialog/dialog-zha-device-info.ts +++ /dev/null @@ -1,113 +0,0 @@ -import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import "../../components/dialog/ha-paper-dialog"; -import type { HaPaperDialog } from "../../components/dialog/ha-paper-dialog"; -import { fetchZHADevice, ZHADevice } from "../../data/zha"; -import "../../panels/config/zha/zha-device-card"; -import type { PolymerChangedEvent } from "../../polymer-types"; -import { haStyleDialog } from "../../resources/styles"; -import type { HomeAssistant } from "../../types"; -import type { ZHADeviceInfoDialogParams } from "./show-dialog-zha-device-info"; - -@customElement("dialog-zha-device-info") -class DialogZHADeviceInfo extends LitElement { - @property() public hass!: HomeAssistant; - - @property() private _params?: ZHADeviceInfoDialogParams; - - @property() private _error?: string; - - @property() private _device?: ZHADevice; - - public async showDialog(params: ZHADeviceInfoDialogParams): Promise { - this._params = params; - this._device = await fetchZHADevice(this.hass, params.ieee); - await this.updateComplete; - this._dialog.open(); - } - - protected render(): TemplateResult { - if (!this._params || !this._device) { - return html``; - } - - return html` - - ${this._error - ? html`
${this._error}
` - : html` - - `} -
- `; - } - - private _openedChanged(ev: PolymerChangedEvent): void { - if (!ev.detail.value) { - this._params = undefined; - this._error = undefined; - this._device = undefined; - } - } - - private _onDeviceRemoved(): void { - this._closeDialog(); - } - - private get _dialog(): HaPaperDialog { - return this.shadowRoot!.querySelector("ha-paper-dialog")!; - } - - private _closeDialog() { - this._dialog.close(); - } - - static get styles(): CSSResult[] { - return [ - haStyleDialog, - css` - ha-paper-dialog > * { - margin: 0; - display: block; - padding: 0; - } - .card { - box-sizing: border-box; - display: flex; - flex: 1 0 300px; - min-width: 0; - max-width: 600px; - word-wrap: break-word; - } - .error { - color: var(--google-red-500); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-zha-device-info": DialogZHADeviceInfo; - } -} diff --git a/src/dialogs/zha-device-info-dialog/show-dialog-zha-device-info.ts b/src/dialogs/zha-device-info-dialog/show-dialog-zha-device-info.ts deleted file mode 100644 index 6ddec9be44..0000000000 --- a/src/dialogs/zha-device-info-dialog/show-dialog-zha-device-info.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { fireEvent } from "../../common/dom/fire_event"; - -export interface ZHADeviceInfoDialogParams { - ieee: string; -} - -export const loadZHADeviceInfoDialog = () => - import( - /* webpackChunkName: "dialog-zha-device-info" */ "./dialog-zha-device-info" - ); - -export const showZHADeviceInfoDialog = ( - element: HTMLElement, - zhaDeviceInfoParams: ZHADeviceInfoDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-zha-device-info", - dialogImport: loadZHADeviceInfoDialog, - dialogParams: zhaDeviceInfoParams, - }); -}; diff --git a/src/panels/config/automation/action/types/ha-automation-action-wait_template.ts b/src/panels/config/automation/action/types/ha-automation-action-wait_template.ts index d785160071..6924787d4b 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-wait_template.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-wait_template.ts @@ -1,4 +1,5 @@ import "@polymer/paper-input/paper-input"; +import "@polymer/paper-input/paper-textarea"; import { customElement, LitElement, property } from "lit-element"; import { html } from "lit-html"; import { WaitAction } from "../../../../../data/script"; @@ -19,7 +20,7 @@ export class HaWaitAction extends LitElement implements ActionElement { const { wait_template, timeout } = this.action; return html` - + > - + > `; } diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-template.ts b/src/panels/config/automation/condition/types/ha-automation-condition-template.ts index 4e79bc9004..c3d06a0355 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-template.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-template.ts @@ -1,5 +1,5 @@ import { customElement, html, LitElement, property } from "lit-element"; -import "../../../../../components/ha-textarea"; +import "@polymer/paper-input/paper-textarea"; import { TemplateCondition } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; import { handleChangeEvent } from "../ha-automation-condition-row"; @@ -17,7 +17,7 @@ export class HaTemplateCondition extends LitElement { protected render() { const { value_template } = this.condition; return html` - + > `; } diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index 8203ee6d6c..70f60c5e0a 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -1,5 +1,6 @@ import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; +import "@polymer/paper-input/paper-textarea"; import "../../../components/ha-icon-button"; import { css, @@ -117,7 +118,7 @@ export class HaAutomationEditor extends LitElement { @value-changed=${this._valueChanged} > - + > ${stateObj ? html` diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts index 8c3b151a2b..b8d4cffd71 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts @@ -2,7 +2,7 @@ import "@polymer/paper-input/paper-input"; import { customElement, html, LitElement, property } from "lit-element"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/entity/ha-entity-picker"; -import "../../../../../components/ha-textarea"; +import "@polymer/paper-input/paper-textarea"; import { ForDict, NumericStateTrigger } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; import { handleChangeEvent } from "../ha-automation-trigger-row"; @@ -61,7 +61,7 @@ export default class HaNumericStateTrigger extends LitElement { .value=${below} @value-changed=${this._valueChanged} > - + > + > `; } diff --git a/src/panels/config/devices/device-detail/ha-device-info-card.ts b/src/panels/config/devices/device-detail/ha-device-info-card.ts index 4e5c4692b6..8344df94fa 100644 --- a/src/panels/config/devices/device-detail/ha-device-info-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-info-card.ts @@ -75,6 +75,7 @@ export class HaDeviceCard extends LitElement { : ""} + `; } @@ -100,7 +101,6 @@ export class HaDeviceCard extends LitElement { } ha-card { flex: 1 0 100%; - padding-bottom: 10px; min-width: 0; } .device { diff --git a/src/panels/config/devices/device-detail/ha-device-card-mqtt.ts b/src/panels/config/devices/device-detail/integration-elements/ha-device-actions-mqtt.ts similarity index 56% rename from src/panels/config/devices/device-detail/ha-device-card-mqtt.ts rename to src/panels/config/devices/device-detail/integration-elements/ha-device-actions-mqtt.ts index 3f0ac8561a..5ff0862c54 100644 --- a/src/panels/config/devices/device-detail/ha-device-card-mqtt.ts +++ b/src/panels/config/devices/device-detail/integration-elements/ha-device-actions-mqtt.ts @@ -5,16 +5,17 @@ import { LitElement, property, TemplateResult, + css, } from "lit-element"; -import { DeviceRegistryEntry } from "../../../../data/device_registry"; -import { removeMQTTDeviceEntry } from "../../../../data/mqtt"; -import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box"; -import { showMQTTDeviceDebugInfoDialog } from "../../../../dialogs/mqtt-device-debug-info-dialog/show-dialog-mqtt-device-debug-info"; -import { haStyle } from "../../../../resources/styles"; -import { HomeAssistant } from "../../../../types"; +import { DeviceRegistryEntry } from "../../../../../data/device_registry"; +import { removeMQTTDeviceEntry } from "../../../../../data/mqtt"; +import { showConfirmationDialog } from "../../../../../dialogs/generic/show-dialog-box"; +import { showMQTTDeviceDebugInfoDialog } from "../../../../../dialogs/mqtt-device-debug-info-dialog/show-dialog-mqtt-device-debug-info"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; -@customElement("ha-device-card-mqtt") -export class HaDeviceCardMqtt extends LitElement { +@customElement("ha-device-actions-mqtt") +export class HaDeviceActionsMqtt extends LitElement { @property() public hass!: HomeAssistant; @property() public device!: DeviceRegistryEntry; @@ -47,7 +48,15 @@ export class HaDeviceCardMqtt extends LitElement { await showMQTTDeviceDebugInfoDialog(this, { device }); } - static get styles(): CSSResult { - return haStyle; + static get styles(): CSSResult[] { + return [ + haStyle, + css` + :host { + display: flex; + justify-content: space-between; + } + `, + ]; } } diff --git a/src/panels/config/devices/device-detail/integration-elements/ha-device-actions-zha.ts b/src/panels/config/devices/device-detail/integration-elements/ha-device-actions-zha.ts new file mode 100644 index 0000000000..641209e782 --- /dev/null +++ b/src/panels/config/devices/device-detail/integration-elements/ha-device-actions-zha.ts @@ -0,0 +1,128 @@ +import { + CSSResult, + customElement, + html, + LitElement, + property, + TemplateResult, + css, + PropertyValues, +} from "lit-element"; +import { DeviceRegistryEntry } from "../../../../../data/device_registry"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import { + ZHADevice, + fetchZHADevice, + reconfigureNode, +} from "../../../../../data/zha"; +import { navigate } from "../../../../../common/navigate"; +import { showZHADeviceZigbeeInfoDialog } from "../../../../../dialogs/zha-device-zigbee-signature-dialog/show-dialog-zha-device-zigbee-info"; +import { showConfirmationDialog } from "../../../../../dialogs/generic/show-dialog-box"; + +@customElement("ha-device-actions-zha") +export class HaDeviceActionsZha extends LitElement { + @property() public hass!: HomeAssistant; + + @property() public device!: DeviceRegistryEntry; + + @property() private _zhaDevice?: ZHADevice; + + protected updated(changedProperties: PropertyValues) { + if (changedProperties.has("device")) { + const zigbeeConnection = this.device.connections.find( + (conn) => conn[0] === "zigbee" + ); + if (!zigbeeConnection) { + return; + } + fetchZHADevice(this.hass, zigbeeConnection[1]).then((device) => { + this._zhaDevice = device; + }); + } + } + + protected render(): TemplateResult { + if (!this._zhaDevice) { + return html``; + } + return html` + ${this._zhaDevice.device_type !== "Coordinator" + ? html` + + ${this.hass!.localize( + "ui.dialogs.zha_device_info.buttons.reconfigure" + )} + + ` + : ""} + ${this._zhaDevice.power_source === "Mains" && + (this._zhaDevice.device_type === "Router" || + this._zhaDevice.device_type === "Coordinator") + ? html` + + ${this.hass!.localize("ui.dialogs.zha_device_info.buttons.add")} + + ` + : ""} + ${this._zhaDevice.device_type !== "Coordinator" + ? html` + + ${this.hass!.localize( + "ui.dialogs.zha_device_info.buttons.zigbee_information" + )} + + + ${this.hass!.localize( + "ui.dialogs.zha_device_info.buttons.remove" + )} + + ` + : ""} + `; + } + + private async _onReconfigureNodeClick(): Promise { + if (!this.hass) { + return; + } + reconfigureNode(this.hass, this._zhaDevice!.ieee); + } + + private _onAddDevicesClick() { + navigate(this, "/config/zha/add/" + this._zhaDevice!.ieee); + } + + private async _handleZigbeeInfoClicked() { + showZHADeviceZigbeeInfoDialog(this, { device: this._zhaDevice! }); + } + + private async _removeDevice() { + const confirmed = await showConfirmationDialog(this, { + text: this.hass.localize( + "ui.dialogs.zha_device_info.confirmations.remove" + ), + }); + + if (!confirmed) { + return; + } + + this.hass.callService("zha", "remove", { + ieee_address: this._zhaDevice!.ieee, + }); + } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + :host { + display: flex; + flex-direction: column; + align-items: flex-start; + } + `, + ]; + } +} diff --git a/src/panels/config/devices/device-detail/integration-elements/ha-device-info-zha.ts b/src/panels/config/devices/device-detail/integration-elements/ha-device-info-zha.ts new file mode 100644 index 0000000000..822cbc0f82 --- /dev/null +++ b/src/panels/config/devices/device-detail/integration-elements/ha-device-info-zha.ts @@ -0,0 +1,93 @@ +import { + CSSResult, + customElement, + html, + LitElement, + property, + TemplateResult, + css, + PropertyValues, +} from "lit-element"; +import { DeviceRegistryEntry } from "../../../../../data/device_registry"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import { ZHADevice, fetchZHADevice } from "../../../../../data/zha"; +import { formatAsPaddedHex } from "../../../integrations/integration-panels/zha/functions"; + +@customElement("ha-device-info-zha") +export class HaDeviceActionsZha extends LitElement { + @property() public hass!: HomeAssistant; + + @property() public device!: DeviceRegistryEntry; + + @property() private _zhaDevice?: ZHADevice; + + protected updated(changedProperties: PropertyValues) { + if (changedProperties.has("device")) { + const zigbeeConnection = this.device.connections.find( + (conn) => conn[0] === "zigbee" + ); + if (!zigbeeConnection) { + return; + } + fetchZHADevice(this.hass, zigbeeConnection[1]).then((device) => { + this._zhaDevice = device; + }); + } + } + + protected render(): TemplateResult { + if (!this._zhaDevice) { + return html``; + } + return html` +

Zigbee info

+
IEEE: ${this._zhaDevice.ieee}
+
Nwk: ${formatAsPaddedHex(this._zhaDevice.nwk)}
+
Device Type: ${this._zhaDevice.device_type}
+
+ LQI: + ${this._zhaDevice.lqi || + this.hass!.localize("ui.dialogs.zha_device_info.unknown")} +
+
+ RSSI: + ${this._zhaDevice.rssi || + this.hass!.localize("ui.dialogs.zha_device_info.unknown")} +
+
+ ${this.hass!.localize("ui.dialogs.zha_device_info.last_seen")}: + ${this._zhaDevice.last_seen || + this.hass!.localize("ui.dialogs.zha_device_info.unknown")} +
+
+ ${this.hass!.localize("ui.dialogs.zha_device_info.power_source")}: + ${this._zhaDevice.power_source || + this.hass!.localize("ui.dialogs.zha_device_info.unknown")} +
+ ${this._zhaDevice.quirk_applied + ? html` +
+ ${this.hass!.localize("ui.dialogs.zha_device_info.quirk")}: + ${this._zhaDevice.quirk_class} +
+ ` + : ""} + `; + } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + h4 { + margin-bottom: 4px; + } + div { + word-break: break-all; + margin-top: 2px; + } + `, + ]; + } +} diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index 56772d3f06..8248cc0f29 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -6,6 +6,7 @@ import { html, LitElement, property, + TemplateResult, } from "lit-element"; import { ifDefined } from "lit-html/directives/if-defined"; import memoizeOne from "memoize-one"; @@ -38,13 +39,12 @@ import "../../../layouts/hass-tabs-subpage"; import { HomeAssistant, Route } from "../../../types"; import "../ha-config-section"; import { configSections } from "../ha-panel-config"; -import "./device-detail/ha-device-card-mqtt"; import "./device-detail/ha-device-entities-card"; import "./device-detail/ha-device-info-card"; import { showDeviceAutomationDialog } from "./device-detail/show-dialog-device-automation"; export interface EntityRegistryStateEntry extends EntityRegistryEntry { - stateName?: string; + stateName?: string | null; } @customElement("ha-config-device-page") @@ -226,16 +226,7 @@ export class HaConfigDevicePage extends LitElement { .devices=${this.devices} .device=${device} > - ${ - integrations.includes("mqtt") - ? html` - - ` - : html`` - } + ${this._renderIntegrationInfo(device, integrations)} ${ @@ -439,7 +430,7 @@ export class HaConfigDevicePage extends LitElement { `; } - private _computeEntityName(entity) { + private _computeEntityName(entity: EntityRegistryEntry) { if (entity.name) { return entity.name; } @@ -480,6 +471,41 @@ export class HaConfigDevicePage extends LitElement { }); } + private _renderIntegrationInfo( + device, + integrations: string[] + ): TemplateResult[] { + const templates: TemplateResult[] = []; + if (integrations.includes("mqtt")) { + import("./device-detail/integration-elements/ha-device-actions-mqtt"); + templates.push(html` +
+ +
+ `); + } + if (integrations.includes("zha")) { + import("./device-detail/integration-elements/ha-device-actions-zha"); + import("./device-detail/integration-elements/ha-device-info-zha"); + templates.push(html` + +
+ +
+ `); + } + return templates; + } + private async _showSettings() { const device = this._device(this.deviceId, this.devices)!; showDeviceRegistryDetailDialog(this, { diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index 7b344b9e5c..a2a7fc05ea 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -163,20 +163,6 @@ export const configSections: { [name: string]: PageNavigation[] } = { advancedOnly: true, }, ], - other: [ - { - component: "zha", - path: "/config/zha", - translationKey: "component.zha.title", - icon: "hass:zigbee", - }, - { - component: "zwave", - path: "/config/zwave", - translationKey: "component.zwave.title", - icon: "hass:z-wave", - }, - ], }; @customElement("ha-panel-config") @@ -327,14 +313,14 @@ class HaPanelConfig extends HassRouterPage { tag: "zha-config-dashboard-router", load: () => import( - /* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-dashboard-router" + /* webpackChunkName: "panel-config-zha" */ "./integrations/integration-panels/zha/zha-config-dashboard-router" ), }, zwave: { tag: "ha-config-zwave", load: () => import( - /* webpackChunkName: "panel-config-zwave" */ "./zwave/ha-config-zwave" + /* webpackChunkName: "panel-config-zwave" */ "./integrations/integration-panels/zwave/ha-config-zwave" ), }, }, diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts index a904ebc338..a23adbd43f 100644 --- a/src/panels/config/integrations/ha-integration-card.ts +++ b/src/panels/config/integrations/ha-integration-card.ts @@ -45,6 +45,17 @@ declare global { } } +const integrationsWithPanel = { + zha: { + buttonLocalizeKey: "ui.panel.config.zha.button", + path: "/config/zha/dashboard", + }, + zwave: { + buttonLocalizeKey: "ui.panel.config.zwave.button", + path: "/config/zwave", + }, +}; + @customElement("ha-integration-card") export class HaIntegrationCard extends LitElement { @property() public hass!: HomeAssistant; @@ -180,13 +191,24 @@ export class HaIntegrationCard extends LitElement { "ui.panel.config.integrations.config_entry.rename" )} - ${item.supports_options + ${item.domain in integrationsWithPanel + ? html` + ${this.hass.localize( + integrationsWithPanel[item.domain].buttonLocalizeKey + )} + ` + : item.supports_options ? html` - ${this.hass.localize( + + ${this.hass.localize( "ui.panel.config.integrations.config_entry.options" - )} + )} + ` : ""} diff --git a/src/panels/config/zha/functions.ts b/src/panels/config/integrations/integration-panels/zha/functions.ts similarity index 83% rename from src/panels/config/zha/functions.ts rename to src/panels/config/integrations/integration-panels/zha/functions.ts index 065fe14ee9..7715d0badc 100644 --- a/src/panels/config/zha/functions.ts +++ b/src/panels/config/integrations/integration-panels/zha/functions.ts @@ -1,4 +1,4 @@ -import { Cluster, ZHADevice, ZHAGroup } from "../../../data/zha"; +import { Cluster, ZHADevice, ZHAGroup } from "../../../../../data/zha"; export const formatAsPaddedHex = (value: string | number): string => { let hex = value; @@ -8,6 +8,9 @@ export const formatAsPaddedHex = (value: string | number): string => { return "0x" + hex.toString(16).padStart(4, "0"); }; +export const getIeeeTail = (ieee: string) => + ieee.split(":").slice(-4).reverse().join(""); + export const sortZHADevices = (a: ZHADevice, b: ZHADevice): number => { const nameA = a.user_given_name ? a.user_given_name : a.name; const nameb = b.user_given_name ? b.user_given_name : b.name; diff --git a/src/panels/config/zha/types.ts b/src/panels/config/integrations/integration-panels/zha/types.ts similarity index 93% rename from src/panels/config/zha/types.ts rename to src/panels/config/integrations/integration-panels/zha/types.ts index 19bff74ff5..dd09861ad9 100644 --- a/src/panels/config/zha/types.ts +++ b/src/panels/config/integrations/integration-panels/zha/types.ts @@ -1,4 +1,4 @@ -import { Cluster, ZHADevice } from "../../../data/zha"; +import { Cluster, ZHADevice } from "../../../../../data/zha"; export interface PickerTarget extends EventTarget { selected: number; diff --git a/src/panels/config/zha/zha-add-devices-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts similarity index 56% rename from src/panels/config/zha/zha-add-devices-page.ts rename to src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts index e77d8e7f4c..f39f60f90f 100644 --- a/src/panels/config/zha/zha-add-devices-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts @@ -1,5 +1,5 @@ import "@material/mwc-button"; -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-spinner/paper-spinner"; import { css, @@ -9,19 +9,24 @@ import { LitElement, property, TemplateResult, + PropertyValues, } from "lit-element"; -import "../../../components/ha-service-description"; -import "../../../components/ha-textarea"; -import { ZHADevice } from "../../../data/zha"; -import "../../../layouts/hass-subpage"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant, Route } from "../../../types"; +import "../../../../../components/ha-service-description"; +import "@polymer/paper-input/paper-textarea"; +import { ZHADevice } from "../../../../../data/zha"; +import "../../../../../layouts/hass-tabs-subpage"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant, Route } from "../../../../../types"; import "./zha-device-card"; +import { zhaTabs } from "./zha-config-dashboard"; +import { IronAutogrowTextareaElement } from "@polymer/iron-autogrow-textarea"; @customElement("zha-add-devices-page") class ZHAAddDevicesPage extends LitElement { @property() public hass!: HomeAssistant; + @property() public narrow?: boolean; + @property() public isWide?: boolean; @property() public route?: Route; @@ -36,6 +41,8 @@ class ZHAAddDevicesPage extends LitElement { @property() private _showHelp = false; + @property() private _showLogs = false; + private _ieeeAddress?: string; private _addDevicesTimeoutHandle: any = undefined; @@ -60,58 +67,63 @@ class ZHAAddDevicesPage extends LitElement { this._formattedEvents = ""; } + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + if ( + changedProps.has("hass") && + !this._active && + !changedProps.get("hass") + ) { + this._subscribe(); + } + } + protected render(): TemplateResult { return html` - - ${this._active - ? html` -

- - ${this.hass!.localize( - "ui.panel.config.zha.add_device_page.spinner" - )} -

- ` - : html` -
- + ${this._showLogs ? "Hide logs" : "Show logs"} +
+ ${this._active + ? html` +

${this.hass!.localize( - "ui.panel.config.zha.add_device_page.search_again" + "ui.panel.config.zha.add_device_page.spinner" )} - - - ${this._showHelp - ? html` - - ` - : ""} -

- `} + + + ` + : html` +
+ + ${this.hass!.localize( + "ui.panel.config.zha.add_device_page.search_again" + )} + +
+ `} +
${this._error ? html`
${this._error}
` : ""} -
${this._discoveredDevices.length < 1 ? html`

${this.hass!.localize( - "ui.panel.config.zha.add_device_page.discovery_text" + "ui.panel.config.zha.add_device_page.pairing_mode" + )} +

+

+ ${this.hass!.localize( + this._active + ? "ui.panel.config.zha.add_device_page.discovered_text" + : "ui.panel.config.zha.add_device_page.no_devices_found" )}

@@ -123,27 +135,38 @@ class ZHAAddDevicesPage extends LitElement { class="card" .hass=${this.hass} .device=${device} - .narrow=${!this.isWide} + .narrow=${this.narrow} .showHelp=${this._showHelp} - .showActions=${!this._active} - .showEntityDetail=${false} > ` )} `}
- - -
+ ${this._showLogs + ? html` + ` + : ""} + `; } + private _toggleLogs() { + this._showLogs = !this._showLogs; + } + private _handleMessage(message: any): void { if (message.type === "log_output") { this._formattedEvents += message.log_entry.message + "\n"; if (this.shadowRoot) { - const textArea = this.shadowRoot.querySelector("ha-textarea"); - if (textArea) { + const paperTextArea = this.shadowRoot.querySelector("paper-textarea"); + if (paperTextArea) { + const textArea = (paperTextArea.inputElement as IronAutogrowTextareaElement) + .textarea; textArea.scrollTop = textArea.scrollHeight; } } @@ -165,69 +188,58 @@ class ZHAAddDevicesPage extends LitElement { } private _subscribe(): void { + if (!this.hass) { + return; + } + this._active = true; const data: any = { type: "zha/devices/permit" }; if (this._ieeeAddress) { data.ieee = this._ieeeAddress; } - this._subscribed = this.hass!.connection.subscribeMessage( + this._subscribed = this.hass.connection.subscribeMessage( (message) => this._handleMessage(message), data ); - this._active = true; this._addDevicesTimeoutHandle = setTimeout( () => this._unsubscribe(), 120000 ); } - private _onHelpTap(): void { - this._showHelp = !this._showHelp; - } - static get styles(): CSSResult[] { return [ haStyle, css` - .discovery-text, - .content-header { - margin: 16px; + .discovery-text { + width: 100%; + padding: 16px; + display: flex; + flex-direction: column; + align-items: center; } .content { - border-top: 1px solid var(--light-primary-color); - min-height: 500px; display: flex; flex-wrap: wrap; padding: 4px; - justify-content: left; - overflow: scroll; + justify-content: center; } .error { color: var(--google-red-500); } paper-spinner { - display: none; - margin-right: 20px; - margin-left: 16px; + padding: 20px; } - paper-spinner[active] { - display: block; - float: left; - margin-right: 20px; - margin-left: 16px; + .searching { + margin-top: 20px; + display: flex; + flex-direction: column; + align-items: center; } .card { - margin-left: 16px; - margin-right: 16px; - margin-bottom: 0px; - margin-top: 10px; + margin: 8px; } - .events { - margin: 16px; - border-top: 1px solid var(--light-primary-color); - padding-top: 16px; - min-height: 200px; - max-height: 200px; - overflow: scroll; + .log { + padding: 16px; } .toggle-help-icon { position: absolute; diff --git a/src/panels/config/zha/zha-add-group-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-add-group-page.ts similarity index 91% rename from src/panels/config/zha/zha-add-group-page.ts rename to src/panels/config/integrations/integration-panels/zha/zha-add-group-page.ts index eb85e899ab..cf1ba78960 100644 --- a/src/panels/config/zha/zha-add-group-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-add-group-page.ts @@ -12,20 +12,20 @@ import { PropertyValues, query, } from "lit-element"; -import type { HASSDomEvent } from "../../../common/dom/fire_event"; -import { navigate } from "../../../common/navigate"; -import type { SelectionChangedEvent } from "../../../components/data-table/ha-data-table"; +import type { HASSDomEvent } from "../../../../../common/dom/fire_event"; +import { navigate } from "../../../../../common/navigate"; +import type { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table"; import { addGroup, fetchGroupableDevices, ZHAGroup, ZHADeviceEndpoint, -} from "../../../data/zha"; -import "../../../layouts/hass-error-screen"; -import "../../../layouts/hass-subpage"; -import type { PolymerChangedEvent } from "../../../polymer-types"; -import type { HomeAssistant } from "../../../types"; -import "../ha-config-section"; +} from "../../../../../data/zha"; +import "../../../../../layouts/hass-error-screen"; +import "../../../../../layouts/hass-subpage"; +import type { PolymerChangedEvent } from "../../../../../polymer-types"; +import type { HomeAssistant } from "../../../../../types"; +import "../../../ha-config-section"; import "./zha-device-endpoint-data-table"; import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table"; diff --git a/src/panels/config/zha/zha-cluster-attributes.ts b/src/panels/config/integrations/integration-panels/zha/zha-cluster-attributes.ts similarity index 95% rename from src/panels/config/zha/zha-cluster-attributes.ts rename to src/panels/config/integrations/integration-panels/zha/zha-cluster-attributes.ts index db04e47114..b92a24269d 100644 --- a/src/panels/config/zha/zha-cluster-attributes.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-cluster-attributes.ts @@ -1,6 +1,6 @@ import "@material/mwc-button"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; @@ -13,9 +13,9 @@ import { PropertyValues, TemplateResult, } from "lit-element"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../components/ha-service-description"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-service-description"; import { Attribute, Cluster, @@ -23,10 +23,10 @@ import { ReadAttributeServiceData, readAttributeValue, ZHADevice, -} from "../../../data/zha"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; -import "../ha-config-section"; +} from "../../../../../data/zha"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import "../../../ha-config-section"; import { formatAsPaddedHex } from "./functions"; import { ChangeEvent, diff --git a/src/panels/config/zha/zha-cluster-commands.ts b/src/panels/config/integrations/integration-panels/zha/zha-cluster-commands.ts similarity index 95% rename from src/panels/config/zha/zha-cluster-commands.ts rename to src/panels/config/integrations/integration-panels/zha/zha-cluster-commands.ts index 5f5c572f56..6c3165776a 100644 --- a/src/panels/config/zha/zha-cluster-commands.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-cluster-commands.ts @@ -1,5 +1,5 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; @@ -12,18 +12,18 @@ import { PropertyValues, TemplateResult, } from "lit-element"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../components/ha-service-description"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-service-description"; import { Cluster, Command, fetchCommandsForCluster, ZHADevice, -} from "../../../data/zha"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; -import "../ha-config-section"; +} from "../../../../../data/zha"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import "../../../ha-config-section"; import { formatAsPaddedHex } from "./functions"; import { ChangeEvent, diff --git a/src/panels/config/zha/zha-clusters-data-table.ts b/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts similarity index 88% rename from src/panels/config/zha/zha-clusters-data-table.ts rename to src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts index e5750edcd3..54cad8cf74 100644 --- a/src/panels/config/zha/zha-clusters-data-table.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts @@ -7,14 +7,14 @@ import { TemplateResult, } from "lit-element"; import memoizeOne from "memoize-one"; -import "../../../components/data-table/ha-data-table"; +import "../../../../../components/data-table/ha-data-table"; import type { DataTableColumnContainer, HaDataTable, -} from "../../../components/data-table/ha-data-table"; -import "../../../components/entity/ha-state-icon"; -import type { Cluster } from "../../../data/zha"; -import type { HomeAssistant } from "../../../types"; +} from "../../../../../components/data-table/ha-data-table"; +import "../../../../../components/entity/ha-state-icon"; +import type { Cluster } from "../../../../../data/zha"; +import type { HomeAssistant } from "../../../../../types"; import { formatAsPaddedHex } from "./functions"; export interface ClusterRowData extends Cluster { diff --git a/src/panels/config/zha/zha-clusters.ts b/src/panels/config/integrations/integration-panels/zha/zha-clusters.ts similarity index 89% rename from src/panels/config/zha/zha-clusters.ts rename to src/panels/config/integrations/integration-panels/zha/zha-clusters.ts index 5c1d6a33e1..c47232bf71 100644 --- a/src/panels/config/zha/zha-clusters.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-clusters.ts @@ -1,5 +1,5 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { @@ -11,14 +11,18 @@ import { PropertyValues, TemplateResult, } from "lit-element"; -import { fireEvent } from "../../../common/dom/fire_event"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../components/ha-service-description"; -import { Cluster, fetchClustersForZhaNode, ZHADevice } from "../../../data/zha"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; -import "../ha-config-section"; +import { fireEvent } from "../../../../../common/dom/fire_event"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-service-description"; +import { + Cluster, + fetchClustersForZhaNode, + ZHADevice, +} from "../../../../../data/zha"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import "../../../ha-config-section"; import { computeClusterKey } from "./functions"; import { ItemSelectedEvent } from "./types"; diff --git a/src/panels/config/zha/zha-config-dashboard-router.ts b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard-router.ts similarity index 73% rename from src/panels/config/zha/zha-config-dashboard-router.ts rename to src/panels/config/integrations/integration-panels/zha/zha-config-dashboard-router.ts index fe71707a75..b6e72c457f 100644 --- a/src/panels/config/zha/zha-config-dashboard-router.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard-router.ts @@ -2,8 +2,9 @@ import { customElement, property } from "lit-element"; import { HassRouterPage, RouterOptions, -} from "../../../layouts/hass-router-page"; -import { HomeAssistant } from "../../../types"; +} from "../../../../../layouts/hass-router-page"; +import { HomeAssistant } from "../../../../../types"; +import { navigate } from "../../../../../common/navigate"; @customElement("zha-config-dashboard-router") class ZHAConfigDashboardRouter extends HassRouterPage { @@ -13,6 +14,10 @@ class ZHAConfigDashboardRouter extends HassRouterPage { @property() public narrow!: boolean; + private _configEntry = new URLSearchParams(window.location.search).get( + "config_entry" + ); + protected routerOptions: RouterOptions = { defaultPage: "dashboard", showLoading: true, @@ -24,13 +29,6 @@ class ZHAConfigDashboardRouter extends HassRouterPage { /* webpackChunkName: "zha-config-dashboard" */ "./zha-config-dashboard" ), }, - device: { - tag: "zha-device-page", - load: () => - import( - /* webpackChunkName: "zha-devices-page" */ "./zha-device-page" - ), - }, add: { tag: "zha-add-devices-page", load: () => @@ -65,11 +63,24 @@ class ZHAConfigDashboardRouter extends HassRouterPage { el.hass = this.hass; el.isWide = this.isWide; el.narrow = this.narrow; + el.configEntryId = this._configEntry; if (this._currentPage === "group") { el.groupId = this.routeTail.path.substr(1); } else if (this._currentPage === "device") { el.ieee = this.routeTail.path.substr(1); } + + const searchParams = new URLSearchParams(window.location.search); + if (this._configEntry && !searchParams.has("config_entry")) { + searchParams.append("config_entry", this._configEntry); + navigate( + this, + `${this.routeTail.prefix}${ + this.routeTail.path + }?${searchParams.toString()}`, + true + ); + } } } diff --git a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts new file mode 100644 index 0000000000..7000ba3f75 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts @@ -0,0 +1,132 @@ +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-item/paper-item-body"; +import "@material/mwc-fab"; +import { + css, + CSSResultArray, + customElement, + html, + LitElement, + property, + TemplateResult, +} from "lit-element"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-icon-next"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../../../types"; +import "../../../ha-config-section"; +import { mdiNetwork, mdiFolderMultipleOutline, mdiPlus } from "@mdi/js"; +import "../../../../../layouts/hass-tabs-subpage"; +import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; +import { computeRTL } from "../../../../../common/util/compute_rtl"; + +export const zhaTabs: PageNavigation[] = [ + { + translationKey: "ui.panel.config.zha.network.caption", + path: `/config/zha/dashboard`, + iconPath: mdiNetwork, + }, + { + translationKey: "ui.panel.config.zha.groups.caption", + path: `/config/zha/groups`, + iconPath: mdiFolderMultipleOutline, + }, +]; + +@customElement("zha-config-dashboard") +class ZHAConfigDashboard extends LitElement { + @property({ type: Object }) public hass!: HomeAssistant; + + @property({ type: Object }) public route!: Route; + + @property({ type: Boolean }) public narrow!: boolean; + + @property({ type: Boolean }) public isWide!: boolean; + + @property() public configEntryId?: string; + + protected render(): TemplateResult { + return html` + + +
+ Network info/settings for specific config entry +
+ ${this.configEntryId + ? html`` + : ""} +
+ + + + + +
+ `; + } + + static get styles(): CSSResultArray { + return [ + haStyle, + css` + ha-card { + margin: auto; + margin-top: 16px; + max-width: 500px; + } + mwc-fab { + position: fixed; + bottom: 16px; + right: 16px; + z-index: 1; + } + + mwc-fab[is-wide] { + bottom: 24px; + right: 24px; + } + mwc-fab[narrow] { + bottom: 84px; + } + mwc-fab[rtl] { + right: auto; + left: 16px; + } + + mwc-fab[rtl][is-wide] { + bottom: 24px; + right: auto; + left: 24px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-config-dashboard": ZHAConfigDashboard; + } +} diff --git a/src/panels/config/zha/zha-device-binding.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-binding.ts similarity index 93% rename from src/panels/config/zha/zha-device-binding.ts rename to src/panels/config/integrations/integration-panels/zha/zha-device-binding.ts index 15acf51c37..fc688b1f8c 100644 --- a/src/panels/config/zha/zha-device-binding.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-binding.ts @@ -1,6 +1,6 @@ import "@material/mwc-button/mwc-button"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { @@ -13,13 +13,13 @@ import { PropertyValues, TemplateResult, } from "lit-element"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../components/ha-service-description"; -import { bindDevices, unbindDevices, ZHADevice } from "../../../data/zha"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; -import "../ha-config-section"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-service-description"; +import { bindDevices, unbindDevices, ZHADevice } from "../../../../../data/zha"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import "../../../ha-config-section"; import { ItemSelectedEvent } from "./types"; @customElement("zha-device-binding-control") diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts new file mode 100644 index 0000000000..0da4c4e0bf --- /dev/null +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts @@ -0,0 +1,243 @@ +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-listbox/paper-listbox"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; +import { + css, + CSSResult, + customElement, + html, + LitElement, + property, + TemplateResult, +} from "lit-element"; +import { fireEvent } from "../../../../../common/dom/fire_event"; +import { computeStateName } from "../../../../../common/entity/compute_state_name"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/entity/state-badge"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-service-description"; +import { updateDeviceRegistryEntry } from "../../../../../data/device_registry"; +import { ZHADevice } from "../../../../../data/zha"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import "../../../../../components/ha-area-picker"; +import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box"; +import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin"; +import { + subscribeEntityRegistry, + EntityRegistryEntry, + updateEntityRegistryEntry, +} from "../../../../../data/entity_registry"; +import { createValidEntityId } from "../../../../../common/entity/valid_entity_id"; +import memoizeOne from "memoize-one"; +import { EntityRegistryStateEntry } from "../../../devices/ha-config-device-page"; +import { compare } from "../../../../../common/string/compare"; +import { getIeeeTail } from "./functions"; + +@customElement("zha-device-card") +class ZHADeviceCard extends SubscribeMixin(LitElement) { + @property() public hass!: HomeAssistant; + + @property() public device?: ZHADevice; + + @property({ type: Boolean }) public narrow?: boolean; + + @property() private _entities: EntityRegistryEntry[] = []; + + private _deviceEntities = memoizeOne( + ( + deviceId: string, + entities: EntityRegistryEntry[] + ): EntityRegistryStateEntry[] => + entities + .filter((entity) => entity.device_id === deviceId) + .map((entity) => { + return { ...entity, stateName: this._computeEntityName(entity) }; + }) + .sort((ent1, ent2) => + compare( + ent1.stateName || `zzz${ent1.entity_id}`, + ent2.stateName || `zzz${ent2.entity_id}` + ) + ) + ); + + public hassSubscribe(): UnsubscribeFunc[] { + return [ + subscribeEntityRegistry(this.hass.connection, (entities) => { + this._entities = entities; + }), + ]; + } + + protected render(): TemplateResult { + if (!this.hass || !this.device) { + return html``; + } + const entities = this._deviceEntities( + this.device.device_reg_id, + this._entities + ); + + return html` + +
+
+
${this.device.model}
+
+ ${this.hass.localize( + "ui.dialogs.zha_device_info.manuf", + "manufacturer", + this.device.manufacturer + )} +
+
+ +
+ ${entities.map( + (entity) => html` + + ` + )} +
+ + +
+
+ `; + } + + private async _rename(event): Promise { + if (!this.hass || !this.device) { + return; + } + const device = this.device; + + const oldDeviceName = device.user_given_name || device.name; + const newDeviceName = event.target.value; + this.device.user_given_name = newDeviceName; + await updateDeviceRegistryEntry(this.hass, device.device_reg_id, { + name_by_user: newDeviceName, + }); + + if (!oldDeviceName || !newDeviceName || oldDeviceName === newDeviceName) { + return; + } + const entities = this._deviceEntities(device.device_reg_id, this._entities); + + const oldDeviceEntityId = createValidEntityId(oldDeviceName); + const newDeviceEntityId = createValidEntityId(newDeviceName); + const ieeeTail = getIeeeTail(device.ieee); + + const updateProms = entities.map((entity) => { + const name = entity.name || entity.stateName; + let newEntityId: string | null = null; + let newName: string | null = null; + + if (name && name.includes(oldDeviceName)) { + newName = name.replace(` ${ieeeTail}`, ""); + newName = newName.replace(oldDeviceName, newDeviceName); + newEntityId = entity.entity_id.replace(`_${ieeeTail}`, ""); + newEntityId = newEntityId.replace(oldDeviceEntityId, newDeviceEntityId); + } + + if (!newName && !newEntityId) { + return new Promise((resolve) => resolve()); + } + + return updateEntityRegistryEntry(this.hass!, entity.entity_id, { + name: newName || name, + disabled_by: entity.disabled_by, + new_entity_id: newEntityId || entity.entity_id, + }); + }); + await Promise.all(updateProms); + } + + private _openMoreInfo(ev: MouseEvent): void { + fireEvent(this, "hass-more-info", { + entityId: (ev.currentTarget as any).stateObj.entity_id, + }); + } + + private _computeEntityName(entity: EntityRegistryEntry): string { + if (this.hass.states[entity.entity_id]) { + return computeStateName(this.hass.states[entity.entity_id]); + } + return entity.name; + } + + private async _areaPicked(ev: CustomEvent) { + const picker = ev.currentTarget as any; + + const area = ev.detail.value; + try { + await updateDeviceRegistryEntry(this.hass, this.device!.device_reg_id, { + area_id: area, + }); + this.device!.area_id = area; + } catch (err) { + showAlertDialog(this, { + text: this.hass.localize( + "ui.panel.config.integrations.config_flow.error_saving_area", + "error", + err.message + ), + }); + picker.value = null; + } + } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + .device-entities { + display: flex; + flex-wrap: wrap; + padding: 4px; + justify-content: left; + min-height: 48px; + } + .device { + width: 30%; + } + .device .name { + font-weight: bold; + } + .device .manuf { + color: var(--secondary-text-color); + margin-bottom: 20px; + } + .extra-info { + margin-top: 8px; + } + state-badge { + cursor: pointer; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-device-card": ZHADeviceCard; + } +} diff --git a/src/panels/config/zha/zha-device-endpoint-data-table.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts similarity index 78% rename from src/panels/config/zha/zha-device-endpoint-data-table.ts rename to src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts index e758bb79e0..e1c926b74e 100644 --- a/src/panels/config/zha/zha-device-endpoint-data-table.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts @@ -9,16 +9,18 @@ import { CSSResult, } from "lit-element"; import memoizeOne from "memoize-one"; -import "../../../components/data-table/ha-data-table"; +import "../../../../../components/data-table/ha-data-table"; import type { DataTableColumnContainer, HaDataTable, DataTableRowData, -} from "../../../components/data-table/ha-data-table"; -import "../../../components/entity/ha-state-icon"; -import type { ZHADeviceEndpoint, ZHAEntityReference } from "../../../data/zha"; -import { showZHADeviceInfoDialog } from "../../../dialogs/zha-device-info-dialog/show-dialog-zha-device-info"; -import type { HomeAssistant } from "../../../types"; +} from "../../../../../components/data-table/ha-data-table"; +import "../../../../../components/entity/ha-state-icon"; +import type { + ZHADeviceEndpoint, + ZHAEntityReference, +} from "../../../../../data/zha"; +import type { HomeAssistant } from "../../../../../types"; export interface DeviceEndpointRowData extends DataTableRowData { id: string; @@ -55,6 +57,7 @@ export class ZHADeviceEndpointDataTable extends LitElement { ieee: deviceEndpoint.device.ieee, endpoint_id: deviceEndpoint.endpoint_id, entities: deviceEndpoint.entities, + dev_id: deviceEndpoint.device.device_reg_id, }); }); @@ -72,14 +75,10 @@ export class ZHADeviceEndpointDataTable extends LitElement { filterable: true, direction: "asc", grows: true, - template: (name) => html` -
+ template: (name, device: any) => html` + ${name} -
+ `, }, endpoint_id: { @@ -95,14 +94,10 @@ export class ZHADeviceEndpointDataTable extends LitElement { filterable: true, direction: "asc", grows: true, - template: (name) => html` -
+ template: (name, device: any) => html` + ${name} -
+ `, }, endpoint_id: { @@ -156,14 +151,6 @@ export class ZHADeviceEndpointDataTable extends LitElement { `; } - private async _handleClicked(ev: CustomEvent) { - const rowId = ((ev.target as HTMLElement).closest( - ".mdc-data-table__row" - ) as any).rowId; - const ieee = rowId.substring(0, rowId.indexOf("_")); - showZHADeviceInfoDialog(this, { ieee }); - } - static get styles(): CSSResult[] { return [ css` diff --git a/src/panels/config/zha/zha-group-binding.ts b/src/panels/config/integrations/integration-panels/zha/zha-group-binding.ts similarity index 93% rename from src/panels/config/zha/zha-group-binding.ts rename to src/panels/config/integrations/integration-panels/zha/zha-group-binding.ts index 64d8969831..884d6f727a 100644 --- a/src/panels/config/zha/zha-group-binding.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-group-binding.ts @@ -1,6 +1,6 @@ import "@material/mwc-button/mwc-button"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { @@ -14,11 +14,11 @@ import { query, TemplateResult, } from "lit-element"; -import type { HASSDomEvent } from "../../../common/dom/fire_event"; -import "../../../components/buttons/ha-call-service-button"; -import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table"; -import "../../../components/ha-card"; -import "../../../components/ha-service-description"; +import type { HASSDomEvent } from "../../../../../common/dom/fire_event"; +import "../../../../../components/buttons/ha-call-service-button"; +import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-service-description"; import { bindDeviceToGroup, Cluster, @@ -26,10 +26,10 @@ import { unbindDeviceFromGroup, ZHADevice, ZHAGroup, -} from "../../../data/zha"; -import { haStyle } from "../../../resources/styles"; -import type { HomeAssistant } from "../../../types"; -import "../ha-config-section"; +} from "../../../../../data/zha"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant } from "../../../../../types"; +import "../../../ha-config-section"; import { ItemSelectedEvent } from "./types"; import "./zha-clusters-data-table"; import type { ZHAClustersDataTable } from "./zha-clusters-data-table"; diff --git a/src/panels/config/zha/zha-group-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-group-page.ts similarity index 87% rename from src/panels/config/zha/zha-group-page.ts rename to src/panels/config/integrations/integration-panels/zha/zha-group-page.ts index 461df7d9fd..9e798f5832 100644 --- a/src/panels/config/zha/zha-group-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-group-page.ts @@ -1,5 +1,5 @@ import "@material/mwc-button"; -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-spinner/paper-spinner"; import { css, @@ -11,9 +11,9 @@ import { PropertyValues, query, } from "lit-element"; -import { HASSDomEvent } from "../../../common/dom/fire_event"; -import { navigate } from "../../../common/navigate"; -import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table"; +import { HASSDomEvent } from "../../../../../common/dom/fire_event"; +import { navigate } from "../../../../../common/navigate"; +import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table"; import { addMembersToGroup, fetchGroup, @@ -22,13 +22,12 @@ import { removeMembersFromGroup, ZHAGroup, ZHADeviceEndpoint, -} from "../../../data/zha"; -import "../../../layouts/hass-error-screen"; -import "../../../layouts/hass-subpage"; -import { HomeAssistant } from "../../../types"; -import "../ha-config-section"; +} from "../../../../../data/zha"; +import "../../../../../layouts/hass-error-screen"; +import "../../../../../layouts/hass-subpage"; +import { HomeAssistant } from "../../../../../types"; +import "../../../ha-config-section"; import { formatAsPaddedHex } from "./functions"; -import "./zha-device-card"; import "./zha-device-endpoint-data-table"; import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table"; @@ -122,25 +121,26 @@ export class ZHAGroupPage extends LitElement {
${this.hass.localize("ui.panel.config.zha.groups.members")}
- - ${this.group.members.length - ? this.group.members.map( - (member) => html` - - ` - ) - : html` -

- This group has no members -

- `} + + ${this.group.members.length + ? this.group.members.map( + (member) => + html` + ${member.device.user_given_name || + member.device.name} + ` + ) + : html` + + This group has no members + + `} + ${this.group.members.length ? html`
@@ -285,6 +285,9 @@ export class ZHAGroupPage extends LitElement { static get styles(): CSSResult[] { return [ css` + hass-subpage { + --app-header-text-color: var(--sidebar-icon-color); + } .header { font-family: var(--paper-font-display1_-_font-family); -webkit-font-smoothing: var( @@ -297,14 +300,15 @@ export class ZHAGroupPage extends LitElement { opacity: var(--dark-primary-opacity); } - ha-config-section *:last-child { - padding-bottom: 24px; - } - .button { float: right; } + a { + color: var(--primary-color); + text-decoration: none; + } + mwc-button paper-spinner { width: 14px; height: 14px; diff --git a/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts b/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts new file mode 100644 index 0000000000..a344750e00 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts @@ -0,0 +1,193 @@ +import "@material/mwc-button"; +import "@material/mwc-fab"; +import "../../../../../components/ha-icon-button"; +import memoizeOne from "memoize-one"; +import { + customElement, + html, + LitElement, + property, + PropertyValues, + TemplateResult, + CSSResultArray, + css, +} from "lit-element"; +import { HASSDomEvent } from "../../../../../common/dom/fire_event"; +import { navigate } from "../../../../../common/navigate"; +import { + DataTableColumnContainer, + RowClickedEvent, +} from "../../../../../components/data-table/ha-data-table"; +import { fetchGroups, ZHAGroup, ZHADevice } from "../../../../../data/zha"; +import "../../../../../layouts/hass-tabs-subpage-data-table"; +import { HomeAssistant, Route } from "../../../../../types"; +import { sortZHAGroups, formatAsPaddedHex } from "./functions"; +import { zhaTabs } from "./zha-config-dashboard"; +import { computeRTL } from "../../../../../common/util/compute_rtl"; +import { mdiPlus } from "@mdi/js"; +import { haStyle } from "../../../../../resources/styles"; + +export interface GroupRowData extends ZHAGroup { + group?: GroupRowData; + id?: string; +} + +@customElement("zha-groups-dashboard") +export class ZHAGroupsDashboard extends LitElement { + @property() public hass!: HomeAssistant; + + @property({ type: Object }) public route!: Route; + + @property({ type: Boolean }) public narrow!: boolean; + + @property({ type: Boolean }) public isWide!: boolean; + + @property() public _groups: ZHAGroup[] = []; + + private _firstUpdatedCalled = false; + + public connectedCallback(): void { + super.connectedCallback(); + if (this.hass && this._firstUpdatedCalled) { + this._fetchGroups(); + } + } + + protected firstUpdated(changedProperties: PropertyValues): void { + super.firstUpdated(changedProperties); + if (this.hass) { + this._fetchGroups(); + } + this._firstUpdatedCalled = true; + } + + private _formattedGroups = memoizeOne((groups: ZHAGroup[]) => { + let outputGroups: GroupRowData[] = groups; + + outputGroups = outputGroups.map((group) => { + return { + ...group, + id: String(group.group_id), + }; + }); + + return outputGroups; + }); + + private _columns = memoizeOne( + (narrow: boolean): DataTableColumnContainer => + narrow + ? { + name: { + title: "Group", + sortable: true, + filterable: true, + direction: "asc", + grows: true, + }, + } + : { + name: { + title: this.hass.localize("ui.panel.config.zha.groups.groups"), + sortable: true, + filterable: true, + direction: "asc", + grows: true, + }, + group_id: { + title: this.hass.localize("ui.panel.config.zha.groups.group_id"), + type: "numeric", + width: "15%", + template: (groupId: number) => { + return html` ${formatAsPaddedHex(groupId)} `; + }, + sortable: true, + }, + members: { + title: this.hass.localize("ui.panel.config.zha.groups.members"), + type: "numeric", + width: "15%", + template: (members: ZHADevice[]) => { + return html` ${members.length} `; + }, + sortable: true, + }, + } + ); + + protected render(): TemplateResult { + return html` + + + + + + + + `; + } + + private async _fetchGroups() { + this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups); + } + + private _handleRowClicked(ev: HASSDomEvent) { + const groupId = ev.detail.id; + navigate(this, `/config/zha/group/${groupId}`); + } + + static get styles(): CSSResultArray { + return [ + haStyle, + css` + mwc-fab { + position: fixed; + bottom: 16px; + right: 16px; + z-index: 1; + } + + mwc-fab[is-wide] { + bottom: 24px; + right: 24px; + } + mwc-fab[narrow] { + bottom: 84px; + } + mwc-fab[rtl] { + right: auto; + left: 16px; + } + + mwc-fab[rtl][is-wide] { + bottom: 24px; + right: auto; + left: 24px; + } + + a { + color: var(--primary-color); + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-groups-dashboard": ZHAGroupsDashboard; + } +} diff --git a/src/panels/config/zwave/ha-config-zwave.js b/src/panels/config/integrations/integration-panels/zwave/ha-config-zwave.js similarity index 95% rename from src/panels/config/zwave/ha-config-zwave.js rename to src/panels/config/integrations/integration-panels/zwave/ha-config-zwave.js index bcaf952720..a292ccab6f 100644 --- a/src/panels/config/zwave/ha-config-zwave.js +++ b/src/panels/config/integrations/integration-panels/zwave/ha-config-zwave.js @@ -1,27 +1,27 @@ import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { computeStateDomain } from "../../../common/entity/compute_state_domain"; -import { computeStateName } from "../../../common/entity/compute_state_name"; -import { sortStatesByName } from "../../../common/entity/states_sort_by_name"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../components/ha-menu-button"; -import "../../../components/ha-icon-button-arrow-prev"; -import "../../../components/ha-service-description"; -import "../../../layouts/ha-app-layout"; -import { EventsMixin } from "../../../mixins/events-mixin"; -import LocalizeMixin from "../../../mixins/localize-mixin"; -import "../../../styles/polymer-ha-style"; -import "../ha-config-section"; -import "../ha-form-style"; +import { computeStateDomain } from "../../../../../common/entity/compute_state_domain"; +import { computeStateName } from "../../../../../common/entity/compute_state_name"; +import { sortStatesByName } from "../../../../../common/entity/states_sort_by_name"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-menu-button"; +import "../../../../../components/ha-icon-button-arrow-prev"; +import "../../../../../components/ha-service-description"; +import "../../../../../layouts/ha-app-layout"; +import { EventsMixin } from "../../../../../mixins/events-mixin"; +import LocalizeMixin from "../../../../../mixins/localize-mixin"; +import "../../../../../styles/polymer-ha-style"; +import "../../../ha-config-section"; +import "../../../ha-form-style"; import "./zwave-groups"; import "./zwave-log"; import "./zwave-network"; diff --git a/src/panels/config/zwave/zwave-groups.js b/src/panels/config/integrations/integration-panels/zwave/zwave-groups.js similarity index 97% rename from src/panels/config/zwave/zwave-groups.js rename to src/panels/config/integrations/integration-panels/zwave/zwave-groups.js index a2d0dd2585..102567a289 100644 --- a/src/panels/config/zwave/zwave-groups.js +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-groups.js @@ -4,10 +4,10 @@ import "@polymer/paper-listbox/paper-listbox"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { computeStateName } from "../../../common/entity/compute_state_name"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../styles/polymer-ha-style"; +import { computeStateName } from "../../../../../common/entity/compute_state_name"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import "../../../../../styles/polymer-ha-style"; class ZwaveGroups extends PolymerElement { static get template() { diff --git a/src/panels/config/zwave/zwave-log-dialog.js b/src/panels/config/integrations/integration-panels/zwave/zwave-log-dialog.js similarity index 91% rename from src/panels/config/zwave/zwave-log-dialog.js rename to src/panels/config/integrations/integration-panels/zwave/zwave-log-dialog.js index f3e16d2c63..14fe3153f3 100644 --- a/src/panels/config/zwave/zwave-log-dialog.js +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-log-dialog.js @@ -2,9 +2,9 @@ import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "../../../components/dialog/ha-paper-dialog"; -import { EventsMixin } from "../../../mixins/events-mixin"; -import "../../../styles/polymer-ha-style-dialog"; +import "../../../../../components/dialog/ha-paper-dialog"; +import { EventsMixin } from "../../../../../mixins/events-mixin"; +import "../../../../../styles/polymer-ha-style-dialog"; class ZwaveLogDialog extends EventsMixin(PolymerElement) { static get template() { diff --git a/src/panels/config/zwave/zwave-log.js b/src/panels/config/integrations/integration-panels/zwave/zwave-log.js similarity index 92% rename from src/panels/config/zwave/zwave-log.js rename to src/panels/config/integrations/integration-panels/zwave/zwave-log.js index 05ea015bb6..4dd0ac2d55 100755 --- a/src/panels/config/zwave/zwave-log.js +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-log.js @@ -4,12 +4,12 @@ import "@polymer/paper-input/paper-input"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import isPwa from "../../../common/config/is_pwa"; -import "../../../components/ha-card"; -import { EventsMixin } from "../../../mixins/events-mixin"; -import LocalizeMixin from "../../../mixins/localize-mixin"; -import "../ha-config-section"; -import "../../../styles/polymer-ha-style"; +import isPwa from "../../../../../common/config/is_pwa"; +import "../../../../../components/ha-card"; +import { EventsMixin } from "../../../../../mixins/events-mixin"; +import LocalizeMixin from "../../../../../mixins/localize-mixin"; +import "../../../ha-config-section"; +import "../../../../../styles/polymer-ha-style"; let registeredDialog = false; diff --git a/src/panels/config/zwave/zwave-network.ts b/src/panels/config/integrations/integration-panels/zwave/zwave-network.ts similarity index 94% rename from src/panels/config/zwave/zwave-network.ts rename to src/panels/config/integrations/integration-panels/zwave/zwave-network.ts index 570d12d512..c0dbc7bbbc 100644 --- a/src/panels/config/zwave/zwave-network.ts +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-network.ts @@ -1,4 +1,4 @@ -import "../../../components/ha-icon-button"; +import "../../../../../components/ha-icon-button"; import "@polymer/paper-spinner/paper-spinner"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { @@ -10,11 +10,11 @@ import { property, TemplateResult, } from "lit-element"; -import "../../../components/buttons/ha-call-api-button"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../components/ha-icon"; -import "../../../components/ha-service-description"; +import "../../../../../components/buttons/ha-call-api-button"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-icon"; +import "../../../../../components/ha-service-description"; import { fetchNetworkStatus, ZWaveNetworkStatus, @@ -22,10 +22,10 @@ import { ZWAVE_NETWORK_STATE_READY, ZWAVE_NETWORK_STATE_STARTED, ZWAVE_NETWORK_STATE_STOPPED, -} from "../../../data/zwave"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; -import "../ha-config-section"; +} from "../../../../../data/zwave"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import "../../../ha-config-section"; @customElement("zwave-network") export class ZwaveNetwork extends LitElement { diff --git a/src/panels/config/zwave/zwave-node-config.ts b/src/panels/config/integrations/integration-panels/zwave/zwave-node-config.ts similarity index 97% rename from src/panels/config/zwave/zwave-node-config.ts rename to src/panels/config/integrations/integration-panels/zwave/zwave-node-config.ts index b50ef6f2c7..831ee5a86b 100644 --- a/src/panels/config/zwave/zwave-node-config.ts +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-node-config.ts @@ -12,16 +12,16 @@ import { PropertyValues, TemplateResult, } from "lit-element"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; import { fetchNodeConfig, ZWaveConfigItem, ZWaveConfigServiceData, ZWaveNode, -} from "../../../data/zwave"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; +} from "../../../../../data/zwave"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; @customElement("zwave-node-config") export class ZwaveNodeConfig extends LitElement { diff --git a/src/panels/config/zwave/zwave-node-protection.js b/src/panels/config/integrations/integration-panels/zwave/zwave-node-protection.js similarity index 96% rename from src/panels/config/zwave/zwave-node-protection.js rename to src/panels/config/integrations/integration-panels/zwave/zwave-node-protection.js index 292fb80bfe..0c6d1a464a 100644 --- a/src/panels/config/zwave/zwave-node-protection.js +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-node-protection.js @@ -5,9 +5,9 @@ import "@polymer/paper-listbox/paper-listbox"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "../../../components/buttons/ha-call-api-button"; -import "../../../components/ha-card"; -import "../../../styles/polymer-ha-style"; +import "../../../../../components/buttons/ha-call-api-button"; +import "../../../../../components/ha-card"; +import "../../../../../styles/polymer-ha-style"; class ZwaveNodeProtection extends PolymerElement { static get template() { diff --git a/src/panels/config/zwave/zwave-usercodes.js b/src/panels/config/integrations/integration-panels/zwave/zwave-usercodes.js similarity index 97% rename from src/panels/config/zwave/zwave-usercodes.js rename to src/panels/config/integrations/integration-panels/zwave/zwave-usercodes.js index 316bc5e7f6..fcdd099185 100644 --- a/src/panels/config/zwave/zwave-usercodes.js +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-usercodes.js @@ -5,9 +5,9 @@ import "@polymer/paper-listbox/paper-listbox"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../styles/polymer-ha-style"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import "../../../../../styles/polymer-ha-style"; class ZwaveUsercodes extends PolymerElement { static get template() { diff --git a/src/panels/config/zwave/zwave-values.ts b/src/panels/config/integrations/integration-panels/zwave/zwave-values.ts similarity index 90% rename from src/panels/config/zwave/zwave-values.ts rename to src/panels/config/integrations/integration-panels/zwave/zwave-values.ts index 20b5eeec35..5e60dd8c2b 100644 --- a/src/panels/config/zwave/zwave-values.ts +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-values.ts @@ -10,11 +10,11 @@ import { property, TemplateResult, } from "lit-element"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import { ZWaveValue } from "../../../data/zwave"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/ha-card"; +import { ZWaveValue } from "../../../../../data/zwave"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; @customElement("zwave-values") export class ZwaveValues extends LitElement { diff --git a/src/panels/config/zha/zha-config-dashboard.ts b/src/panels/config/zha/zha-config-dashboard.ts deleted file mode 100644 index 88422f56c8..0000000000 --- a/src/panels/config/zha/zha-config-dashboard.ts +++ /dev/null @@ -1,188 +0,0 @@ -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResultArray, - customElement, - html, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; -import memoizeOne from "memoize-one"; -import { navigate } from "../../../common/navigate"; -import "../../../components/data-table/ha-data-table"; -import type { - DataTableColumnContainer, - RowClickedEvent, - DataTableRowData, -} from "../../../components/data-table/ha-data-table"; -import "../../../components/ha-card"; -import "../../../components/ha-icon-next"; -import { fetchDevices } from "../../../data/zha"; -import type { ZHADevice } from "../../../data/zha"; -import "../../../layouts/hass-subpage"; -import { haStyle } from "../../../resources/styles"; -import type { HomeAssistant, Route } from "../../../types"; -import "../ha-config-section"; -import { formatAsPaddedHex, sortZHADevices } from "./functions"; - -export interface DeviceRowData extends DataTableRowData { - device?: DeviceRowData; -} - -@customElement("zha-config-dashboard") -class ZHAConfigDashboard extends LitElement { - @property({ type: Object }) public hass!: HomeAssistant; - - @property({ type: Object }) public route!: Route; - - @property({ type: Boolean }) public narrow!: boolean; - - @property({ type: Boolean }) public isWide!: boolean; - - @property() private _devices: ZHADevice[] = []; - - private pages: string[] = ["add", "groups"]; - - private _firstUpdatedCalled = false; - - private _memoizeDevices = memoizeOne((devices: ZHADevice[]) => { - let outputDevices: DeviceRowData[] = devices; - - outputDevices = outputDevices.map((device) => { - return { - ...device, - name: device.user_given_name ? device.user_given_name : device.name, - nwk: formatAsPaddedHex(device.nwk), - }; - }); - - return outputDevices; - }); - - private _columns = memoizeOne( - (narrow: boolean): DataTableColumnContainer => - narrow - ? { - name: { - title: "Devices", - sortable: true, - filterable: true, - direction: "asc", - grows: true, - }, - } - : { - name: { - title: "Name", - sortable: true, - filterable: true, - direction: "asc", - grows: true, - }, - nwk: { - title: "Nwk", - sortable: true, - filterable: true, - width: "15%", - }, - ieee: { - title: "IEEE", - sortable: true, - filterable: true, - width: "30%", - }, - } - ); - - public connectedCallback(): void { - super.connectedCallback(); - if (this.hass && this._firstUpdatedCalled) { - this._fetchDevices(); - } - } - - protected firstUpdated(changedProperties: PropertyValues): void { - super.firstUpdated(changedProperties); - if (this.hass) { - this._fetchDevices(); - } - this._firstUpdatedCalled = true; - } - - protected render(): TemplateResult { - return html` - - -
- ${this.hass.localize("ui.panel.config.zha.header")} -
- -
- ${this.hass.localize("ui.panel.config.zha.introduction")} -
- - - ${this.pages.map((page) => { - return html` - - - - ${this.hass.localize( - `ui.panel.config.zha.${page}.caption` - )} -
- ${this.hass.localize( - `ui.panel.config.zha.${page}.description` - )} -
-
- -
-
- `; - })} -
- - - -
-
- `; - } - - private async _fetchDevices() { - this._devices = (await fetchDevices(this.hass!)).sort(sortZHADevices); - } - - private async _handleDeviceClicked(ev: CustomEvent) { - const deviceId = (ev.detail as RowClickedEvent).id; - navigate(this, `/config/zha/device/${deviceId}`); - } - - static get styles(): CSSResultArray { - return [ - haStyle, - css` - a { - text-decoration: none; - color: var(--primary-text-color); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-config-dashboard": ZHAConfigDashboard; - } -} diff --git a/src/panels/config/zha/zha-device-card.ts b/src/panels/config/zha/zha-device-card.ts deleted file mode 100644 index 1bac828040..0000000000 --- a/src/panels/config/zha/zha-device-card.ts +++ /dev/null @@ -1,566 +0,0 @@ -import "@material/mwc-button"; -import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; -import "@polymer/paper-input/paper-input"; -import "@polymer/paper-item/paper-icon-item"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-item/paper-item-body"; -import "@polymer/paper-listbox/paper-listbox"; -import { HassEvent, UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; -import { fireEvent } from "../../../common/dom/fire_event"; -import { computeStateName } from "../../../common/entity/compute_state_name"; -import { navigate } from "../../../common/navigate"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/entity/state-badge"; -import "../../../components/ha-card"; -import "../../../components/ha-service-description"; -import { - AreaRegistryEntry, - subscribeAreaRegistry, -} from "../../../data/area_registry"; -import { - DeviceRegistryEntryMutableParams, - updateDeviceRegistryEntry, -} from "../../../data/device_registry"; -import { - reconfigureNode, - ZHADevice, - ZHAEntityReference, -} from "../../../data/zha"; -import { showZHADeviceZigbeeInfoDialog } from "../../../dialogs/zha-device-zigbee-signature-dialog/show-dialog-zha-device-zigbee-info"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; -import { addEntitiesToLovelaceView } from "../../lovelace/editor/add-entities-to-view"; -import { formatAsPaddedHex } from "./functions"; -import { ItemSelectedEvent, NodeServiceData } from "./types"; - -declare global { - // for fire event - interface HASSDomEvents { - "zha-device-removed": { - device?: ZHADevice; - }; - } -} - -@customElement("zha-device-card") -class ZHADeviceCard extends LitElement { - @property() public hass!: HomeAssistant; - - @property() public device?: ZHADevice; - - @property({ type: Boolean }) public narrow?: boolean; - - @property({ type: Boolean }) public showHelp?: boolean = false; - - @property({ type: Boolean }) public showActions?: boolean = true; - - @property({ type: Boolean }) public showName?: boolean = true; - - @property({ type: Boolean }) public showEntityDetail?: boolean = true; - - @property({ type: Boolean }) public showModelInfo?: boolean = true; - - @property({ type: Boolean }) public showEditableInfo?: boolean = true; - - @property() private _serviceData?: NodeServiceData; - - @property() private _areas: AreaRegistryEntry[] = []; - - @property() private _selectedAreaIndex = -1; - - @property() private _userGivenName?: string; - - private _unsubAreas?: UnsubscribeFunc; - - private _unsubEntities?: UnsubscribeFunc; - - public disconnectedCallback() { - super.disconnectedCallback(); - if (this._unsubAreas) { - this._unsubAreas(); - } - if (this._unsubEntities) { - this._unsubEntities(); - } - } - - public connectedCallback() { - super.connectedCallback(); - this._unsubAreas = subscribeAreaRegistry(this.hass.connection, (areas) => { - this._areas = areas; - if (this.device) { - this._selectedAreaIndex = - this._areas.findIndex( - (area) => area.area_id === this.device!.area_id - ) + 1; // account for the no area selected index - } - }); - this.hass.connection - .subscribeEvents((event: HassEvent) => { - if (this.device) { - this.device!.entities.forEach((deviceEntity) => { - if (event.data.old_entity_id === deviceEntity.entity_id) { - deviceEntity.entity_id = event.data.entity_id; - } - }); - } - }, "entity_registry_updated") - .then((unsub) => { - this._unsubEntities = unsub; - }); - } - - protected firstUpdated(changedProperties: PropertyValues): void { - super.firstUpdated(changedProperties); - this.addEventListener("hass-service-called", (ev) => - this.serviceCalled(ev) - ); - } - - protected updated(changedProperties: PropertyValues): void { - if (changedProperties.has("device")) { - if (!this._areas || !this.device || !this.device.area_id) { - this._selectedAreaIndex = 0; - } else { - this._selectedAreaIndex = - this._areas.findIndex( - (area) => area.area_id === this.device!.area_id - ) + 1; - } - this._userGivenName = this.device!.user_given_name; - this._serviceData = { - ieee_address: this.device!.ieee, - }; - } - super.update(changedProperties); - } - - protected serviceCalled(ev): void { - // Check if this is for us - if (ev.detail.success && ev.detail.service === "remove") { - fireEvent(this, "zha-device-removed", { - device: this.device, - }); - } - } - - protected render(): TemplateResult { - return html` - - ${ - this.showModelInfo - ? html` -
-
${this.device!.model}
-
- ${this.hass!.localize( - "ui.dialogs.zha_device_info.manuf", - "manufacturer", - this.device!.manufacturer - )} -
-
- ` - : "" - } -
-
-
IEEE:
-
${this.device!.ieee}
-
Nwk:
-
${formatAsPaddedHex(this.device!.nwk)}
-
Device Type:
-
${this.device!.device_type}
-
LQI:
-
${ - this.device!.lqi || - this.hass!.localize("ui.dialogs.zha_device_info.unknown") - }
-
RSSI:
-
${ - this.device!.rssi || - this.hass!.localize("ui.dialogs.zha_device_info.unknown") - }
-
${this.hass!.localize( - "ui.dialogs.zha_device_info.last_seen" - )}:
-
${ - this.device!.last_seen || - this.hass!.localize("ui.dialogs.zha_device_info.unknown") - }
-
${this.hass!.localize( - "ui.dialogs.zha_device_info.power_source" - )}:
-
${ - this.device!.power_source || - this.hass!.localize("ui.dialogs.zha_device_info.unknown") - }
- ${ - this.device!.quirk_applied - ? html` -
- ${this.hass!.localize( - "ui.dialogs.zha_device_info.quirk" - )}: -
-
${this.device!.quirk_class}
- ` - : "" - } -
-
- -
- ${this.device!.entities.map( - (entity) => html` - - - ${this.showEntityDetail - ? html` - -
- ${this._computeEntityName(entity)} -
-
- ${entity.entity_id} -
-
- ` - : ""} -
- ` - )} -
- ${ - this.device!.entities && this.device!.entities.length > 0 - ? html` -
- - ${this.hass.localize( - "ui.panel.config.devices.entities.add_entities_lovelace" - )} - -
- ` - : "" - } - ${ - this.showEditableInfo - ? html` -
- -
-
- - - - ${this.hass!.localize( - "ui.dialogs.zha_device_info.no_area" - )} - - - ${this._areas.map( - (entry) => html` - ${entry.name} - ` - )} - - -
- ` - : "" - } - ${ - this.showActions - ? html` -
- ${this.device!.device_type !== "Coordinator" - ? html` - - ${this.hass!.localize( - "ui.dialogs.zha_device_info.buttons.reconfigure" - )} - - ${this.showHelp - ? html` -
- ${this.hass!.localize( - "ui.dialogs.zha_device_info.services.reconfigure" - )} -
- ` - : ""} - - - ${this.hass!.localize( - "ui.dialogs.zha_device_info.buttons.remove" - )} - - ${this.showHelp - ? html` -
- ${this.hass!.localize( - "ui.dialogs.zha_device_info.services.remove" - )} -
- ` - : ""} - ` - : ""} - ${this.device!.power_source === "Mains" && - (this.device!.device_type === "Router" || - this.device!.device_type === "Coordinator") - ? html` - - ${this.hass!.localize( - "ui.panel.config.zha.common.add_devices" - )} - - ${this.showHelp - ? html` - - ` - : ""} - ` - : ""} - ${this.device!.device_type !== "Coordinator" - ? html` - - ${this.hass!.localize( - "ui.dialogs.zha_device_info.buttons.zigbee_information" - )} - - ${this.showHelp - ? html` -
- ${this.hass!.localize( - "ui.dialogs.zha_device_info.services.zigbee_information" - )} -
- ` - : ""} - ` - : ""} -
- ` - : "" - } -
- - `; - } - - private async _onReconfigureNodeClick(): Promise { - if (this.hass) { - await reconfigureNode(this.hass, this.device!.ieee); - } - } - - private _computeEntityName(entity: ZHAEntityReference): string { - if (this.hass.states[entity.entity_id]) { - return computeStateName(this.hass.states[entity.entity_id]); - } - return entity.name; - } - - private async _saveCustomName(event): Promise { - if (this.hass) { - const values: DeviceRegistryEntryMutableParams = { - name_by_user: event.target.value, - area_id: this.device!.area_id ? this.device!.area_id : undefined, - }; - - await updateDeviceRegistryEntry( - this.hass, - this.device!.device_reg_id, - values - ); - - this.device!.user_given_name = event.target.value; - } - } - - private _openMoreInfo(ev: MouseEvent): void { - fireEvent(this, "hass-more-info", { - entityId: (ev.currentTarget as any).entity.entity_id, - }); - } - - private async _selectedAreaChanged(event: ItemSelectedEvent) { - if (!this.device || !this._areas) { - return; - } - this._selectedAreaIndex = event!.target!.selected; - const area = this._areas[this._selectedAreaIndex - 1]; // account for No Area - if ( - (!area && !this.device.area_id) || - (area && area.area_id === this.device.area_id) - ) { - return; - } - - const newAreaId = area ? area.area_id : undefined; - await updateDeviceRegistryEntry(this.hass!, this.device.device_reg_id, { - area_id: newAreaId, - name_by_user: this.device!.user_given_name, - }); - this.device!.area_id = newAreaId; - } - - private _onAddDevicesClick() { - navigate(this, "/config/zha/add/" + this.device!.ieee); - } - - private async _handleZigbeeInfoClicked() { - showZHADeviceZigbeeInfoDialog(this, { device: this.device! }); - } - - private _addToLovelaceView(): void { - addEntitiesToLovelaceView( - this, - this.hass, - this.device!.entities.map((entity) => entity.entity_id) - ); - } - - static get styles(): CSSResult[] { - return [ - haStyle, - css` - :host(:not([narrow])) .device-entities { - max-height: 225px; - overflow-y: auto; - display: flex; - flex-wrap: wrap; - padding: 4px; - justify-content: left; - } - ha-card { - flex: 1 0 100%; - padding-bottom: 10px; - min-width: 300px; - } - .device { - width: 30%; - } - .device .name { - font-weight: bold; - } - .device .manuf { - color: var(--secondary-text-color); - margin-bottom: 20px; - } - .extra-info { - margin-top: 8px; - } - .manuf, - .zha-info, - .name { - text-overflow: ellipsis; - } - .entity-id { - text-overflow: ellipsis; - color: var(--secondary-text-color); - } - .info { - margin-left: 16px; - } - dl { - display: flex; - flex-wrap: wrap; - width: 100%; - } - dl dt { - display: inline-block; - width: 30%; - padding-left: 12px; - float: left; - text-align: left; - } - dl dd { - width: 60%; - overflow-wrap: break-word; - margin-inline-start: 20px; - } - paper-icon-item { - overflow-x: hidden; - cursor: pointer; - padding-top: 4px; - padding-bottom: 4px; - } - .editable { - padding-left: 28px; - padding-right: 28px; - padding-bottom: 10px; - } - .help-text { - color: grey; - padding: 16px; - } - .menu { - width: 100%; - } - .node-picker { - align-items: center; - padding-left: 28px; - padding-right: 28px; - padding-bottom: 10px; - } - .buttons .icon { - margin-right: 16px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-device-card": ZHADeviceCard; - } -} diff --git a/src/panels/config/zha/zha-device-page.ts b/src/panels/config/zha/zha-device-page.ts deleted file mode 100755 index 8eea9949fe..0000000000 --- a/src/panels/config/zha/zha-device-page.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; -import { HASSDomEvent } from "../../../common/dom/fire_event"; -import { - Cluster, - fetchBindableDevices, - fetchGroups, - fetchZHADevice, - ZHADevice, - ZHAGroup, -} from "../../../data/zha"; -import "../../../layouts/hass-subpage"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; -import { sortZHADevices, sortZHAGroups } from "./functions"; -import { ZHAClusterSelectedParams } from "./types"; -import "./zha-cluster-attributes"; -import "./zha-cluster-commands"; -import "./zha-clusters"; -import "./zha-device-binding"; -import "./zha-group-binding"; -import "./zha-node"; - -@customElement("zha-device-page") -export class ZHADevicePage extends LitElement { - @property() public hass?: HomeAssistant; - - @property() public isWide?: boolean; - - @property() public ieee?: string; - - @property() public device?: ZHADevice; - - @property() public narrow?: boolean; - - @property() private _selectedCluster?: Cluster; - - @property() private _bindableDevices: ZHADevice[] = []; - - @property() private _groups: ZHAGroup[] = []; - - protected updated(changedProperties: PropertyValues): void { - if (changedProperties.has("ieee")) { - this._fetchData(); - } - super.update(changedProperties); - } - - protected render(): TemplateResult { - return html` - - - - ${this.device && this.device.device_type !== "Coordinator" - ? html` - - ${this._selectedCluster - ? html` - - - - ` - : ""} - ${this._bindableDevices.length > 0 - ? html` - - ` - : ""} - ${this.device && this._groups.length > 0 - ? html` - - ` - : ""} - ` - : ""} -
-
- `; - } - - private _onClusterSelected( - selectedClusterEvent: HASSDomEvent - ): void { - this._selectedCluster = selectedClusterEvent.detail.cluster; - } - - private async _fetchData(): Promise { - if (this.ieee && this.hass) { - this.device = await fetchZHADevice(this.hass, this.ieee); - this._bindableDevices = - this.device && this.device.device_type !== "Coordinator" - ? (await fetchBindableDevices(this.hass, this.ieee)).sort( - sortZHADevices - ) - : []; - this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups); - } - } - - static get styles(): CSSResult[] { - return [ - haStyle, - css` - .spacer { - height: 50px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-device-page": ZHADevicePage; - } -} diff --git a/src/panels/config/zha/zha-groups-dashboard.ts b/src/panels/config/zha/zha-groups-dashboard.ts deleted file mode 100644 index b8e3674974..0000000000 --- a/src/panels/config/zha/zha-groups-dashboard.ts +++ /dev/null @@ -1,172 +0,0 @@ -import "@material/mwc-button"; -import "../../../components/ha-icon-button"; -import "@polymer/paper-spinner/paper-spinner"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; -import { HASSDomEvent } from "../../../common/dom/fire_event"; -import { navigate } from "../../../common/navigate"; -import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table"; -import { fetchGroups, removeGroups, ZHAGroup } from "../../../data/zha"; -import "../../../layouts/hass-subpage"; -import { HomeAssistant } from "../../../types"; -import { sortZHAGroups } from "./functions"; -import "./zha-groups-data-table"; - -@customElement("zha-groups-dashboard") -export class ZHAGroupsDashboard extends LitElement { - @property() public hass!: HomeAssistant; - - @property() public narrow = false; - - @property() public _groups?: ZHAGroup[]; - - @property() private _processingRemove = false; - - @property() private _selectedGroupsToRemove: number[] = []; - - private _firstUpdatedCalled = false; - - public connectedCallback(): void { - super.connectedCallback(); - if (this.hass && this._firstUpdatedCalled) { - this._fetchGroups(); - } - } - - protected firstUpdated(changedProperties: PropertyValues): void { - super.firstUpdated(changedProperties); - if (this.hass) { - this._fetchGroups(); - } - this._firstUpdatedCalled = true; - } - - protected render(): TemplateResult { - return html` - - - -
- ${this._groups - ? html` - - ` - : html` - - `} -
-
- - - ${this.hass!.localize( - "ui.panel.config.zha.groups.remove_groups" - )} -
-
- `; - } - - private async _fetchGroups() { - this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups); - } - - private _handleRemoveSelectionChanged( - ev: HASSDomEvent - ): void { - this._selectedGroupsToRemove = ev.detail.value.map((value) => - Number(value) - ); - } - - private async _removeGroup(): Promise { - this._processingRemove = true; - this._groups = await removeGroups(this.hass, this._selectedGroupsToRemove); - this._selectedGroupsToRemove = []; - this._processingRemove = false; - } - - private async _addGroup(): Promise { - navigate(this, `/config/zha/group-add`); - } - - static get styles(): CSSResult[] { - return [ - css` - .content { - padding: 4px; - } - zha-groups-data-table { - width: 100%; - } - .button { - float: right; - } - .table { - height: 200px; - overflow: auto; - } - mwc-button paper-spinner { - width: 14px; - height: 14px; - margin-right: 20px; - } - paper-spinner { - display: none; - } - paper-spinner[active] { - display: block; - } - .paper-dialog-buttons { - align-items: flex-end; - padding: 8px; - } - .paper-dialog-buttons .warning { - --mdc-theme-primary: var(--google-red-500); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-groups-dashboard": ZHAGroupsDashboard; - } -} diff --git a/src/panels/config/zha/zha-groups-data-table.ts b/src/panels/config/zha/zha-groups-data-table.ts deleted file mode 100644 index ead1a9f20a..0000000000 --- a/src/panels/config/zha/zha-groups-data-table.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; -import memoizeOne from "memoize-one"; -import { navigate } from "../../../common/navigate"; -import "../../../components/data-table/ha-data-table"; -import type { - DataTableColumnContainer, - HaDataTable, -} from "../../../components/data-table/ha-data-table"; -import "../../../components/entity/ha-state-icon"; -import type { ZHADevice, ZHAGroup } from "../../../data/zha"; -import type { HomeAssistant } from "../../../types"; -import { formatAsPaddedHex } from "./functions"; - -export interface GroupRowData extends ZHAGroup { - group?: GroupRowData; - id?: string; -} - -@customElement("zha-groups-data-table") -export class ZHAGroupsDataTable extends LitElement { - @property() public hass!: HomeAssistant; - - @property() public narrow = false; - - @property() public groups: ZHAGroup[] = []; - - @property() public selectable = false; - - @query("ha-data-table") private _dataTable!: HaDataTable; - - private _groups = memoizeOne((groups: ZHAGroup[]) => { - let outputGroups: GroupRowData[] = groups; - - outputGroups = outputGroups.map((group) => { - return { - ...group, - id: String(group.group_id), - }; - }); - - return outputGroups; - }); - - private _columns = memoizeOne( - (narrow: boolean): DataTableColumnContainer => - narrow - ? { - name: { - title: "Group", - sortable: true, - filterable: true, - direction: "asc", - grows: true, - template: (name) => html` -
- ${name} -
- `, - }, - } - : { - name: { - title: this.hass.localize("ui.panel.config.zha.groups.groups"), - sortable: true, - filterable: true, - direction: "asc", - grows: true, - template: (name) => html` -
- ${name} -
- `, - }, - group_id: { - title: this.hass.localize("ui.panel.config.zha.groups.group_id"), - type: "numeric", - width: "15%", - template: (groupId: number) => { - return html` ${formatAsPaddedHex(groupId)} `; - }, - sortable: true, - }, - members: { - title: this.hass.localize("ui.panel.config.zha.groups.members"), - type: "numeric", - width: "15%", - template: (members: ZHADevice[]) => { - return html` ${members.length} `; - }, - sortable: true, - }, - } - ); - - public clearSelection() { - this._dataTable.clearSelection(); - } - - protected render(): TemplateResult { - return html` - - `; - } - - private _handleRowClicked(ev: CustomEvent) { - const groupId = ((ev.target as HTMLElement).closest( - ".mdc-data-table__row" - ) as any).rowId; - navigate(this, `/config/zha/group/${groupId}`); - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-groups-data-table": ZHAGroupsDataTable; - } -} diff --git a/src/panels/config/zha/zha-node.ts b/src/panels/config/zha/zha-node.ts deleted file mode 100644 index 4968675463..0000000000 --- a/src/panels/config/zha/zha-node.ts +++ /dev/null @@ -1,148 +0,0 @@ -import "../../../components/ha-icon-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { navigate } from "../../../common/navigate"; -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-card"; -import "../../../components/ha-service-description"; -import { ZHADevice } from "../../../data/zha"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; -import "../ha-config-section"; -import "./zha-device-card"; - -@customElement("zha-node") -export class ZHANode extends LitElement { - @property() public hass?: HomeAssistant; - - @property() public isWide?: boolean; - - @property() public device?: ZHADevice; - - @property() private _showHelp = false; - - protected render(): TemplateResult { - return html` - -
- ${this.hass!.localize( - "ui.panel.config.zha.node_management.header" - )} - -
- - ${this.hass!.localize( - "ui.panel.config.zha.node_management.introduction" - )} -

- ${this.hass!.localize( - "ui.panel.config.zha.node_management.hint_battery_devices" - )} -

- ${this.hass!.localize( - "ui.panel.config.zha.node_management.hint_wakeup" - )} -
-
- ${this.device - ? html` - - ` - : html` - - `} -
-
- `; - } - - private _onHelpTap(): void { - this._showHelp = !this._showHelp; - } - - private _onDeviceRemoved(): void { - this.device = undefined; - navigate(this, `/config/zha`, true); - } - - static get styles(): CSSResult[] { - return [ - haStyle, - css` - .node-info { - margin-left: 16px; - } - - .help-text { - color: grey; - padding-left: 28px; - padding-right: 28px; - padding-bottom: 16px; - } - - .content { - max-width: 680px; - } - - .card { - padding: 28px 20px 0; - margin-top: 24px; - } - - ha-service-description { - display: block; - color: grey; - } - - [hidden] { - display: none; - } - - .header { - flex-grow: 1; - } - - .toggle-help-icon { - float: right; - top: 6px; - right: 0; - padding-right: 0px; - color: var(--primary-color); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-node": ZHANode; - } -} diff --git a/src/state/hass-element.ts b/src/state/hass-element.ts index 977ee68f9d..a5cb0992ae 100644 --- a/src/state/hass-element.ts +++ b/src/state/hass-element.ts @@ -12,7 +12,6 @@ import SidebarMixin from "./sidebar-mixin"; import ThemesMixin from "./themes-mixin"; import TranslationsMixin from "./translations-mixin"; import { urlSyncMixin } from "./url-sync-mixin"; -import ZHADialogMixin from "./zha-dialog-mixin"; const ext = (baseClass: T, mixins): T => mixins.reduceRight((base, mixin) => mixin(base), baseClass); @@ -28,7 +27,6 @@ export class HassElement extends ext(HassBaseEl, [ NotificationMixin, dialogManagerMixin, urlSyncMixin, - ZHADialogMixin, hapticMixin, panelTitleMixin, ]) {} diff --git a/src/state/zha-dialog-mixin.ts b/src/state/zha-dialog-mixin.ts deleted file mode 100644 index 82721b8e80..0000000000 --- a/src/state/zha-dialog-mixin.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { UpdatingElement } from "lit-element"; -import { HASSDomEvent } from "../common/dom/fire_event"; -import { - showZHADeviceInfoDialog, - ZHADeviceInfoDialogParams, -} from "../dialogs/zha-device-info-dialog/show-dialog-zha-device-info"; -import { Constructor } from "../types"; -import { HassBaseEl } from "./hass-base-mixin"; - -declare global { - // for fire event - interface HASSDomEvents { - "zha-show-device-dialog": { - ieee: string; - }; - } -} - -export default (superClass: Constructor) => - class extends superClass { - protected firstUpdated(changedProps) { - super.firstUpdated(changedProps); - this.addEventListener("zha-show-device-dialog", (e) => - showZHADeviceInfoDialog( - e.target as HTMLElement, - (e as HASSDomEvent).detail - ) - ); - } - }; diff --git a/src/translations/en.json b/src/translations/en.json index a57584da22..637832b9fa 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -441,10 +441,10 @@ "no_area": "No Area", "device_signature": "Zigbee device signature", "buttons": { - "add": "Add Devices", + "add": "Add Devices via this device", "remove": "Remove Device", "reconfigure": "Reconfigure Device", - "zigbee_information": "Zigbee Information" + "zigbee_information": "Zigbee device signature" }, "services": { "reconfigure": "Reconfigure ZHA device (heal device). Use this if you are having issues with the device. If the device in question is a battery powered device please ensure it is awake and accepting commands when you use this service.", @@ -460,9 +460,7 @@ "power_source": "Power Source", "unknown": "Unknown", "zha_device_card": { - "device_name_placeholder": "User given name", - "area_picker_label": "Area", - "update_name_button": "Update Name" + "device_name_placeholder": "Change device name" } }, "domain_toggler": { @@ -1504,6 +1502,7 @@ } }, "zha": { + "button": "Configure", "header": "Configure Zigbee Home Automation", "introduction": "Here it is possible to configure the ZHA component. Not everything is possible to configure from the UI yet, but we're working on it.", "description": "Zigbee Home Automation network management", @@ -1515,9 +1514,10 @@ "value": "Value" }, "add_device_page": { - "header": "Zigbee Home Automation - Add Devices", "spinner": "Searching for ZHA Zigbee devices...", - "discovery_text": "Discovered devices will show up here. Follow the instructions for your device(s) and place the device(s) in pairing mode.", + "pairing_mode": "Make sure your devices are in pairing mode. Check the instructions of your device on how to do this.", + "discovered_text": "Devices will show up here once discovered.", + "no_devices_found": "No devices where found, make sure they are in paring mode and keep them awake while discovering is running.", "search_again": "Search Again" }, "network_management": { @@ -1560,6 +1560,9 @@ "issue_zigbee_command": "Issue Zigbee Command", "help_command_dropdown": "Select a command to interact with." }, + "network": { + "caption": "Network" + }, "groups": { "caption": "Groups", "description": "Create and modify Zigbee groups", @@ -1600,6 +1603,7 @@ } }, "zwave": { + "button": "Configure", "description": "Manage your Z-Wave network", "learn_more": "Learn more about Z-Wave", "common": {