diff --git a/Overlord-Server/public/assets/main.js b/Overlord-Server/public/assets/main.js index 9ab35b7..efb6999 100644 --- a/Overlord-Server/public/assets/main.js +++ b/Overlord-Server/public/assets/main.js @@ -65,6 +65,19 @@ function detectClientPlatform(clientId) { return "unknown"; } +function getClientCard(clientId) { + if (!clientId) return null; + const selectorId = + typeof CSS !== "undefined" && typeof CSS.escape === "function" + ? CSS.escape(clientId) + : clientId; + return document.querySelector(`article[data-id="${selectorId}"]`); +} + +function isClientOnline(clientId) { + return getClientCard(clientId)?.dataset.online === "true"; +} + function applyMenuSupportRules(clientId) { const platform = detectClientPlatform(clientId); const isWindows = platform === "windows"; @@ -240,7 +253,7 @@ function initializeRenderer() { pageLabel, openMenu: (id, x, y) => { applyMenuSupportRules(id); - openMenu(id, x, y, setContext); + openMenu(id, x, y, setContext, { isOnline: isClientOnline(id) }); loadPluginsForClient(id); }, openModal, @@ -510,6 +523,27 @@ window.removeClientFromDashboard = async (clientId) => { } }; +window.setClientNickname = async (clientId, nickname) => { + if (!clientId) return false; + try { + const res = await fetch(`/api/clients/${clientId}/nickname`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ nickname: nickname || "" }), + }); + if (!res.ok) { + const data = await res.json().catch(() => ({})); + alert(data.error || "Failed to update client nickname"); + return false; + } + return true; + } catch (err) { + console.error(err); + alert("Failed to update client nickname"); + return false; + } +}; + window.banClient = async (clientId) => { if (!clientId) return; if (!confirm(`Ban IP for ${clientId} and block future connections?`)) return; @@ -686,6 +720,31 @@ menu.addEventListener("click", async (e) => { } closeMenu(clearContext); return; + } else if (action === "set-nickname") { + const card = getClientCard(contextCard); + const currentNickname = (card?.dataset.nickname || "").trim(); + const input = prompt( + `Set nickname for ${contextCard}\n\nLeave blank to clear nickname.`, + currentNickname, + ); + if (input === null) { + closeMenu(clearContext); + return; + } + + const trimmed = input.trim(); + const updated = await window.setClientNickname(contextCard, trimmed || null); + if (updated) { + setTimeout(() => loadWithOptions({ force: true }), 200); + } + closeMenu(clearContext); + return; + } + + if (!isClientOnline(contextCard)) { + alert("Client is offline. This command can only be used while the client is online."); + closeMenu(clearContext); + return; } const ok = await sendCommand(contextCard, action); diff --git a/Overlord-Server/public/assets/render.js b/Overlord-Server/public/assets/render.js index 5759755..80b71b9 100644 --- a/Overlord-Server/public/assets/render.js +++ b/Overlord-Server/public/assets/render.js @@ -132,8 +132,6 @@ export function createRenderer({ card.addEventListener("contextmenu", (e) => { e.preventDefault(); if (isViewer) return; - const isOnline = card.dataset.online === "true"; - if (!isOnline) return; const clientId = card.dataset.id; if (!clientId) return; const { clientX, clientY } = e; @@ -167,12 +165,15 @@ export function createRenderer({ card.dataset.online = String(!!client.online); card.dataset.os = String(client.os || "").toLowerCase(); + card.dataset.nickname = String(client.nickname || ""); const os = osBadge(client.os || "unknown"); const arch = archBadge(client.arch || ""); const ver = versionBadge(client.version || ""); const mons = monitorsBadge(client.monitors); const deviceId = shortId(client.id); const hwid = shortId(client.hwid || ""); + const nickname = String(client.nickname || "").trim(); + const displayName = nickname || client.host || deviceId; card.className = `card rounded-xl border border-slate-800 bg-slate-900/70 p-4 shadow-lg ${client.online ? "" : "card-offline"} tone-${os.tone}`; const cardThumb = client.thumbnail ? (() => { @@ -202,7 +203,8 @@ export function createRenderer({
${countryToFlag(client.country)} - ${escapeHtml(client.host || deviceId)} + ${escapeHtml(displayName)} + ${nickname && client.host ? ` ${escapeHtml(client.host)}` : ""} ${escapeHtml(client.user || "unknown")} @@ -223,7 +225,7 @@ export function createRenderer({
${formatPing(client.pingMs)} - ${isViewer ? "" : ``} + ${isViewer ? "" : ``} ${isViewer ? "" : ``}
diff --git a/Overlord-Server/public/assets/ui.js b/Overlord-Server/public/assets/ui.js index c80766b..74a6485 100644 --- a/Overlord-Server/public/assets/ui.js +++ b/Overlord-Server/public/assets/ui.js @@ -19,7 +19,8 @@ menu.innerHTML = ` - + +