From 156dcaa822f83fa0769866fcce01b61bc05c97ee Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Thu, 27 Aug 2020 14:14:30 -0400 Subject: [PATCH 01/16] WIP: OZW config panel nodes list --- src/data/ozw.ts | 9 + .../ozw/ozw-config-network.ts | 241 +++-------------- .../integration-panels/ozw/ozw-config-node.ts | 63 +++++ .../ozw/ozw-config-router.ts | 32 +-- .../ozw/ozw-network-dashboard.ts | 243 ++++++++++++++++++ .../ozw/ozw-network-nodes.ts | 176 +++++++++++++ .../ozw/ozw-network-router.ts | 66 +++++ .../ozw/ozw-node-dashboard.ts | 132 ++++++++++ .../integration-panels/ozw/ozw-node-router.ts | 66 +++++ 9 files changed, 813 insertions(+), 215 deletions(-) create mode 100644 src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts create mode 100644 src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts create mode 100644 src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts create mode 100644 src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts create mode 100644 src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts create mode 100644 src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts diff --git a/src/data/ozw.ts b/src/data/ozw.ts index b24692c01f7f..5cc627029053 100644 --- a/src/data/ozw.ts +++ b/src/data/ozw.ts @@ -147,6 +147,15 @@ export const fetchOZWNetworkStatistics = ( ozw_instance: ozw_instance, }); +export const fetchOZWNodes = ( + hass: HomeAssistant, + ozw_instance: number +): Promise => + hass.callWS({ + type: "ozw/get_nodes", + ozw_instance: ozw_instance, + }); + export const fetchOZWNodeStatus = ( hass: HomeAssistant, ozw_instance: number, diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts index 6d67ed779e8e..ed8aef3b026d 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts @@ -1,36 +1,19 @@ -import "@material/mwc-fab"; import { - css, CSSResultArray, customElement, html, - internalProperty, LitElement, property, TemplateResult, } from "lit-element"; +import { mdiNetwork, mdiServerNetwork } from "@mdi/js"; import { navigate } from "../../../../../common/navigate"; -import "../../../../../components/ha-card"; -import "../../../../../components/ha-icon-next"; -import "../../../../../components/buttons/ha-call-service-button"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant, Route } from "../../../../../types"; -import "../../../ha-config-section"; -import { mdiCircle, mdiCheckCircle, mdiCloseCircle } from "@mdi/js"; import "../../../../../layouts/hass-tabs-subpage"; import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; -import "@material/mwc-button/mwc-button"; -import { - OZWInstance, - fetchOZWNetworkStatus, - fetchOZWNetworkStatistics, - networkOnlineStatuses, - networkOfflineStatuses, - networkStartingStatuses, - OZWNetworkStatistics, -} from "../../../../../data/ozw"; - -export const ozwTabs: PageNavigation[] = []; +import "./ozw-network-router"; +import { computeTail } from "./ozw-config-router"; @customElement("ozw-config-network") class OZWConfigNetwork extends LitElement { @@ -46,203 +29,61 @@ class OZWConfigNetwork extends LitElement { @property() public ozw_instance = 0; - @internalProperty() private _network?: OZWInstance; - - @internalProperty() private _statistics?: OZWNetworkStatistics; - - @internalProperty() private _status = "unknown"; - - @internalProperty() private _icon = mdiCircle; - public connectedCallback(): void { super.connectedCallback(); if (this.ozw_instance <= 0) { navigate(this, "/config/ozw/dashboard", true); } - if (this.hass) { - this._fetchData(); - } } - private async _fetchData() { - this._network = await fetchOZWNetworkStatus(this.hass!, this.ozw_instance); - this._statistics = await fetchOZWNetworkStatistics( - this.hass!, - this.ozw_instance - ); - if (networkOnlineStatuses.includes(this._network.Status)) { - this._status = "online"; - this._icon = mdiCheckCircle; - } - if (networkStartingStatuses.includes(this._network.Status)) { - this._status = "starting"; - } - if (networkOfflineStatuses.includes(this._network.Status)) { - this._status = "offline"; - this._icon = mdiCloseCircle; - } - } + protected render(): TemplateResult { + const route = computeTail(this.route); + + const ozwTabs: PageNavigation[] = [ + { + translationKey: "ui.panel.config.ozw.navigation.network", + path: `/config/ozw/network/${this.ozw_instance}/dashboard`, + iconPath: mdiServerNetwork, + }, + { + translationKey: "ui.panel.config.ozw.navigation.nodes", + path: `/config/ozw/network/${this.ozw_instance}/nodes`, + iconPath: mdiNetwork, + }, + ]; - private _generateServiceButton(service: string) { - return html` - - ${this.hass!.localize("ui.panel.config.ozw.services." + service)} - - `; - } + if (route.path !== "/nodes") { + return html` + + + + + `; + } - protected render(): TemplateResult { return html` - - -
- ${this.hass.localize("ui.panel.config.ozw.network.header")} -
- -
- ${this.hass.localize("ui.panel.config.ozw.network.introduction")} -
- ${this._network - ? html` - -
-
- - ${this.hass.localize( - "ui.panel.config.ozw.common.network" - )} - ${this.hass.localize( - "ui.panel.config.ozw.network_status." + this._status - )} -
- - ${this.hass.localize( - "ui.panel.config.ozw.network_status.details." + - this._network.Status.toLowerCase() - )} - -
-
- ${this.hass.localize( - "ui.panel.config.ozw.common.ozw_instance" - )} - ${this._network.ozw_instance} - ${this._statistics - ? html` - • - ${this.hass.localize( - "ui.panel.config.ozw.network.node_count", - "count", - this._statistics.node_count - )} - ` - : ``} -
- ${this.hass.localize( - "ui.panel.config.ozw.common.controller" - )}: - ${this._network.getControllerPath}
- OZWDaemon ${this._network.OZWDaemon_Version} (OpenZWave - ${this._network.OpenZWave_Version}) -
-
-
- ${this._generateServiceButton("add_node")} - ${this._generateServiceButton("remove_node")} -
-
- ` - : ``} -
-
+ `; } static get styles(): CSSResultArray { - return [ - haStyle, - css` - .secondary { - color: var(--secondary-text-color); - } - .online { - color: green; - } - .starting { - color: orange; - } - .offline { - color: red; - } - .content { - margin-top: 24px; - } - - .sectionHeader { - position: relative; - padding-right: 40px; - } - - .network-status { - text-align: center; - } - - .network-status div.details { - font-size: 1.5rem; - margin-bottom: 16px; - } - - .network-status ha-svg-icon { - display: block; - margin: 0px auto 16px; - width: 48px; - height: 48px; - } - - .network-status small { - font-size: 1rem; - } - - ha-card { - margin: 0 auto; - max-width: 600px; - } - - .card-actions.warning ha-call-service-button { - color: var(--error-color); - } - - .toggle-help-icon { - position: absolute; - top: -6px; - right: 0; - color: var(--primary-color); - } - - ha-service-description { - display: block; - color: grey; - padding: 0 8px 12px; - } - - [hidden] { - display: none; - } - `, - ]; + return [haStyle]; } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts new file mode 100644 index 000000000000..0c383f8c8564 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts @@ -0,0 +1,63 @@ +import { + CSSResultArray, + customElement, + html, + LitElement, + property, + TemplateResult, +} from "lit-element"; +import memoizeOne from "memoize-one"; +import { navigate } from "../../../../../common/navigate"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../../../types"; +import "../../../../../layouts/hass-tabs-subpage"; +import "./ozw-node-router"; +import { computeTail } from "./ozw-config-router"; + +@customElement("ozw-config-node") +class OZWConfigNode 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; + + @property() public ozw_instance = 0; + + @property() public node_id = 0; + + public connectedCallback(): void { + super.connectedCallback(); + if (this.ozw_instance <= 0) { + navigate(this, "/config/ozw/dashboard", true); + } + } + + protected render(): TemplateResult { + const route = computeTail(this.route); + return html` + + + `; + } + + static get styles(): CSSResultArray { + return [haStyle]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ozw-config-node": OZWConfigNode; + } +} diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-router.ts index 28402cbe4c4f..80fa59cc2ba2 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-router.ts @@ -1,10 +1,23 @@ import { customElement, property } from "lit-element"; +import memoizeOne from "memoize-one"; import { HassRouterPage, RouterOptions, } from "../../../../../layouts/hass-router-page"; -import { HomeAssistant } from "../../../../../types"; -import { navigate } from "../../../../../common/navigate"; +import { HomeAssistant, Route } from "../../../../../types"; + +export const computeTail = memoizeOne((route: Route) => { + const dividerPos = route.path.indexOf("/", 1); + return dividerPos === -1 + ? { + prefix: route.prefix + route.path, + path: "", + } + : { + prefix: route.prefix + route.path.substr(0, dividerPos), + path: route.path.substr(dividerPos), + }; +}); @customElement("ozw-config-router") class OZWConfigRouter extends HassRouterPage { @@ -46,19 +59,8 @@ class OZWConfigRouter extends HassRouterPage { el.narrow = this.narrow; el.configEntryId = this._configEntry; if (this._currentPage === "network") { - el.ozw_instance = 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 - ); + const path = this.routeTail.path.split("/"); + el.ozw_instance = path[1]; } } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts new file mode 100644 index 000000000000..6c02463888f6 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts @@ -0,0 +1,243 @@ +import "@material/mwc-fab"; +import { + css, + CSSResultArray, + customElement, + html, + internalProperty, + LitElement, + property, + TemplateResult, +} from "lit-element"; +import { navigate } from "../../../../../common/navigate"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-icon-next"; +import "../../../../../components/buttons/ha-call-service-button"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../../../types"; +import "../../../ha-config-section"; +import { mdiCircle, mdiCheckCircle, mdiCloseCircle } from "@mdi/js"; +import "../../../../../layouts/hass-tabs-subpage"; +import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; +import "@material/mwc-button/mwc-button"; +import { + OZWInstance, + fetchOZWNetworkStatus, + fetchOZWNetworkStatistics, + networkOnlineStatuses, + networkOfflineStatuses, + networkStartingStatuses, + OZWNetworkStatistics, +} from "../../../../../data/ozw"; + +export const ozwTabs: PageNavigation[] = []; + +@customElement("ozw-network-dashboard") +class OZWNetworkDashboard 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; + + @property() public ozw_instance = 0; + + @internalProperty() private _network?: OZWInstance; + + @internalProperty() private _statistics?: OZWNetworkStatistics; + + @internalProperty() private _status = "unknown"; + + @internalProperty() private _icon = mdiCircle; + + public connectedCallback(): void { + super.connectedCallback(); + if (this.ozw_instance <= 0) { + navigate(this, "/config/ozw/dashboard", true); + } else if (this.hass) { + this._fetchData(); + } + } + + private async _fetchData() { + this._network = await fetchOZWNetworkStatus(this.hass!, this.ozw_instance); + this._statistics = await fetchOZWNetworkStatistics( + this.hass!, + this.ozw_instance + ); + if (networkOnlineStatuses.includes(this._network.Status)) { + this._status = "online"; + this._icon = mdiCheckCircle; + } + if (networkStartingStatuses.includes(this._network.Status)) { + this._status = "starting"; + } + if (networkOfflineStatuses.includes(this._network.Status)) { + this._status = "offline"; + this._icon = mdiCloseCircle; + } + } + + private _generateServiceButton(service: string) { + return html` + + ${this.hass!.localize("ui.panel.config.ozw.services." + service)} + + `; + } + + protected render(): TemplateResult { + return html` + +
+ ${this.hass.localize("ui.panel.config.ozw.network.header")} +
+ +
+ ${this.hass.localize("ui.panel.config.ozw.network.introduction")} +
+ ${this._network + ? html` + +
+
+ + ${this.hass.localize("ui.panel.config.ozw.common.network")} + ${this.hass.localize( + "ui.panel.config.ozw.network_status." + this._status + )} +
+ + ${this.hass.localize( + "ui.panel.config.ozw.network_status.details." + + this._network.Status.toLowerCase() + )} + +
+
+ ${this.hass.localize( + "ui.panel.config.ozw.common.ozw_instance" + )} + ${this._network.ozw_instance} + ${this._statistics + ? html` + • + ${this.hass.localize( + "ui.panel.config.ozw.network.node_count", + "count", + this._statistics.node_count + )} + ` + : ``} +
+ ${this.hass.localize( + "ui.panel.config.ozw.common.controller" + )}: + ${this._network.getControllerPath}
+ OZWDaemon ${this._network.OZWDaemon_Version} (OpenZWave + ${this._network.OpenZWave_Version}) +
+
+
+ ${this._generateServiceButton("add_node")} + ${this._generateServiceButton("remove_node")} +
+
+ ` + : ``} +
+ `; + } + + static get styles(): CSSResultArray { + return [ + haStyle, + css` + .secondary { + color: var(--secondary-text-color); + } + .online { + color: green; + } + .starting { + color: orange; + } + .offline { + color: red; + } + .content { + margin-top: 24px; + } + + .sectionHeader { + position: relative; + padding-right: 40px; + } + + .network-status { + text-align: center; + } + + .network-status div.details { + font-size: 1.5rem; + margin-bottom: 16px; + } + + .network-status ha-svg-icon { + display: block; + margin: 0px auto 16px; + width: 48px; + height: 48px; + } + + .network-status small { + font-size: 1rem; + } + + ha-card { + margin: 0 auto; + max-width: 600px; + } + + .card-actions.warning ha-call-service-button { + color: var(--error-color); + } + + .toggle-help-icon { + position: absolute; + top: -6px; + right: 0; + color: var(--primary-color); + } + + ha-service-description { + display: block; + color: grey; + padding: 0 8px 12px; + } + + [hidden] { + display: none; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ozw-network-dashboard": OZWNetworkDashboard; + } +} diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts new file mode 100644 index 000000000000..f1a272d3eab7 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts @@ -0,0 +1,176 @@ +import "@material/mwc-fab"; +import { + css, + CSSResultArray, + customElement, + html, + internalProperty, + LitElement, + property, + TemplateResult, +} from "lit-element"; +import memoizeOne from "memoize-one"; +import { mdiCheck, mdiAlert, mdiServerNetwork, mdiNetwork } from "@mdi/js"; +import { navigate } from "../../../../../common/navigate"; +import { DataTableColumnContainer } from "../../../../../components/data-table/ha-data-table"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-icon-next"; +import "../../../../../components/buttons/ha-call-service-button"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../../../types"; +import "../../../ha-config-section"; +import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; +import "../../../../../layouts/hass-tabs-subpage"; +import "../../../../../layouts/hass-tabs-subpage-data-table"; +import "@material/mwc-button/mwc-button"; +import { OZWDevice, fetchOZWNodes } from "../../../../../data/ozw"; +import { computeTail } from "./ozw-config-router"; + +export interface NodeRowData extends OZWDevice { + node?: NodeRowData; + id?: number; +} + +@customElement("ozw-network-nodes") +class OZWNetworkNodes 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; + + @property() public ozw_instance = 0; + + @internalProperty() private _nodes: OZWDevice[] = []; + + public connectedCallback(): void { + super.connectedCallback(); + if (this.ozw_instance <= 0) { + navigate(this, "/config/ozw/dashboard", true); + } else if (this.hass) { + this._fetchData(); + } + } + + private async _fetchData() { + this._nodes = await fetchOZWNodes(this.hass!, this.ozw_instance); + } + + private _formattedNodes = memoizeOne((nodes: OZWDevice[]) => { + let outputNodes: NodeRowData[] = nodes; + + outputNodes = outputNodes.map((node) => { + return { + ...node, + id: node.node_id, + }; + }); + + return outputNodes; + }); + + private _columns = memoizeOne( + (narrow: boolean): DataTableColumnContainer => + narrow + ? { + node_id: { + title: "ID", + sortable: true, + type: "numeric", + width: "72px", + filterable: true, + direction: "asc", + }, + node_product_name: { + title: "Model", + sortable: true, + grows: true, + }, + } + : { + id: { + title: "ID", + sortable: true, + type: "numeric", + width: "72px", + filterable: true, + direction: "asc", + }, + node_manufacturer_name: { + title: "Manufacturer", + sortable: true, + width: "25%", + }, + node_product_name: { + title: "Model", + sortable: true, + width: "25%", + }, + node_query_stage: { + title: "Query Stage", + sortable: true, + width: "25%", + }, + is_zwave_plus: { + title: "Z-Wave Plus", + template: (value: boolean) => { + return html`${value + ? html` ` + : ``} `; + }, + }, + is_failed: { + title: "Failed", + template: (value: boolean) => { + return html`${value + ? html` ` + : ``} `; + }, + }, + } + ); + + protected render(): TemplateResult { + const route = computeTail(this.route); + + const ozwTabs: PageNavigation[] = [ + { + translationKey: "ui.panel.config.ozw.navigation.network", + path: `/config/ozw/network/${this.ozw_instance}/dashboard`, + iconPath: mdiServerNetwork, + }, + { + translationKey: "ui.panel.config.ozw.navigation.nodes", + path: `/config/ozw/network/${this.ozw_instance}/nodes`, + iconPath: mdiNetwork, + }, + ]; + + return html` + + + `; + } + + static get styles(): CSSResultArray { + return [haStyle]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ozw-network-nodes": OZWNetworkNodes; + } +} diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts new file mode 100644 index 000000000000..1bfd77c0dc26 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts @@ -0,0 +1,66 @@ +import { customElement, property } from "lit-element"; +import { + HassRouterPage, + RouterOptions, +} from "../../../../../layouts/hass-router-page"; +import { HomeAssistant } from "../../../../../types"; + +@customElement("ozw-network-router") +class OZWNetworkRouter extends HassRouterPage { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public isWide!: boolean; + + @property() public narrow!: boolean; + + @property() public ozw_instance!: number; + + private _configEntry = new URLSearchParams(window.location.search).get( + "config_entry" + ); + + protected routerOptions: RouterOptions = { + defaultPage: "dashboard", + showLoading: true, + routes: { + dashboard: { + tag: "ozw-network-dashboard", + load: () => + import( + /* webpackChunkName: "ozw-network-dashboard" */ "./ozw-network-dashboard" + ), + }, + nodes: { + tag: "ozw-network-nodes", + load: () => + import( + /* webpackChunkName: "ozw-network-nodes" */ "./ozw-network-nodes" + ), + }, + node: { + tag: "ozw-config-node", + load: () => + import(/* webpackChunkName: "ozw-config-node" */ "./ozw-config-node"), + }, + }, + }; + + protected updatePageEl(el): void { + el.route = this.routeTail; + el.hass = this.hass; + el.isWide = this.isWide; + el.narrow = this.narrow; + el.configEntryId = this._configEntry; + el.ozw_instance = this.ozw_instance; + if (this._currentPage === "node") { + const path = this.routeTail.path.split("/"); + el.node_id = path[1]; + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "ozw-network-router": OZWNetworkRouter; + } +} diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts new file mode 100644 index 000000000000..0886c31b7369 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -0,0 +1,132 @@ +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 "../../../../../components/buttons/ha-call-service-button"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../../../types"; +import "../../../ha-config-section"; +import "../../../../../layouts/hass-tabs-subpage"; +import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; +import "@material/mwc-button/mwc-button"; + +export const ozwTabs: PageNavigation[] = []; + +@customElement("ozw-node-dashboard") +class OZWNodeDashboard 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; + + @property() public ozw_instance = 0; + + @property() public node_id = 0; + + protected render(): TemplateResult { + return html` + +
+ Node Details +
+ +
+ Soon you will be able to view and manage a specific OZW node... +
+
+ `; + } + + static get styles(): CSSResultArray { + return [ + haStyle, + css` + .secondary { + color: var(--secondary-text-color); + } + .online { + color: green; + } + .starting { + color: orange; + } + .offline { + color: red; + } + .content { + margin-top: 24px; + } + + .sectionHeader { + position: relative; + padding-right: 40px; + } + + .network-status { + text-align: center; + } + + .network-status div.details { + font-size: 1.5rem; + margin-bottom: 16px; + } + + .network-status ha-svg-icon { + display: block; + margin: 0px auto 16px; + width: 48px; + height: 48px; + } + + .network-status small { + font-size: 1rem; + } + + ha-card { + margin: 0 auto; + max-width: 600px; + } + + .card-actions.warning ha-call-service-button { + color: var(--error-color); + } + + .toggle-help-icon { + position: absolute; + top: -6px; + right: 0; + color: var(--primary-color); + } + + ha-service-description { + display: block; + color: grey; + padding: 0 8px 12px; + } + + [hidden] { + display: none; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ozw-node-dashboard": OZWNodeDashboard; + } +} diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts new file mode 100644 index 000000000000..d52f97034b75 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts @@ -0,0 +1,66 @@ +import { customElement, property } from "lit-element"; +import { + HassRouterPage, + RouterOptions, +} from "../../../../../layouts/hass-router-page"; +import { HomeAssistant } from "../../../../../types"; +import { navigate } from "../../../../../common/navigate"; + +@customElement("ozw-node-router") +class OZWNodeRouter extends HassRouterPage { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public isWide!: boolean; + + @property() public narrow!: boolean; + + @property() public ozw_instance!: number; + + @property() public node_id!: number; + + private _configEntry = new URLSearchParams(window.location.search).get( + "config_entry" + ); + + protected routerOptions: RouterOptions = { + defaultPage: "dashboard", + showLoading: true, + routes: { + dashboard: { + tag: "ozw-node-dashboard", + load: () => + import( + /* webpackChunkName: "ozw-node-dashboard" */ "./ozw-node-dashboard" + ), + }, + }, + }; + + protected updatePageEl(el): void { + el.route = this.routeTail; + el.hass = this.hass; + el.isWide = this.isWide; + el.narrow = this.narrow; + el.configEntryId = this._configEntry; + el.ozw_instance = this.ozw_instance; + el.node_id = this.node_id; + + 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 + ); + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "ozw-node-router": OZWNodeRouter; + } +} From cc2e4e7ae27ae659c11032e75bd0c1a78f9cd686 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sat, 29 Aug 2020 18:19:44 +0200 Subject: [PATCH 02/16] Comments --- .../ozw/ozw-config-dashboard.ts | 51 +++--- .../ozw/ozw-config-network.ts | 47 +++-- .../integration-panels/ozw/ozw-config-node.ts | 21 +-- .../ozw/ozw-config-router.ts | 2 +- .../ozw/ozw-network-dashboard.ts | 98 +++++----- .../ozw/ozw-network-nodes.ts | 168 +++++++----------- .../ozw/ozw-network-router.ts | 4 +- .../ozw/ozw-node-dashboard.ts | 13 +- .../integration-panels/ozw/ozw-node-router.ts | 10 +- 9 files changed, 176 insertions(+), 238 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-dashboard.ts index f23d7a711451..478ede0f8ee5 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-dashboard.ts @@ -1,6 +1,8 @@ +import "@material/mwc-button/mwc-button"; +import "@material/mwc-fab"; +import { mdiCheckCircle, mdiCircle, mdiCloseCircle, mdiZWave } from "@mdi/js"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; -import "@material/mwc-fab"; import { css, CSSResultArray, @@ -14,20 +16,18 @@ import { import { navigate } from "../../../../../common/navigate"; 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 { mdiCircle, mdiCheckCircle, mdiCloseCircle, mdiZWave } from "@mdi/js"; -import "../../../../../layouts/hass-tabs-subpage"; -import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; -import "@material/mwc-button/mwc-button"; import { - OZWInstance, fetchOZWInstances, - networkOnlineStatuses, networkOfflineStatuses, + networkOnlineStatuses, networkStartingStatuses, + OZWInstance, } from "../../../../../data/ozw"; +import "../../../../../layouts/hass-tabs-subpage"; +import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../../../types"; +import "../../../ha-config-section"; export const ozwTabs: PageNavigation[] = []; @@ -45,22 +45,8 @@ class OZWConfigDashboard extends LitElement { @internalProperty() private _instances: OZWInstance[] = []; - public connectedCallback(): void { - super.connectedCallback(); - if (this.hass) { - this._fetchData(); - } - } - - private async _fetchData() { - this._instances = await fetchOZWInstances(this.hass!); - if (this._instances.length === 1) { - navigate( - this, - `/config/ozw/network/${this._instances[0].ozw_instance}`, - true - ); - } + protected firstUpdated() { + this._fetchData(); } protected render(): TemplateResult { @@ -142,12 +128,23 @@ class OZWConfigDashboard extends LitElement { `; })} ` - : ``} + : ""} `; } + private async _fetchData() { + this._instances = await fetchOZWInstances(this.hass!); + if (this._instances.length === 1) { + navigate( + this, + `/config/ozw/network/${this._instances[0].ozw_instance}`, + true + ); + } + } + static get styles(): CSSResultArray { return [ haStyle, diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts index ed8aef3b026d..6240d16fb1e5 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts @@ -1,3 +1,4 @@ +import { mdiNetwork, mdiServerNetwork } from "@mdi/js"; import { CSSResultArray, customElement, @@ -6,14 +7,26 @@ import { property, TemplateResult, } from "lit-element"; -import { mdiNetwork, mdiServerNetwork } from "@mdi/js"; import { navigate } from "../../../../../common/navigate"; -import { haStyle } from "../../../../../resources/styles"; -import type { HomeAssistant, Route } from "../../../../../types"; import "../../../../../layouts/hass-tabs-subpage"; import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; -import "./ozw-network-router"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../../../types"; import { computeTail } from "./ozw-config-router"; +import "./ozw-network-router"; + +export const ozwNetworkTabs: PageNavigation[] = [ + { + translationKey: "ui.panel.config.ozw.navigation.network", + path: `/config/ozw/network/${this.ozwInstance}/dashboard`, + iconPath: mdiServerNetwork, + }, + { + translationKey: "ui.panel.config.ozw.navigation.nodes", + path: `/config/ozw/network/${this.ozwInstance}/nodes`, + iconPath: mdiNetwork, + }, +]; @customElement("ozw-config-network") class OZWConfigNetwork extends LitElement { @@ -27,11 +40,10 @@ class OZWConfigNetwork extends LitElement { @property() public configEntryId?: string; - @property() public ozw_instance = 0; + @property({ type: Number }) public ozwInstance?; - public connectedCallback(): void { - super.connectedCallback(); - if (this.ozw_instance <= 0) { + protected firstUpdated() { + if (!this.ozwInstance) { navigate(this, "/config/ozw/dashboard", true); } } @@ -39,29 +51,16 @@ class OZWConfigNetwork extends LitElement { protected render(): TemplateResult { const route = computeTail(this.route); - const ozwTabs: PageNavigation[] = [ - { - translationKey: "ui.panel.config.ozw.navigation.network", - path: `/config/ozw/network/${this.ozw_instance}/dashboard`, - iconPath: mdiServerNetwork, - }, - { - translationKey: "ui.panel.config.ozw.navigation.nodes", - path: `/config/ozw/network/${this.ozw_instance}/nodes`, - iconPath: mdiNetwork, - }, - ]; - if (route.path !== "/nodes") { return html` - ${this.hass!.localize("ui.panel.config.ozw.services." + service)} - - `; - } - protected render(): TemplateResult { return html` @@ -111,18 +77,19 @@ class OZWNetworkDashboard extends LitElement {
${this.hass.localize("ui.panel.config.ozw.common.network")} ${this.hass.localize( - "ui.panel.config.ozw.network_status." + this._status + `ui.panel.config.ozw.network_status.${this._status}` )}
${this.hass.localize( - "ui.panel.config.ozw.network_status.details." + - this._network.Status.toLowerCase() + `ui.panel.config.ozw.network_status.details.${this._network.Status.toLowerCase()}` )}
@@ -161,6 +128,37 @@ class OZWNetworkDashboard extends LitElement { `; } + private async _fetchData() { + this._network = await fetchOZWNetworkStatus(this.hass!, this.ozw_instance); + this._statistics = await fetchOZWNetworkStatistics( + this.hass!, + this.ozw_instance + ); + if (networkOnlineStatuses.includes(this._network.Status)) { + this._status = "online"; + this._icon = mdiCheckCircle; + } + if (networkStartingStatuses.includes(this._network.Status)) { + this._status = "starting"; + } + if (networkOfflineStatuses.includes(this._network.Status)) { + this._status = "offline"; + this._icon = mdiCloseCircle; + } + } + + private _generateServiceButton(service: string) { + return html` + + ${this.hass!.localize(`ui.panel.config.ozw.services.${service}`)} + + `; + } + static get styles(): CSSResultArray { return [ haStyle, diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts index f1a272d3eab7..4624017a3bfc 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts @@ -1,6 +1,7 @@ +import "@material/mwc-button/mwc-button"; import "@material/mwc-fab"; +import { mdiAlert, mdiCheck } from "@mdi/js"; import { - css, CSSResultArray, customElement, html, @@ -10,20 +11,18 @@ import { TemplateResult, } from "lit-element"; import memoizeOne from "memoize-one"; -import { mdiCheck, mdiAlert, mdiServerNetwork, mdiNetwork } from "@mdi/js"; import { navigate } from "../../../../../common/navigate"; +import "../../../../../components/buttons/ha-call-service-button"; import { DataTableColumnContainer } from "../../../../../components/data-table/ha-data-table"; import "../../../../../components/ha-card"; import "../../../../../components/ha-icon-next"; -import "../../../../../components/buttons/ha-call-service-button"; +import { fetchOZWNodes, OZWDevice } from "../../../../../data/ozw"; +import "../../../../../layouts/hass-tabs-subpage"; +import "../../../../../layouts/hass-tabs-subpage-data-table"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant, Route } from "../../../../../types"; import "../../../ha-config-section"; -import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; -import "../../../../../layouts/hass-tabs-subpage"; -import "../../../../../layouts/hass-tabs-subpage-data-table"; -import "@material/mwc-button/mwc-button"; -import { OZWDevice, fetchOZWNodes } from "../../../../../data/ozw"; +import { ozwNetworkTabs } from "./ozw-config-network"; import { computeTail } from "./ozw-config-router"; export interface NodeRowData extends OZWDevice { @@ -43,127 +42,84 @@ class OZWNetworkNodes extends LitElement { @property() public configEntryId?: string; - @property() public ozw_instance = 0; + @property() public ozwInstance?: number; @internalProperty() private _nodes: OZWDevice[] = []; - public connectedCallback(): void { - super.connectedCallback(); - if (this.ozw_instance <= 0) { + private _columns = memoizeOne( + (narrow: boolean): DataTableColumnContainer => { + return { + node_id: { + title: "ID", + sortable: true, + type: "numeric", + width: "72px", + filterable: true, + direction: "asc", + }, + node_product_name: { + title: "Model", + sortable: true, + grows: true, + }, + node_manufacturer_name: { + title: "Manufacturer", + sortable: true, + hide: narrow, + width: "25%", + }, + node_query_stage: { + title: "Query Stage", + sortable: true, + hide: narrow, + width: "25%", + }, + is_zwave_plus: { + title: "Z-Wave Plus", + hide: narrow, + template: (value: boolean) => + value ? html` ` : "", + }, + is_failed: { + title: "Failed", + hide: narrow, + template: (value: boolean) => + value ? html` ` : "", + }, + }; + } + ); + + protected firstUpdated() { + if (!this.ozwInstance) { navigate(this, "/config/ozw/dashboard", true); } else if (this.hass) { this._fetchData(); } } - private async _fetchData() { - this._nodes = await fetchOZWNodes(this.hass!, this.ozw_instance); - } - - private _formattedNodes = memoizeOne((nodes: OZWDevice[]) => { - let outputNodes: NodeRowData[] = nodes; - - outputNodes = outputNodes.map((node) => { - return { - ...node, - id: node.node_id, - }; - }); - - return outputNodes; - }); - - private _columns = memoizeOne( - (narrow: boolean): DataTableColumnContainer => - narrow - ? { - node_id: { - title: "ID", - sortable: true, - type: "numeric", - width: "72px", - filterable: true, - direction: "asc", - }, - node_product_name: { - title: "Model", - sortable: true, - grows: true, - }, - } - : { - id: { - title: "ID", - sortable: true, - type: "numeric", - width: "72px", - filterable: true, - direction: "asc", - }, - node_manufacturer_name: { - title: "Manufacturer", - sortable: true, - width: "25%", - }, - node_product_name: { - title: "Model", - sortable: true, - width: "25%", - }, - node_query_stage: { - title: "Query Stage", - sortable: true, - width: "25%", - }, - is_zwave_plus: { - title: "Z-Wave Plus", - template: (value: boolean) => { - return html`${value - ? html` ` - : ``} `; - }, - }, - is_failed: { - title: "Failed", - template: (value: boolean) => { - return html`${value - ? html` ` - : ``} `; - }, - }, - } - ); - protected render(): TemplateResult { const route = computeTail(this.route); - const ozwTabs: PageNavigation[] = [ - { - translationKey: "ui.panel.config.ozw.navigation.network", - path: `/config/ozw/network/${this.ozw_instance}/dashboard`, - iconPath: mdiServerNetwork, - }, - { - translationKey: "ui.panel.config.ozw.navigation.nodes", - path: `/config/ozw/network/${this.ozw_instance}/nodes`, - iconPath: mdiNetwork, - }, - ]; - return html` `; } + private async _fetchData() { + this._nodes = await fetchOZWNodes(this.hass!, this.ozwInstance!); + } + static get styles(): CSSResultArray { return [haStyle]; } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts index 1bfd77c0dc26..b4cb99e0ce37 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts @@ -13,7 +13,7 @@ class OZWNetworkRouter extends HassRouterPage { @property() public narrow!: boolean; - @property() public ozw_instance!: number; + @property() public ozwInstance!: number; private _configEntry = new URLSearchParams(window.location.search).get( "config_entry" @@ -51,7 +51,7 @@ class OZWNetworkRouter extends HassRouterPage { el.isWide = this.isWide; el.narrow = this.narrow; el.configEntryId = this._configEntry; - el.ozw_instance = this.ozw_instance; + el.ozwInstance = this.ozwInstance; if (this._currentPage === "node") { const path = this.routeTail.path.split("/"); el.node_id = path[1]; diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index 0886c31b7369..5d539365d98e 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -1,3 +1,4 @@ +import "@material/mwc-button/mwc-button"; import "@material/mwc-fab"; import { css, @@ -8,17 +9,13 @@ import { property, TemplateResult, } from "lit-element"; +import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; import "../../../../../components/ha-icon-next"; -import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant, Route } from "../../../../../types"; import "../../../ha-config-section"; -import "../../../../../layouts/hass-tabs-subpage"; -import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; -import "@material/mwc-button/mwc-button"; - -export const ozwTabs: PageNavigation[] = []; @customElement("ozw-node-dashboard") class OZWNodeDashboard extends LitElement { @@ -32,9 +29,9 @@ class OZWNodeDashboard extends LitElement { @property() public configEntryId?: string; - @property() public ozw_instance = 0; + @property() public ozwInstance?: number; - @property() public node_id = 0; + @property() public nodeId?: number; protected render(): TemplateResult { return html` diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts index d52f97034b75..baf68ddc969a 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts @@ -1,10 +1,10 @@ import { customElement, property } from "lit-element"; +import { navigate } from "../../../../../common/navigate"; import { HassRouterPage, RouterOptions, } from "../../../../../layouts/hass-router-page"; import { HomeAssistant } from "../../../../../types"; -import { navigate } from "../../../../../common/navigate"; @customElement("ozw-node-router") class OZWNodeRouter extends HassRouterPage { @@ -14,9 +14,9 @@ class OZWNodeRouter extends HassRouterPage { @property() public narrow!: boolean; - @property() public ozw_instance!: number; + @property() public ozwInstance!: number; - @property() public node_id!: number; + @property() public nodeId!: number; private _configEntry = new URLSearchParams(window.location.search).get( "config_entry" @@ -42,8 +42,8 @@ class OZWNodeRouter extends HassRouterPage { el.isWide = this.isWide; el.narrow = this.narrow; el.configEntryId = this._configEntry; - el.ozw_instance = this.ozw_instance; - el.node_id = this.node_id; + el.ozwInstance = this.ozwInstance; + el.nodeId = this.nodeId; const searchParams = new URLSearchParams(window.location.search); if (this._configEntry && !searchParams.has("config_entry")) { From c8ab8fb51c15b949c9a4d8166b518e3b95c8669f Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Sat, 29 Aug 2020 13:05:15 -0400 Subject: [PATCH 03/16] Tweaks --- .../ozw/ozw-config-network.ts | 28 ++++++++++--------- .../ozw/ozw-network-dashboard.ts | 4 +-- .../ozw/ozw-network-nodes.ts | 4 +-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts index 6240d16fb1e5..36d4bd438bee 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts @@ -15,18 +15,20 @@ import type { HomeAssistant, Route } from "../../../../../types"; import { computeTail } from "./ozw-config-router"; import "./ozw-network-router"; -export const ozwNetworkTabs: PageNavigation[] = [ - { - translationKey: "ui.panel.config.ozw.navigation.network", - path: `/config/ozw/network/${this.ozwInstance}/dashboard`, - iconPath: mdiServerNetwork, - }, - { - translationKey: "ui.panel.config.ozw.navigation.nodes", - path: `/config/ozw/network/${this.ozwInstance}/nodes`, - iconPath: mdiNetwork, - }, -]; +export function ozwNetworkTabs(instance: number): PageNavigation[] { + return [ + { + translationKey: "ui.panel.config.ozw.navigation.network", + path: `/config/ozw/network/${instance}/dashboard`, + iconPath: mdiServerNetwork, + }, + { + translationKey: "ui.panel.config.ozw.navigation.nodes", + path: `/config/ozw/network/${instance}/nodes`, + iconPath: mdiNetwork, + }, + ]; +} @customElement("ozw-config-network") class OZWConfigNetwork extends LitElement { @@ -57,7 +59,7 @@ class OZWConfigNetwork extends LitElement { .hass=${this.hass} .narrow=${this.narrow} .route=${route} - .tabs=${ozwNetworkTabs} + .tabs=${ozwNetworkTabs(this.ozwInstance)} > Date: Sat, 29 Aug 2020 14:57:18 -0400 Subject: [PATCH 04/16] Cleanup --- .../integration-panels/ozw/ozw-config-network.ts | 6 +++--- .../integrations/integration-panels/ozw/ozw-config-node.ts | 6 +++--- .../integration-panels/ozw/ozw-network-dashboard.ts | 4 ++-- .../integration-panels/ozw/ozw-network-nodes.ts | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts index 36d4bd438bee..e5da08688ddc 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts @@ -1,6 +1,6 @@ import { mdiNetwork, mdiServerNetwork } from "@mdi/js"; import { - CSSResultArray, + CSSResult, customElement, html, LitElement, @@ -83,8 +83,8 @@ class OZWConfigNetwork extends LitElement { `; } - static get styles(): CSSResultArray { - return [haStyle]; + static get styles(): CSSResult { + return haStyle; } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts index 87b3a14540c4..525625533358 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts @@ -1,5 +1,5 @@ import { - CSSResultArray, + CSSResult, customElement, html, LitElement, @@ -42,8 +42,8 @@ class OZWConfigNode extends LitElement { `; } - static get styles(): CSSResultArray { - return [haStyle]; + static get styles(): CSSResult { + return haStyle; } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts index 3f2127d80556..55f03c202f24 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts @@ -129,10 +129,10 @@ class OZWNetworkDashboard extends LitElement { } private async _fetchData() { - this._network = await fetchOZWNetworkStatus(this.hass!, this.ozw_instance); + this._network = await fetchOZWNetworkStatus(this.hass!, this.ozwInstance); this._statistics = await fetchOZWNetworkStatistics( this.hass!, - this.ozw_instance + this.ozwInstance ); if (networkOnlineStatuses.includes(this._network.Status)) { this._status = "online"; diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts index 0c9bec893919..512424d2ddef 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts @@ -2,7 +2,7 @@ import "@material/mwc-button/mwc-button"; import "@material/mwc-fab"; import { mdiAlert, mdiCheck } from "@mdi/js"; import { - CSSResultArray, + CSSResult, customElement, html, internalProperty, @@ -120,8 +120,8 @@ class OZWNetworkNodes extends LitElement { this._nodes = await fetchOZWNodes(this.hass!, this.ozwInstance!); } - static get styles(): CSSResultArray { - return [haStyle]; + static get styles(): CSSResult { + return haStyle; } } From 34c2f4e84751e2e9968cc44d09c0a3d7d8f09653 Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Mon, 31 Aug 2020 09:12:11 -0400 Subject: [PATCH 05/16] Update function declaration --- .../integrations/integration-panels/ozw/ozw-config-network.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts index e5da08688ddc..81d46a2e67ac 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts @@ -15,7 +15,7 @@ import type { HomeAssistant, Route } from "../../../../../types"; import { computeTail } from "./ozw-config-router"; import "./ozw-network-router"; -export function ozwNetworkTabs(instance: number): PageNavigation[] { +export const ozwNetworkTabs = (instance: number): PageNavigation[] => { return [ { translationKey: "ui.panel.config.ozw.navigation.network", @@ -28,7 +28,7 @@ export function ozwNetworkTabs(instance: number): PageNavigation[] { iconPath: mdiNetwork, }, ]; -} +}; @customElement("ozw-config-network") class OZWConfigNetwork extends LitElement { From 608140b7390844a314b6192d0ad5ac5ce5c2662b Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Mon, 31 Aug 2020 09:28:03 -0400 Subject: [PATCH 06/16] Tweak column sizes and add translations --- .../ozw/ozw-network-nodes.ts | 29 +++++++++++-------- src/translations/en.json | 8 +++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts index 512424d2ddef..37c30fff71dc 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts @@ -50,7 +50,7 @@ class OZWNetworkNodes extends LitElement { (narrow: boolean): DataTableColumnContainer => { return { node_id: { - title: "ID", + title: this.hass.localize("ui.panel.config.ozw.nodes_table.id"), sortable: true, type: "numeric", width: "72px", @@ -58,31 +58,36 @@ class OZWNetworkNodes extends LitElement { direction: "asc", }, node_product_name: { - title: "Model", + title: this.hass.localize("ui.panel.config.ozw.nodes_table.model"), sortable: true, - grows: true, + width: narrow ? "75%" : "25%", }, node_manufacturer_name: { - title: "Manufacturer", + title: this.hass.localize( + "ui.panel.config.ozw.nodes_table.manufacturer" + ), sortable: true, - hide: narrow, + hidden: narrow, width: "25%", }, node_query_stage: { - title: "Query Stage", + title: this.hass.localize( + "ui.panel.config.ozw.nodes_table.query_stage" + ), sortable: true, - hide: narrow, - width: "25%", + width: narrow ? "25%" : "15%", }, is_zwave_plus: { - title: "Z-Wave Plus", - hide: narrow, + title: this.hass.localize( + "ui.panel.config.ozw.nodes_table.zwave_plus" + ), + hidden: narrow, template: (value: boolean) => value ? html` ` : "", }, is_failed: { - title: "Failed", - hide: narrow, + title: this.hass.localize("ui.panel.config.ozw.nodes_table.failed"), + hidden: narrow, template: (value: boolean) => value ? html` ` : "", }, diff --git a/src/translations/en.json b/src/translations/en.json index d922b5f91940..4bd4e0e9c2c1 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1783,6 +1783,14 @@ "introduction": "Manage network-wide functions.", "node_count": "{count} nodes" }, + "nodes_table": { + "id": "ID", + "manufacturer": "Manufacturer", + "model": "Model", + "query_stage": "Query Stage", + "zwave_plus": "Z-Wave Plus", + "failed": "Failed" + }, "services": { "add_node": "Add Node", "remove_node": "Remove Node" From 21765e20586dac57222f6beb6497b21563ab8458 Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Mon, 31 Aug 2020 11:39:57 -0400 Subject: [PATCH 07/16] Add basic node info to node dashboard page --- src/data/ozw.ts | 2 + .../ozw/ozw-network-router.ts | 2 +- .../ozw/ozw-node-dashboard.ts | 137 +++++++++++++----- 3 files changed, 107 insertions(+), 34 deletions(-) diff --git a/src/data/ozw.ts b/src/data/ozw.ts index 5cc627029053..80ad9882b7b7 100644 --- a/src/data/ozw.ts +++ b/src/data/ozw.ts @@ -14,6 +14,8 @@ export interface OZWDevice { is_zwave_plus: boolean; ozw_instance: number; event: string; + node_manufacturer_name: string; + node_product_name: string; } export interface OZWDeviceMetaDataResponse { diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts index b4cb99e0ce37..5395f0239e2c 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts @@ -54,7 +54,7 @@ class OZWNetworkRouter extends HassRouterPage { el.ozwInstance = this.ozwInstance; if (this._currentPage === "node") { const path = this.routeTail.path.split("/"); - el.node_id = path[1]; + el.nodeId = path[1]; } } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index 5d539365d98e..b1914f0d2e78 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -6,9 +6,11 @@ import { customElement, html, LitElement, + internalProperty, property, TemplateResult, } from "lit-element"; +import { navigate } from "../../../../../common/navigate"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; import "../../../../../components/ha-icon-next"; @@ -16,6 +18,13 @@ import "../../../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant, Route } from "../../../../../types"; import "../../../ha-config-section"; +import { + fetchOZWNodeStatus, + fetchOZWNodeMetadata, + OZWDevice, + OZWDeviceMetaDataResponse, +} from "../../../../../data/ozw"; +import { showOZWRefreshNodeDialog } from "./show-dialog-ozw-refresh-node"; @customElement("ozw-node-dashboard") class OZWNodeDashboard extends LitElement { @@ -29,24 +38,114 @@ class OZWNodeDashboard extends LitElement { @property() public configEntryId?: string; - @property() public ozwInstance?: number; + @property() public ozwInstance = 0; + + @property() public nodeId = 0; + + @internalProperty() private _node?: OZWDevice; - @property() public nodeId?: number; + @internalProperty() private _metadata?: OZWDeviceMetaDataResponse; + + protected firstUpdated() { + if (this.ozwInstance <= 0) { + navigate(this, "/config/ozw/dashboard", true); + } else if (this.nodeId <= 0) { + navigate(this, `/config/ozw/network/${this.ozwInstance}/nodes`, true); + } else if (this.hass) { + this._fetchData(); + } + } protected render(): TemplateResult { return html`
- Node Details + Node Management
- Soon you will be able to view and manage a specific OZW node... + View the status of a node and manage its configuration.
+ + ${this._node + ? html` + +
+ ${this._node.node_manufacturer_name} + ${this._node.node_product_name}
+ Node ID: ${this._node.node_id}
+ Query Stage: ${this._node.node_query_stage} + ${this._metadata?.metadata.ProductManualURL + ? html` +

Product Manual

+
` + : ``} +
+
+ + Refresh Node + +
+
+ ` + : ``} + ${this._metadata + ? html` + +
+ ${this._metadata.metadata.Description} +
+
+ +
+ ${this._metadata.metadata.InclusionHelp} +
+
+ +
+ ${this._metadata.metadata.ExclusionHelp} +
+
+ +
+ ${this._metadata.metadata.ResetHelp} +
+
+ +
+ ${this._metadata.metadata.WakeupHelp} +
+
+ ` + : ``}
`; } + private async _fetchData() { + this._node = await fetchOZWNodeStatus( + this.hass!, + this.ozwInstance, + this.nodeId + ); + this._metadata = await fetchOZWNodeMetadata( + this.hass!, + this.ozwInstance, + this.nodeId + ); + } + + private async _refreshNodeClicked() { + showOZWRefreshNodeDialog(this, { + node_id: this.nodeId, + ozw_instance: this.ozwInstance, + }); + } + static get styles(): CSSResultArray { return [ haStyle, @@ -54,15 +153,7 @@ class OZWNodeDashboard extends LitElement { .secondary { color: var(--secondary-text-color); } - .online { - color: green; - } - .starting { - color: orange; - } - .offline { - color: red; - } + .content { margin-top: 24px; } @@ -72,26 +163,6 @@ class OZWNodeDashboard extends LitElement { padding-right: 40px; } - .network-status { - text-align: center; - } - - .network-status div.details { - font-size: 1.5rem; - margin-bottom: 16px; - } - - .network-status ha-svg-icon { - display: block; - margin: 0px auto 16px; - width: 48px; - height: 48px; - } - - .network-status small { - font-size: 1rem; - } - ha-card { margin: 0 auto; max-width: 600px; From 33ebdf67e924e7274c519a39a3f4e54283355a77 Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Mon, 31 Aug 2020 11:45:06 -0400 Subject: [PATCH 08/16] Add click handler --- .../integration-panels/ozw/ozw-network-nodes.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts index 37c30fff71dc..1d9e0328831a 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts @@ -13,7 +13,11 @@ import { import memoizeOne from "memoize-one"; import { navigate } from "../../../../../common/navigate"; import "../../../../../components/buttons/ha-call-service-button"; -import { DataTableColumnContainer } from "../../../../../components/data-table/ha-data-table"; +import { HASSDomEvent } from "../../../../../common/dom/fire_event"; +import { + DataTableColumnContainer, + RowClickedEvent, +} from "../../../../../components/data-table/ha-data-table"; import "../../../../../components/ha-card"; import "../../../../../components/ha-icon-next"; import { fetchOZWNodes, OZWDevice } from "../../../../../data/ozw"; @@ -115,6 +119,7 @@ class OZWNetworkNodes extends LitElement { .columns=${this._columns(this.narrow)} .data=${this._nodes} id="node_id" + @row-click=${this._handleRowClicked} back-path="/config/ozw/network/${this.ozwInstance}/dashboard" > @@ -125,6 +130,11 @@ class OZWNetworkNodes extends LitElement { this._nodes = await fetchOZWNodes(this.hass!, this.ozwInstance!); } + private _handleRowClicked(ev: HASSDomEvent) { + const nodeId = ev.detail.id; + navigate(this, `/config/ozw/network/${this.ozwInstance}/node/${nodeId}`); + } + static get styles(): CSSResult { return haStyle; } From c8545e8d6f6c9ee68e732f96dc620103c4ad5d3c Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Thu, 3 Sep 2020 11:32:46 -0400 Subject: [PATCH 09/16] Simplify node-level routing --- .../integration-panels/ozw/ozw-config-node.ts | 54 ------------------- .../ozw/ozw-network-router.ts | 10 +++- 2 files changed, 8 insertions(+), 56 deletions(-) delete mode 100644 src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts deleted file mode 100644 index 525625533358..000000000000 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-node.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import "../../../../../layouts/hass-tabs-subpage"; -import { haStyle } from "../../../../../resources/styles"; -import type { HomeAssistant, Route } from "../../../../../types"; -import { computeTail } from "./ozw-config-router"; -import "./ozw-node-router"; - -@customElement("ozw-config-node") -class OZWConfigNode 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; - - @property() public ozwInstance?: number; - - @property() public nodeId?: number; - - protected render(): TemplateResult { - const route = computeTail(this.route); - return html` - - - `; - } - - static get styles(): CSSResult { - return haStyle; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ozw-config-node": OZWConfigNode; - } -} diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts index 5395f0239e2c..da6267c71e33 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts @@ -4,6 +4,7 @@ import { RouterOptions, } from "../../../../../layouts/hass-router-page"; import { HomeAssistant } from "../../../../../types"; +import { computeTail } from "./ozw-config-router"; @customElement("ozw-network-router") class OZWNetworkRouter extends HassRouterPage { @@ -38,9 +39,9 @@ class OZWNetworkRouter extends HassRouterPage { ), }, node: { - tag: "ozw-config-node", + tag: "ozw-node-router", load: () => - import(/* webpackChunkName: "ozw-config-node" */ "./ozw-config-node"), + import(/* webpackChunkName: "ozw-node-router" */ "./ozw-node-router"), }, }, }; @@ -55,6 +56,11 @@ class OZWNetworkRouter extends HassRouterPage { if (this._currentPage === "node") { const path = this.routeTail.path.split("/"); el.nodeId = path[1]; + if (path[2]) { + el.route.path = `/${path[2]}`; + } else { + el.route.path = "/dashboard"; + } } } } From a5595794bb9136b5ce1c432e23dbd6fd2befe7e9 Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Thu, 3 Sep 2020 14:36:00 -0400 Subject: [PATCH 10/16] Finish cleaning up routers --- .../ozw/ozw-config-network.ts | 95 ------------ .../ozw/ozw-config-router.ts | 5 +- .../ozw/ozw-network-dashboard.ts | 128 ++++++++-------- .../ozw/ozw-network-nodes.ts | 7 +- .../ozw/ozw-network-router.ts | 23 ++- .../ozw/ozw-node-dashboard.ts | 138 +++++++++--------- 6 files changed, 165 insertions(+), 231 deletions(-) delete mode 100644 src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts deleted file mode 100644 index 81d46a2e67ac..000000000000 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-network.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { mdiNetwork, mdiServerNetwork } from "@mdi/js"; -import { - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { navigate } from "../../../../../common/navigate"; -import "../../../../../layouts/hass-tabs-subpage"; -import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; -import { haStyle } from "../../../../../resources/styles"; -import type { HomeAssistant, Route } from "../../../../../types"; -import { computeTail } from "./ozw-config-router"; -import "./ozw-network-router"; - -export const ozwNetworkTabs = (instance: number): PageNavigation[] => { - return [ - { - translationKey: "ui.panel.config.ozw.navigation.network", - path: `/config/ozw/network/${instance}/dashboard`, - iconPath: mdiServerNetwork, - }, - { - translationKey: "ui.panel.config.ozw.navigation.nodes", - path: `/config/ozw/network/${instance}/nodes`, - iconPath: mdiNetwork, - }, - ]; -}; - -@customElement("ozw-config-network") -class OZWConfigNetwork 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; - - @property({ type: Number }) public ozwInstance?; - - protected firstUpdated() { - if (!this.ozwInstance) { - navigate(this, "/config/ozw/dashboard", true); - } - } - - protected render(): TemplateResult { - const route = computeTail(this.route); - - if (route.path !== "/nodes") { - return html` - - - - - `; - } - - return html` - - - `; - } - - static get styles(): CSSResult { - return haStyle; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ozw-config-network": OZWConfigNetwork; - } -} diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-router.ts index cd151f498f85..804e2073afb2 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-router.ts @@ -43,10 +43,10 @@ class OZWConfigRouter extends HassRouterPage { ), }, network: { - tag: "ozw-config-network", + tag: "ozw-network-router", load: () => import( - /* webpackChunkName: "ozw-config-network" */ "./ozw-config-network" + /* webpackChunkName: "ozw-network-router" */ "./ozw-network-router" ), }, }, @@ -61,6 +61,7 @@ class OZWConfigRouter extends HassRouterPage { if (this._currentPage === "network") { const path = this.routeTail.path.split("/"); el.ozwInstance = path[1]; + el.route = computeTail(this.routeTail); } } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts index 55f03c202f24..3d64194ff8cc 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts @@ -29,6 +29,7 @@ import "../../../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant, Route } from "../../../../../types"; import "../../../ha-config-section"; +import { ozwNetworkTabs } from "./ozw-network-router"; @customElement("ozw-network-dashboard") class OZWNetworkDashboard extends LitElement { @@ -62,69 +63,78 @@ class OZWNetworkDashboard extends LitElement { protected render(): TemplateResult { return html` - -
- ${this.hass.localize("ui.panel.config.ozw.network.header")} -
- -
- ${this.hass.localize("ui.panel.config.ozw.network.introduction")} -
- ${this._network - ? html` - -
-
- - ${this.hass.localize("ui.panel.config.ozw.common.network")} - ${this.hass.localize( - `ui.panel.config.ozw.network_status.${this._status}` - )} -
- + + +
+ ${this.hass.localize("ui.panel.config.ozw.network.header")} +
+ +
+ ${this.hass.localize("ui.panel.config.ozw.network.introduction")} +
+ ${this._network + ? html` + +
+
+ + ${this.hass.localize( + "ui.panel.config.ozw.common.network" + )} ${this.hass.localize( - `ui.panel.config.ozw.network_status.details.${this._network.Status.toLowerCase()}` + `ui.panel.config.ozw.network_status.${this._status}` )} - +
+ + ${this.hass.localize( + `ui.panel.config.ozw.network_status.details.${this._network.Status.toLowerCase()}` + )} + +
+
+ ${this.hass.localize( + "ui.panel.config.ozw.common.ozw_instance" + )} + ${this._network.ozw_instance} + ${this._statistics + ? html` + • + ${this.hass.localize( + "ui.panel.config.ozw.network.node_count", + "count", + this._statistics.node_count + )} + ` + : ``} +
+ ${this.hass.localize( + "ui.panel.config.ozw.common.controller" + )}: + ${this._network.getControllerPath}
+ OZWDaemon ${this._network.OZWDaemon_Version} (OpenZWave + ${this._network.OpenZWave_Version}) +
-
- ${this.hass.localize( - "ui.panel.config.ozw.common.ozw_instance" - )} - ${this._network.ozw_instance} - ${this._statistics - ? html` - • - ${this.hass.localize( - "ui.panel.config.ozw.network.node_count", - "count", - this._statistics.node_count - )} - ` - : ``} -
- ${this.hass.localize( - "ui.panel.config.ozw.common.controller" - )}: - ${this._network.getControllerPath}
- OZWDaemon ${this._network.OZWDaemon_Version} (OpenZWave - ${this._network.OpenZWave_Version}) +
+ ${this._generateServiceButton("add_node")} + ${this._generateServiceButton("remove_node")}
-
-
- ${this._generateServiceButton("add_node")} - ${this._generateServiceButton("remove_node")} -
- - ` - : ``} - + + ` + : ``} + + `; } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts index 1d9e0328831a..11d6a3c2a391 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts @@ -26,8 +26,7 @@ import "../../../../../layouts/hass-tabs-subpage-data-table"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant, Route } from "../../../../../types"; import "../../../ha-config-section"; -import { ozwNetworkTabs } from "./ozw-config-network"; -import { computeTail } from "./ozw-config-router"; +import { ozwNetworkTabs } from "./ozw-network-router"; export interface NodeRowData extends OZWDevice { node?: NodeRowData; @@ -108,13 +107,11 @@ class OZWNetworkNodes extends LitElement { } protected render(): TemplateResult { - const route = computeTail(this.route); - return html` { + return [ + { + translationKey: "ui.panel.config.ozw.navigation.network", + path: `/config/ozw/network/${instance}/dashboard`, + iconPath: mdiServerNetwork, + }, + { + translationKey: "ui.panel.config.ozw.navigation.nodes", + path: `/config/ozw/network/${instance}/nodes`, + iconPath: mdiNetwork, + }, + ]; +}; @customElement("ozw-network-router") class OZWNetworkRouter extends HassRouterPage { @@ -56,11 +73,7 @@ class OZWNetworkRouter extends HassRouterPage { if (this._currentPage === "node") { const path = this.routeTail.path.split("/"); el.nodeId = path[1]; - if (path[2]) { - el.route.path = `/${path[2]}`; - } else { - el.route.path = "/dashboard"; - } + el.route = computeTail(this.routeTail); } } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index b1914f0d2e78..5f91108a90a5 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -25,6 +25,7 @@ import { OZWDeviceMetaDataResponse, } from "../../../../../data/ozw"; import { showOZWRefreshNodeDialog } from "./show-dialog-ozw-refresh-node"; +import { ozwNetworkTabs } from "./ozw-network-router"; @customElement("ozw-node-dashboard") class OZWNodeDashboard extends LitElement { @@ -58,71 +59,78 @@ class OZWNodeDashboard extends LitElement { protected render(): TemplateResult { return html` - -
- Node Management -
- -
- View the status of a node and manage its configuration. -
- - ${this._node - ? html` - -
- ${this._node.node_manufacturer_name} - ${this._node.node_product_name}
- Node ID: ${this._node.node_id}
- Query Stage: ${this._node.node_query_stage} - ${this._metadata?.metadata.ProductManualURL - ? html` -

Product Manual

-
` - : ``} -
-
- - Refresh Node - -
-
- ` - : ``} - ${this._metadata - ? html` - -
- ${this._metadata.metadata.Description} -
-
- -
- ${this._metadata.metadata.InclusionHelp} -
-
- -
- ${this._metadata.metadata.ExclusionHelp} -
-
- -
- ${this._metadata.metadata.ResetHelp} -
-
- -
- ${this._metadata.metadata.WakeupHelp} -
-
- ` - : ``} -
+ + +
+ Node Management +
+ +
+ View the status of a node and manage its configuration. +
+ + ${this._node + ? html` + +
+ ${this._node.node_manufacturer_name} + ${this._node.node_product_name}
+ Node ID: ${this._node.node_id}
+ Query Stage: ${this._node.node_query_stage} + ${this._metadata?.metadata.ProductManualURL + ? html` +

Product Manual

+
` + : ``} +
+
+ + Refresh Node + +
+
+ ` + : ``} + ${this._metadata + ? html` + +
+ ${this._metadata.metadata.Description} +
+
+ +
+ ${this._metadata.metadata.InclusionHelp} +
+
+ +
+ ${this._metadata.metadata.ExclusionHelp} +
+
+ +
+ ${this._metadata.metadata.ResetHelp} +
+
+ +
+ ${this._metadata.metadata.WakeupHelp} +
+
+ ` + : ``} +
+
`; } From f681268d2e6a47cd2e26cf11abcbd6bdb9184647 Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Thu, 3 Sep 2020 14:44:03 -0400 Subject: [PATCH 11/16] Review comments --- .../integration-panels/ozw/ozw-network-dashboard.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts index 3d64194ff8cc..3a7669e3afd9 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts @@ -43,7 +43,7 @@ class OZWNetworkDashboard extends LitElement { @property() public configEntryId?: string; - @property() public ozwInstance = 0; + @property() public ozwInstance?: number; @internalProperty() private _network?: OZWInstance; @@ -54,7 +54,7 @@ class OZWNetworkDashboard extends LitElement { @internalProperty() private _icon = mdiCircle; protected firstUpdated() { - if (this.ozwInstance <= 0) { + if (!this.ozwInstance) { navigate(this, "/config/ozw/dashboard", true); } else if (this.hass) { this._fetchData(); @@ -67,7 +67,7 @@ class OZWNetworkDashboard extends LitElement { .hass=${this.hass} .narrow=${this.narrow} .route=${this.route} - .tabs=${ozwNetworkTabs(this.ozwInstance)} + .tabs=${ozwNetworkTabs(this.ozwInstance!)} >
From bb25144950207749b3b591c9140ba4724ecbbbf3 Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Thu, 3 Sep 2020 14:55:56 -0400 Subject: [PATCH 12/16] lint --- .../integration-panels/ozw/ozw-network-dashboard.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts index 3a7669e3afd9..98ae8a28a635 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts @@ -139,19 +139,20 @@ class OZWNetworkDashboard extends LitElement { } private async _fetchData() { + if (!this.ozwInstance) return; this._network = await fetchOZWNetworkStatus(this.hass!, this.ozwInstance); this._statistics = await fetchOZWNetworkStatistics( this.hass!, this.ozwInstance ); - if (networkOnlineStatuses.includes(this._network.Status)) { + if (networkOnlineStatuses.includes(this._network!.Status)) { this._status = "online"; this._icon = mdiCheckCircle; } - if (networkStartingStatuses.includes(this._network.Status)) { + if (networkStartingStatuses.includes(this._network!.Status)) { this._status = "starting"; } - if (networkOfflineStatuses.includes(this._network.Status)) { + if (networkOfflineStatuses.includes(this._network!.Status)) { this._status = "offline"; this._icon = mdiCloseCircle; } From 69b74aedfb1c22cfb8f29c8c2108993748e9c8eb Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Fri, 4 Sep 2020 09:42:08 -0400 Subject: [PATCH 13/16] Update ozwInstance and nodeId handling --- .../integration-panels/ozw/ozw-network-router.ts | 6 ++---- .../integration-panels/ozw/ozw-node-dashboard.ts | 10 ++++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts index c4b98338b9d9..f98660bed0ee 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts @@ -64,16 +64,14 @@ class OZWNetworkRouter extends HassRouterPage { }; protected updatePageEl(el): void { - el.route = this.routeTail; + el.route = computeTail(this.routeTail); el.hass = this.hass; el.isWide = this.isWide; el.narrow = this.narrow; el.configEntryId = this._configEntry; el.ozwInstance = this.ozwInstance; if (this._currentPage === "node") { - const path = this.routeTail.path.split("/"); - el.nodeId = path[1]; - el.route = computeTail(this.routeTail); + el.nodeId = this.routeTail.path.split("/")[1]; } } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index 5f91108a90a5..199e04558063 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -39,18 +39,18 @@ class OZWNodeDashboard extends LitElement { @property() public configEntryId?: string; - @property() public ozwInstance = 0; + @property() public ozwInstance?; - @property() public nodeId = 0; + @property() public nodeId?; @internalProperty() private _node?: OZWDevice; @internalProperty() private _metadata?: OZWDeviceMetaDataResponse; protected firstUpdated() { - if (this.ozwInstance <= 0) { + if (!this.ozwInstance) { navigate(this, "/config/ozw/dashboard", true); - } else if (this.nodeId <= 0) { + } else if (!this.nodeId) { navigate(this, `/config/ozw/network/${this.ozwInstance}/nodes`, true); } else if (this.hass) { this._fetchData(); @@ -135,6 +135,8 @@ class OZWNodeDashboard extends LitElement { } private async _fetchData() { + if (!this.ozwInstance || !this.nodeId) return; + this._node = await fetchOZWNodeStatus( this.hass!, this.ozwInstance, From f7ca57a62966ddbc77453cb82023e7807491b509 Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Fri, 4 Sep 2020 10:19:14 -0400 Subject: [PATCH 14/16] Guard for node not found --- .../ozw/ozw-node-dashboard.ts | 55 ++++++++++--------- src/translations/en.json | 3 + 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index 199e04558063..d14ffe349dd0 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -58,6 +58,14 @@ class OZWNodeDashboard extends LitElement { } protected render(): TemplateResult { + if (!this._node) { + return html` + + `; + } + return html` - ${this._node - ? html` - -
- ${this._node.node_manufacturer_name} - ${this._node.node_product_name}
- Node ID: ${this._node.node_id}
- Query Stage: ${this._node.node_query_stage} - ${this._metadata?.metadata.ProductManualURL - ? html` -

Product Manual

-
` - : ``} -
-
- - Refresh Node - -
-
- ` - : ``} + +
+ ${this._node.node_manufacturer_name} + ${this._node.node_product_name}
+ Node ID: ${this._node.node_id}
+ Query Stage: ${this._node.node_query_stage} + ${this._metadata?.metadata.ProductManualURL + ? html` +

Product Manual

+
` + : ``} +
+
+ + Refresh Node + +
+
+ ${this._metadata ? html` diff --git a/src/translations/en.json b/src/translations/en.json index 4bd4e0e9c2c1..cc13e6624eff 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1791,6 +1791,9 @@ "zwave_plus": "Z-Wave Plus", "failed": "Failed" }, + "node": { + "not_found": "Node not found" + }, "services": { "add_node": "Add Node", "remove_node": "Remove Node" From 11052d1bc8ed629f3954671c4fadd980031801cb Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Fri, 4 Sep 2020 10:59:21 -0400 Subject: [PATCH 15/16] Improve handling of node not found errors --- .../ozw/ozw-node-dashboard.ts | 126 ++++++++++-------- 1 file changed, 71 insertions(+), 55 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index d14ffe349dd0..ce04b8688519 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -24,6 +24,7 @@ import { OZWDevice, OZWDeviceMetaDataResponse, } from "../../../../../data/ozw"; +import { ERR_NOT_FOUND } from "../../../../../data/websocket_api"; import { showOZWRefreshNodeDialog } from "./show-dialog-ozw-refresh-node"; import { ozwNetworkTabs } from "./ozw-network-router"; @@ -47,6 +48,8 @@ class OZWNodeDashboard extends LitElement { @internalProperty() private _metadata?: OZWDeviceMetaDataResponse; + @internalProperty() private _not_found = false; + protected firstUpdated() { if (!this.ozwInstance) { navigate(this, "/config/ozw/dashboard", true); @@ -58,7 +61,7 @@ class OZWNodeDashboard extends LitElement { } protected render(): TemplateResult { - if (!this._node) { + if (this._not_found) { return html` View the status of a node and manage its configuration.
- - -
- ${this._node.node_manufacturer_name} - ${this._node.node_product_name}
- Node ID: ${this._node.node_id}
- Query Stage: ${this._node.node_query_stage} - ${this._metadata?.metadata.ProductManualURL - ? html` -

Product Manual

-
` - : ``} -
-
- - Refresh Node - -
-
- - ${this._metadata + ${this._node ? html` - -
- ${this._metadata.metadata.Description} -
-
- +
- ${this._metadata.metadata.InclusionHelp} + ${this._node.node_manufacturer_name} + ${this._node.node_product_name}
+ Node ID: ${this._node.node_id}
+ Query Stage: ${this._node.node_query_stage} + ${this._metadata?.metadata.ProductManualURL + ? html` +

Product Manual

+
` + : ``}
-
- -
- ${this._metadata.metadata.ExclusionHelp} -
-
- -
- ${this._metadata.metadata.ResetHelp} -
-
- -
- ${this._metadata.metadata.WakeupHelp} +
+ + Refresh Node +
+ + ${this._metadata + ? html` + +
+ ${this._metadata.metadata.Description} +
+
+ +
+ ${this._metadata.metadata.InclusionHelp} +
+
+ +
+ ${this._metadata.metadata.ExclusionHelp} +
+
+ +
+ ${this._metadata.metadata.ResetHelp} +
+
+ +
+ ${this._metadata.metadata.WakeupHelp} +
+
+ ` + : ``} ` : ``} @@ -140,16 +148,24 @@ class OZWNodeDashboard extends LitElement { private async _fetchData() { if (!this.ozwInstance || !this.nodeId) return; - this._node = await fetchOZWNodeStatus( - this.hass!, - this.ozwInstance, - this.nodeId - ); - this._metadata = await fetchOZWNodeMetadata( - this.hass!, - this.ozwInstance, - this.nodeId - ); + try { + this._node = await fetchOZWNodeStatus( + this.hass!, + this.ozwInstance, + this.nodeId + ); + this._metadata = await fetchOZWNodeMetadata( + this.hass!, + this.ozwInstance, + this.nodeId + ); + } catch (err) { + if (err.code === ERR_NOT_FOUND) { + this._not_found = true; + return; + } + throw err; + } } private async _refreshNodeClicked() { From 547292cb8c4c4701c67671484d3237a34fb6704e Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Fri, 4 Sep 2020 13:26:31 -0400 Subject: [PATCH 16/16] Review comments --- .../integration-panels/ozw/ozw-node-dashboard.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index ce04b8688519..bd2fa6af3e75 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -64,7 +64,7 @@ class OZWNodeDashboard extends LitElement { if (this._not_found) { return html` `; } @@ -146,7 +146,9 @@ class OZWNodeDashboard extends LitElement { } private async _fetchData() { - if (!this.ozwInstance || !this.nodeId) return; + if (!this.ozwInstance || !this.nodeId) { + return; + } try { this._node = await fetchOZWNodeStatus(