From ef847c8bba2f3a68d30b1ad55e4c8bb0227dbd05 Mon Sep 17 00:00:00 2001 From: philon- Date: Sat, 9 Aug 2025 23:18:47 +0200 Subject: [PATCH 1/2] Improve NodeDetailsDialog UI and add security info Refactored NodeDetailsDialog to use tables for better layout and readability, added a security section displaying public key and verification status, and included messageable status. Updated i18n files with new keys and improved battery level formatting. Fixed logic in Nodes page for handling location packets and improved hardware model sorting. --- .../web/public/i18n/locales/en/common.json | 4 +- .../web/public/i18n/locales/en/dialog.json | 9 +- .../NodeDetailsDialog/NodeDetailsDialog.tsx | 219 ++++++++++++------ packages/web/src/pages/Nodes/index.tsx | 8 +- 4 files changed, 160 insertions(+), 80 deletions(-) diff --git a/packages/web/public/i18n/locales/en/common.json b/packages/web/public/i18n/locales/en/common.json index 8f40e7c85..d858b28bf 100644 --- a/packages/web/public/i18n/locales/en/common.json +++ b/packages/web/public/i18n/locales/en/common.json @@ -108,5 +108,7 @@ "managed": "At least one admin key is requred if the node is managed.", "key": "Key is required." } - } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/en/dialog.json b/packages/web/public/i18n/locales/en/dialog.json index b443e7e35..8d7ecad6a 100644 --- a/packages/web/public/i18n/locales/en/dialog.json +++ b/packages/web/public/i18n/locales/en/dialog.json @@ -93,7 +93,7 @@ "deviceMetrics": "Device Metrics:", "hardware": "Hardware: ", "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: !", + "nodeHexPrefix": "Node Hex: ", "nodeNumber": "Node Number: ", "position": "Position:", "role": "Role: ", @@ -102,7 +102,12 @@ "title": "Node Details for {{identifier}}", "ignoreNode": "Ignore node", "removeNode": "Remove node", - "unignoreNode": "Unignore node" + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" }, "pkiBackup": { "loseKeysWarning": "If you lose your keys, you will need to reset your device.", diff --git a/packages/web/src/components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx b/packages/web/src/components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx index eff2f756f..bb0b5b24a 100644 --- a/packages/web/src/components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx +++ b/packages/web/src/components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx @@ -1,3 +1,4 @@ +import { base64Encode } from "@bufbuild/protobuf/wire"; import { DeviceImage } from "@components/generic/DeviceImage.tsx"; import { TimeAgo } from "@components/generic/TimeAgo.tsx"; import { Uptime } from "@components/generic/Uptime.tsx"; @@ -167,7 +168,8 @@ export const NodeDetailsDialog = ({ key: "batteryLevel", label: t("nodeDetails.batteryLevel"), value: node.deviceMetrics?.batteryLevel, - format: (val: number) => `${val.toFixed(2)}%`, + format: (val: number) => + val === 101 ? t("batteryStatus.pluggedIn") : `${val.toFixed(2)}%`, }, { key: "voltage", @@ -177,6 +179,9 @@ export const NodeDetailsDialog = ({ }, ]; + const sectionClassName = + "text-slate-900 dark:text-slate-100 bg-slate-100 dark:bg-slate-800 p-4 rounded-lg mt-3"; + return ( @@ -192,7 +197,7 @@ export const NodeDetailsDialog = ({ -
+
-
+
+

+ {t("nodeDetails.security")} +

+ + + + + + + + + + + +
{t("nodeDetails.publicKey")} +
+                          {node.user?.publicKey &&
+                          node.user?.publicKey.length > 0
+                            ? base64Encode(node.user.publicKey)
+                            : t("unknown.longName")}
+                        
+
+ {node.isKeyManuallyVerified + ? t("nodeDetails.KeyManuallyVerifiedTrue") + : t("nodeDetails.KeyManuallyVerifiedFalse")} +
+
+ +

{t("nodeDetails.position")}

{node.position ? ( - <> - {node.position.latitudeI && node.position.longitudeI && ( -

- {t("locationResponse.coordinates")} - - {node.position.latitudeI / 1e7},{" "} - {node.position.longitudeI / 1e7} - -

- )} - {node.position.altitude && ( -

- {t("locationResponse.altitude")} - {node.position.altitude} - {t("unit.meter.one")} -

- )} - + + + {node.position.latitudeI && node.position.longitudeI && ( + + + + + )} + {node.position.altitude && ( + + + + + )} + +
{t("locationResponse.coordinates")} + + {node.position.latitudeI / 1e7},{" "} + {node.position.longitudeI / 1e7} + +
{t("locationResponse.altitude")} + {node.position.altitude} + {t("unit.meter.suffix")} +
) : ( -

{t("unknown.shortName")}

+

{t("unknown.longName")}

)}