@matter-server/dashboard 0.2.7-alpha.0-20260118-45c7af0 → 0.2.7-alpha.0-20260119-49e7237
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/dist/esm/components/dialogs/binding/node-binding-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js +3 -2
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js +2 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js +3 -2
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js +5 -4
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js.map +1 -1
- package/dist/esm/components/dialogs/settings/log-level-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/settings/log-level-dialog.js +6 -2
- package/dist/esm/components/dialogs/settings/log-level-dialog.js.map +1 -1
- package/dist/esm/pages/cluster-commands/clusters/level-control-commands.d.ts.map +1 -1
- package/dist/esm/pages/cluster-commands/clusters/level-control-commands.js +5 -2
- package/dist/esm/pages/cluster-commands/clusters/level-control-commands.js.map +1 -1
- package/dist/esm/pages/cluster-commands/clusters/on-off-commands.d.ts.map +1 -1
- package/dist/esm/pages/cluster-commands/clusters/on-off-commands.js +6 -3
- package/dist/esm/pages/cluster-commands/clusters/on-off-commands.js.map +1 -1
- package/dist/esm/pages/components/node-details.d.ts.map +1 -1
- package/dist/esm/pages/components/node-details.js +6 -5
- package/dist/esm/pages/components/node-details.js.map +1 -1
- package/dist/esm/pages/components/server-details.d.ts.map +1 -1
- package/dist/esm/pages/components/server-details.js +3 -2
- package/dist/esm/pages/components/server-details.js.map +1 -1
- package/dist/esm/pages/matter-server-view.d.ts.map +1 -1
- package/dist/esm/pages/matter-server-view.js +14 -1
- package/dist/esm/pages/matter-server-view.js.map +1 -1
- package/dist/esm/util/async-handler.d.ts +50 -0
- package/dist/esm/util/async-handler.d.ts.map +1 -0
- package/dist/esm/util/async-handler.js +33 -0
- package/dist/esm/util/async-handler.js.map +6 -0
- package/dist/esm/util/fire_event.d.ts.map +1 -1
- package/dist/esm/util/fire_event.js +1 -2
- package/dist/esm/util/fire_event.js.map +1 -1
- package/dist/esm/util/format_hex.d.ts +13 -2
- package/dist/esm/util/format_hex.d.ts.map +1 -1
- package/dist/esm/util/format_hex.js +6 -1
- package/dist/esm/util/format_hex.js.map +1 -1
- package/dist/web/js/{commission-node-dialog-CoaDIV2Y.js → commission-node-dialog-B4_wgFye.js} +5 -5
- package/dist/web/js/{commission-node-existing-DEU_mJjO.js → commission-node-existing-BktL7vHX.js} +6 -6
- package/dist/web/js/{commission-node-thread-DZ6DghSs.js → commission-node-thread-ox6fB3dO.js} +7 -7
- package/dist/web/js/{commission-node-wifi-DOyin0q3.js → commission-node-wifi-Dlayi41Z.js} +9 -9
- package/dist/web/js/{dialog-box-B5sunUPv.js → dialog-box-DFs0hcPv.js} +2 -2
- package/dist/web/js/{fire_event-C9Duc1j-.js → fire_event-oVtV3_P5.js} +2 -3
- package/dist/web/js/{log-level-dialog-B7LsZYUL.js → log-level-dialog-BVxKJJ49.js} +8 -5
- package/dist/web/js/main.js +151 -73
- package/dist/web/js/{matter-dashboard-app-DlHSE_Qh.js → matter-dashboard-app-Dr-IYMsD.js} +62 -17
- package/dist/web/js/{node-binding-dialog-BifZsigR.js → node-binding-dialog-CqE3VuZN.js} +6 -6
- package/dist/web/js/{outlined-text-field-D2BOt1yD.js → outlined-text-field-BVcHUxiS.js} +3 -3
- package/dist/web/js/{prevent_default-CuW2EnKR.js → prevent_default-tLhqZmsK.js} +1 -1
- package/dist/web/js/{validator-MOJiFndw.js → validator-muF28wYx.js} +1 -1
- package/package.json +3 -3
- package/src/components/dialogs/binding/node-binding-dialog.ts +3 -2
- package/src/components/dialogs/commission-node-dialog/commission-node-existing.ts +2 -1
- package/src/components/dialogs/commission-node-dialog/commission-node-thread.ts +3 -2
- package/src/components/dialogs/commission-node-dialog/commission-node-wifi.ts +5 -4
- package/src/components/dialogs/settings/log-level-dialog.ts +6 -2
- package/src/pages/cluster-commands/clusters/level-control-commands.ts +5 -2
- package/src/pages/cluster-commands/clusters/on-off-commands.ts +6 -3
- package/src/pages/components/node-details.ts +6 -5
- package/src/pages/components/server-details.ts +3 -3
- package/src/pages/matter-server-view.ts +17 -2
- package/src/util/async-handler.ts +74 -0
- package/src/util/fire_event.ts +1 -3
- package/src/util/format_hex.ts +17 -2
|
@@ -16,6 +16,7 @@ import "../../../components/ha-svg-icon";
|
|
|
16
16
|
import { AccessControlEntry, BindingTarget, MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
17
17
|
import { css, html, LitElement, nothing } from "lit";
|
|
18
18
|
import { customElement, property, query } from "lit/decorators.js";
|
|
19
|
+
import { handleAsync } from "../../../util/async-handler.js";
|
|
19
20
|
import { preventDefault } from "../../../util/prevent_default.js";
|
|
20
21
|
import { BindingEntryDataTransformer, BindingEntryStruct, InputType } from "./model.js";
|
|
21
22
|
|
|
@@ -314,7 +315,7 @@ export class NodeBindingDialog extends LitElement {
|
|
|
314
315
|
</div>
|
|
315
316
|
<div slot="end">
|
|
316
317
|
<md-text-button
|
|
317
|
-
@click=${() => this.deleteBindingHandler(index)}
|
|
318
|
+
@click=${handleAsync(() => this.deleteBindingHandler(index))}
|
|
318
319
|
>delete</md-text-button
|
|
319
320
|
</div>
|
|
320
321
|
</md-list-item>
|
|
@@ -368,7 +369,7 @@ export class NodeBindingDialog extends LitElement {
|
|
|
368
369
|
</div>
|
|
369
370
|
</div>
|
|
370
371
|
<div slot="actions">
|
|
371
|
-
<md-text-button @click=${this.addBindingHandler}>Add</md-text-button>
|
|
372
|
+
<md-text-button @click=${handleAsync(() => this.addBindingHandler())}>Add</md-text-button>
|
|
372
373
|
<md-text-button @click=${this._close}>Cancel</md-text-button>
|
|
373
374
|
</div>
|
|
374
375
|
</md-dialog>
|
|
@@ -12,6 +12,7 @@ import { MatterClient } from "@matter-server/ws-client";
|
|
|
12
12
|
import { LitElement, html, nothing } from "lit";
|
|
13
13
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
14
14
|
import { clientContext } from "../../../client/client-context.js";
|
|
15
|
+
import { handleAsync } from "../../../util/async-handler.js";
|
|
15
16
|
import { fireEvent } from "../../../util/fire_event.js";
|
|
16
17
|
|
|
17
18
|
@customElement("commission-node-existing")
|
|
@@ -30,7 +31,7 @@ export class CommissionNodeExisting extends LitElement {
|
|
|
30
31
|
return html`<md-outlined-text-field label="Share code" .disabled="${this._loading}"> </md-outlined-text-field>
|
|
31
32
|
<br />
|
|
32
33
|
<br />
|
|
33
|
-
<md-outlined-button @click=${this._commissionNode} .disabled="${this._loading}"
|
|
34
|
+
<md-outlined-button @click=${handleAsync(() => this._commissionNode())} .disabled="${this._loading}"
|
|
34
35
|
>Commission</md-outlined-button
|
|
35
36
|
>${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
|
|
36
37
|
}
|
|
@@ -12,6 +12,7 @@ import { MatterClient } from "@matter-server/ws-client";
|
|
|
12
12
|
import { LitElement, html, nothing } from "lit";
|
|
13
13
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
14
14
|
import { clientContext } from "../../../client/client-context.js";
|
|
15
|
+
import { handleAsync } from "../../../util/async-handler.js";
|
|
15
16
|
import { fireEvent } from "../../../util/fire_event.js";
|
|
16
17
|
|
|
17
18
|
@customElement("commission-node-thread")
|
|
@@ -34,14 +35,14 @@ export class CommissionNodeThread extends LitElement {
|
|
|
34
35
|
</md-outlined-text-field>
|
|
35
36
|
<br />
|
|
36
37
|
<br />
|
|
37
|
-
<md-outlined-button @click=${this._setThreadDataset} .disabled="${this._loading}"
|
|
38
|
+
<md-outlined-button @click=${handleAsync(() => this._setThreadDataset())} .disabled="${this._loading}"
|
|
38
39
|
>Set Thread Dataset</md-outlined-button
|
|
39
40
|
>${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
|
|
40
41
|
}
|
|
41
42
|
return html`<md-outlined-text-field label="Pairing code" .disabled="${this._loading}"> </md-outlined-text-field>
|
|
42
43
|
<br />
|
|
43
44
|
<br />
|
|
44
|
-
<md-outlined-button @click=${this._commissionNode} .disabled="${this._loading}"
|
|
45
|
+
<md-outlined-button @click=${handleAsync(() => this._commissionNode())} .disabled="${this._loading}"
|
|
45
46
|
>Commission</md-outlined-button
|
|
46
47
|
>${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
|
|
47
48
|
}
|
|
@@ -12,6 +12,7 @@ import { MatterClient } from "@matter-server/ws-client";
|
|
|
12
12
|
import { LitElement, html, nothing } from "lit";
|
|
13
13
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
14
14
|
import { clientContext } from "../../../client/client-context.js";
|
|
15
|
+
import { handleAsync } from "../../../util/async-handler.js";
|
|
15
16
|
import { fireEvent } from "../../../util/fire_event.js";
|
|
16
17
|
|
|
17
18
|
@customElement("commission-node-wifi")
|
|
@@ -37,7 +38,7 @@ export class CommissionNodeWifi extends LitElement {
|
|
|
37
38
|
</md-outlined-text-field>
|
|
38
39
|
<br />
|
|
39
40
|
<br />
|
|
40
|
-
<md-outlined-button @click=${this._setWifiCredentials} .disabled="${this._loading}"
|
|
41
|
+
<md-outlined-button @click=${handleAsync(() => this._setWifiCredentials())} .disabled="${this._loading}"
|
|
41
42
|
>Set WiFi Credentials</md-outlined-button
|
|
42
43
|
>${this._loading
|
|
43
44
|
? html`<md-circular-progress indeterminate .visible="${this._loading}"></md-circular-progress>`
|
|
@@ -46,12 +47,12 @@ export class CommissionNodeWifi extends LitElement {
|
|
|
46
47
|
return html`<md-outlined-text-field label="Pairing code" .disabled="${this._loading}"> </md-outlined-text-field>
|
|
47
48
|
<br />
|
|
48
49
|
<br />
|
|
49
|
-
<md-outlined-button @click=${this._commissionNode} .disabled="${this._loading}"
|
|
50
|
+
<md-outlined-button @click=${handleAsync(() => this._commissionNode())} .disabled="${this._loading}"
|
|
50
51
|
>Commission</md-outlined-button
|
|
51
52
|
>${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
private _setWifiCredentials() {
|
|
55
|
+
private async _setWifiCredentials() {
|
|
55
56
|
const ssid = this._ssidField.value;
|
|
56
57
|
if (!ssid) {
|
|
57
58
|
alert("SSID is required");
|
|
@@ -64,7 +65,7 @@ export class CommissionNodeWifi extends LitElement {
|
|
|
64
65
|
}
|
|
65
66
|
this._loading = true;
|
|
66
67
|
try {
|
|
67
|
-
this.client.setWifiCredentials(ssid, password);
|
|
68
|
+
await this.client.setWifiCredentials(ssid, password);
|
|
68
69
|
} catch (err) {
|
|
69
70
|
alert(`Error setting WiFi credentials: \n${(err as Error).message}`);
|
|
70
71
|
} finally {
|
|
@@ -13,6 +13,7 @@ import "@material/web/select/select-option";
|
|
|
13
13
|
import { LogLevelString, MatterClient } from "@matter-server/ws-client";
|
|
14
14
|
import { css, html, LitElement, nothing } from "lit";
|
|
15
15
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
16
|
+
import { fireAndForget, handleAsync } from "../../../util/async-handler.js";
|
|
16
17
|
import { preventDefault } from "../../../util/prevent_default.js";
|
|
17
18
|
|
|
18
19
|
const LOG_LEVELS: { value: LogLevelString; label: string }[] = [
|
|
@@ -41,7 +42,7 @@ export class LogLevelDialog extends LitElement {
|
|
|
41
42
|
|
|
42
43
|
override connectedCallback() {
|
|
43
44
|
super.connectedCallback();
|
|
44
|
-
|
|
45
|
+
fireAndForget(this._loadLogLevels());
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
private async _loadLogLevels() {
|
|
@@ -133,7 +134,10 @@ export class LogLevelDialog extends LitElement {
|
|
|
133
134
|
</div>
|
|
134
135
|
<div slot="actions">
|
|
135
136
|
<md-text-button @click=${this._close}>Cancel</md-text-button>
|
|
136
|
-
<md-text-button
|
|
137
|
+
<md-text-button
|
|
138
|
+
@click=${handleAsync(() => this._apply())}
|
|
139
|
+
?disabled=${this._loading || this._applying}
|
|
140
|
+
>
|
|
137
141
|
${this._applying ? "Applying..." : "Apply"}
|
|
138
142
|
</md-text-button>
|
|
139
143
|
</div>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import "@material/web/button/filled-button";
|
|
8
8
|
import { html } from "lit";
|
|
9
9
|
import { customElement, state } from "lit/decorators.js";
|
|
10
|
+
import { handleAsync } from "../../../util/async-handler.js";
|
|
10
11
|
import { BaseClusterCommands } from "../base-cluster-commands.js";
|
|
11
12
|
import { registerClusterCommands } from "../registry.js";
|
|
12
13
|
|
|
@@ -60,8 +61,10 @@ class LevelControlClusterCommands extends BaseClusterCommands {
|
|
|
60
61
|
/>
|
|
61
62
|
Execute if Off
|
|
62
63
|
</label>
|
|
63
|
-
<md-outlined-button @click=${this._handleMoveToLevel}
|
|
64
|
-
|
|
64
|
+
<md-outlined-button @click=${handleAsync(() => this._handleMoveToLevel())}
|
|
65
|
+
>MoveToLevel</md-outlined-button
|
|
66
|
+
>
|
|
67
|
+
<md-outlined-button @click=${handleAsync(() => this._handleMoveToLevelWithOnOff())}
|
|
65
68
|
>MoveToLevelWithOnOff</md-outlined-button
|
|
66
69
|
>
|
|
67
70
|
</div>
|
|
@@ -8,6 +8,7 @@ import "@material/web/button/filled-button";
|
|
|
8
8
|
import "@material/web/button/outlined-button";
|
|
9
9
|
import { html } from "lit";
|
|
10
10
|
import { customElement } from "lit/decorators.js";
|
|
11
|
+
import { handleAsync } from "../../../util/async-handler.js";
|
|
11
12
|
import { BaseClusterCommands } from "../base-cluster-commands.js";
|
|
12
13
|
import { registerClusterCommands } from "../registry.js";
|
|
13
14
|
|
|
@@ -25,9 +26,11 @@ class OnOffClusterCommands extends BaseClusterCommands {
|
|
|
25
26
|
<summary>OnOff Commands</summary>
|
|
26
27
|
<div class="command-content">
|
|
27
28
|
<div class="command-row">
|
|
28
|
-
<md-outlined-button @click=${this._handleOn}>On</md-outlined-button>
|
|
29
|
-
<md-outlined-button @click=${this._handleOff}>Off</md-outlined-button>
|
|
30
|
-
<md-outlined-button @click=${this._handleToggle}
|
|
29
|
+
<md-outlined-button @click=${handleAsync(() => this._handleOn())}>On</md-outlined-button>
|
|
30
|
+
<md-outlined-button @click=${handleAsync(() => this._handleOff())}>Off</md-outlined-button>
|
|
31
|
+
<md-outlined-button @click=${handleAsync(() => this._handleToggle())}
|
|
32
|
+
>Toggle</md-outlined-button
|
|
33
|
+
>
|
|
31
34
|
</div>
|
|
32
35
|
</div>
|
|
33
36
|
</details>
|
|
@@ -21,6 +21,7 @@ import { DeviceType } from "../../client/models/descriptions.js";
|
|
|
21
21
|
import { showAlertDialog, showPromptDialog } from "../../components/dialog-box/show-dialog-box.js";
|
|
22
22
|
import { showNodeBindingDialog } from "../../components/dialogs/binding/show-node-binding-dialog.js";
|
|
23
23
|
import "../../components/ha-svg-icon";
|
|
24
|
+
import { handleAsync } from "../../util/async-handler.js";
|
|
24
25
|
import { getEndpointDeviceTypes } from "../matter-endpoint-view.js";
|
|
25
26
|
import { bindingContext } from "./context.js";
|
|
26
27
|
|
|
@@ -104,7 +105,7 @@ export class NodeDetails extends LitElement {
|
|
|
104
105
|
</div>`}
|
|
105
106
|
</md-list-item>
|
|
106
107
|
<md-list-item class="btn">
|
|
107
|
-
<md-outlined-button @click=${this._reinterview}
|
|
108
|
+
<md-outlined-button @click=${handleAsync(() => this._reinterview())}
|
|
108
109
|
>Interview<ha-svg-icon slot="icon" .path=${mdiChatProcessing}></ha-svg-icon
|
|
109
110
|
></md-outlined-button>
|
|
110
111
|
${this._updateInitiated
|
|
@@ -118,22 +119,22 @@ export class NodeDetails extends LitElement {
|
|
|
118
119
|
this.node.updateStateProgress,
|
|
119
120
|
)}<ha-svg-icon slot="icon" .path=${mdiUpdate}></ha-svg-icon
|
|
120
121
|
></md-outlined-button>`
|
|
121
|
-
: html`<md-outlined-button @click=${this._searchUpdate}
|
|
122
|
+
: html`<md-outlined-button @click=${handleAsync(() => this._searchUpdate())}
|
|
122
123
|
>Update<ha-svg-icon slot="icon" .path=${mdiUpdate}></ha-svg-icon
|
|
123
124
|
></md-outlined-button>`}
|
|
124
125
|
${bindings
|
|
125
126
|
? html`
|
|
126
|
-
<md-outlined-button @click=${this._binding}>
|
|
127
|
+
<md-outlined-button @click=${handleAsync(() => this._binding())}>
|
|
127
128
|
Binding
|
|
128
129
|
<ha-svg-icon slot="icon" .path=${mdiLink}></ha-svg-icon>
|
|
129
130
|
</md-outlined-button>
|
|
130
131
|
`
|
|
131
132
|
: nothing}
|
|
132
133
|
|
|
133
|
-
<md-outlined-button @click=${this._openCommissioningWindow}
|
|
134
|
+
<md-outlined-button @click=${handleAsync(() => this._openCommissioningWindow())}
|
|
134
135
|
>Share<ha-svg-icon slot="icon" .path=${mdiShareVariant}></ha-svg-icon
|
|
135
136
|
></md-outlined-button>
|
|
136
|
-
<md-outlined-button @click=${this._remove}
|
|
137
|
+
<md-outlined-button @click=${handleAsync(() => this._remove())}
|
|
137
138
|
>Remove<ha-svg-icon slot="icon" .path=${mdiTrashCan}></ha-svg-icon
|
|
138
139
|
></md-outlined-button>
|
|
139
140
|
</md-list-item>
|
|
@@ -18,6 +18,7 @@ import { customElement } from "lit/decorators.js";
|
|
|
18
18
|
import { showAlertDialog, showPromptDialog } from "../../components/dialog-box/show-dialog-box.js";
|
|
19
19
|
import { showCommissionNodeDialog } from "../../components/dialogs/commission-node-dialog/show-commission-node-dialog.js";
|
|
20
20
|
import "../../components/ha-svg-icon";
|
|
21
|
+
import { handleAsync } from "../../util/async-handler.js";
|
|
21
22
|
|
|
22
23
|
@customElement("server-details")
|
|
23
24
|
export class ServerDetails extends LitElement {
|
|
@@ -54,7 +55,7 @@ export class ServerDetails extends LitElement {
|
|
|
54
55
|
<md-list-item class="btn">
|
|
55
56
|
<span>
|
|
56
57
|
<md-outlined-button @click=${this._commissionNode}>Commission node<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon></md-outlined-button>
|
|
57
|
-
<md-outlined-button @click=${this._uploadDiagnosticsDumpFile}>Import node<ha-svg-icon slot="icon" .path=${mdiFile}></ha-svg-icon></md-outlined-button>
|
|
58
|
+
<md-outlined-button @click=${handleAsync(() => this._uploadDiagnosticsDumpFile())}>Import node<ha-svg-icon slot="icon" .path=${mdiFile}></ha-svg-icon></md-outlined-button>
|
|
58
59
|
</md-list-item>
|
|
59
60
|
</md-list>
|
|
60
61
|
<!-- hidden file element for the upload diagnostics -->
|
|
@@ -83,8 +84,7 @@ export class ServerDetails extends LitElement {
|
|
|
83
84
|
) {
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
const fileElem = this.renderRoot.getElementById("fileElem") as HTMLInputElement;
|
|
87
|
+
const fileElem = this.shadowRoot!.getElementById("fileElem") as HTMLInputElement;
|
|
88
88
|
fileElem.click();
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -8,11 +8,12 @@ import "@material/web/divider/divider";
|
|
|
8
8
|
import "@material/web/iconbutton/icon-button";
|
|
9
9
|
import "@material/web/list/list";
|
|
10
10
|
import "@material/web/list/list-item";
|
|
11
|
-
import { MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
11
|
+
import { isTestNodeId, MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
12
12
|
import { mdiChevronRight } from "@mdi/js";
|
|
13
|
-
import {
|
|
13
|
+
import { css, html, LitElement, nothing } from "lit";
|
|
14
14
|
import { customElement, property } from "lit/decorators.js";
|
|
15
15
|
import "../components/ha-svg-icon";
|
|
16
|
+
import { formatNodeAddress } from "../util/format_hex.js";
|
|
16
17
|
import "./components/footer";
|
|
17
18
|
import "./components/header";
|
|
18
19
|
import "./components/server-details";
|
|
@@ -65,6 +66,15 @@ class MatterServerView extends LitElement {
|
|
|
65
66
|
<md-list-item type="link" href=${`#node/${node.node_id}`}>
|
|
66
67
|
<div slot="headline">
|
|
67
68
|
Node ${node.node_id}
|
|
69
|
+
<span class="hex-id"
|
|
70
|
+
>(${formatNodeAddress(
|
|
71
|
+
isTestNodeId(node.node_id) ||
|
|
72
|
+
this.client.serverInfo.fabric_index === undefined
|
|
73
|
+
? undefined
|
|
74
|
+
: this.client.serverInfo.fabric_index,
|
|
75
|
+
node.node_id,
|
|
76
|
+
)})</span
|
|
77
|
+
>
|
|
68
78
|
${node.available ? "" : html`<span class="status">OFFLINE</span>`}
|
|
69
79
|
</div>
|
|
70
80
|
<div slot="supporting-text">
|
|
@@ -113,5 +123,10 @@ class MatterServerView extends LitElement {
|
|
|
113
123
|
font-weight: bold;
|
|
114
124
|
font-size: 0.8em;
|
|
115
125
|
}
|
|
126
|
+
|
|
127
|
+
.hex-id {
|
|
128
|
+
color: var(--text-color, rgba(0, 0, 0, 0.6));
|
|
129
|
+
font-size: 0.85em;
|
|
130
|
+
}
|
|
116
131
|
`;
|
|
117
132
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Wraps an async function to be used as an event handler.
|
|
9
|
+
* Catches any errors and logs them, optionally calling an error callback.
|
|
10
|
+
*
|
|
11
|
+
* Usage in Lit templates:
|
|
12
|
+
* ```
|
|
13
|
+
* <button @click=${handleAsync(() => this._save())}>Save</button>
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* With custom error handling:
|
|
17
|
+
* ```
|
|
18
|
+
* <button @click=${handleAsync(() => this._save(), (e) => this._showError(e))}>Save</button>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @param fn - Async function to execute
|
|
22
|
+
* @param onError - Optional error callback
|
|
23
|
+
* @returns Event handler function
|
|
24
|
+
*/
|
|
25
|
+
export function handleAsync<T>(fn: () => Promise<T>, onError?: (error: Error) => void): () => void {
|
|
26
|
+
return () => {
|
|
27
|
+
fn().catch((error: Error) => {
|
|
28
|
+
console.error("Async operation failed:", error);
|
|
29
|
+
onError?.(error);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Wraps an async function that takes an event parameter.
|
|
36
|
+
*
|
|
37
|
+
* Usage:
|
|
38
|
+
* ```
|
|
39
|
+
* <input @change=${handleAsyncEvent((e) => this._handleChange(e))}>
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function handleAsyncEvent<E extends Event, T>(
|
|
43
|
+
fn: (event: E) => Promise<T>,
|
|
44
|
+
onError?: (error: Error) => void,
|
|
45
|
+
): (event: E) => void {
|
|
46
|
+
return (event: E) => {
|
|
47
|
+
fn(event).catch((error: Error) => {
|
|
48
|
+
console.error("Async operation failed:", error);
|
|
49
|
+
onError?.(error);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Fire-and-forget helper for calling async methods from sync contexts.
|
|
56
|
+
* Use this when you need to call an async method but can't await it.
|
|
57
|
+
*
|
|
58
|
+
* Usage in lifecycle methods:
|
|
59
|
+
* ```
|
|
60
|
+
* connectedCallback() {
|
|
61
|
+
* super.connectedCallback();
|
|
62
|
+
* fireAndForget(this._loadData());
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @param promise - Promise to execute
|
|
67
|
+
* @param onError - Optional error callback
|
|
68
|
+
*/
|
|
69
|
+
export function fireAndForget<T>(promise: Promise<T>, onError?: (error: Error) => void): void {
|
|
70
|
+
promise.catch((error: Error) => {
|
|
71
|
+
console.error("Async operation failed:", error);
|
|
72
|
+
onError?.(error);
|
|
73
|
+
});
|
|
74
|
+
}
|
package/src/util/fire_event.ts
CHANGED
|
@@ -70,14 +70,12 @@ export const fireEvent = <HassEvent extends ValidHassDomEvent>(
|
|
|
70
70
|
},
|
|
71
71
|
) => {
|
|
72
72
|
options = options || {};
|
|
73
|
-
// @ts-expect-error why?
|
|
74
|
-
detail = detail === null || detail === undefined ? {} : detail;
|
|
75
73
|
const event = new Event(type, {
|
|
76
74
|
bubbles: options.bubbles === undefined ? true : options.bubbles,
|
|
77
75
|
cancelable: Boolean(options.cancelable),
|
|
78
76
|
composed: options.composed === undefined ? true : options.composed,
|
|
79
77
|
});
|
|
80
|
-
(event as any).detail = detail;
|
|
78
|
+
(event as any).detail = detail ?? {};
|
|
81
79
|
node.dispatchEvent(event);
|
|
82
80
|
return event;
|
|
83
81
|
};
|
package/src/util/format_hex.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Format a number as a hex string with 0x prefix.
|
|
8
|
+
* Format a number or bigint as a hex string with 0x prefix.
|
|
9
9
|
* Ensures even number of digits with a minimum of 4 digits.
|
|
10
10
|
*
|
|
11
11
|
* Examples:
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* 65535 -> "0xFFFF"
|
|
15
15
|
* 65536 -> "0x010000"
|
|
16
16
|
*/
|
|
17
|
-
export function formatHex(value: number): string {
|
|
17
|
+
export function formatHex(value: number | bigint): string {
|
|
18
18
|
let hex = value.toString(16).toUpperCase();
|
|
19
19
|
|
|
20
20
|
// Ensure minimum 4 digits
|
|
@@ -28,3 +28,18 @@ export function formatHex(value: number): string {
|
|
|
28
28
|
|
|
29
29
|
return `0x${hex}`;
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Format a node address in Matter format: @fabricIndex:nodeIdHex
|
|
34
|
+
* For test nodes (where fabric index is unknown), uses "?" as the fabric index.
|
|
35
|
+
*
|
|
36
|
+
* Examples:
|
|
37
|
+
* (1, 2) -> "@1:2"
|
|
38
|
+
* (1, 255) -> "@1:ff"
|
|
39
|
+
* (2, 65535) -> "@2:ffff"
|
|
40
|
+
* (undefined, 2) -> "@?:2"
|
|
41
|
+
*/
|
|
42
|
+
export function formatNodeAddress(fabricIndex: number | undefined, nodeId: number | bigint): string {
|
|
43
|
+
const fabricPart = fabricIndex !== undefined ? fabricIndex : "?";
|
|
44
|
+
return `@${fabricPart}:${nodeId.toString(16)}`;
|
|
45
|
+
}
|