From 8a0d04fa86fbe5e61153007920288c31b4180542 Mon Sep 17 00:00:00 2001 From: "Valentin V. Bartenev" Date: Sun, 17 May 2026 15:40:10 +0300 Subject: [PATCH] Web: add meshcoretel.ru profile link button next to public key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a hidden `ℹ` button (meshcoretelProfileBtn) in the Public Key field of the Info panel. After initApp() finishes loading the "Loading info..." section, the public key value is read from the DOM and validated against /^[0-9A-F]{64}$/. If it passes, an onclick handler is attached that opens https://meshcoretel.ru/ in a new tab, and the button is made visible. The button remains hidden if the key fails to load or does not match the expected 64-char uppercase hex pattern, so the UI degrades gracefully on any firmware that does not return a valid public key. The container div is changed from fieldline (2-column grid: 1fr auto) to inline-actions (3-column grid: minmax(0,1fr) auto auto) to accommodate the second action button without wrapping. --- src/helpers/web/WebPanelServer.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/helpers/web/WebPanelServer.cpp b/src/helpers/web/WebPanelServer.cpp index 3c3e2938..961c8206 100644 --- a/src/helpers/web/WebPanelServer.cpp +++ b/src/helpers/web/WebPanelServer.cpp @@ -656,9 +656,10 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
-
+
+
@@ -2723,6 +2724,12 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML( () => loadField("clock", "clockUtc", null, quiet), () => loadField("get public.key", "publicKey", "uppercase", quiet) ]); + const pubKeyValue = document.getElementById("publicKey").value.trim(); + const profileBtn = document.getElementById("meshcoretelProfileBtn"); + if (profileBtn && /^[0-9A-F]{64}$/.test(pubKeyValue)) { + profileBtn.onclick = () => window.open("https://meshcoretel.ru/" + encodeURIComponent(pubKeyValue), "_blank", "noopener,noreferrer"); + profileBtn.style.display = ""; + } await loadSection("Loading repeater settings...", [ () => loadField("get name", "nodeName", null, quiet), () => loadField("get lat", "nodeLat", null, quiet),