From 54150689171ab9ac5dcc49fae10d76458a60e36f Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Wed, 8 Jan 2020 12:35:21 -0500 Subject: [PATCH] Rework the ZHA config panel (#4415) * convert zha config panel to tabs * add spacer to prevent combobox from hitting bottom * break clusters out into their own section * cleanup buttons * remove header * make devices default tab * convert from tabs to a list view * convert to table on dashboard * fix anchor on mobile safari * cleanup CSS to fix display on mobile * cleanup card css * more css cleanup * fix group page * remove translations changes * Update src/panels/config/zha/zha-clusters.ts Co-Authored-By: Bram Kragten * Update src/panels/config/zha/zha-config-dashboard.ts Co-Authored-By: Bram Kragten * Update src/panels/config/zha/zha-device-page.ts Co-Authored-By: Bram Kragten * Update src/panels/config/zha/zha-groups-dashboard.ts Co-Authored-By: Bram Kragten * review comments * fix dangling quote after commit suggestion * css cleanup * remove flex rules * remove flex rules * css cleanup * remove dialog per review comments Co-authored-by: Bram Kragten --- src/panels/config/ha-panel-config.ts | 4 +- src/panels/config/zha/zha-binding.ts | 36 +--- .../config/zha/zha-cluster-attributes.ts | 26 +-- src/panels/config/zha/zha-cluster-commands.ts | 30 +-- src/panels/config/zha/zha-clusters.ts | 119 ++++++++---- ...anel.ts => zha-config-dashboard-router.ts} | 29 +-- src/panels/config/zha/zha-config-dashboard.ts | 175 ++++++++++++++++++ src/panels/config/zha/zha-device-card.ts | 38 ++-- .../{ha-config-zha.ts => zha-device-page.ts} | 85 +++++---- src/panels/config/zha/zha-groups-dashboard.ts | 8 +- src/panels/config/zha/zha-groups-tile.ts | 108 ----------- src/panels/config/zha/zha-network.ts | 124 ------------- src/panels/config/zha/zha-node.ts | 164 +++------------- src/translations/en.json | 22 ++- 14 files changed, 411 insertions(+), 557 deletions(-) rename src/panels/config/zha/{zha-config-panel.ts => zha-config-dashboard-router.ts} (70%) create mode 100644 src/panels/config/zha/zha-config-dashboard.ts rename src/panels/config/zha/{ha-config-zha.ts => zha-device-page.ts} (62%) delete mode 100644 src/panels/config/zha/zha-groups-tile.ts delete mode 100644 src/panels/config/zha/zha-network.ts diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index d1401f91a6..213977a577 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -127,10 +127,10 @@ class HaPanelConfig extends HassRouterPage { ), }, zha: { - tag: "zha-config-panel", + tag: "zha-config-dashboard-router", load: () => import( - /* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-panel" + /* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-dashboard-router" ), }, zwave: { diff --git a/src/panels/config/zha/zha-binding.ts b/src/panels/config/zha/zha-binding.ts index 3912a96c28..06a3d1b2dc 100644 --- a/src/panels/config/zha/zha-binding.ts +++ b/src/panels/config/zha/zha-binding.ts @@ -44,7 +44,7 @@ export class ZHABindingControl extends LitElement { protected render(): TemplateResult | void { return html` -
+
Device Binding
- + -
+
${this.hass!.localize( "ui.panel.config.zha.cluster_attributes.header" @@ -86,7 +86,7 @@ export class ZHAClusterAttributes extends LitElement { label="${this.hass!.localize( "ui.panel.config.zha.cluster_attributes.attributes_of_cluster" )}" - class="flex" + class="menu" > -
+
${this.hass!.localize( "ui.panel.config.zha.cluster_commands.header" @@ -81,7 +81,7 @@ export class ZHAClusterCommands extends LitElement { label="${this.hass!.localize( "ui.panel.config.zha.cluster_commands.commands_of_cluster" )}" - class="flex" + class="menu" > { export class ZHAClusters extends LitElement { @property() public hass?: HomeAssistant; @property() public isWide?: boolean; - @property() public showHelp = false; @property() public selectedDevice?: ZHADevice; + @property() public showHelp = false; @property() private _selectedClusterIndex = -1; @property() private _clusters: Cluster[] = []; @@ -60,33 +61,54 @@ export class ZHAClusters extends LitElement { protected render(): TemplateResult | void { return html` -
- - +
+ + ${this.hass!.localize("ui.panel.config.zha.clusters.header")} + + - ${this._clusters.map( - (entry) => html` - ${computeClusterKey(entry)} - ` - )} - - -
- ${this.showHelp - ? html` -
- ${this.hass!.localize( - "ui.panel.config.zha.clusters.help_cluster_dropdown" + +
+ + ${this.hass!.localize("ui.panel.config.zha.clusters.introduction")} + + + +
+ - ` - : ""} + class="menu" + > + + ${this._clusters.map( + (entry) => html` + ${computeClusterKey(entry)} + ` + )} + + +
+ ${this.showHelp + ? html` +
+ ${this.hass!.localize( + "ui.panel.config.zha.clusters.help_cluster_dropdown" + )} +
+ ` + : ""} +
+ `; } @@ -109,32 +131,49 @@ export class ZHAClusters extends LitElement { }); } + private _onHelpTap(): void { + this.showHelp = !this.showHelp; + } + static get styles(): CSSResult[] { return [ haStyle, css` - .flex { - -ms-flex: 1 1 0.000000001px; - -webkit-flex: 1; - flex: 1; - -webkit-flex-basis: 0.000000001px; - flex-basis: 0.000000001px; + .menu { + width: 100%; + } + + .content { + margin-top: 24px; + } + + .header { + flex-grow: 1; + } + + ha-card { + margin: 0 auto; + max-width: 600px; } .node-picker { - display: -ms-flexbox; - display: -webkit-flex; - display: flex; - -ms-flex-direction: row; - -webkit-flex-direction: row; - flex-direction: row; - -ms-flex-align: center; - -webkit-align-items: center; align-items: center; padding-left: 28px; padding-right: 28px; padding-bottom: 10px; } + + .toggle-help-icon { + float: right; + top: -6px; + right: 0; + color: var(--primary-color); + } + + [hidden] { + display: none; + } + .help-text { color: grey; padding-left: 28px; diff --git a/src/panels/config/zha/zha-config-panel.ts b/src/panels/config/zha/zha-config-dashboard-router.ts similarity index 70% rename from src/panels/config/zha/zha-config-panel.ts rename to src/panels/config/zha/zha-config-dashboard-router.ts index f0c0124fc2..9a45e1e456 100644 --- a/src/panels/config/zha/zha-config-panel.ts +++ b/src/panels/config/zha/zha-config-dashboard-router.ts @@ -1,29 +1,34 @@ -import "../../../layouts/hass-loading-screen"; - -import { customElement, property } from "lit-element"; - import { HassRouterPage, RouterOptions, } from "../../../layouts/hass-router-page"; +import { customElement, property } from "lit-element"; import { HomeAssistant } from "../../../types"; -@customElement("zha-config-panel") -class ZHAConfigPanel extends HassRouterPage { +@customElement("zha-config-dashboard-router") +class ZHAConfigDashboardRouter extends HassRouterPage { @property() public hass!: HomeAssistant; @property() public isWide!: boolean; @property() public narrow!: boolean; protected routerOptions: RouterOptions = { - defaultPage: "configuration", + defaultPage: "dashboard", cacheAll: true, preloadAll: true, + showLoading: true, routes: { - configuration: { - tag: "ha-config-zha", + dashboard: { + tag: "zha-config-dashboard", load: () => import( - /* webpackChunkName: "zha-configuration-page" */ "./ha-config-zha" + /* webpackChunkName: "zha-config-dashboard" */ "./zha-config-dashboard" + ), + }, + device: { + tag: "zha-device-page", + load: () => + import( + /* webpackChunkName: "zha-devices-page" */ "./zha-device-page" ), }, add: { @@ -62,12 +67,14 @@ class ZHAConfigPanel extends HassRouterPage { el.narrow = this.narrow; if (this._currentPage === "group") { el.groupId = this.routeTail.path.substr(1); + } else if (this._currentPage === "device") { + el.ieee = this.routeTail.path.substr(1); } } } declare global { interface HTMLElementTagNameMap { - "zha-config-panel": ZHAConfigPanel; + "zha-config-dashboard-router": ZHAConfigDashboardRouter; } } diff --git a/src/panels/config/zha/zha-config-dashboard.ts b/src/panels/config/zha/zha-config-dashboard.ts new file mode 100644 index 0000000000..2a280551ca --- /dev/null +++ b/src/panels/config/zha/zha-config-dashboard.ts @@ -0,0 +1,175 @@ +import { + LitElement, + TemplateResult, + html, + CSSResultArray, + css, + customElement, + property, + PropertyValues, +} from "lit-element"; +import "@polymer/paper-item/paper-item-body"; +import "@polymer/paper-item/paper-item"; +import "../../../components/ha-card"; +import "../../../components/ha-icon-next"; +import "../../../layouts/hass-subpage"; +import "../ha-config-section"; + +import { haStyle } from "../../../resources/styles"; +import { HomeAssistant, Route } from "../../../types"; +import { fetchDevices, ZHADevice } from "../../../data/zha"; +import { sortZHADevices, formatAsPaddedHex } from "./functions"; +import memoizeOne from "memoize-one"; +import { + DataTableColumnContainer, + RowClickedEvent, +} from "../../../components/data-table/ha-data-table"; +import { navigate } from "../../../common/navigate"; + +export interface DeviceRowData extends ZHADevice { + device?: DeviceRowData; +} + +@customElement("zha-config-dashboard") +class ZHAConfigDashboard extends LitElement { + @property() public hass!: HomeAssistant; + @property() public route!: Route; + @property() public narrow!: boolean; + @property() public isWide!: boolean; + @property() private _devices: ZHADevice[] = []; + private pages: string[] = ["add", "groups"]; + private _firstUpdatedCalled: boolean = 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), + id: device.ieee, + }; + }); + + return outputDevices; + }); + + private _columns = memoizeOne( + (narrow: boolean): DataTableColumnContainer => + narrow + ? { + name: { + title: "Devices", + sortable: true, + filterable: true, + direction: "asc", + }, + } + : { + name: { + title: "Name", + sortable: true, + filterable: true, + direction: "asc", + }, + nwk: { + title: "Nwk", + sortable: true, + filterable: true, + }, + ieee: { + title: "IEEE", + sortable: true, + filterable: true, + }, + } + ); + + 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 | void { + 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 index 268f3b6d03..db11c81568 100644 --- a/src/panels/config/zha/zha-device-card.ts +++ b/src/panels/config/zha/zha-device-card.ts @@ -233,7 +233,7 @@ class ZHADeviceCard extends LitElement { label="${this.hass!.localize( "ui.dialogs.zha_device_info.zha_device_card.area_picker_label" )}" - class="flex" + class="menu" > - - - - + + ${this._selectedCluster ? html` ` : ""} - ${this._selectedDevice && this._bindableDevices.length > 0 + ${this._bindableDevices.length > 0 ? html` ` : ""} +
`; } @@ -94,30 +100,29 @@ export class HaConfigZha extends LitElement { this._selectedCluster = selectedClusterEvent.detail.cluster; } - private _onDeviceSelected( - selectedNodeEvent: HASSDomEvent - ): void { - this._selectedDevice = selectedNodeEvent.detail.node; - this._selectedCluster = undefined; - } - - private async _fetchBindableDevices(): Promise { - if (this._selectedDevice && this.hass) { + private async _fetchData(): Promise { + if (this.ieee && this.hass) { + this.device = await fetchZHADevice(this.hass, this.ieee); this._bindableDevices = ( - await fetchBindableDevices(this.hass, this._selectedDevice!.ieee) + await fetchBindableDevices(this.hass, this.ieee) ).sort(sortZHADevices); } } static get styles(): CSSResult[] { - return [haStyle]; + return [ + haStyle, + css` + .spacer { + height: 50px; + } + `, + ]; } } declare global { interface HTMLElementTagNameMap { - "ha-config-zha": HaConfigZha; + "zha-device-page": ZHADevicePage; } } - -customElements.define("ha-config-zha", HaConfigZha); diff --git a/src/panels/config/zha/zha-groups-dashboard.ts b/src/panels/config/zha/zha-groups-dashboard.ts index 9b9f8e60a5..874918fd84 100644 --- a/src/panels/config/zha/zha-groups-dashboard.ts +++ b/src/panels/config/zha/zha-groups-dashboard.ts @@ -1,4 +1,3 @@ -import "../../../layouts/hass-subpage"; import "./zha-groups-data-table"; import { @@ -19,6 +18,7 @@ import "@material/mwc-button"; import "@polymer/paper-spinner/paper-spinner"; import "@polymer/paper-icon-button/paper-icon-button"; import { navigate } from "../../../common/navigate"; +import "../../../layouts/hass-subpage"; @customElement("zha-groups-dashboard") export class ZHAGroupsDashboard extends LitElement { @@ -47,9 +47,9 @@ export class ZHAGroupsDashboard extends LitElement { protected render(): TemplateResult { return html` -
- - ${this.hass!.localize("ui.panel.config.zha.groups.header")} - - -
- - ${this.hass!.localize("ui.panel.config.zha.groups.introduction")} - - - -
- - ${this.hass!.localize("ui.panel.config.zha.groups.manage_groups")} - -
-
- - `; - } - - private _onHelpTap(): void { - this._showHelp = !this._showHelp; - } - - private _onManageGroupsClick() { - navigate(this, "groups"); - } - - static get styles(): CSSResult[] { - return [ - haStyle, - css` - .content { - margin-top: 24px; - } - - ha-card { - margin: 0 auto; - max-width: 600px; - } - - .card-actions.warning ha-call-service-button { - color: var(--google-red-500); - } - - .toggle-help-icon { - position: absolute; - top: -6px; - right: 0; - color: var(--primary-color); - } - - ha-service-description { - display: block; - color: grey; - } - - [hidden] { - display: none; - } - - .help-text2 { - color: grey; - padding: 16px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-groups-tile": ZHAGroupsTile; - } -} diff --git a/src/panels/config/zha/zha-network.ts b/src/panels/config/zha/zha-network.ts deleted file mode 100644 index 78ee69857b..0000000000 --- a/src/panels/config/zha/zha-network.ts +++ /dev/null @@ -1,124 +0,0 @@ -import "../../../components/buttons/ha-call-service-button"; -import "../../../components/ha-service-description"; -import "../../../components/ha-card"; -import "../ha-config-section"; -import "@material/mwc-button"; -import "@polymer/paper-icon-button/paper-icon-button"; - -import { - css, - CSSResult, - html, - LitElement, - TemplateResult, - property, -} from "lit-element"; - -import { navigate } from "../../../common/navigate"; -import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; - -export class ZHANetwork extends LitElement { - @property() public hass?: HomeAssistant; - @property() public isWide?: boolean; - @property() private _showHelp = false; - - protected render(): TemplateResult | void { - return html` - -
- - ${this.hass!.localize( - "ui.panel.config.zha.network_management.header" - )} - - -
- - ${this.hass!.localize( - "ui.panel.config.zha.network_management.introduction" - )} - - - -
- - ${this.hass!.localize("ui.panel.config.zha.common.add_devices")} - - ${this._showHelp - ? html` - - ` - : ""} -
-
-
- `; - } - - private _onHelpTap(): void { - this._showHelp = !this._showHelp; - } - - private _onAddDevicesClick() { - navigate(this, "add"); - } - - static get styles(): CSSResult[] { - return [ - haStyle, - css` - .content { - margin-top: 24px; - } - - ha-card { - margin: 0 auto; - max-width: 600px; - } - - .card-actions.warning ha-call-service-button { - color: var(--google-red-500); - } - - .toggle-help-icon { - position: absolute; - top: -6px; - right: 0; - color: var(--primary-color); - } - - ha-service-description { - display: block; - color: grey; - } - - [hidden] { - display: none; - } - - .help-text2 { - color: grey; - padding: 16px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-network": ZHANetwork; - } -} - -customElements.define("zha-network", ZHANetwork); diff --git a/src/panels/config/zha/zha-node.ts b/src/panels/config/zha/zha-node.ts index 4343953d5c..8281823bd3 100644 --- a/src/panels/config/zha/zha-node.ts +++ b/src/panels/config/zha/zha-node.ts @@ -2,13 +2,8 @@ import "../../../components/buttons/ha-call-service-button"; import "../../../components/ha-service-description"; import "../../../components/ha-card"; import "../ha-config-section"; -import "./zha-clusters"; import "./zha-device-card"; -import "@material/mwc-button"; import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/paper-input/paper-input"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; import { css, @@ -20,40 +15,22 @@ import { TemplateResult, } from "lit-element"; -import { fireEvent } from "../../../common/dom/fire_event"; -import { fetchDevices, ZHADevice } from "../../../data/zha"; +import { ZHADevice } from "../../../data/zha"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; -import { sortZHADevices } from "./functions"; -import { ItemSelectedEvent, ZHADeviceRemovedEvent } from "./types"; - -declare global { - // for fire event - interface HASSDomEvents { - "zha-node-selected": { - node?: ZHADevice; - }; - } -} +import { navigate } from "../../../common/navigate"; @customElement("zha-node") export class ZHANode extends LitElement { @property() public hass?: HomeAssistant; @property() public isWide?: boolean; + @property() public device?: ZHADevice; @property() private _showHelp: boolean = false; - @property() private _selectedDeviceIndex: number = -1; - @property() private _selectedDevice?: ZHADevice; - @property() private _nodes: ZHADevice[] = []; - - public connectedCallback(): void { - super.connectedCallback(); - this._fetchDevices(); - } protected render(): TemplateResult | void { return html` -
+
${this.hass!.localize( "ui.panel.config.zha.node_management.header" @@ -78,115 +55,37 @@ export class ZHANode extends LitElement { "ui.panel.config.zha.node_management.hint_wakeup" )} - -
- - - ${this._nodes.map( - (entry) => html` - ${entry.user_given_name - ? entry.user_given_name - : entry.name} - ` - )} - - -
- ${this._showHelp - ? html` -
- ${this.hass!.localize( - "ui.panel.config.zha.node_management.help_node_dropdown" - )} -
- ` - : ""} - ${this._selectedDeviceIndex !== -1 - ? html` - - ` - : ""} - ${this._selectedDevice ? this._renderClusters() : ""} -
+ `; } - private _renderClusters(): TemplateResult { - return html` - - `; - } - private _onHelpTap(): void { this._showHelp = !this._showHelp; } - private _selectedDeviceChanged(event: ItemSelectedEvent): void { - this._selectedDeviceIndex = event!.target!.selected; - this._selectedDevice = this._nodes[this._selectedDeviceIndex]; - fireEvent(this, "zha-node-selected", { node: this._selectedDevice }); - } - - private async _fetchDevices() { - this._nodes = (await fetchDevices(this.hass!)).sort(sortZHADevices); - } - - private _onDeviceRemoved(event: ZHADeviceRemovedEvent): void { - this._selectedDeviceIndex = -1; - this._nodes.splice(this._nodes.indexOf(event.detail!.device!), 1); - this._selectedDevice = undefined; - fireEvent(this, "zha-node-selected", { node: this._selectedDevice }); + private _onDeviceRemoved(): void { + this.device = undefined; + navigate(this, `/config/zha`, true); } static get styles(): CSSResult[] { return [ haStyle, css` - .flex { - -ms-flex: 1 1 0.000000001px; - -webkit-flex: 1; - flex: 1; - -webkit-flex-basis: 0.000000001px; - flex-basis: 0.000000001px; - } - - .content { - margin-top: 24px; - } - .node-info { margin-left: 16px; } - .sectionHeader { - position: relative; - } - .help-text { color: grey; padding-left: 28px; @@ -199,30 +98,11 @@ export class ZHANode extends LitElement { max-width: 600px; } - .node-picker { - display: -ms-flexbox; - display: -webkit-flex; - display: flex; - -ms-flex-direction: row; - -webkit-flex-direction: row; - flex-direction: row; - -ms-flex-align: center; - -webkit-align-items: center; - align-items: center; - padding-left: 28px; - padding-right: 28px; - padding-bottom: 10px; - } - .card { + margin-top: 24px; box-sizing: border-box; display: flex; - flex: 1 0 300px; - min-width: 0; - max-width: 600px; - padding-left: 28px; - padding-right: 28px; - padding-bottom: 10px; + flex: 1; word-wrap: break-word; } @@ -235,8 +115,12 @@ export class ZHANode extends LitElement { display: none; } + .header { + flex-grow: 1; + } + .toggle-help-icon { - position: absolute; + float: right; top: 6px; right: 0; color: var(--primary-color); diff --git a/src/translations/en.json b/src/translations/en.json index ab09ff0518..a5067120f6 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1424,6 +1424,9 @@ }, "zha": { "caption": "ZHA", + "title": "Zigbee Home Automation", + "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", "common": { "add_devices": "Add Devices", @@ -1442,6 +1445,13 @@ "header": "Network Management", "introduction": "Commands that affect the entire network" }, + "add": { + "caption": "Add Devices", + "description": "Add devices to the Zigbee network" + }, + "devices": { + "header": "Zigbee Home Automation - Device" + }, "node_management": { "header": "Device Management", "introduction": "Run ZHA commands that affect a single device. Pick a device to see a list of available commands.", @@ -1450,7 +1460,9 @@ "help_node_dropdown": "Select a device to view per-device options." }, "clusters": { - "help_cluster_dropdown": "Select a cluster to view attributes and commands." + "header": "Clusters", + "help_cluster_dropdown": "Select a cluster to view attributes and commands.", + "introduction": "Clusters are the building blocks for Zigbee functionality. They seperate functionality into logical units. There are client and server types and that are comprised of attributes and commands." }, "cluster_attributes": { "header": "Cluster Attributes", @@ -1470,12 +1482,16 @@ "help_command_dropdown": "Select a command to interact with." }, "groups": { + "caption": "Groups", + "description": "Create and modify Zigbee groups", "zha_zigbee_groups": "ZHA Zigbee Groups", "manage_groups": "Manage Zigbee Groups", "groups": "Groups", "group_id": "Group ID", "members": "Members", - "header": "Zigbee Group Management", + "header": "Zigbee Home Automation - Group Management", + "groups-header": "Zigbee Home Automation - Group Management", + "group-header": "Zigbee Home Automation - Group Details", "introduction": "Create and modify zigbee groups", "remove_groups": "Remove Groups", "removing_groups": "Removing Groups", @@ -1488,7 +1504,7 @@ "removing_members": "Removing Members", "create_group_details": "Enter the required details to create a new zigbee group", "group_name_placeholder": "Group Name", - "create_group": "Create New ZHA Zigbee Group", + "create_group": "Zigbee Home Automation - Create Group", "create": "Create Group", "creating_group": "Creating Group" }