226 lines
10 KiB
PHP
226 lines
10 KiB
PHP
@extends('frontend.layouts.master')
|
|
|
|
@push('viewStyles')
|
|
<link rel="stylesheet" href="{{ asset('lib/wmks/css/wmks-all.css') }}" />
|
|
<link rel="stylesheet" href="{{ asset('css/service/console.css') }}">
|
|
@endpush
|
|
|
|
@section('content')
|
|
<div class="min-h-screen bg-gray-50">
|
|
<div class="container mx-auto px-6 py-8">
|
|
<!-- Main Layout: 2 Columns -->
|
|
<div class="flex flex-col gap-3">
|
|
<div class="w-full">
|
|
<div class="console-container">
|
|
<!-- Console Header -->
|
|
<div class="console-header">
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center space-x-3">
|
|
<div class="text-white">
|
|
<h3 class="font-medium text-base">VM Console</h3>
|
|
<p class="text-sm text-gray-400">{{ $product->name ?? 'Virtual Machine' }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center space-x-3">
|
|
<span class="status-dot status-connecting" id="statusDot"></span>
|
|
<span class="text-sm text-gray-400" id="statusText">Đang kết nối...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Loading State -->
|
|
<div id="loadingState" class="w-full h-[70vh] flex items-center justify-center bg-gray-900">
|
|
<div class="text-center">
|
|
<div class="loading-spinner mx-auto mb-4"></div>
|
|
<h3 class="text-xl font-medium text-white mb-2">Đang kết nối với vCenter</h3>
|
|
<p class="text-gray-400">Vui lòng chờ...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Console Display -->
|
|
<div id="wmksContainer" class="w-full h-[70vh] relative bg-black hidden">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="w-full">
|
|
<div class="control-panel">
|
|
<div class="flex flex-row gap-2 items-center p-2">
|
|
<button onclick="enterFullScreen()" class="btn-secondary flex items-center justify-center">
|
|
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
|
|
</svg>
|
|
Toàn màn hình
|
|
</button>
|
|
|
|
<button onclick="sendCAD()" class="btn-secondary flex items-center justify-center">
|
|
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
|
</svg>
|
|
Ctrl + Alt + Del
|
|
</button>
|
|
<div class="flex flex-row gap-2 items-center">
|
|
<input type="text" id="sendStringText" placeholder="Type your message..."
|
|
class="input-field" />
|
|
|
|
<button onclick="sendInputString()" class="btn-primary flex items-center justify-center">
|
|
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
|
|
</svg>
|
|
Gửi
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="{{ asset('lib/jquery/jquery.min.js') }}"></script>
|
|
<script src="{{ asset('lib/jquery-ui/jquery-ui.min.js') }}"></script>
|
|
<script src="{{ asset('lib/wmks/wmks.min.js') }}"></script>
|
|
<script src="{{ asset('lib/wmks/wmks-sdk-example.js') }}"></script>
|
|
|
|
<script type="text/javascript">
|
|
// Show loading state initially
|
|
$(document).ready(function() {
|
|
$('#loadingState').removeClass('hidden');
|
|
$('#wmksContainer').addClass('hidden');
|
|
});
|
|
|
|
let WMKSContainer = $('#wmksContainer');
|
|
// Retry and connection state variables
|
|
var isConnected = false;
|
|
var retryCount = 0;
|
|
const maxRetries = 30;
|
|
const retryDelay = 500; // ms
|
|
|
|
var wmks = WMKS.createWMKS("wmksContainer", {})
|
|
.register(WMKS.CONST.Events.CONNECTION_STATE_CHANGE, function(event, data) {
|
|
if (data.state === WMKS.CONST.ConnectionState.CONNECTED) {
|
|
console.log("Connected successfully");
|
|
isConnected = true;
|
|
retryCount = 0; // reset retries on success
|
|
|
|
// Update status
|
|
$('#statusDot').removeClass('status-connecting').addClass('status-connected');
|
|
$('#statusText').text('Connected');
|
|
|
|
// Hide loading and show console
|
|
$('#loadingState').addClass('hidden');
|
|
$('#wmksContainer').removeClass('hidden');
|
|
} else if (data.state === WMKS.CONST.ConnectionState.DISCONNECTED) {
|
|
console.log('WMKS disconnected');
|
|
isConnected = false;
|
|
$('#statusDot').removeClass('status-connecting status-connected').addClass('status-error');
|
|
$('#statusText').text('Disconnected');
|
|
}
|
|
});
|
|
|
|
const getTicket = new Promise((resolve, reject) => {
|
|
$.ajax({
|
|
url: '{{ route('api.user.GetConsoleTicket') }}',
|
|
type: 'get',
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Authorization': 'Bearer {{ request()->cookie('aut_accessToken') }}'
|
|
},
|
|
data: {
|
|
product: {{ $product->id }}
|
|
},
|
|
success: function(response) {
|
|
if (response.error === false) {
|
|
resolve(response)
|
|
} else {
|
|
reject(response.message)
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('API Error:', xhr.responseText);
|
|
reject('API request failed: ' + error);
|
|
}
|
|
})
|
|
});
|
|
|
|
getTicket
|
|
.then(result => {
|
|
if (result !== false) {
|
|
const wmksHost = '{{ config('vmware.wmks_host', '10.10.10.120') }}';
|
|
wmks.connect(`wss://${wmksHost}/ticket/${result.data}`);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.log(`Connection error: ${error}`)
|
|
|
|
// Update status
|
|
$('#statusDot').removeClass('status-connecting').addClass('status-error');
|
|
$('#statusText').text('Connection Failed');
|
|
|
|
// Hide loading state and show error
|
|
$('#loadingState').addClass('hidden');
|
|
$('#wmksContainer').removeClass('hidden');
|
|
|
|
WMKSContainer.html(`
|
|
<div class="flex items-center justify-center w-full h-full bg-gray-900">
|
|
<div class="text-center">
|
|
<div class="inline-flex items-center justify-center w-16 h-16 bg-red-100 rounded-full mb-4">
|
|
<svg class="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
</svg>
|
|
</div>
|
|
<h3 class="text-lg font-medium text-white mb-2">Connection Failed</h3>
|
|
<p class="text-gray-400 mb-4">Unable to connect to VM console</p>
|
|
<button onclick="location.reload()"
|
|
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors">
|
|
Try Again
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`);
|
|
})
|
|
|
|
// Control Functions
|
|
window.enterFullScreen = function() {
|
|
if (wmks) {
|
|
wmks.enterFullScreen();
|
|
}
|
|
};
|
|
|
|
window.sendCAD = function() {
|
|
if (wmks) {
|
|
wmks.sendCAD();
|
|
}
|
|
};
|
|
|
|
window.sendInputString = function() {
|
|
const text = document.getElementById('sendStringText').value;
|
|
if (text && wmks) {
|
|
wmks.sendInputString(text);
|
|
document.getElementById('sendStringText').value = '';
|
|
}
|
|
};
|
|
|
|
// Keyboard shortcuts
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'F11') {
|
|
e.preventDefault();
|
|
enterFullScreen();
|
|
}
|
|
|
|
if (e.ctrlKey && e.key === 'Enter') {
|
|
sendInputString();
|
|
}
|
|
});
|
|
|
|
// Enter key for text input
|
|
document.getElementById('sendStringText').addEventListener('keypress', function(e) {
|
|
if (e.key === 'Enter') {
|
|
sendInputString();
|
|
}
|
|
});
|
|
</script>
|
|
@endsection
|