From 17b364b58a43d48779db6c76717ddaf2cfade9d9 Mon Sep 17 00:00:00 2001
From: Marc Brooks <IDisposable@gmail.com>
Date: Fri, 13 Jun 2025 06:20:24 -0500
Subject: [PATCH] feat(ui) Add deviceName or deviceID to the browser tab title

Addresses #304. In local mode will show the deviceId, in cloud connection will show the deviceName.

Would be nice to show the hostname, but that would require device-side code changes to the /device endpoint.
---
 ui/src/routes/devices.$id.tsx | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/ui/src/routes/devices.$id.tsx b/ui/src/routes/devices.$id.tsx
index 8cdb5b3..26f17dd 100644
--- a/ui/src/routes/devices.$id.tsx
+++ b/ui/src/routes/devices.$id.tsx
@@ -58,9 +58,11 @@ import { SystemVersionInfo } from "./devices.$id.settings.general.update";
 
 interface LocalLoaderResp {
   authMode: "password" | "noPassword" | null;
+  deviceId: string;
 }
 
 interface CloudLoaderResp {
+  deviceId: string;
   deviceName: string;
   user: User | null;
   iceConfig: {
@@ -85,7 +87,7 @@ const deviceLoader = async () => {
   if (deviceRes.status === 401) return redirect("/login-local");
   if (deviceRes.ok) {
     const device = (await deviceRes.json()) as LocalDevice;
-    return { authMode: device.authMode };
+    return { authMode: device.authMode, deviceId: device.deviceId };
   }
 
   throw new Error("Error fetching device");
@@ -111,7 +113,7 @@ const cloudLoader = async (params: Params<string>): Promise<CloudLoaderResp> =>
     device: { id: string; name: string; user: { googleId: string } };
   };
 
-  return { user, iceConfig, deviceName: device.name || device.id };
+  return { user, iceConfig, deviceName: device.name || device.id, deviceId: device.id };
 };
 
 const loader = async ({ params }: LoaderFunctionArgs) => {
@@ -123,6 +125,7 @@ export default function KvmIdRoute() {
   // Depending on the mode, we set the appropriate variables
   const user = "user" in loaderResp ? loaderResp.user : null;
   const deviceName = "deviceName" in loaderResp ? loaderResp.deviceName : null;
+  const deviceId = "deviceId" in loaderResp ? loaderResp.deviceId : null;
   const iceConfig = "iceConfig" in loaderResp ? loaderResp.iceConfig : null;
   const authMode = "authMode" in loaderResp ? loaderResp.authMode : null;
 
@@ -788,6 +791,14 @@ export default function KvmIdRoute() {
     setupPeerConnection,
   ]);
 
+  // update the browser tab title with the name of the JetKVM we're discussing
+  useEffect(() => {
+    const name = deviceName || deviceId;
+    document.title = (name && name.length > 0)
+                    ? "JetKVM-" + name
+                    : "JetKVM";
+  }, [deviceName, deviceId]);
+
   return (
     <FeatureFlagProvider appVersion={appVersion}>
       {!outlet && otaState.updating && (