/** * @license * Copyright 2025-2026 Open Home Foundation * SPDX-License-Identifier: Apache-2.0 */ import "@material/web/divider/divider"; import "@material/web/iconbutton/icon-button"; import "@material/web/list/list"; import "@material/web/list/list-item"; import { consume } from "@lit/context"; import { isTestNodeId, MatterClient, MatterNode } from "@matter-server/ws-client"; import { mdiChevronRight } from "@mdi/js"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators.js"; import { clientContext, tickContext } from "../client/client-context.js"; import "../components/ha-svg-icon"; import { getDeviceIcon } from "../util/device-icons.js"; import { formatNodeAddress } from "../util/format_hex.js"; import "./components/footer"; import "./components/header"; import type { ActiveView } from "./components/header.js"; import "./components/server-details"; declare global { interface HTMLElementTagNameMap { "matter-server-view": MatterServerView; } } @customElement("matter-server-view") class MatterServerView extends LitElement { @consume({ context: clientContext }) public client!: MatterClient; @consume({ context: tickContext, subscribe: true }) protected _tick = 0; @property() public nodes!: MatterClient["nodes"]; @property() public activeView?: ActiveView; @property({ type: Boolean }) public hasThreadDevices?: boolean; @property({ type: Boolean }) public hasWifiDevices?: boolean; private _cachedNodes?: MatterClient["nodes"]; private _cachedNodeEntries?: [string, MatterNode][]; private getNodeEntries(nodes: MatterClient["nodes"]): [string, MatterNode][] { if (nodes !== this._cachedNodes) { this._cachedNodes = nodes; this._cachedNodeEntries = Object.entries(nodes); } return this._cachedNodeEntries!; } override render() { const nodes = this.getNodeEntries(this.nodes); return html`
Nodes
${nodes.map(([_id, node]) => { return html`
Node ${node.node_id} (${formatNodeAddress( isTestNodeId(node.node_id) || this.client.serverInfo.fabric_index === undefined ? undefined : this.client.serverInfo.fabric_index, node.node_id, )}) ${node.available ? "" : html` OFFLINE `}
${node.nodeLabel ? `${node.nodeLabel} | ` : nothing} ${node.vendorName} | ${node.productName}
`; })}
`; } static override styles = css` :host { display: flex; background-color: var(--md-sys-color-background); box-sizing: border-box; flex-direction: column; } .container { padding: 16px; max-width: 95%; margin: 0 auto; flex: 1; width: 100%; } @media (max-width: 600px) { .container { padding: 16px 0; } } .device-icon { --icon-primary-color: var(--md-sys-color-on-surface-variant, #666); } span[slot="start"] { width: 40px; text-align: center; } .status { color: var(--danger-color); font-weight: bold; font-size: 0.8em; margin-left: 8px; } .hex-id { color: var(--text-color, rgba(0, 0, 0, 0.6)); font-size: 0.85em; word-break: break-all; } @media (max-width: 400px) { .hex-id { display: block; margin-top: 2px; } } `; }