@matter-server/dashboard 0.6.7 → 0.7.0-alpha.0-20260512-b404bea

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 (42) hide show
  1. package/dist/esm/client/models/descriptions.d.ts.map +1 -1
  2. package/dist/esm/client/models/descriptions.js +2485 -415
  3. package/dist/esm/client/models/descriptions.js.map +1 -1
  4. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts +2 -0
  5. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts.map +1 -1
  6. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js +11 -1
  7. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js.map +1 -1
  8. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts +7 -0
  9. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts.map +1 -1
  10. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js +43 -2
  11. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js.map +1 -1
  12. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts +7 -0
  13. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts.map +1 -1
  14. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js +43 -2
  15. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js.map +1 -1
  16. package/dist/esm/components/dialogs/settings/settings-dialog.d.ts +19 -0
  17. package/dist/esm/components/dialogs/settings/settings-dialog.d.ts.map +1 -1
  18. package/dist/esm/components/dialogs/settings/settings-dialog.js +287 -2
  19. package/dist/esm/components/dialogs/settings/settings-dialog.js.map +1 -1
  20. package/dist/esm/components/dialogs/settings/show-settings-dialog.d.ts +1 -1
  21. package/dist/esm/components/dialogs/settings/show-settings-dialog.d.ts.map +1 -1
  22. package/dist/esm/components/dialogs/settings/show-settings-dialog.js +2 -1
  23. package/dist/esm/components/dialogs/settings/show-settings-dialog.js.map +1 -1
  24. package/dist/web/js/{attribute-write-dialog-DvCdBC5h.js → attribute-write-dialog-DzMWN_T3.js} +1 -1
  25. package/dist/web/js/{command-invoke-dialog-wg-tTS3n.js → command-invoke-dialog-BhAOXzjX.js} +1 -1
  26. package/dist/web/js/{commission-node-dialog-DrlOw53q.js → commission-node-dialog-DF87YIqR.js} +17 -5
  27. package/dist/web/js/{commission-node-existing-BujgZH95.js → commission-node-existing-DLcWvJTL.js} +2 -2
  28. package/dist/web/js/{commission-node-thread-C8FyqV6l.js → commission-node-thread-m2fqED-2.js} +43 -4
  29. package/dist/web/js/{commission-node-wifi-DiaG9EmR.js → commission-node-wifi-PCsot-CX.js} +43 -4
  30. package/dist/web/js/{dialog-box-QK2bjCAa.js → dialog-box-DiqYXM8c.js} +1 -1
  31. package/dist/web/js/{fire_event-CfuDUSb7.js → fire_event-BnpND_gK.js} +1 -1
  32. package/dist/web/js/main.js +7 -1
  33. package/dist/web/js/{matter-dashboard-app-Dh-6FL-7.js → matter-dashboard-app-BZOhBELR.js} +2345 -335
  34. package/dist/web/js/{node-binding-dialog-DbsGaTS6.js → node-binding-dialog-B3lVN-FU.js} +1 -1
  35. package/dist/web/js/{settings-dialog-BZwpJ82T.js → settings-dialog-D75IAPKe.js} +289 -1
  36. package/package.json +4 -4
  37. package/src/client/models/descriptions.ts +2485 -415
  38. package/src/components/dialogs/commission-node-dialog/commission-node-dialog.ts +13 -1
  39. package/src/components/dialogs/commission-node-dialog/commission-node-thread.ts +49 -2
  40. package/src/components/dialogs/commission-node-dialog/commission-node-wifi.ts +49 -2
  41. package/src/components/dialogs/settings/settings-dialog.ts +294 -2
  42. package/src/components/dialogs/settings/show-settings-dialog.ts +2 -1
@@ -24,7 +24,11 @@ export class ComissionNodeDialog extends LitElement {
24
24
  return html`
25
25
  <md-dialog open @cancel=${preventDefault} @closed=${this._handleClosed}>
26
26
  <div slot="headline">Commission node</div>
27
- <div slot="content" @node-commissioned=${this._nodeCommissioned}>
27
+ <div
28
+ slot="content"
29
+ @node-commissioned=${this._nodeCommissioned}
30
+ @request-settings=${this._requestSettings}
31
+ >
28
32
  ${!this._mode
29
33
  ? html`<md-list>
30
34
  <md-list-item
@@ -82,6 +86,13 @@ export class ComissionNodeDialog extends LitElement {
82
86
  this._close();
83
87
  }
84
88
 
89
+ private _requestSettings() {
90
+ import("../settings/show-settings-dialog.js").then(({ showSettingsDialog }) => {
91
+ showSettingsDialog(this.client, "network-credentials");
92
+ });
93
+ this._close();
94
+ }
95
+
85
96
  private _close() {
86
97
  this.shadowRoot!.querySelector<MdDialog>("md-dialog")!.close();
87
98
  }
@@ -98,5 +109,6 @@ declare global {
98
109
 
99
110
  interface HASSDomEvents {
100
111
  "node-commissioned": MatterNode;
112
+ "request-settings": Record<string, never>;
101
113
  }
102
114
  }
@@ -9,15 +9,48 @@ import "@material/web/progress/circular-progress";
9
9
  import "@material/web/textfield/outlined-text-field";
10
10
  import type { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field.js";
11
11
  import { MatterClient } from "@matter-server/ws-client";
12
- import { LitElement, html, nothing } from "lit";
12
+ import { mdiAccessPoint } from "@mdi/js";
13
+ import { LitElement, css, html, nothing } from "lit";
13
14
  import { customElement, property, query, state } from "lit/decorators.js";
14
15
  import { clientContext } from "../../../client/client-context.js";
15
16
  import { handleAsync } from "../../../util/async-handler.js";
16
17
  import { fireEvent } from "../../../util/fire_event.js";
17
18
  import { showAlertDialog } from "../../dialog-box/show-dialog-box.js";
19
+ import "../../ha-svg-icon.js";
18
20
 
19
21
  @customElement("commission-node-thread")
20
22
  export class CommissionNodeThread extends LitElement {
23
+ static override styles = css`
24
+ .cred-chip {
25
+ display: flex;
26
+ width: fit-content;
27
+ align-items: center;
28
+ gap: 6px;
29
+ background: var(--md-sys-color-surface-container);
30
+ color: var(--md-sys-color-on-surface-variant);
31
+ border-radius: 16px;
32
+ padding: 4px 10px 4px 6px;
33
+ font-size: 0.85em;
34
+ margin-bottom: 12px;
35
+ }
36
+ .cred-chip ha-svg-icon {
37
+ width: 18px;
38
+ height: 18px;
39
+ flex-shrink: 0;
40
+ }
41
+ .cred-chip .sep {
42
+ opacity: 0.5;
43
+ }
44
+ .cred-chip .edit-link {
45
+ cursor: pointer;
46
+ color: var(--md-sys-color-primary);
47
+ background: none;
48
+ border: none;
49
+ padding: 0;
50
+ font: inherit;
51
+ font-size: inherit;
52
+ }
53
+ `;
21
54
  @consume({ context: clientContext, subscribe: true })
22
55
  @property({ attribute: false })
23
56
  public client!: MatterClient;
@@ -44,7 +77,15 @@ export class CommissionNodeThread extends LitElement {
44
77
  >Set Thread Dataset</md-outlined-button
45
78
  >${this._loading ? html` <md-circular-progress indeterminate></md-circular-progress> ` : nothing}`;
46
79
  }
47
- return html`<md-outlined-text-field label="Pairing code" .disabled="${this._loading}"> </md-outlined-text-field>
80
+ return html`<div class="cred-chip">
81
+ <ha-svg-icon .path=${mdiAccessPoint}></ha-svg-icon>
82
+ <span>Thread network set</span>
83
+ <span class="sep">·</span>
84
+ <button class="edit-link" @click=${() => fireEvent(this, "request-settings", {})}>
85
+ Edit in Settings
86
+ </button>
87
+ </div>
88
+ <md-outlined-text-field label="Pairing code" .disabled="${this._loading}"> </md-outlined-text-field>
48
89
  <br />
49
90
  <br />
50
91
  <md-outlined-button @click=${handleAsync(() => this._commissionNode())} .disabled="${this._loading}"
@@ -87,3 +128,9 @@ export class CommissionNodeThread extends LitElement {
87
128
  }
88
129
  }
89
130
  }
131
+
132
+ declare global {
133
+ interface HASSDomEvents {
134
+ "request-settings": Record<string, never>;
135
+ }
136
+ }
@@ -9,15 +9,48 @@ import "@material/web/progress/circular-progress";
9
9
  import "@material/web/textfield/outlined-text-field";
10
10
  import type { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field.js";
11
11
  import { MatterClient } from "@matter-server/ws-client";
12
- import { LitElement, html, nothing } from "lit";
12
+ import { mdiWifi } from "@mdi/js";
13
+ import { LitElement, css, html, nothing } from "lit";
13
14
  import { customElement, property, query, state } from "lit/decorators.js";
14
15
  import { clientContext } from "../../../client/client-context.js";
15
16
  import { handleAsync } from "../../../util/async-handler.js";
16
17
  import { fireEvent } from "../../../util/fire_event.js";
17
18
  import { showAlertDialog } from "../../dialog-box/show-dialog-box.js";
19
+ import "../../ha-svg-icon.js";
18
20
 
19
21
  @customElement("commission-node-wifi")
20
22
  export class CommissionNodeWifi extends LitElement {
23
+ static override styles = css`
24
+ .cred-chip {
25
+ display: flex;
26
+ width: fit-content;
27
+ align-items: center;
28
+ gap: 6px;
29
+ background: var(--md-sys-color-surface-container);
30
+ color: var(--md-sys-color-on-surface-variant);
31
+ border-radius: 16px;
32
+ padding: 4px 10px 4px 6px;
33
+ font-size: 0.85em;
34
+ margin-bottom: 12px;
35
+ }
36
+ .cred-chip ha-svg-icon {
37
+ width: 18px;
38
+ height: 18px;
39
+ flex-shrink: 0;
40
+ }
41
+ .cred-chip .sep {
42
+ opacity: 0.5;
43
+ }
44
+ .cred-chip .edit-link {
45
+ cursor: pointer;
46
+ color: var(--md-sys-color-primary);
47
+ background: none;
48
+ border: none;
49
+ padding: 0;
50
+ font: inherit;
51
+ font-size: inherit;
52
+ }
53
+ `;
21
54
  @consume({ context: clientContext, subscribe: true })
22
55
  @property({ attribute: false })
23
56
  public client!: MatterClient;
@@ -48,7 +81,15 @@ export class CommissionNodeWifi extends LitElement {
48
81
  >Set WiFi Credentials</md-outlined-button
49
82
  >${this._loading ? html`<md-circular-progress indeterminate></md-circular-progress>` : nothing}`;
50
83
  }
51
- return html`<md-outlined-text-field label="Pairing code" .disabled="${this._loading}"> </md-outlined-text-field>
84
+ return html`<div class="cred-chip">
85
+ <ha-svg-icon .path=${mdiWifi}></ha-svg-icon>
86
+ <span>WiFi: ${this.client.serverInfo.wifi_ssid ?? "network set"}</span>
87
+ <span class="sep">·</span>
88
+ <button class="edit-link" @click=${() => fireEvent(this, "request-settings", {})}>
89
+ Edit in Settings
90
+ </button>
91
+ </div>
92
+ <md-outlined-text-field label="Pairing code" .disabled="${this._loading}"> </md-outlined-text-field>
52
93
  <br />
53
94
  <br />
54
95
  <md-outlined-button @click=${handleAsync(() => this._commissionNode())} .disabled="${this._loading}"
@@ -93,3 +134,9 @@ export class CommissionNodeWifi extends LitElement {
93
134
  }
94
135
  }
95
136
  }
137
+
138
+ declare global {
139
+ interface HASSDomEvents {
140
+ "request-settings": Record<string, never>;
141
+ }
142
+ }
@@ -4,17 +4,25 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ import "@material/web/button/filled-button";
7
8
  import "@material/web/button/text-button";
8
9
  import "@material/web/dialog/dialog";
9
10
  import type { MdDialog } from "@material/web/dialog/dialog.js";
10
11
  import "@material/web/divider/divider";
12
+ import "@material/web/iconbutton/icon-button";
11
13
  import "@material/web/switch/switch";
12
14
  import type { MdSwitch } from "@material/web/switch/switch.js";
15
+ import "@material/web/textfield/outlined-text-field";
16
+ import type { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field.js";
13
17
  import { MatterClient } from "@matter-server/ws-client";
14
- import { css, html, LitElement } from "lit";
15
- import { customElement, property, state } from "lit/decorators.js";
18
+ import { mdiAccessPoint, mdiEye, mdiEyeOff, mdiWifi } from "@mdi/js";
19
+ import { css, html, LitElement, nothing } from "lit";
20
+ import { customElement, property, query, state } from "lit/decorators.js";
21
+ import { handleAsync } from "../../../util/async-handler.js";
16
22
  import { DevModeService } from "../../../util/dev-mode-service.js";
17
23
  import { preventDefault } from "../../../util/prevent_default.js";
24
+ import "../../../components/ha-svg-icon.js";
25
+ import { showAlertDialog } from "../../dialog-box/show-dialog-box.js";
18
26
  import "./log-level-section.js";
19
27
 
20
28
  @customElement("settings-dialog")
@@ -26,6 +34,16 @@ export class SettingsDialog extends LitElement {
26
34
 
27
35
  private _unsubscribeDev?: () => void;
28
36
 
37
+ @property({ attribute: false }) public scrollToSection?: string;
38
+
39
+ @state() private _expandedRow: "wifi" | "thread" | null = null;
40
+ @state() private _credLoading = false;
41
+ @state() private _showPassword = false;
42
+
43
+ @query("#cred-wifi-ssid") private _wifiSsidField!: MdOutlinedTextField;
44
+ @query("#cred-wifi-password") private _wifiPasswordField!: MdOutlinedTextField;
45
+ @query("#cred-thread-dataset") private _threadDatasetField!: MdOutlinedTextField;
46
+
29
47
  override connectedCallback() {
30
48
  super.connectedCallback();
31
49
  this._unsubscribeDev = DevModeService.subscribe(active => {
@@ -38,6 +56,18 @@ export class SettingsDialog extends LitElement {
38
56
  this._unsubscribeDev?.();
39
57
  }
40
58
 
59
+ override firstUpdated() {
60
+ const knownSections = new Set(["network-credentials"]);
61
+ if (this.scrollToSection && knownSections.has(this.scrollToSection)) {
62
+ requestAnimationFrame(() => {
63
+ this.renderRoot.querySelector(`#${this.scrollToSection}`)?.scrollIntoView({
64
+ behavior: "smooth",
65
+ block: "start",
66
+ });
67
+ });
68
+ }
69
+ }
70
+
41
71
  private _close() {
42
72
  this.shadowRoot!.querySelector<MdDialog>("md-dialog")!.close();
43
73
  }
@@ -59,6 +89,93 @@ export class SettingsDialog extends LitElement {
59
89
  });
60
90
  }
61
91
 
92
+ private _toggleExpand(row: "wifi" | "thread") {
93
+ this._expandedRow = this._expandedRow === row ? null : row;
94
+ this._showPassword = false;
95
+ }
96
+
97
+ private _cancelCred() {
98
+ this._expandedRow = null;
99
+ this._showPassword = false;
100
+ }
101
+
102
+ private _togglePassword() {
103
+ this._showPassword = !this._showPassword;
104
+ }
105
+
106
+ private async _saveWifi() {
107
+ const ssid = this._wifiSsidField.value.trim();
108
+ if (!ssid) {
109
+ showAlertDialog({ title: "Validation error", text: "SSID is required" });
110
+ return;
111
+ }
112
+ const password = this._wifiPasswordField.value;
113
+ if (!password) {
114
+ showAlertDialog({ title: "Validation error", text: "Password is required" });
115
+ return;
116
+ }
117
+ this._credLoading = true;
118
+ try {
119
+ await this.client.setWifiCredentials(ssid, password);
120
+ this._expandedRow = null;
121
+ this._showPassword = false;
122
+ } catch (err) {
123
+ showAlertDialog({ title: "Error saving WiFi credentials", text: (err as Error).message });
124
+ } finally {
125
+ this._credLoading = false;
126
+ }
127
+ }
128
+
129
+ private async _removeWifi() {
130
+ this._credLoading = true;
131
+ try {
132
+ await this.client.removeWifiCredentials();
133
+ this._expandedRow = null;
134
+ this._showPassword = false;
135
+ } catch (err) {
136
+ showAlertDialog({ title: "Error removing WiFi credentials", text: (err as Error).message });
137
+ } finally {
138
+ this._credLoading = false;
139
+ }
140
+ }
141
+
142
+ private async _saveThread() {
143
+ const dataset = this._threadDatasetField.value.trim();
144
+ if (!dataset) {
145
+ showAlertDialog({ title: "Validation error", text: "Thread dataset is required" });
146
+ return;
147
+ }
148
+ if (!/^[0-9a-fA-F]*$/.test(dataset) || dataset.length % 2 !== 0) {
149
+ showAlertDialog({
150
+ title: "Invalid Thread dataset",
151
+ text: "Must be a hex string with even length (each byte is two hex characters)",
152
+ });
153
+ return;
154
+ }
155
+ this._credLoading = true;
156
+ try {
157
+ await this.client.setThreadOperationalDataset(dataset);
158
+ this._expandedRow = null;
159
+ } catch (err) {
160
+ showAlertDialog({ title: "Error saving Thread dataset", text: (err as Error).message });
161
+ } finally {
162
+ this._credLoading = false;
163
+ }
164
+ }
165
+
166
+ private async _removeThread() {
167
+ this._credLoading = true;
168
+ try {
169
+ await this.client.removeThreadDataset();
170
+ this._expandedRow = null;
171
+ this._showPassword = false;
172
+ } catch (err) {
173
+ showAlertDialog({ title: "Error removing Thread dataset", text: (err as Error).message });
174
+ } finally {
175
+ this._credLoading = false;
176
+ }
177
+ }
178
+
62
179
  protected override render() {
63
180
  return html`
64
181
  <md-dialog open @cancel=${preventDefault} @closed=${this._handleClosed}>
@@ -91,6 +208,107 @@ export class SettingsDialog extends LitElement {
91
208
  <h3 class="section-title">Server log levels</h3>
92
209
  <log-level-section .client=${this.client}></log-level-section>
93
210
  </section>
211
+
212
+ <md-divider></md-divider>
213
+
214
+ <section id="network-credentials" class="section">
215
+ <h3 class="section-title">Network credentials</h3>
216
+
217
+ <div class="cred-row">
218
+ <div class="cred-info">
219
+ <ha-svg-icon .path=${mdiWifi}></ha-svg-icon>
220
+ <span class="cred-label">WiFi</span>
221
+ ${this.client.serverInfo.wifi_credentials_set
222
+ ? html`<span class="cred-value">${this.client.serverInfo.wifi_ssid}</span>`
223
+ : html`<span class="cred-unset">Not configured</span>`}
224
+ </div>
225
+ <md-text-button @click=${() => this._toggleExpand("wifi")} .disabled=${this._credLoading}
226
+ >Edit</md-text-button
227
+ >
228
+ </div>
229
+
230
+ ${this._expandedRow === "wifi"
231
+ ? html` <div class="cred-form">
232
+ <md-outlined-text-field
233
+ id="cred-wifi-ssid"
234
+ label="SSID"
235
+ .value=${this.client.serverInfo.wifi_ssid ?? ""}
236
+ .disabled=${this._credLoading}
237
+ ></md-outlined-text-field>
238
+ <div class="password-row">
239
+ <md-outlined-text-field
240
+ id="cred-wifi-password"
241
+ label="Password"
242
+ .type=${this._showPassword ? "text" : "password"}
243
+ .disabled=${this._credLoading}
244
+ ></md-outlined-text-field>
245
+ <md-icon-button @click=${this._togglePassword}>
246
+ <ha-svg-icon .path=${this._showPassword ? mdiEyeOff : mdiEye}></ha-svg-icon>
247
+ </md-icon-button>
248
+ </div>
249
+ <div class="form-actions">
250
+ <md-text-button @click=${this._cancelCred} .disabled=${this._credLoading}
251
+ >Cancel</md-text-button
252
+ >
253
+ ${this.client.serverInfo.wifi_credentials_set
254
+ ? html`<md-text-button
255
+ @click=${handleAsync(() => this._removeWifi())}
256
+ .disabled=${this._credLoading}
257
+ >Remove</md-text-button
258
+ >`
259
+ : nothing}
260
+ <md-filled-button
261
+ @click=${handleAsync(() => this._saveWifi())}
262
+ .disabled=${this._credLoading}
263
+ >Save</md-filled-button
264
+ >
265
+ </div>
266
+ </div>`
267
+ : nothing}
268
+
269
+ <div class="cred-row cred-row-thread">
270
+ <div class="cred-info">
271
+ <ha-svg-icon .path=${mdiAccessPoint}></ha-svg-icon>
272
+ <span class="cred-label">Thread</span>
273
+ ${this.client.serverInfo.thread_credentials_set
274
+ ? html`<span class="cred-value">Thread network set</span>`
275
+ : html`<span class="cred-unset">Not configured</span>`}
276
+ </div>
277
+ <md-text-button @click=${() => this._toggleExpand("thread")} .disabled=${this._credLoading}
278
+ >Edit</md-text-button
279
+ >
280
+ </div>
281
+
282
+ ${this._expandedRow === "thread"
283
+ ? html` <div class="cred-form">
284
+ <md-outlined-text-field
285
+ id="cred-thread-dataset"
286
+ label="Thread dataset"
287
+ supporting-text="Hex string (e.g. 0E080000...)"
288
+ .disabled=${this._credLoading}
289
+ ></md-outlined-text-field>
290
+ <div class="form-actions">
291
+ <md-text-button @click=${this._cancelCred} .disabled=${this._credLoading}
292
+ >Cancel</md-text-button
293
+ >
294
+ ${this.client.serverInfo.thread_credentials_set
295
+ ? html`<md-text-button
296
+ @click=${handleAsync(() => this._removeThread())}
297
+ .disabled=${this._credLoading}
298
+ >Remove</md-text-button
299
+ >`
300
+ : nothing}
301
+ <md-filled-button
302
+ @click=${handleAsync(() => this._saveThread())}
303
+ .disabled=${this._credLoading}
304
+ >Save</md-filled-button
305
+ >
306
+ </div>
307
+ </div>`
308
+ : nothing}
309
+
310
+ <p class="cred-hint">Used when commissioning new devices. Existing devices are not affected.</p>
311
+ </section>
94
312
  </div>
95
313
  <div slot="actions">
96
314
  <md-text-button @click=${this._close}>Close</md-text-button>
@@ -155,6 +373,80 @@ export class SettingsDialog extends LitElement {
155
373
  md-divider {
156
374
  margin: 12px 0;
157
375
  }
376
+
377
+ .cred-row {
378
+ display: flex;
379
+ align-items: center;
380
+ justify-content: space-between;
381
+ padding: 4px 0;
382
+ }
383
+
384
+ .cred-row-thread {
385
+ margin-top: 8px;
386
+ }
387
+
388
+ .cred-info {
389
+ display: flex;
390
+ align-items: center;
391
+ gap: 10px;
392
+ font-size: 0.9rem;
393
+ color: var(--md-sys-color-on-surface);
394
+ }
395
+
396
+ .cred-label {
397
+ font-weight: 500;
398
+ min-width: 52px;
399
+ }
400
+
401
+ .cred-value {
402
+ color: var(--md-sys-color-on-surface-variant);
403
+ }
404
+
405
+ .cred-unset {
406
+ color: var(--md-sys-color-on-surface-variant);
407
+ font-style: italic;
408
+ }
409
+
410
+ .cred-form {
411
+ display: flex;
412
+ flex-direction: column;
413
+ gap: 10px;
414
+ padding: 8px 0 4px 0;
415
+ }
416
+
417
+ .password-row {
418
+ display: flex;
419
+ align-items: center;
420
+ gap: 4px;
421
+ }
422
+
423
+ .password-row md-outlined-text-field {
424
+ flex: 1;
425
+ }
426
+
427
+ .form-actions {
428
+ display: flex;
429
+ gap: 4px;
430
+ justify-content: flex-end;
431
+ }
432
+
433
+ .cred-hint {
434
+ margin: 10px 0 0 0;
435
+ font-size: 0.8rem;
436
+ color: var(--md-sys-color-on-surface-variant);
437
+ }
438
+
439
+ .cred-info ha-svg-icon {
440
+ width: 18px;
441
+ height: 18px;
442
+ color: var(--md-sys-color-on-surface-variant);
443
+ }
444
+
445
+ .password-row ha-svg-icon {
446
+ width: 18px;
447
+ height: 18px;
448
+ color: var(--md-sys-color-on-surface-variant);
449
+ }
158
450
  `;
159
451
  }
160
452
 
@@ -6,9 +6,10 @@
6
6
 
7
7
  import { MatterClient } from "@matter-server/ws-client";
8
8
 
9
- export const showSettingsDialog = async (client: MatterClient) => {
9
+ export const showSettingsDialog = async (client: MatterClient, section?: string) => {
10
10
  await import("./settings-dialog.js");
11
11
  const dialog = document.createElement("settings-dialog");
12
12
  dialog.client = client;
13
+ if (section) dialog.scrollToSection = section;
13
14
  document.querySelector("matter-dashboard-app")?.renderRoot.appendChild(dialog);
14
15
  };