Native viewer: use guruconnect:// protocol with fallback to download
This commit is contained in:
@@ -596,14 +596,17 @@
|
||||
<div class="connect-option-desc">Full keyboard capture including Win key, Alt+Tab, and Ctrl+Alt+Del.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="nativeCommandContainer" style="display: none;">
|
||||
<div class="native-command">
|
||||
<button class="copy-btn" onclick="copyNativeCommand()">Copy</button>
|
||||
<code id="nativeCommandText"></code>
|
||||
</div>
|
||||
<p style="margin-top: 12px; font-size: 12px; color: hsl(var(--muted-foreground));">
|
||||
Run this command in PowerShell or CMD where guruconnect-viewer.exe is located.
|
||||
<div id="nativeNotInstalled" style="display: none; margin-top: 16px; padding: 16px; background: hsla(45, 93%, 47%, 0.1); border: 1px solid hsla(45, 93%, 47%, 0.3); border-radius: 8px;">
|
||||
<p style="margin-bottom: 12px; color: hsl(45, 93%, 55%);">
|
||||
<strong>Native viewer not installed</strong>
|
||||
</p>
|
||||
<p style="font-size: 13px; margin-bottom: 12px; color: hsl(var(--muted-foreground));">
|
||||
Download and run GuruConnect to register the protocol handler, then click "Try Again".
|
||||
</p>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<a href="/downloads/guruconnect.exe" class="btn btn-primary" style="text-decoration: none;">Download GuruConnect</a>
|
||||
<button class="btn btn-outline" onclick="retryNativeViewer()">Try Again</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user