@matter-server/dashboard 0.5.15 → 0.6.0

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 (111) hide show
  1. package/dist/esm/components/dialog-box/dialog-box.d.ts +1 -0
  2. package/dist/esm/components/dialog-box/dialog-box.d.ts.map +1 -1
  3. package/dist/esm/components/dialog-box/dialog-box.js +15 -1
  4. package/dist/esm/components/dialog-box/dialog-box.js.map +1 -1
  5. package/dist/esm/components/dialogs/binding/node-binding-dialog.js +15 -19
  6. package/dist/esm/components/dialogs/binding/node-binding-dialog.js.map +1 -1
  7. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts.map +1 -1
  8. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js +2 -1
  9. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js.map +1 -1
  10. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts.map +1 -1
  11. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js +13 -5
  12. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js.map +1 -1
  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 +13 -9
  15. package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js.map +1 -1
  16. package/dist/esm/components/dialogs/settings/log-level-dialog.d.ts.map +1 -1
  17. package/dist/esm/components/dialogs/settings/log-level-dialog.js +2 -1
  18. package/dist/esm/components/dialogs/settings/log-level-dialog.js.map +1 -1
  19. package/dist/esm/components/ha-svg-icon.d.ts.map +1 -1
  20. package/dist/esm/components/ha-svg-icon.js +0 -1
  21. package/dist/esm/components/ha-svg-icon.js.map +1 -1
  22. package/dist/esm/entrypoint/main.js +1 -1
  23. package/dist/esm/entrypoint/main.js.map +1 -1
  24. package/dist/esm/pages/cluster-commands/base-cluster-commands.d.ts.map +1 -1
  25. package/dist/esm/pages/cluster-commands/base-cluster-commands.js +72 -68
  26. package/dist/esm/pages/cluster-commands/base-cluster-commands.js.map +1 -1
  27. package/dist/esm/pages/components/header.d.ts +1 -1
  28. package/dist/esm/pages/components/header.d.ts.map +1 -1
  29. package/dist/esm/pages/components/header.js +59 -55
  30. package/dist/esm/pages/components/header.js.map +1 -1
  31. package/dist/esm/pages/components/node-details.js +1 -1
  32. package/dist/esm/pages/components/server-details.d.ts.map +1 -1
  33. package/dist/esm/pages/components/server-details.js +2 -0
  34. package/dist/esm/pages/components/server-details.js.map +1 -1
  35. package/dist/esm/pages/matter-cluster-view.d.ts +2 -1
  36. package/dist/esm/pages/matter-cluster-view.d.ts.map +1 -1
  37. package/dist/esm/pages/matter-cluster-view.js +49 -39
  38. package/dist/esm/pages/matter-cluster-view.js.map +1 -1
  39. package/dist/esm/pages/matter-endpoint-view.d.ts +2 -1
  40. package/dist/esm/pages/matter-endpoint-view.d.ts.map +1 -1
  41. package/dist/esm/pages/matter-endpoint-view.js +44 -35
  42. package/dist/esm/pages/matter-endpoint-view.js.map +1 -1
  43. package/dist/esm/pages/matter-network-view.d.ts +1 -1
  44. package/dist/esm/pages/matter-network-view.d.ts.map +1 -1
  45. package/dist/esm/pages/matter-network-view.js +216 -207
  46. package/dist/esm/pages/matter-network-view.js.map +1 -1
  47. package/dist/esm/pages/matter-node-view.d.ts +2 -1
  48. package/dist/esm/pages/matter-node-view.d.ts.map +1 -1
  49. package/dist/esm/pages/matter-node-view.js +104 -94
  50. package/dist/esm/pages/matter-node-view.js.map +1 -1
  51. package/dist/esm/pages/network/base-network-graph.d.ts.map +1 -1
  52. package/dist/esm/pages/network/base-network-graph.js +12 -5
  53. package/dist/esm/pages/network/base-network-graph.js.map +1 -1
  54. package/dist/esm/pages/network/device-panel.d.ts +1 -0
  55. package/dist/esm/pages/network/device-panel.d.ts.map +1 -1
  56. package/dist/esm/pages/network/device-panel.js +19 -5
  57. package/dist/esm/pages/network/device-panel.js.map +1 -1
  58. package/dist/esm/pages/network/network-details.d.ts +1 -1
  59. package/dist/esm/pages/network/network-details.d.ts.map +1 -1
  60. package/dist/esm/pages/network/network-details.js +275 -272
  61. package/dist/esm/pages/network/network-details.js.map +1 -1
  62. package/dist/esm/pages/network/network-utils.d.ts +5 -0
  63. package/dist/esm/pages/network/network-utils.d.ts.map +1 -1
  64. package/dist/esm/pages/network/network-utils.js +47 -17
  65. package/dist/esm/pages/network/network-utils.js.map +1 -1
  66. package/dist/esm/pages/network/update-connections-dialog.d.ts +1 -1
  67. package/dist/esm/pages/network/update-connections-dialog.d.ts.map +1 -1
  68. package/dist/esm/pages/network/update-connections-dialog.js +51 -47
  69. package/dist/esm/pages/network/update-connections-dialog.js.map +1 -1
  70. package/dist/esm/util/device-icons.d.ts.map +1 -1
  71. package/dist/esm/util/device-icons.js +6 -6
  72. package/dist/esm/util/device-icons.js.map +1 -1
  73. package/dist/esm/util/shared-styles.d.ts +10 -0
  74. package/dist/esm/util/shared-styles.d.ts.map +1 -0
  75. package/dist/esm/util/shared-styles.js +56 -0
  76. package/dist/esm/util/shared-styles.js.map +6 -0
  77. package/dist/web/index.html +53 -1
  78. package/dist/web/js/{commission-node-dialog-ByflSEDK.js → commission-node-dialog-DfwKU9qk.js} +4 -4
  79. package/dist/web/js/{commission-node-existing-CD6-Epwb.js → commission-node-existing-C7ITvNfj.js} +6 -3
  80. package/dist/web/js/{commission-node-thread-CekKshVL.js → commission-node-thread-D-icSzto.js} +23 -7
  81. package/dist/web/js/{commission-node-wifi-D_VKTWwF.js → commission-node-wifi-DwUkXlWz.js} +29 -11
  82. package/dist/web/js/{dialog-box-DdVdxz2_.js → dialog-box-BmpaTrvT.js} +16 -2
  83. package/dist/web/js/{fire_event-uMluKQub.js → fire_event-2ZxL-AHZ.js} +1 -1
  84. package/dist/web/js/{log-level-dialog-BO1OSL0z.js → log-level-dialog-D4hubdib.js} +5 -2
  85. package/dist/web/js/main.js +2 -2
  86. package/dist/web/js/{matter-dashboard-app-b1R3Pout.js → matter-dashboard-app-BtHTmAPq.js} +874 -788
  87. package/dist/web/js/{node-binding-dialog-rikORH9_.js → node-binding-dialog-MMx9rkCF.js} +40 -20
  88. package/package.json +4 -4
  89. package/src/components/dialog-box/dialog-box.ts +16 -1
  90. package/src/components/dialogs/binding/node-binding-dialog.ts +15 -15
  91. package/src/components/dialogs/commission-node-dialog/commission-node-existing.ts +2 -1
  92. package/src/components/dialogs/commission-node-dialog/commission-node-thread.ts +13 -5
  93. package/src/components/dialogs/commission-node-dialog/commission-node-wifi.ts +13 -9
  94. package/src/components/dialogs/settings/log-level-dialog.ts +2 -1
  95. package/src/components/ha-svg-icon.ts +0 -1
  96. package/src/entrypoint/main.ts +1 -1
  97. package/src/pages/cluster-commands/base-cluster-commands.ts +84 -80
  98. package/src/pages/components/header.ts +59 -55
  99. package/src/pages/components/node-details.ts +1 -1
  100. package/src/pages/components/server-details.ts +2 -0
  101. package/src/pages/matter-cluster-view.ts +49 -39
  102. package/src/pages/matter-endpoint-view.ts +49 -40
  103. package/src/pages/matter-network-view.ts +200 -191
  104. package/src/pages/matter-node-view.ts +94 -84
  105. package/src/pages/network/base-network-graph.ts +12 -5
  106. package/src/pages/network/device-panel.ts +20 -5
  107. package/src/pages/network/network-details.ts +236 -231
  108. package/src/pages/network/network-utils.ts +51 -17
  109. package/src/pages/network/update-connections-dialog.ts +51 -47
  110. package/src/util/device-icons.ts +12 -6
  111. package/src/util/shared-styles.ts +58 -0
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import type { MatterNode } from "@matter-server/ws-client";
8
+ import { getCssVar } from "../../util/shared-styles.js";
8
9
  import type {
9
10
  CategorizedDevices,
10
11
  NetworkType,
@@ -27,10 +28,16 @@ const SIGNAL_MEDIUM_THRESHOLD = -85;
27
28
  const LQI_STRONG_THRESHOLD = 200;
28
29
  const LQI_MEDIUM_THRESHOLD = 100;
29
30
 
30
- // Signal colors
31
- const SIGNAL_COLOR_STRONG = "#4caf50"; // Green
32
- const SIGNAL_COLOR_MEDIUM = "#ff9800"; // Orange
33
- const SIGNAL_COLOR_WEAK = "#f44336"; // Red
31
+ // Signal colors — read from CSS variables for theme awareness
32
+ function getSignalColorStrong(): string {
33
+ return getCssVar("--signal-color-strong", "#4caf50");
34
+ }
35
+ function getSignalColorMedium(): string {
36
+ return getCssVar("--signal-color-medium", "#ff9800");
37
+ }
38
+ function getSignalColorWeak(): string {
39
+ return getCssVar("--signal-color-weak", "#f44336");
40
+ }
34
41
 
35
42
  /**
36
43
  * WiFi Diagnostics info from cluster 0x36/54.
@@ -444,6 +451,33 @@ export function findUnknownDevices(
444
451
  return Array.from(unknownMap.values());
445
452
  }
446
453
 
454
+ export type SignalLevel = "strong" | "medium" | "weak";
455
+
456
+ /** Determine signal level from a Thread neighbor's RSSI/LQI. */
457
+ export function getSignalLevel(neighbor: ThreadNeighbor): SignalLevel {
458
+ const rssi = neighbor.avgRssi ?? neighbor.lastRssi;
459
+ if (rssi !== null) {
460
+ if (rssi > SIGNAL_STRONG_THRESHOLD) return "strong";
461
+ if (rssi > SIGNAL_MEDIUM_THRESHOLD) return "medium";
462
+ return "weak";
463
+ }
464
+ if (neighbor.lqi > LQI_STRONG_THRESHOLD) return "strong";
465
+ if (neighbor.lqi > LQI_MEDIUM_THRESHOLD) return "medium";
466
+ return "weak";
467
+ }
468
+
469
+ /** Map a signal level to its theme-aware color. */
470
+ export function signalLevelToColor(level: SignalLevel): string {
471
+ switch (level) {
472
+ case "strong":
473
+ return getSignalColorStrong();
474
+ case "medium":
475
+ return getSignalColorMedium();
476
+ case "weak":
477
+ return getSignalColorWeak();
478
+ }
479
+ }
480
+
447
481
  /**
448
482
  * Gets the signal color based on RSSI or LQI values.
449
483
  * Green: Strong signal
@@ -456,22 +490,22 @@ export function getSignalColor(neighbor: ThreadNeighbor): string {
456
490
 
457
491
  if (rssi !== null) {
458
492
  if (rssi > SIGNAL_STRONG_THRESHOLD) {
459
- return SIGNAL_COLOR_STRONG;
493
+ return getSignalColorStrong();
460
494
  }
461
495
  if (rssi > SIGNAL_MEDIUM_THRESHOLD) {
462
- return SIGNAL_COLOR_MEDIUM;
496
+ return getSignalColorMedium();
463
497
  }
464
- return SIGNAL_COLOR_WEAK;
498
+ return getSignalColorWeak();
465
499
  }
466
500
 
467
501
  // Fallback to LQI (0-255, higher is better)
468
502
  if (neighbor.lqi > LQI_STRONG_THRESHOLD) {
469
- return SIGNAL_COLOR_STRONG;
503
+ return getSignalColorStrong();
470
504
  }
471
505
  if (neighbor.lqi > LQI_MEDIUM_THRESHOLD) {
472
- return SIGNAL_COLOR_MEDIUM;
506
+ return getSignalColorMedium();
473
507
  }
474
- return SIGNAL_COLOR_WEAK;
508
+ return getSignalColorWeak();
475
509
  }
476
510
 
477
511
  /**
@@ -481,12 +515,12 @@ export function getSignalColor(neighbor: ThreadNeighbor): string {
481
515
  */
482
516
  export function getSignalColorFromLqi(lqi: number): string {
483
517
  if (lqi > LQI_STRONG_THRESHOLD) {
484
- return SIGNAL_COLOR_STRONG;
518
+ return getSignalColorStrong();
485
519
  }
486
520
  if (lqi > LQI_MEDIUM_THRESHOLD) {
487
- return SIGNAL_COLOR_MEDIUM;
521
+ return getSignalColorMedium();
488
522
  }
489
- return SIGNAL_COLOR_WEAK;
523
+ return getSignalColorWeak();
490
524
  }
491
525
 
492
526
  /**
@@ -577,15 +611,15 @@ export function getWiFiDiagnostics(node: MatterNode): WiFiDiagnostics {
577
611
  */
578
612
  export function getSignalColorFromRssi(rssi: number | null): string {
579
613
  if (rssi === null) {
580
- return SIGNAL_COLOR_MEDIUM; // Default to medium if unknown
614
+ return getSignalColorMedium(); // Default to medium if unknown
581
615
  }
582
616
  if (rssi > SIGNAL_STRONG_THRESHOLD) {
583
- return SIGNAL_COLOR_STRONG;
617
+ return getSignalColorStrong();
584
618
  }
585
619
  if (rssi > SIGNAL_MEDIUM_THRESHOLD) {
586
- return SIGNAL_COLOR_MEDIUM;
620
+ return getSignalColorMedium();
587
621
  }
588
- return SIGNAL_COLOR_WEAK;
622
+ return getSignalColorWeak();
589
623
  }
590
624
 
591
625
  /**
@@ -12,6 +12,7 @@ import type { MatterClient, MatterNode } from "@matter-server/ws-client";
12
12
  import { mdiLoading } from "@mdi/js";
13
13
  import { LitElement, css, html, nothing, svg } from "lit";
14
14
  import { customElement, property, state } from "lit/decorators.js";
15
+ import { reducedMotionStyles } from "../../util/shared-styles.js";
15
16
  import { getNetworkType } from "./network-utils.js";
16
17
 
17
18
  declare global {
@@ -267,61 +268,64 @@ export class UpdateConnectionsDialog extends LitElement {
267
268
  `;
268
269
  }
269
270
 
270
- static override styles = css`
271
- md-dialog {
272
- --md-dialog-container-color: var(--md-sys-color-surface, #fff);
273
- }
274
-
275
- [slot="content"] {
276
- padding: 0 24px;
277
- }
271
+ static override styles = [
272
+ reducedMotionStyles,
273
+ css`
274
+ md-dialog {
275
+ --md-dialog-container-color: var(--md-sys-color-surface, #fff);
276
+ }
278
277
 
279
- [slot="content"] p {
280
- margin: 0 0 16px 0;
281
- font-size: 0.875rem;
282
- line-height: 1.5;
283
- color: var(--md-sys-color-on-surface, #333);
284
- }
278
+ [slot="content"] {
279
+ padding: 0 24px;
280
+ }
285
281
 
286
- [slot="content"] p:last-child {
287
- margin-bottom: 0;
288
- }
282
+ [slot="content"] p {
283
+ margin: 0 0 16px 0;
284
+ font-size: 0.875rem;
285
+ line-height: 1.5;
286
+ color: var(--md-sys-color-on-surface, #333);
287
+ }
289
288
 
290
- .checkbox-row {
291
- display: flex;
292
- align-items: center;
293
- gap: 8px;
294
- cursor: pointer;
295
- font-size: 0.875rem;
296
- color: var(--md-sys-color-on-surface, #333);
297
- }
289
+ [slot="content"] p:last-child {
290
+ margin-bottom: 0;
291
+ }
298
292
 
299
- .updating-content {
300
- display: inline-flex;
301
- align-items: center;
302
- gap: 8px;
303
- }
293
+ .checkbox-row {
294
+ display: flex;
295
+ align-items: center;
296
+ gap: 8px;
297
+ cursor: pointer;
298
+ font-size: 0.875rem;
299
+ color: var(--md-sys-color-on-surface, #333);
300
+ }
304
301
 
305
- .spinner {
306
- animation: spin 1s linear infinite;
307
- flex-shrink: 0;
308
- }
302
+ .updating-content {
303
+ display: inline-flex;
304
+ align-items: center;
305
+ gap: 8px;
306
+ }
309
307
 
310
- .updating-content svg {
311
- color: inherit;
312
- }
308
+ .spinner {
309
+ animation: spin 1s linear infinite;
310
+ flex-shrink: 0;
311
+ }
313
312
 
314
- @keyframes spin {
315
- from {
316
- transform: rotate(0deg);
313
+ .updating-content svg {
314
+ color: inherit;
317
315
  }
318
- to {
319
- transform: rotate(360deg);
316
+
317
+ @keyframes spin {
318
+ from {
319
+ transform: rotate(0deg);
320
+ }
321
+ to {
322
+ transform: rotate(360deg);
323
+ }
320
324
  }
321
- }
322
325
 
323
- md-filled-button {
324
- min-width: 140px;
325
- }
326
- `;
326
+ md-filled-button {
327
+ min-width: 140px;
328
+ }
329
+ `,
330
+ ];
327
331
  }
@@ -56,13 +56,13 @@ import {
56
56
  mdiWeatherRainy,
57
57
  mdiWifi,
58
58
  } from "@mdi/js";
59
- import { ThemeService } from "./theme-service.js";
59
+ import { getCssVar } from "./shared-styles.js";
60
60
 
61
61
  /**
62
62
  * Get theme-aware default icon color.
63
63
  */
64
64
  function getDefaultIconColor(): string {
65
- return ThemeService.effectiveTheme === "dark" ? "#b0b0b0" : "#666666";
65
+ return getCssVar("--node-color-default", "#666666");
66
66
  }
67
67
 
68
68
  /**
@@ -483,9 +483,11 @@ export function createNodeIconDataUrl(
483
483
  const iconPath = getDeviceIcon(node, threadRole);
484
484
  let color: string;
485
485
  if (isSelected) {
486
- color = isOffline ? "#b71c1c" : "#1976d2"; // Dark red for selected+offline, blue for selected
486
+ color = isOffline
487
+ ? getCssVar("--node-color-selected-offline", "#b71c1c")
488
+ : getCssVar("--node-color-selected", "#1976d2");
487
489
  } else if (isOffline) {
488
- color = "#d32f2f"; // Red for offline
490
+ color = getCssVar("--node-color-offline", "#d32f2f");
489
491
  } else {
490
492
  color = getDefaultIconColor(); // Theme-aware default
491
493
  }
@@ -500,7 +502,9 @@ export function createNodeIconDataUrl(
500
502
  */
501
503
  export function createUnknownDeviceIconDataUrl(isRouter: boolean = false, isSelected: boolean = false): string {
502
504
  const iconPath = isRouter ? mdiAccessPoint : mdiHelp;
503
- const color = isSelected ? "#1976d2" : "#ff9800"; // Orange for unknown
505
+ const color = isSelected
506
+ ? getCssVar("--node-color-selected", "#1976d2")
507
+ : getCssVar("--node-color-unknown", "#ff9800");
504
508
  return createIconDataUrl(iconPath, color);
505
509
  }
506
510
 
@@ -510,6 +514,8 @@ export function createUnknownDeviceIconDataUrl(isRouter: boolean = false, isSele
510
514
  * @returns A data URL containing the SVG
511
515
  */
512
516
  export function createWiFiRouterIconDataUrl(isSelected: boolean = false): string {
513
- const color = isSelected ? "#1976d2" : "#ff9800"; // Orange for external infrastructure (same as Thread unknown)
517
+ const color = isSelected
518
+ ? getCssVar("--node-color-selected", "#1976d2")
519
+ : getCssVar("--node-color-unknown", "#ff9800");
514
520
  return createIconDataUrl(mdiWifi, color);
515
521
  }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { css } from "lit";
8
+ import { ThemeService } from "./theme-service.js";
9
+
10
+ // Cache resolved CSS var values — getComputedStyle() is called in graph render loops (per node/edge),
11
+ // so we avoid repeated style lookups and invalidate on theme change.
12
+ const cssVarCache = new Map<string, string>();
13
+ ThemeService.subscribe(() => cssVarCache.clear());
14
+
15
+ /** Read a CSS custom property value from the document body (for JS-driven rendering like vis-network). */
16
+ export function getCssVar(name: string, fallback: string = ""): string {
17
+ let value = cssVarCache.get(name);
18
+ if (value === undefined) {
19
+ value = getComputedStyle(document.body).getPropertyValue(name).trim();
20
+ cssVarCache.set(name, value);
21
+ }
22
+ return value || fallback;
23
+ }
24
+
25
+ export const reducedMotionStyles = css`
26
+ @media (prefers-reduced-motion: reduce) {
27
+ *,
28
+ *::before,
29
+ *::after {
30
+ animation-duration: 0.01ms !important;
31
+ animation-iteration-count: 1 !important;
32
+ transition-duration: 0.01ms !important;
33
+ }
34
+ }
35
+ `;
36
+
37
+ export const notFoundStyles = css`
38
+ .not-found {
39
+ display: flex;
40
+ flex-direction: column;
41
+ align-items: center;
42
+ justify-content: center;
43
+ padding: 48px 16px;
44
+ gap: 16px;
45
+ color: var(--md-sys-color-on-surface-variant);
46
+ }
47
+
48
+ .not-found ha-svg-icon {
49
+ --icon-primary-color: var(--md-sys-color-error);
50
+ width: 48px;
51
+ height: 48px;
52
+ }
53
+
54
+ .not-found p {
55
+ margin: 0;
56
+ font-size: 1.1rem;
57
+ }
58
+ `;