@matter-server/dashboard 0.2.0-alpha.0-00000000-000000000
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +11 -0
- package/dist/esm/client/client-context.d.ts +10 -0
- package/dist/esm/client/client-context.d.ts.map +1 -0
- package/dist/esm/client/client-context.js +11 -0
- package/dist/esm/client/client-context.js.map +6 -0
- package/dist/esm/client/models/descriptions.d.ts +20 -0
- package/dist/esm/client/models/descriptions.d.ts.map +1 -0
- package/dist/esm/client/models/descriptions.js +10929 -0
- package/dist/esm/client/models/descriptions.js.map +6 -0
- package/dist/esm/components/dialog-box/dialog-box.d.ts +25 -0
- package/dist/esm/components/dialog-box/dialog-box.d.ts.map +1 -0
- package/dist/esm/components/dialog-box/dialog-box.js +66 -0
- package/dist/esm/components/dialog-box/dialog-box.js.map +6 -0
- package/dist/esm/components/dialog-box/show-dialog-box.d.ts +18 -0
- package/dist/esm/components/dialog-box/show-dialog-box.d.ts.map +1 -0
- package/dist/esm/components/dialog-box/show-dialog-box.js +22 -0
- package/dist/esm/components/dialog-box/show-dialog-box.js.map +6 -0
- package/dist/esm/components/dialogs/acl/model.d.ts +33 -0
- package/dist/esm/components/dialogs/acl/model.d.ts.map +1 -0
- package/dist/esm/components/dialogs/acl/model.js +79 -0
- package/dist/esm/components/dialogs/acl/model.js.map +6 -0
- package/dist/esm/components/dialogs/binding/model.d.ts +20 -0
- package/dist/esm/components/dialogs/binding/model.d.ts.map +1 -0
- package/dist/esm/components/dialogs/binding/model.js +45 -0
- package/dist/esm/components/dialogs/binding/model.js.map +6 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.d.ts +49 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js +357 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js.map +6 -0
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.d.ts +8 -0
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.js +17 -0
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts +31 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js +94 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts +17 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js +64 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts +19 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js +91 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts +20 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js +106 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.d.ts +8 -0
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.js +15 -0
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.js.map +6 -0
- package/dist/esm/components/ha-svg-icon.d.ts +19 -0
- package/dist/esm/components/ha-svg-icon.d.ts.map +1 -0
- package/dist/esm/components/ha-svg-icon.js +77 -0
- package/dist/esm/components/ha-svg-icon.js.map +6 -0
- package/dist/esm/entrypoint/main.d.ts +7 -0
- package/dist/esm/entrypoint/main.d.ts.map +1 -0
- package/dist/esm/entrypoint/main.js +45 -0
- package/dist/esm/entrypoint/main.js.map +6 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/pages/components/context.d.ts +9 -0
- package/dist/esm/pages/components/context.d.ts.map +1 -0
- package/dist/esm/pages/components/context.js +11 -0
- package/dist/esm/pages/components/context.js.map +6 -0
- package/dist/esm/pages/components/footer.d.ts +11 -0
- package/dist/esm/pages/components/footer.d.ts.map +1 -0
- package/dist/esm/pages/components/footer.js +52 -0
- package/dist/esm/pages/components/footer.js.map +6 -0
- package/dist/esm/pages/components/header.d.ts +27 -0
- package/dist/esm/pages/components/header.d.ts.map +1 -0
- package/dist/esm/pages/components/header.js +90 -0
- package/dist/esm/pages/components/header.js.map +6 -0
- package/dist/esm/pages/components/node-details.d.ts +29 -0
- package/dist/esm/pages/components/node-details.d.ts.map +1 -0
- package/dist/esm/pages/components/node-details.js +241 -0
- package/dist/esm/pages/components/node-details.js.map +6 -0
- package/dist/esm/pages/components/server-details.d.ts +24 -0
- package/dist/esm/pages/components/server-details.d.ts.map +1 -0
- package/dist/esm/pages/components/server-details.js +130 -0
- package/dist/esm/pages/components/server-details.js.map +6 -0
- package/dist/esm/pages/matter-cluster-view.d.ts +30 -0
- package/dist/esm/pages/matter-cluster-view.d.ts.map +1 -0
- package/dist/esm/pages/matter-cluster-view.js +154 -0
- package/dist/esm/pages/matter-cluster-view.js.map +6 -0
- package/dist/esm/pages/matter-dashboard-app.d.ts +27 -0
- package/dist/esm/pages/matter-dashboard-app.d.ts.map +1 -0
- package/dist/esm/pages/matter-dashboard-app.js +122 -0
- package/dist/esm/pages/matter-dashboard-app.js.map +6 -0
- package/dist/esm/pages/matter-endpoint-view.d.ts +29 -0
- package/dist/esm/pages/matter-endpoint-view.d.ts.map +1 -0
- package/dist/esm/pages/matter-endpoint-view.js +149 -0
- package/dist/esm/pages/matter-endpoint-view.js.map +6 -0
- package/dist/esm/pages/matter-node-view.d.ts +28 -0
- package/dist/esm/pages/matter-node-view.d.ts.map +1 -0
- package/dist/esm/pages/matter-node-view.js +122 -0
- package/dist/esm/pages/matter-node-view.js.map +6 -0
- package/dist/esm/pages/matter-server-view.d.ts +31 -0
- package/dist/esm/pages/matter-server-view.d.ts.map +1 -0
- package/dist/esm/pages/matter-server-view.js +113 -0
- package/dist/esm/pages/matter-server-view.js.map +6 -0
- package/dist/esm/util/clone_class.d.ts +7 -0
- package/dist/esm/util/clone_class.d.ts.map +1 -0
- package/dist/esm/util/clone_class.js +10 -0
- package/dist/esm/util/clone_class.js.map +6 -0
- package/dist/esm/util/fire_event.d.ts +34 -0
- package/dist/esm/util/fire_event.d.ts.map +1 -0
- package/dist/esm/util/fire_event.js +21 -0
- package/dist/esm/util/fire_event.js.map +6 -0
- package/dist/esm/util/prevent_default.d.ts +7 -0
- package/dist/esm/util/prevent_default.d.ts.map +1 -0
- package/dist/esm/util/prevent_default.js +10 -0
- package/dist/esm/util/prevent_default.js.map +6 -0
- package/dist/esm/util/routing.d.ts +10 -0
- package/dist/esm/util/routing.d.ts.map +1 -0
- package/dist/esm/util/routing.js +6 -0
- package/dist/esm/util/routing.js.map +6 -0
- package/dist/web/index.html +40 -0
- package/dist/web/js/commission-node-dialog-BJsfA4IV.js +78 -0
- package/dist/web/js/commission-node-dialog-DEZ3EqYO.js +78 -0
- package/dist/web/js/commission-node-existing-CzRtUgBm.js +50 -0
- package/dist/web/js/commission-node-existing-OK1ybPFI.js +50 -0
- package/dist/web/js/commission-node-thread-DLmclivF.js +75 -0
- package/dist/web/js/commission-node-thread-FcLFz84I.js +75 -0
- package/dist/web/js/commission-node-wifi-C8ho-UYb.js +88 -0
- package/dist/web/js/commission-node-wifi-C8iGfy7c.js +88 -0
- package/dist/web/js/dialog-box-BPz-oO3d.js +52 -0
- package/dist/web/js/dialog-box-DN32sjfR.js +52 -0
- package/dist/web/js/fire_event-BERTqZpV.js +169 -0
- package/dist/web/js/fire_event-BlsbXpOL.js +169 -0
- package/dist/web/js/main.js +547 -0
- package/dist/web/js/matter-dashboard-app-5UjO1Ik8.js +16068 -0
- package/dist/web/js/matter-dashboard-app-BazvuIIi.js +16068 -0
- package/dist/web/js/node-binding-dialog-2yitVn0R.js +443 -0
- package/dist/web/js/node-binding-dialog-Cw6QEmL3.js +443 -0
- package/dist/web/js/outlined-text-field-BMLYwwlc.js +2086 -0
- package/dist/web/js/outlined-text-field-Sqd4JHxo.js +2086 -0
- package/dist/web/js/prevent_default-BsT53c0u.js +814 -0
- package/dist/web/js/prevent_default-D4GG_QeD.js +814 -0
- package/package.json +54 -0
- package/src/client/client-context.ts +10 -0
- package/src/client/models/descriptions.ts +10948 -0
- package/src/components/dialog-box/dialog-box.ts +62 -0
- package/src/components/dialog-box/show-dialog-box.ts +32 -0
- package/src/components/dialogs/acl/model.ts +105 -0
- package/src/components/dialogs/binding/model.ts +58 -0
- package/src/components/dialogs/binding/node-binding-dialog.ts +419 -0
- package/src/components/dialogs/binding/show-node-binding-dialog.ts +16 -0
- package/src/components/dialogs/commission-node-dialog/commission-node-dialog.ts +102 -0
- package/src/components/dialogs/commission-node-dialog/commission-node-existing.ts +49 -0
- package/src/components/dialogs/commission-node-dialog/commission-node-thread.ts +76 -0
- package/src/components/dialogs/commission-node-dialog/commission-node-wifi.ts +90 -0
- package/src/components/dialogs/commission-node-dialog/show-commission-node-dialog.ts +14 -0
- package/src/components/ha-svg-icon.ts +66 -0
- package/src/entrypoint/main.ts +60 -0
- package/src/pages/components/context.ts +10 -0
- package/src/pages/components/footer.ts +39 -0
- package/src/pages/components/header.ts +87 -0
- package/src/pages/components/node-details.ts +252 -0
- package/src/pages/components/server-details.ts +124 -0
- package/src/pages/matter-cluster-view.ts +162 -0
- package/src/pages/matter-dashboard-app.ts +125 -0
- package/src/pages/matter-endpoint-view.ts +152 -0
- package/src/pages/matter-node-view.ts +126 -0
- package/src/pages/matter-server-view.ts +117 -0
- package/src/tsconfig.json +16 -0
- package/src/util/clone_class.ts +7 -0
- package/src/util/fire_event.ts +83 -0
- package/src/util/prevent_default.ts +7 -0
- package/src/util/routing.ts +10 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import "@material/web/divider/divider";
|
|
8
|
+
import "@material/web/iconbutton/icon-button";
|
|
9
|
+
import "@material/web/list/list";
|
|
10
|
+
import "@material/web/list/list-item";
|
|
11
|
+
import { MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
12
|
+
import { mdiChevronRight } from "@mdi/js";
|
|
13
|
+
import { LitElement, css, html } from "lit";
|
|
14
|
+
import { customElement, property } from "lit/decorators.js";
|
|
15
|
+
import { guard } from "lit/directives/guard.js";
|
|
16
|
+
import { DeviceType, clusters, device_types } from "../client/models/descriptions.js";
|
|
17
|
+
import "../components/ha-svg-icon";
|
|
18
|
+
|
|
19
|
+
declare global {
|
|
20
|
+
interface HTMLElementTagNameMap {
|
|
21
|
+
"matter-endpoint-view": MatterEndpointView;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getUniqueClusters(node: MatterNode, endpoint: number) {
|
|
26
|
+
return Array.from(
|
|
27
|
+
new Set(
|
|
28
|
+
Object.keys(node.attributes)
|
|
29
|
+
.filter(key => key.startsWith(`${endpoint.toString()}/`))
|
|
30
|
+
.map(key => Number(key.split("/")[1])),
|
|
31
|
+
),
|
|
32
|
+
).sort((a, b) => {
|
|
33
|
+
return a - b;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getEndpointDeviceTypes(node: MatterNode, endpoint: number): DeviceType[] {
|
|
38
|
+
const rawValues = node.attributes[`${endpoint}/29/0`] as Record<string, number>[] | undefined;
|
|
39
|
+
if (!rawValues) return [];
|
|
40
|
+
return rawValues.map(rawValue => {
|
|
41
|
+
const id = rawValue["0"] ?? rawValue["deviceType"];
|
|
42
|
+
return device_types[id] || { id: id ?? -1, label: `Unknown Device Type (${id})`, clusters: [] };
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@customElement("matter-endpoint-view")
|
|
47
|
+
class MatterEndpointView extends LitElement {
|
|
48
|
+
public client!: MatterClient;
|
|
49
|
+
|
|
50
|
+
@property()
|
|
51
|
+
public node?: MatterNode;
|
|
52
|
+
|
|
53
|
+
@property()
|
|
54
|
+
public endpoint?: number;
|
|
55
|
+
|
|
56
|
+
override render() {
|
|
57
|
+
if (!this.node || this.endpoint == undefined) {
|
|
58
|
+
return html`
|
|
59
|
+
<p>Node or endpoint not found!</p>
|
|
60
|
+
<button @click=${this._goBack}>Back</button>
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return html`
|
|
65
|
+
<dashboard-header
|
|
66
|
+
.title=${`Node ${this.node.node_id} | Endpoint ${this.endpoint}`}
|
|
67
|
+
.backButton=${`#node/${this.node.node_id}`}
|
|
68
|
+
.client=${this.client}
|
|
69
|
+
></dashboard-header>
|
|
70
|
+
|
|
71
|
+
<!-- node details section -->
|
|
72
|
+
<div class="container">
|
|
73
|
+
<node-details .node=${this.node} .client=${this.client}></node-details>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<!-- Endpoint clusters listing -->
|
|
77
|
+
<div class="container">
|
|
78
|
+
<md-list>
|
|
79
|
+
<md-list-item>
|
|
80
|
+
<div slot="headline">
|
|
81
|
+
<b>Clusters on Endpoint ${this.endpoint}</b>
|
|
82
|
+
</div>
|
|
83
|
+
<div slot="supporting-text">
|
|
84
|
+
Device Type(s):
|
|
85
|
+
${getEndpointDeviceTypes(this.node, this.endpoint)
|
|
86
|
+
.map(deviceType => {
|
|
87
|
+
return deviceType.label;
|
|
88
|
+
})
|
|
89
|
+
.join(" / ")}
|
|
90
|
+
</div>
|
|
91
|
+
</md-list-item>
|
|
92
|
+
${guard([this.node?.attributes.length], () =>
|
|
93
|
+
getUniqueClusters(this.node!, this.endpoint!).map(cluster => {
|
|
94
|
+
return html`
|
|
95
|
+
<md-list-item
|
|
96
|
+
type="link"
|
|
97
|
+
href=${`#node/${this.node!.node_id}/${this.endpoint}/${cluster}`}
|
|
98
|
+
>
|
|
99
|
+
<div slot="headline">${clusters[cluster]?.label || "Custom/Unknown Cluster"}</div>
|
|
100
|
+
<div slot="supporting-text">ClusterId ${cluster} (0x00${cluster.toString(16)})</div>
|
|
101
|
+
<ha-svg-icon slot="end" .path=${mdiChevronRight}></ha-svg-icon>
|
|
102
|
+
</md-list-item>
|
|
103
|
+
`;
|
|
104
|
+
}),
|
|
105
|
+
)}
|
|
106
|
+
</md-list>
|
|
107
|
+
</div>
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private _goBack() {
|
|
112
|
+
history.back();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static override styles = css`
|
|
116
|
+
:host {
|
|
117
|
+
display: block;
|
|
118
|
+
background-color: var(--md-sys-color-background);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.header {
|
|
122
|
+
background-color: var(--md-sys-color-primary);
|
|
123
|
+
color: var(--md-sys-color-on-primary);
|
|
124
|
+
--icon-primary-color: var(--md-sys-color-on-primary);
|
|
125
|
+
font-weight: 400;
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
padding-right: 8px;
|
|
129
|
+
height: 48px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
md-icon-button {
|
|
133
|
+
margin-right: 8px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.flex {
|
|
137
|
+
flex: 1;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.container {
|
|
141
|
+
padding: 16px;
|
|
142
|
+
max-width: 95%;
|
|
143
|
+
margin: 0 auto;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.status {
|
|
147
|
+
color: var(--danger-color);
|
|
148
|
+
font-weight: bold;
|
|
149
|
+
font-size: 0.8em;
|
|
150
|
+
}
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import "@material/web/divider/divider";
|
|
8
|
+
import "@material/web/iconbutton/icon-button";
|
|
9
|
+
import "@material/web/list/list";
|
|
10
|
+
import "@material/web/list/list-item";
|
|
11
|
+
import { MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
12
|
+
import { mdiChevronRight } from "@mdi/js";
|
|
13
|
+
import { LitElement, css, html } from "lit";
|
|
14
|
+
import { customElement, property } from "lit/decorators.js";
|
|
15
|
+
import { guard } from "lit/directives/guard.js";
|
|
16
|
+
import "../components/ha-svg-icon";
|
|
17
|
+
import "./components/header";
|
|
18
|
+
import "./components/node-details";
|
|
19
|
+
import { getEndpointDeviceTypes } from "./matter-endpoint-view.js";
|
|
20
|
+
|
|
21
|
+
declare global {
|
|
22
|
+
interface HTMLElementTagNameMap {
|
|
23
|
+
"matter-node-view": MatterNodeView;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getUniqueEndpoints(node: MatterNode) {
|
|
28
|
+
// extract unique endpoints from the node attributes, as (sorted) array
|
|
29
|
+
return Array.from(new Set(Object.keys(node.attributes).map(key => Number(key.split("/")[0])))).sort((a, b) => {
|
|
30
|
+
return a - b;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@customElement("matter-node-view")
|
|
35
|
+
class MatterNodeView extends LitElement {
|
|
36
|
+
public client!: MatterClient;
|
|
37
|
+
|
|
38
|
+
@property()
|
|
39
|
+
public node?: MatterNode;
|
|
40
|
+
|
|
41
|
+
override render() {
|
|
42
|
+
if (!this.node) {
|
|
43
|
+
return html`
|
|
44
|
+
<p>Node not found!</p>
|
|
45
|
+
<button @click=${this._goBack}>Back</button>
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return html`
|
|
50
|
+
<dashboard-header
|
|
51
|
+
.title=${"Node " + this.node.node_id}
|
|
52
|
+
.client=${this.client}
|
|
53
|
+
backButton="#"
|
|
54
|
+
></dashboard-header>
|
|
55
|
+
|
|
56
|
+
<!-- node details section -->
|
|
57
|
+
<div class="container">
|
|
58
|
+
<node-details .node=${this.node} .client=${this.client}></node-details>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<!-- Node Endpoints listing -->
|
|
62
|
+
<div class="container">
|
|
63
|
+
<md-list>
|
|
64
|
+
<md-list-item>
|
|
65
|
+
<div slot="headline">
|
|
66
|
+
<b>Endpoints</b>
|
|
67
|
+
</div>
|
|
68
|
+
</md-list-item>
|
|
69
|
+
${guard([this.node?.attributes.length], () =>
|
|
70
|
+
getUniqueEndpoints(this.node!).map(endPointId => {
|
|
71
|
+
return html`
|
|
72
|
+
<md-list-item type="link" href=${`#node/${this.node!.node_id}/${endPointId}`}>
|
|
73
|
+
<div slot="headline">Endpoint ${endPointId}</div>
|
|
74
|
+
<div slot="supporting-text">
|
|
75
|
+
Device Type(s):
|
|
76
|
+
${getEndpointDeviceTypes(this.node!, endPointId)
|
|
77
|
+
.map(deviceType => {
|
|
78
|
+
return deviceType.label;
|
|
79
|
+
})
|
|
80
|
+
.join(" / ")}
|
|
81
|
+
</div>
|
|
82
|
+
<ha-svg-icon slot="end" .path=${mdiChevronRight}></ha-svg-icon>
|
|
83
|
+
</md-list-item>
|
|
84
|
+
`;
|
|
85
|
+
}),
|
|
86
|
+
)}
|
|
87
|
+
</md-list>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<dashboard-footer />
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private _goBack() {
|
|
95
|
+
history.back();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static override styles = css`
|
|
99
|
+
:host {
|
|
100
|
+
display: flex;
|
|
101
|
+
background-color: var(--md-sys-color-background);
|
|
102
|
+
box-sizing: border-box;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
min-height: 100vh;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.container {
|
|
108
|
+
padding: 16px;
|
|
109
|
+
max-width: 95%;
|
|
110
|
+
margin: 0 auto;
|
|
111
|
+
width: 100%;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@media (max-width: 600px) {
|
|
115
|
+
.container {
|
|
116
|
+
padding: 16px 0;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.status {
|
|
121
|
+
color: var(--danger-color);
|
|
122
|
+
font-weight: bold;
|
|
123
|
+
font-size: 0.8em;
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import "@material/web/divider/divider";
|
|
8
|
+
import "@material/web/iconbutton/icon-button";
|
|
9
|
+
import "@material/web/list/list";
|
|
10
|
+
import "@material/web/list/list-item";
|
|
11
|
+
import { MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
12
|
+
import { mdiChevronRight } from "@mdi/js";
|
|
13
|
+
import { LitElement, css, html, nothing } from "lit";
|
|
14
|
+
import { customElement, property } from "lit/decorators.js";
|
|
15
|
+
import "../components/ha-svg-icon";
|
|
16
|
+
import "./components/footer";
|
|
17
|
+
import "./components/header";
|
|
18
|
+
import "./components/server-details";
|
|
19
|
+
|
|
20
|
+
declare global {
|
|
21
|
+
interface HTMLElementTagNameMap {
|
|
22
|
+
"matter-server-view": MatterServerView;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@customElement("matter-server-view")
|
|
27
|
+
class MatterServerView extends LitElement {
|
|
28
|
+
public client!: MatterClient;
|
|
29
|
+
|
|
30
|
+
@property()
|
|
31
|
+
public nodes!: MatterClient["nodes"];
|
|
32
|
+
|
|
33
|
+
private _cachedNodes?: MatterClient["nodes"];
|
|
34
|
+
private _cachedNodeEntries?: [string, MatterNode][];
|
|
35
|
+
|
|
36
|
+
private getNodeEntries(nodes: MatterClient["nodes"]): [string, MatterNode][] {
|
|
37
|
+
if (nodes !== this._cachedNodes) {
|
|
38
|
+
this._cachedNodes = nodes;
|
|
39
|
+
this._cachedNodeEntries = Object.entries(nodes);
|
|
40
|
+
}
|
|
41
|
+
return this._cachedNodeEntries!;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
override render() {
|
|
45
|
+
const nodes = this.getNodeEntries(this.nodes);
|
|
46
|
+
|
|
47
|
+
return html`
|
|
48
|
+
<dashboard-header title="Open Home Foundation Matter Server" .client=${this.client}></dashboard-header>
|
|
49
|
+
|
|
50
|
+
<!-- server details section -->
|
|
51
|
+
<div class="container">
|
|
52
|
+
<server-details .client=${this.client}></server-details>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<!-- Nodes listing -->
|
|
56
|
+
<div class="container">
|
|
57
|
+
<md-list>
|
|
58
|
+
<md-list-item>
|
|
59
|
+
<div slot="headline">
|
|
60
|
+
<b>Nodes</b>
|
|
61
|
+
</div>
|
|
62
|
+
</md-list-item>
|
|
63
|
+
${nodes.map(([_id, node]) => {
|
|
64
|
+
return html`
|
|
65
|
+
<md-list-item type="link" href=${`#node/${node.node_id}`}>
|
|
66
|
+
<div slot="headline">
|
|
67
|
+
Node ${node.node_id}
|
|
68
|
+
${node.available ? "" : html`<span class="status">OFFLINE</span>`}
|
|
69
|
+
</div>
|
|
70
|
+
<div slot="supporting-text">
|
|
71
|
+
${node.nodeLabel ? `${node.nodeLabel} | ` : nothing} ${node.vendorName} |
|
|
72
|
+
${node.productName}
|
|
73
|
+
</div>
|
|
74
|
+
<ha-svg-icon slot="end" .path=${mdiChevronRight}></ha-svg-icon>
|
|
75
|
+
</md-list-item>
|
|
76
|
+
`;
|
|
77
|
+
})}
|
|
78
|
+
</md-list>
|
|
79
|
+
</div>
|
|
80
|
+
<dashboard-footer />
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static override styles = css`
|
|
85
|
+
:host {
|
|
86
|
+
display: flex;
|
|
87
|
+
background-color: var(--md-sys-color-background);
|
|
88
|
+
box-sizing: border-box;
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.container {
|
|
93
|
+
padding: 16px;
|
|
94
|
+
max-width: 95%;
|
|
95
|
+
margin: 0 auto;
|
|
96
|
+
flex: 1;
|
|
97
|
+
width: 100%;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@media (max-width: 600px) {
|
|
101
|
+
.container {
|
|
102
|
+
padding: 16px 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
span[slot="start"] {
|
|
107
|
+
width: 40px;
|
|
108
|
+
text-align: center;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.status {
|
|
112
|
+
color: var(--danger-color);
|
|
113
|
+
font-weight: bold;
|
|
114
|
+
font-size: 0.8em;
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tools/tsc/tsconfig.lib.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"types": [
|
|
5
|
+
"globals"
|
|
6
|
+
],
|
|
7
|
+
"experimentalDecorators": true,
|
|
8
|
+
"useDefineForClassFields": false,
|
|
9
|
+
"allowSyntheticDefaultImports": true
|
|
10
|
+
},
|
|
11
|
+
"references": [
|
|
12
|
+
{
|
|
13
|
+
"path": "../../ws-client/src"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Polymer legacy event helpers used courtesy of the Polymer project.
|
|
8
|
+
//
|
|
9
|
+
// Copyright (c) 2017 The Polymer Authors. All rights reserved.
|
|
10
|
+
//
|
|
11
|
+
// Redistribution and use in source and binary forms, with or without
|
|
12
|
+
// modification, are permitted provided that the following conditions are
|
|
13
|
+
// met:
|
|
14
|
+
//
|
|
15
|
+
// * Redistributions of source code must retain the above copyright
|
|
16
|
+
// notice, this list of conditions and the following disclaimer.
|
|
17
|
+
// * Redistributions in binary form must reproduce the above
|
|
18
|
+
// copyright notice, this list of conditions and the following disclaimer
|
|
19
|
+
// in the documentation and/or other materials provided with the
|
|
20
|
+
// distribution.
|
|
21
|
+
// * Neither the name of Google Inc. nor the names of its
|
|
22
|
+
// contributors may be used to endorse or promote products derived from
|
|
23
|
+
// this software without specific prior written permission.
|
|
24
|
+
//
|
|
25
|
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
26
|
+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
27
|
+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
28
|
+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
29
|
+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
30
|
+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
31
|
+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
32
|
+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
33
|
+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
34
|
+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
35
|
+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
36
|
+
|
|
37
|
+
declare global {
|
|
38
|
+
interface HASSDomEvents {}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type ValidHassDomEvent = keyof HASSDomEvents;
|
|
42
|
+
|
|
43
|
+
export interface HASSDomEvent<T> extends Event {
|
|
44
|
+
detail: T;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Dispatches a custom event with an optional detail value.
|
|
49
|
+
*
|
|
50
|
+
* @param {string} type Name of event type.
|
|
51
|
+
* @param {*=} detail Detail value containing event-specific
|
|
52
|
+
* payload.
|
|
53
|
+
* @param {{ bubbles: (boolean|undefined),
|
|
54
|
+
* cancelable: (boolean|undefined),
|
|
55
|
+
* composed: (boolean|undefined) }=}
|
|
56
|
+
* options Object specifying options. These may include:
|
|
57
|
+
* `bubbles` (boolean, defaults to `true`),
|
|
58
|
+
* `cancelable` (boolean, defaults to false), and
|
|
59
|
+
* `node` on which to fire the event (HTMLElement, defaults to `this`).
|
|
60
|
+
* @return {Event} The new event that was fired.
|
|
61
|
+
*/
|
|
62
|
+
export const fireEvent = <HassEvent extends ValidHassDomEvent>(
|
|
63
|
+
node: HTMLElement | Window,
|
|
64
|
+
type: HassEvent,
|
|
65
|
+
detail?: HASSDomEvents[HassEvent],
|
|
66
|
+
options?: {
|
|
67
|
+
bubbles?: boolean;
|
|
68
|
+
cancelable?: boolean;
|
|
69
|
+
composed?: boolean;
|
|
70
|
+
},
|
|
71
|
+
) => {
|
|
72
|
+
options = options || {};
|
|
73
|
+
// @ts-expect-error why?
|
|
74
|
+
detail = detail === null || detail === undefined ? {} : detail;
|
|
75
|
+
const event = new Event(type, {
|
|
76
|
+
bubbles: options.bubbles === undefined ? true : options.bubbles,
|
|
77
|
+
cancelable: Boolean(options.cancelable),
|
|
78
|
+
composed: options.composed === undefined ? true : options.composed,
|
|
79
|
+
});
|
|
80
|
+
(event as any).detail = detail;
|
|
81
|
+
node.dispatchEvent(event);
|
|
82
|
+
return event;
|
|
83
|
+
};
|