diff --git a/server/static/dashboard.html b/server/static/dashboard.html
index b3c2093..e2784fc 100644
--- a/server/static/dashboard.html
+++ b/server/static/dashboard.html
@@ -596,14 +596,17 @@
Full keyboard capture including Win key, Alt+Tab, and Ctrl+Alt+Del.
-
-
-
-
-
-
- Run this command in PowerShell or CMD where guruconnect-viewer.exe is located.
+
+
+ Native viewer not installed
+
+ Download and run GuruConnect to register the protocol handler, then click "Try Again".
+
+
@@ -927,24 +930,26 @@
// Connect modal state
let connectSessionId = null;
let connectMachineName = null;
+ let protocolCheckTimeout = null;
const connectModal = document.getElementById("connectModal");
const connectClose = document.getElementById("connectClose");
const connectWeb = document.getElementById("connectWeb");
const connectNative = document.getElementById("connectNative");
- const nativeCommandContainer = document.getElementById("nativeCommandContainer");
- const nativeCommandText = document.getElementById("nativeCommandText");
+ const nativeNotInstalled = document.getElementById("nativeNotInstalled");
const connectMachineNameEl = document.getElementById("connectMachineName");
connectClose.addEventListener("click", () => {
connectModal.classList.remove("active");
- nativeCommandContainer.style.display = "none";
+ nativeNotInstalled.style.display = "none";
+ if (protocolCheckTimeout) clearTimeout(protocolCheckTimeout);
});
connectModal.addEventListener("click", (e) => {
if (e.target === connectModal) {
connectModal.classList.remove("active");
- nativeCommandContainer.style.display = "none";
+ nativeNotInstalled.style.display = "none";
+ if (protocolCheckTimeout) clearTimeout(protocolCheckTimeout);
}
});
@@ -953,27 +958,63 @@
const viewerUrl = "/viewer.html?session_id=" + connectSessionId;
window.open(viewerUrl, "viewer_" + connectSessionId, "width=1280,height=800,menubar=no,toolbar=no,location=no,status=no");
connectModal.classList.remove("active");
- nativeCommandContainer.style.display = "none";
+ nativeNotInstalled.style.display = "none";
}
});
connectNative.addEventListener("click", () => {
- if (connectSessionId) {
- const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
- const serverUrl = protocol + "//" + window.location.host + "/ws/viewer";
- const cmd = `guruconnect-viewer.exe -i ${connectSessionId} -s ${serverUrl}`;
- nativeCommandText.textContent = cmd;
- nativeCommandContainer.style.display = "block";
- }
+ launchNativeViewer();
});
- function copyNativeCommand() {
- const cmd = nativeCommandText.textContent;
- navigator.clipboard.writeText(cmd).then(() => {
- const btn = document.querySelector(".copy-btn");
- btn.textContent = "Copied!";
- setTimeout(() => btn.textContent = "Copy", 2000);
- });
+ function launchNativeViewer() {
+ if (!connectSessionId) return;
+
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
+ const serverUrl = encodeURIComponent(protocol + "//" + window.location.host + "/ws/viewer");
+ const protocolUrl = `guruconnect://view/${connectSessionId}?server=${serverUrl}`;
+
+ // Try to launch the protocol handler
+ // We use a hidden iframe to avoid navigation issues
+ const iframe = document.createElement("iframe");
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+
+ // Set up timeout to detect if protocol handler didn't work
+ let launched = false;
+ const startTime = Date.now();
+
+ // If window loses focus quickly, protocol likely worked
+ const blurHandler = () => {
+ if (Date.now() - startTime < 2000) {
+ launched = true;
+ connectModal.classList.remove("active");
+ nativeNotInstalled.style.display = "none";
+ }
+ };
+ window.addEventListener("blur", blurHandler, { once: true });
+
+ // Try to launch
+ try {
+ iframe.contentWindow.location.href = protocolUrl;
+ } catch (e) {
+ // Some browsers throw on custom protocols
+ }
+
+ // Fallback: also try window.location for browsers that block iframe protocols
+ protocolCheckTimeout = setTimeout(() => {
+ window.removeEventListener("blur", blurHandler);
+ document.body.removeChild(iframe);
+
+ if (!launched) {
+ // Protocol handler probably not installed, show download option
+ nativeNotInstalled.style.display = "block";
+ }
+ }, 1500);
+ }
+
+ function retryNativeViewer() {
+ nativeNotInstalled.style.display = "none";
+ launchNativeViewer();
}
function connectToMachine(sessionId) {
@@ -981,7 +1022,7 @@
connectSessionId = sessionId;
connectMachineName = machine?.agent_name || sessionId.slice(0, 8);
connectMachineNameEl.textContent = connectMachineName;
- nativeCommandContainer.style.display = "none";
+ nativeNotInstalled.style.display = "none";
connectModal.classList.add("active");
}