vnc embedded option

This commit is contained in:
Yuri Karamian
2025-12-18 23:41:18 +01:00
parent 9c09719fb9
commit f2f2222df7
11 changed files with 192 additions and 19 deletions
@@ -644,7 +644,7 @@
<script type="text/javascript">
var productURL = '{$WEB_ROOT}/clientarea.php?action=productdetails&id={$serviceid}';
var serverInfoInitial = JSON.parse('{$serverInfo|@json_encode}');
var serverInfoInitial = JSON.parse('{$serverInfo|json_encode}');
var lang = {
moduleactionfailed: 'Action failed!',
moduleactionsuccess: 'Action completed successfully',
@@ -1547,6 +1547,13 @@
<i class="fa fa-cog"></i> {$_LANG['Navbar']['Settings']}
</a>
</li>
{if $vncMode == 'embedded'}
<li class="nav-item">
<a class="nav-link" id="vnc-tab" data-toggle="tab" href="#vnc" role="tab" aria-controls="vnc" aria-selected="false" onclick="loadVNCConsole()">
<i class="fa fa-desktop"></i> {$_LANG['VNC']}
</a>
</li>
{/if}
</ul>
<div class="tab-content" id="pills-tabContent">
<div class="tab-pane fade show active" id="overview" role="tabpanel" aria-labelledby="overview-tab">
@@ -1732,11 +1739,17 @@
onclick="return confirmRestart();">
<i class="fa fa-sync mr-1"></i> {$_LANG['Restart']}
</button>
{if $vncMode == 'embedded'}
<button class="btn btn-info" onclick="$('#vnc-tab').tab('show'); loadVNCConsole();">
<i class="fa fa-desktop mr-1"></i> {$_LANG['VNC']}
</button>
{else}
<a href="{$WEB_ROOT}/clientarea.php?action=productdetails&id={$serviceid}&modop=custom&a=VNC"
target="_blank"
class="btn btn-info">
<i class="fa fa-desktop mr-1"></i> {$_LANG['VNC']}
</a>
{/if}
</div>
</div>
</div>
@@ -2114,6 +2127,32 @@
</div>
</div>
</div>
{if $vncMode == 'embedded'}
<!-- VNC Tab -->
<div class="tab-pane fade" id="vnc" role="tabpanel" aria-labelledby="vnc-tab">
<div class="card" id="vncCard">
<div class="card-header bg-info text-white d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fa fa-desktop mr-2"></i>{$_LANG['VNC']}</h5>
<div>
<button class="btn btn-sm btn-light" onclick="openVNCNewTab()" title="Open in New Tab">
<i class="fa fa-external-link-alt"></i>
</button>
<button class="btn btn-sm btn-light ml-1" onclick="toggleVNCFullscreen()" title="Fullscreen" id="vncFullscreenBtn">
<i class="fa fa-expand"></i>
</button>
</div>
</div>
<div class="card-body p-0" id="vncContainer">
<div id="vncLoading" class="text-center p-5">
<i class="fa fa-spinner fa-spin fa-3x"></i>
<p class="mt-3">Loading VNC Console...</p>
</div>
<iframe id="vncIframe" src="" style="width: 100%; height: 600px; border: none; display: none;"></iframe>
</div>
</div>
</div>
{/if}
</div>
</div>
</div>
@@ -2161,5 +2200,103 @@ jQuery(document).ready(function($) {
}
});
// Handle hash navigation for VNC tab (when coming from sidebar)
function handleVNCHash() {
if (window.location.hash === '#vnc') {
$('#vnc-tab').tab('show');
loadVNCConsole();
}
}
// Check on page load
if (window.location.hash === '#vnc') {
setTimeout(handleVNCHash, 100);
}
// Listen for hash changes (when clicking sidebar link while already on page)
$(window).on('hashchange', handleVNCHash);
// Intercept sidebar VNC link clicks
$('a[href$="#vnc"]').on('click', function(e) {
e.preventDefault();
$('#vnc-tab').tab('show');
loadVNCConsole();
history.pushState(null, null, '#vnc');
});
});
</script>
// VNC Tab functions
var vncLoaded = false;
function loadVNCConsole() {
if (vncLoaded) return;
var iframe = document.getElementById('vncIframe');
var loading = document.getElementById('vncLoading');
var container = document.getElementById('vncContainer');
if (!iframe || !container) return;
// Fetch VNC URL via API and load directly
jQuery.get(productURL + '&modop=custom&a=ClientAreaAPI&api=VNC Console&token={$token}', function(data) {
console.log('VNC API response:', data);
if (data && data.vnc_url) {
iframe.src = data.vnc_url;
iframe.style.display = 'block';
if (loading) loading.style.display = 'none';
vncLoaded = true;
} else if (data && data.message) {
container.innerHTML = '<div class="alert alert-danger m-3">' + data.message + '</div>';
} else {
container.innerHTML = '<div class="alert alert-warning m-3">VNC URL not available. Response: ' + JSON.stringify(data) + '</div>';
}
}).fail(function(xhr, status, error) {
console.log('VNC API error:', status, error);
container.innerHTML = '<div class="alert alert-danger m-3">Failed to load VNC console: ' + error + '</div>';
});
}
// Open VNC in new tab
function openVNCNewTab() {
window.open(productURL + '&modop=custom&a=VNC', '_blank');
}
// Toggle fullscreen for VNC
function toggleVNCFullscreen() {
var card = document.getElementById('vncCard');
var iframe = document.getElementById('vncIframe');
var btn = document.getElementById('vncFullscreenBtn');
if (!document.fullscreenElement) {
if (card.requestFullscreen) {
card.requestFullscreen();
} else if (card.webkitRequestFullscreen) {
card.webkitRequestFullscreen();
} else if (card.msRequestFullscreen) {
card.msRequestFullscreen();
}
iframe.style.height = '100vh';
btn.innerHTML = '<i class="fa fa-compress"></i>';
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
iframe.style.height = '600px';
btn.innerHTML = '<i class="fa fa-expand"></i>';
}
}
// Handle fullscreen change events
document.addEventListener('fullscreenchange', function() {
var iframe = document.getElementById('vncIframe');
var btn = document.getElementById('vncFullscreenBtn');
if (!document.fullscreenElement && iframe && btn) {
iframe.style.height = '600px';
btn.innerHTML = '<i class="fa fa-expand"></i>';
}
});
</script>