@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.
Files changed (172) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +11 -0
  3. package/dist/esm/client/client-context.d.ts +10 -0
  4. package/dist/esm/client/client-context.d.ts.map +1 -0
  5. package/dist/esm/client/client-context.js +11 -0
  6. package/dist/esm/client/client-context.js.map +6 -0
  7. package/dist/esm/client/models/descriptions.d.ts +20 -0
  8. package/dist/esm/client/models/descriptions.d.ts.map +1 -0
  9. package/dist/esm/client/models/descriptions.js +10929 -0
  10. package/dist/esm/client/models/descriptions.js.map +6 -0
  11. package/dist/esm/components/dialog-box/dialog-box.d.ts +25 -0
  12. package/dist/esm/components/dialog-box/dialog-box.d.ts.map +1 -0
  13. package/dist/esm/components/dialog-box/dialog-box.js +66 -0
  14. package/dist/esm/components/dialog-box/dialog-box.js.map +6 -0
  15. package/dist/esm/components/dialog-box/show-dialog-box.d.ts +18 -0
  16. package/dist/esm/components/dialog-box/show-dialog-box.d.ts.map +1 -0
  17. package/dist/esm/components/dialog-box/show-dialog-box.js +22 -0
  18. package/dist/esm/components/dialog-box/show-dialog-box.js.map +6 -0
  19. package/dist/esm/components/dialogs/acl/model.d.ts +33 -0
  20. package/dist/esm/components/dialogs/acl/model.d.ts.map +1 -0
  21. package/dist/esm/components/dialogs/acl/model.js +79 -0
  22. package/dist/esm/components/dialogs/acl/model.js.map +6 -0
  23. package/dist/esm/components/dialogs/binding/model.d.ts +20 -0
  24. package/dist/esm/components/dialogs/binding/model.d.ts.map +1 -0
  25. package/dist/esm/components/dialogs/binding/model.js +45 -0
  26. package/dist/esm/components/dialogs/binding/model.js.map +6 -0
  27. package/dist/esm/components/dialogs/binding/node-binding-dialog.d.ts +49 -0
  28. package/dist/esm/components/dialogs/binding/node-binding-dialog.d.ts.map +1 -0
  29. package/dist/esm/components/dialogs/binding/node-binding-dialog.js +357 -0
  30. package/dist/esm/components/dialogs/binding/node-binding-dialog.js.map +6 -0
  31. package/dist/esm/components/dialogs/binding/show-node-binding-dialog.d.ts +8 -0
  32. package/dist/esm/components/dialogs/binding/show-node-binding-dialog.d.ts.map +1 -0
  33. package/dist/esm/components/dialogs/binding/show-node-binding-dialog.js +17 -0
  34. package/dist/esm/components/dialogs/binding/show-node-binding-dialog.js.map +6 -0
  35. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts +31 -0
  36. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts.map +1 -0
  37. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js +94 -0
  38. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js.map +6 -0
  39. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts +17 -0
  40. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts.map +1 -0
  41. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js +64 -0
  42. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js.map +6 -0
  43. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts +19 -0
  44. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts.map +1 -0
  45. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js +91 -0
  46. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js.map +6 -0
  47. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts +20 -0
  48. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts.map +1 -0
  49. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js +106 -0
  50. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js.map +6 -0
  51. package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.d.ts +8 -0
  52. package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.d.ts.map +1 -0
  53. package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.js +15 -0
  54. package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.js.map +6 -0
  55. package/dist/esm/components/ha-svg-icon.d.ts +19 -0
  56. package/dist/esm/components/ha-svg-icon.d.ts.map +1 -0
  57. package/dist/esm/components/ha-svg-icon.js +77 -0
  58. package/dist/esm/components/ha-svg-icon.js.map +6 -0
  59. package/dist/esm/entrypoint/main.d.ts +7 -0
  60. package/dist/esm/entrypoint/main.d.ts.map +1 -0
  61. package/dist/esm/entrypoint/main.js +45 -0
  62. package/dist/esm/entrypoint/main.js.map +6 -0
  63. package/dist/esm/package.json +3 -0
  64. package/dist/esm/pages/components/context.d.ts +9 -0
  65. package/dist/esm/pages/components/context.d.ts.map +1 -0
  66. package/dist/esm/pages/components/context.js +11 -0
  67. package/dist/esm/pages/components/context.js.map +6 -0
  68. package/dist/esm/pages/components/footer.d.ts +11 -0
  69. package/dist/esm/pages/components/footer.d.ts.map +1 -0
  70. package/dist/esm/pages/components/footer.js +52 -0
  71. package/dist/esm/pages/components/footer.js.map +6 -0
  72. package/dist/esm/pages/components/header.d.ts +27 -0
  73. package/dist/esm/pages/components/header.d.ts.map +1 -0
  74. package/dist/esm/pages/components/header.js +90 -0
  75. package/dist/esm/pages/components/header.js.map +6 -0
  76. package/dist/esm/pages/components/node-details.d.ts +29 -0
  77. package/dist/esm/pages/components/node-details.d.ts.map +1 -0
  78. package/dist/esm/pages/components/node-details.js +241 -0
  79. package/dist/esm/pages/components/node-details.js.map +6 -0
  80. package/dist/esm/pages/components/server-details.d.ts +24 -0
  81. package/dist/esm/pages/components/server-details.d.ts.map +1 -0
  82. package/dist/esm/pages/components/server-details.js +130 -0
  83. package/dist/esm/pages/components/server-details.js.map +6 -0
  84. package/dist/esm/pages/matter-cluster-view.d.ts +30 -0
  85. package/dist/esm/pages/matter-cluster-view.d.ts.map +1 -0
  86. package/dist/esm/pages/matter-cluster-view.js +154 -0
  87. package/dist/esm/pages/matter-cluster-view.js.map +6 -0
  88. package/dist/esm/pages/matter-dashboard-app.d.ts +27 -0
  89. package/dist/esm/pages/matter-dashboard-app.d.ts.map +1 -0
  90. package/dist/esm/pages/matter-dashboard-app.js +122 -0
  91. package/dist/esm/pages/matter-dashboard-app.js.map +6 -0
  92. package/dist/esm/pages/matter-endpoint-view.d.ts +29 -0
  93. package/dist/esm/pages/matter-endpoint-view.d.ts.map +1 -0
  94. package/dist/esm/pages/matter-endpoint-view.js +149 -0
  95. package/dist/esm/pages/matter-endpoint-view.js.map +6 -0
  96. package/dist/esm/pages/matter-node-view.d.ts +28 -0
  97. package/dist/esm/pages/matter-node-view.d.ts.map +1 -0
  98. package/dist/esm/pages/matter-node-view.js +122 -0
  99. package/dist/esm/pages/matter-node-view.js.map +6 -0
  100. package/dist/esm/pages/matter-server-view.d.ts +31 -0
  101. package/dist/esm/pages/matter-server-view.d.ts.map +1 -0
  102. package/dist/esm/pages/matter-server-view.js +113 -0
  103. package/dist/esm/pages/matter-server-view.js.map +6 -0
  104. package/dist/esm/util/clone_class.d.ts +7 -0
  105. package/dist/esm/util/clone_class.d.ts.map +1 -0
  106. package/dist/esm/util/clone_class.js +10 -0
  107. package/dist/esm/util/clone_class.js.map +6 -0
  108. package/dist/esm/util/fire_event.d.ts +34 -0
  109. package/dist/esm/util/fire_event.d.ts.map +1 -0
  110. package/dist/esm/util/fire_event.js +21 -0
  111. package/dist/esm/util/fire_event.js.map +6 -0
  112. package/dist/esm/util/prevent_default.d.ts +7 -0
  113. package/dist/esm/util/prevent_default.d.ts.map +1 -0
  114. package/dist/esm/util/prevent_default.js +10 -0
  115. package/dist/esm/util/prevent_default.js.map +6 -0
  116. package/dist/esm/util/routing.d.ts +10 -0
  117. package/dist/esm/util/routing.d.ts.map +1 -0
  118. package/dist/esm/util/routing.js +6 -0
  119. package/dist/esm/util/routing.js.map +6 -0
  120. package/dist/web/index.html +40 -0
  121. package/dist/web/js/commission-node-dialog-BJsfA4IV.js +78 -0
  122. package/dist/web/js/commission-node-dialog-DEZ3EqYO.js +78 -0
  123. package/dist/web/js/commission-node-existing-CzRtUgBm.js +50 -0
  124. package/dist/web/js/commission-node-existing-OK1ybPFI.js +50 -0
  125. package/dist/web/js/commission-node-thread-DLmclivF.js +75 -0
  126. package/dist/web/js/commission-node-thread-FcLFz84I.js +75 -0
  127. package/dist/web/js/commission-node-wifi-C8ho-UYb.js +88 -0
  128. package/dist/web/js/commission-node-wifi-C8iGfy7c.js +88 -0
  129. package/dist/web/js/dialog-box-BPz-oO3d.js +52 -0
  130. package/dist/web/js/dialog-box-DN32sjfR.js +52 -0
  131. package/dist/web/js/fire_event-BERTqZpV.js +169 -0
  132. package/dist/web/js/fire_event-BlsbXpOL.js +169 -0
  133. package/dist/web/js/main.js +547 -0
  134. package/dist/web/js/matter-dashboard-app-5UjO1Ik8.js +16068 -0
  135. package/dist/web/js/matter-dashboard-app-BazvuIIi.js +16068 -0
  136. package/dist/web/js/node-binding-dialog-2yitVn0R.js +443 -0
  137. package/dist/web/js/node-binding-dialog-Cw6QEmL3.js +443 -0
  138. package/dist/web/js/outlined-text-field-BMLYwwlc.js +2086 -0
  139. package/dist/web/js/outlined-text-field-Sqd4JHxo.js +2086 -0
  140. package/dist/web/js/prevent_default-BsT53c0u.js +814 -0
  141. package/dist/web/js/prevent_default-D4GG_QeD.js +814 -0
  142. package/package.json +54 -0
  143. package/src/client/client-context.ts +10 -0
  144. package/src/client/models/descriptions.ts +10948 -0
  145. package/src/components/dialog-box/dialog-box.ts +62 -0
  146. package/src/components/dialog-box/show-dialog-box.ts +32 -0
  147. package/src/components/dialogs/acl/model.ts +105 -0
  148. package/src/components/dialogs/binding/model.ts +58 -0
  149. package/src/components/dialogs/binding/node-binding-dialog.ts +419 -0
  150. package/src/components/dialogs/binding/show-node-binding-dialog.ts +16 -0
  151. package/src/components/dialogs/commission-node-dialog/commission-node-dialog.ts +102 -0
  152. package/src/components/dialogs/commission-node-dialog/commission-node-existing.ts +49 -0
  153. package/src/components/dialogs/commission-node-dialog/commission-node-thread.ts +76 -0
  154. package/src/components/dialogs/commission-node-dialog/commission-node-wifi.ts +90 -0
  155. package/src/components/dialogs/commission-node-dialog/show-commission-node-dialog.ts +14 -0
  156. package/src/components/ha-svg-icon.ts +66 -0
  157. package/src/entrypoint/main.ts +60 -0
  158. package/src/pages/components/context.ts +10 -0
  159. package/src/pages/components/footer.ts +39 -0
  160. package/src/pages/components/header.ts +87 -0
  161. package/src/pages/components/node-details.ts +252 -0
  162. package/src/pages/components/server-details.ts +124 -0
  163. package/src/pages/matter-cluster-view.ts +162 -0
  164. package/src/pages/matter-dashboard-app.ts +125 -0
  165. package/src/pages/matter-endpoint-view.ts +152 -0
  166. package/src/pages/matter-node-view.ts +126 -0
  167. package/src/pages/matter-server-view.ts +117 -0
  168. package/src/tsconfig.json +16 -0
  169. package/src/util/clone_class.ts +7 -0
  170. package/src/util/fire_event.ts +83 -0
  171. package/src/util/prevent_default.ts +7 -0
  172. package/src/util/routing.ts +10 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import "@material/web/button/text-button";
8
+ import "@material/web/dialog/dialog";
9
+ import type { MdDialog } from "@material/web/dialog/dialog.js";
10
+ import "@material/web/list/list";
11
+ import "@material/web/list/list-item";
12
+ import { MatterClient, MatterNode } from "@matter-server/ws-client";
13
+ import { html, LitElement } from "lit";
14
+ import { customElement, property, state } from "lit/decorators.js";
15
+ import { preventDefault } from "../../../util/prevent_default.js";
16
+
17
+ @customElement("commission-node-dialog")
18
+ export class ComissionNodeDialog extends LitElement {
19
+ @property({ attribute: false }) public client!: MatterClient;
20
+
21
+ @state() private _mode?: "wifi" | "thread" | "existing";
22
+
23
+ protected override render() {
24
+ return html`
25
+ <md-dialog open @cancel=${preventDefault} @closed=${this._handleClosed}>
26
+ <div slot="headline">Commission node</div>
27
+ <div slot="content" @node-commissioned=${this._nodeCommissioned}>
28
+ ${!this._mode
29
+ ? html`<md-list>
30
+ <md-list-item
31
+ type="button"
32
+ .disabled=${!this.client.serverInfo.bluetooth_enabled}
33
+ @click=${this._commissionWifi}
34
+ >Commission new WiFi device</md-list-item
35
+ >
36
+ <md-list-item
37
+ type="button"
38
+ .disabled=${!this.client.serverInfo.bluetooth_enabled}
39
+ @click=${this._commissionThread}
40
+ >Commission new Thread device</md-list-item
41
+ >
42
+ <md-list-item type="button" @click=${this._commissionExisting}
43
+ >Commission existing device</md-list-item
44
+ >
45
+ </md-list>`
46
+ : this._mode === "wifi"
47
+ ? html`<commission-node-wifi></commission-node-wifi>`
48
+ : this._mode === "thread"
49
+ ? html`<commission-node-thread></commission-node-thread>`
50
+ : html`<commission-node-existing></commission-node-existing>`}
51
+ </div>
52
+ <div slot="actions">
53
+ <md-text-button @click=${this._close}>Cancel</md-text-button>
54
+ </div>
55
+ </md-dialog>
56
+ `;
57
+ }
58
+
59
+ private _commissionWifi() {
60
+ if (!this.client.serverInfo.bluetooth_enabled) {
61
+ return;
62
+ }
63
+ import("./commission-node-wifi.js");
64
+ this._mode = "wifi";
65
+ }
66
+
67
+ private _commissionThread() {
68
+ if (!this.client.serverInfo.bluetooth_enabled) {
69
+ return;
70
+ }
71
+ import("./commission-node-thread.js");
72
+ this._mode = "thread";
73
+ }
74
+
75
+ private _commissionExisting() {
76
+ import("./commission-node-existing.js");
77
+ this._mode = "existing";
78
+ }
79
+
80
+ private _nodeCommissioned(ev: CustomEvent<MatterNode>) {
81
+ window.location.href = `#node/${ev.detail.node_id}`;
82
+ this._close();
83
+ }
84
+
85
+ private _close() {
86
+ this.shadowRoot!.querySelector<MdDialog>("md-dialog")!.close();
87
+ }
88
+
89
+ private _handleClosed() {
90
+ this.parentNode!.removeChild(this);
91
+ }
92
+ }
93
+
94
+ declare global {
95
+ interface HTMLElementTagNameMap {
96
+ "commission-node-dialog": ComissionNodeDialog;
97
+ }
98
+
99
+ interface HASSDomEvents {
100
+ "node-commissioned": MatterNode;
101
+ }
102
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { consume } from "@lit/context";
8
+ import "@material/web/progress/circular-progress";
9
+ import "@material/web/textfield/outlined-text-field";
10
+ import type { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field.js";
11
+ import { MatterClient } from "@matter-server/ws-client";
12
+ import { LitElement, html, nothing } from "lit";
13
+ import { customElement, property, query, state } from "lit/decorators.js";
14
+ import { clientContext } from "../../../client/client-context.js";
15
+ import { fireEvent } from "../../../util/fire_event.js";
16
+
17
+ @customElement("commission-node-existing")
18
+ export class CommissionNodeExisting extends LitElement {
19
+ @consume({ context: clientContext, subscribe: true })
20
+ @property({ attribute: false })
21
+ public client!: MatterClient;
22
+
23
+ @state()
24
+ private _loading: boolean = false;
25
+
26
+ @query("md-outlined-text-field[label='Share code']")
27
+ private _pairingCodeField!: MdOutlinedTextField;
28
+
29
+ protected override render() {
30
+ return html`<md-outlined-text-field label="Share code" .disabled="${this._loading}"> </md-outlined-text-field>
31
+ <br />
32
+ <br />
33
+ <md-outlined-button @click=${this._commissionNode} .disabled="${this._loading}"
34
+ >Commission</md-outlined-button
35
+ >${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
36
+ }
37
+
38
+ private async _commissionNode() {
39
+ this._loading = true;
40
+ try {
41
+ const node = await this.client.commissionWithCode(this._pairingCodeField.value, true);
42
+ fireEvent(this, "node-commissioned", node);
43
+ } catch (err) {
44
+ alert(`Error commissioning node: ${(err as Error).message}`);
45
+ } finally {
46
+ this._loading = false;
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { consume } from "@lit/context";
8
+ import "@material/web/progress/circular-progress";
9
+ import "@material/web/textfield/outlined-text-field";
10
+ import type { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field.js";
11
+ import { MatterClient } from "@matter-server/ws-client";
12
+ import { LitElement, html, nothing } from "lit";
13
+ import { customElement, property, query, state } from "lit/decorators.js";
14
+ import { clientContext } from "../../../client/client-context.js";
15
+ import { fireEvent } from "../../../util/fire_event.js";
16
+
17
+ @customElement("commission-node-thread")
18
+ export class CommissionNodeThread extends LitElement {
19
+ @consume({ context: clientContext, subscribe: true })
20
+ @property({ attribute: false })
21
+ public client!: MatterClient;
22
+
23
+ @state()
24
+ private _loading: boolean = false;
25
+
26
+ @query("md-outlined-text-field[label='Thread dataset']")
27
+ private _datasetField!: MdOutlinedTextField;
28
+ @query("md-outlined-text-field[label='Pairing code']")
29
+ private _pairingCodeField!: MdOutlinedTextField;
30
+
31
+ protected override render() {
32
+ if (!this.client.serverInfo.thread_credentials_set) {
33
+ return html`<md-outlined-text-field label="Thread dataset" .disabled="${this._loading}">
34
+ </md-outlined-text-field>
35
+ <br />
36
+ <br />
37
+ <md-outlined-button @click=${this._setThreadDataset} .disabled="${this._loading}"
38
+ >Set Thread Dataset</md-outlined-button
39
+ >${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
40
+ }
41
+ return html`<md-outlined-text-field label="Pairing code" .disabled="${this._loading}"> </md-outlined-text-field>
42
+ <br />
43
+ <br />
44
+ <md-outlined-button @click=${this._commissionNode} .disabled="${this._loading}"
45
+ >Commission</md-outlined-button
46
+ >${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
47
+ }
48
+
49
+ private async _setThreadDataset() {
50
+ const dataset = this._datasetField.value;
51
+ if (!dataset) {
52
+ alert("Dataset is required");
53
+ return;
54
+ }
55
+ this._loading = true;
56
+ try {
57
+ await this.client.setThreadOperationalDataset(dataset);
58
+ } catch (err) {
59
+ alert(`Error setting Thread dataset: ${(err as Error).message}`);
60
+ } finally {
61
+ this._loading = false;
62
+ }
63
+ }
64
+
65
+ private async _commissionNode() {
66
+ this._loading = true;
67
+ try {
68
+ const node = await this.client.commissionWithCode(this._pairingCodeField.value, false);
69
+ fireEvent(this, "node-commissioned", node);
70
+ } catch (err) {
71
+ alert(`Error commissioning node: ${(err as Error).message}`);
72
+ } finally {
73
+ this._loading = false;
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { consume } from "@lit/context";
8
+ import "@material/web/progress/circular-progress";
9
+ import "@material/web/textfield/outlined-text-field";
10
+ import type { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field.js";
11
+ import { MatterClient } from "@matter-server/ws-client";
12
+ import { LitElement, html, nothing } from "lit";
13
+ import { customElement, property, query, state } from "lit/decorators.js";
14
+ import { clientContext } from "../../../client/client-context.js";
15
+ import { fireEvent } from "../../../util/fire_event.js";
16
+
17
+ @customElement("commission-node-wifi")
18
+ export class CommissionNodeWifi extends LitElement {
19
+ @consume({ context: clientContext, subscribe: true })
20
+ @property({ attribute: false })
21
+ public client!: MatterClient;
22
+
23
+ @state()
24
+ private _loading: boolean = false;
25
+
26
+ @query("md-outlined-text-field[label='SSID']")
27
+ private _ssidField!: MdOutlinedTextField;
28
+ @query("md-outlined-text-field[label='Password']")
29
+ private _passwordField!: MdOutlinedTextField;
30
+ @query("md-outlined-text-field[label='Pairing code']")
31
+ private _pairingCodeField!: MdOutlinedTextField;
32
+
33
+ protected override render() {
34
+ if (!this.client.serverInfo.wifi_credentials_set) {
35
+ return html`<md-outlined-text-field label="SSID" .disabled="${this._loading}"> </md-outlined-text-field>
36
+ <md-outlined-text-field label="Password" type="password" .disabled="${this._loading}">
37
+ </md-outlined-text-field>
38
+ <br />
39
+ <br />
40
+ <md-outlined-button @click=${this._setWifiCredentials} .disabled="${this._loading}"
41
+ >Set WiFi Credentials</md-outlined-button
42
+ >${this._loading
43
+ ? html`<md-circular-progress indeterminate .visible="${this._loading}"></md-circular-progress>`
44
+ : nothing}`;
45
+ }
46
+ return html`<md-outlined-text-field label="Pairing code" .disabled="${this._loading}"> </md-outlined-text-field>
47
+ <br />
48
+ <br />
49
+ <md-outlined-button @click=${this._commissionNode} .disabled="${this._loading}"
50
+ >Commission</md-outlined-button
51
+ >${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
52
+ }
53
+
54
+ private _setWifiCredentials() {
55
+ const ssid = this._ssidField.value;
56
+ if (!ssid) {
57
+ alert("SSID is required");
58
+ return;
59
+ }
60
+ const password = this._passwordField.value;
61
+ if (!password) {
62
+ alert("Password is required");
63
+ return;
64
+ }
65
+ this._loading = true;
66
+ try {
67
+ this.client.setWifiCredentials(ssid, password);
68
+ } catch (err) {
69
+ alert(`Error setting WiFi credentials: \n${(err as Error).message}`);
70
+ } finally {
71
+ this._loading = false;
72
+ }
73
+ }
74
+
75
+ private async _commissionNode() {
76
+ try {
77
+ if (!this._pairingCodeField.value) {
78
+ alert("Pairing code is required");
79
+ return;
80
+ }
81
+ this._loading = true;
82
+ const node = await this.client.commissionWithCode(this._pairingCodeField.value, false);
83
+ fireEvent(this, "node-commissioned", node);
84
+ } catch (err) {
85
+ alert(`Error commissioning node: \n${(err as Error).message}`);
86
+ } finally {
87
+ this._loading = false;
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { MatterClient } from "@matter-server/ws-client";
8
+
9
+ export const showCommissionNodeDialog = async (client: MatterClient) => {
10
+ await import("./commission-node-dialog.js");
11
+ const dialog = document.createElement("commission-node-dialog");
12
+ dialog.client = client;
13
+ document.querySelector("matter-dashboard-app")?.renderRoot.appendChild(dialog);
14
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { css, CSSResultGroup, LitElement, nothing, svg, SVGTemplateResult } from "lit";
8
+ import { customElement, property } from "lit/decorators.js";
9
+
10
+ @customElement("ha-svg-icon")
11
+ export class HaSvgIcon extends LitElement {
12
+ @property() public path?: string;
13
+
14
+ @property() public secondaryPath?: string;
15
+
16
+ @property() public viewBox?: string;
17
+
18
+ protected override render(): SVGTemplateResult {
19
+ return svg`
20
+ <svg
21
+ viewBox=${this.viewBox || "0 0 24 24"}
22
+ preserveAspectRatio="xMidYMid meet"
23
+ focusable="false"
24
+ role="img"
25
+ aria-hidden="true"
26
+ >
27
+ <g>
28
+ ${this.path ? svg`<path class="primary-path" d=${this.path}></path>` : nothing}
29
+ ${this.secondaryPath ? svg`<path class="secondary-path" d=${this.secondaryPath}></path>` : nothing}
30
+ </g>
31
+ </svg>`;
32
+ }
33
+
34
+ static override get styles(): CSSResultGroup {
35
+ return css`
36
+ :host {
37
+ display: var(--ha-icon-display, inline-flex);
38
+ align-items: center;
39
+ justify-content: center;
40
+ position: relative;
41
+ vertical-align: middle;
42
+ fill: var(--icon-primary-color, currentcolor);
43
+ width: var(--mdc-icon-size, 24px);
44
+ height: var(--mdc-icon-size, 24px);
45
+ }
46
+ svg {
47
+ width: 100%;
48
+ height: 100%;
49
+ pointer-events: none;
50
+ display: block;
51
+ }
52
+ path.primary-path {
53
+ opacity: var(--icon-primary-opactity, 1);
54
+ }
55
+ path.secondary-path {
56
+ fill: var(--icon-secondary-color, currentcolor);
57
+ opacity: var(--icon-secondary-opactity, 0.5);
58
+ }
59
+ `;
60
+ }
61
+ }
62
+ declare global {
63
+ interface HTMLElementTagNameMap {
64
+ "ha-svg-icon": HaSvgIcon;
65
+ }
66
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { MatterClient } from "@matter-server/ws-client";
8
+
9
+ async function main() {
10
+ import("../pages/matter-dashboard-app.js");
11
+
12
+ let url = "";
13
+
14
+ // Detect if we're running in the (production) webserver included in the matter server or not.
15
+ const isProductionServer =
16
+ location.origin.includes(":5580") ||
17
+ location.href.includes("hassio_ingress") ||
18
+ location.href.includes("/api/ingress/");
19
+
20
+ if (!isProductionServer) {
21
+ // development server, ask for url to matter server
22
+ let storageUrl = localStorage.getItem("matterURL");
23
+ if (!storageUrl) {
24
+ const urlParams = new URLSearchParams(window.location.search);
25
+ const suggestedUrl = urlParams.get("url");
26
+ storageUrl = prompt(
27
+ "Enter Websocket URL to a running Matter Server",
28
+ suggestedUrl || "ws://localhost:5580/ws",
29
+ );
30
+ if (!storageUrl) {
31
+ alert("Unable to connect without URL");
32
+ return;
33
+ }
34
+ if (suggestedUrl) {
35
+ // Remove suggested url from address without redirecting
36
+ history.pushState({}, "", window.location.pathname);
37
+ }
38
+ localStorage.setItem("matterURL", storageUrl);
39
+ }
40
+ url = storageUrl;
41
+ } else {
42
+ // assume a production server running inside the matter server
43
+ // Turn httpX url into wsX url and append "/ws"
44
+ let baseUrl = window.location.origin + window.location.pathname;
45
+ if (baseUrl.endsWith("/")) {
46
+ baseUrl = baseUrl.slice(0, -1);
47
+ }
48
+ url = baseUrl.replace("http", "ws") + "/ws";
49
+ console.log(`Connecting to Matter Server API using url: ${url}`);
50
+ }
51
+
52
+ const client = new MatterClient(url);
53
+ client.isProduction = isProductionServer;
54
+
55
+ const dashboard = document.createElement("matter-dashboard-app");
56
+ dashboard.client = client;
57
+ document.body.append(dashboard);
58
+ }
59
+
60
+ main();
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { createContext } from "@lit/context";
8
+
9
+ // export const bindingContext = createContext<string>("");
10
+ export const bindingContext = createContext<number>("binding");
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { LitElement, css, html } from "lit";
8
+ import { customElement } from "lit/decorators.js";
9
+
10
+ @customElement("dashboard-footer")
11
+ export class DashboardFooter extends LitElement {
12
+ protected override render() {
13
+ return html`
14
+ <div class="footer">
15
+ The OHF Matter Server is a project by the Open Home Foundation.
16
+ <a href="https://www.openhomefoundation.org/structure/#support-our-work" target="_blank"
17
+ >Support development</a
18
+ >
19
+ </div>
20
+ `;
21
+ }
22
+
23
+ static override styles = css`
24
+ .footer {
25
+ padding: 16px;
26
+ text-align: center;
27
+ font-size: 0.8em;
28
+ color: var(--md-sys-color-on-surface);
29
+ display: flex;
30
+ flex-direction: column;
31
+ position: relative;
32
+ clear: both;
33
+ }
34
+
35
+ .footer a {
36
+ color: var(--md-sys-color-on-surface);
37
+ }
38
+ `;
39
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import "@material/web/button/outlined-button";
8
+ import "@material/web/divider/divider";
9
+ import "@material/web/iconbutton/icon-button";
10
+ import "@material/web/list/list";
11
+ import "@material/web/list/list-item";
12
+ import { MatterClient } from "@matter-server/ws-client";
13
+ import { mdiArrowLeft, mdiLogout } from "@mdi/js";
14
+ import { LitElement, css, html, nothing } from "lit";
15
+ import { customElement, property } from "lit/decorators.js";
16
+ import "../../components/ha-svg-icon";
17
+
18
+ interface HeaderAction {
19
+ label: string;
20
+ icon: string;
21
+ action: void;
22
+ }
23
+
24
+ @customElement("dashboard-header")
25
+ export class DashboardHeader extends LitElement {
26
+ @property() public backButton?: string;
27
+ @property() public actions?: HeaderAction[];
28
+
29
+ public client?: MatterClient;
30
+
31
+ protected override render() {
32
+ return html`
33
+ <div class="header">
34
+ <!-- optional back button -->
35
+ ${this.backButton
36
+ ? html` <a .href=${this.backButton}>
37
+ <md-icon-button>
38
+ <ha-svg-icon .path=${mdiArrowLeft}></ha-svg-icon>
39
+ </md-icon-button>
40
+ </a>`
41
+ : ""}
42
+
43
+ <div>${this.title || ""}</div>
44
+ <div class="flex"></div>
45
+ <div class="actions">
46
+ ${this.actions?.map(action => {
47
+ return html`
48
+ <md-icon-button @click=${action.action} .title=${action.label}>
49
+ <ha-svg-icon .path=${action.icon}></ha-svg-icon>
50
+ </md-icon-button>
51
+ `;
52
+ })}
53
+ <!-- optional logout button -->
54
+ ${this.client?.isProduction
55
+ ? nothing
56
+ : html`
57
+ <md-icon-button @click=${this.client?.disconnect}>
58
+ <ha-svg-icon .path=${mdiLogout}></ha-svg-icon>
59
+ </md-icon-button>
60
+ `}
61
+ </div>
62
+ </div>
63
+ `;
64
+ }
65
+
66
+ static override styles = css`
67
+ .header {
68
+ background-color: var(--md-sys-color-primary);
69
+ color: var(--md-sys-color-on-primary);
70
+ --icon-primary-color: var(--md-sys-color-on-primary);
71
+ font-weight: 400;
72
+ display: flex;
73
+ align-items: center;
74
+ padding-left: 18px;
75
+ padding-right: 8px;
76
+ height: 48px;
77
+ }
78
+
79
+ md-icon-button {
80
+ margin-right: 8px;
81
+ }
82
+
83
+ .flex {
84
+ flex: 1;
85
+ }
86
+ `;
87
+ }