feat: enhance VM console loading UI with a new spinner and status text styles
This commit is contained in:
@@ -1,72 +1,84 @@
|
||||
/* Admin Console */
|
||||
|
||||
/* Loading Animation Styles */
|
||||
/* Simple Loading Container */
|
||||
.loading-container {
|
||||
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
|
||||
background: #1a1a2e;
|
||||
min-height: 500px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.2);
|
||||
border-left: 4px solid #007bff;
|
||||
/* LDS Roller Spinner */
|
||||
.lds-roller,
|
||||
.lds-roller div,
|
||||
.lds-roller div:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.lds-roller {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.lds-roller div {
|
||||
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
||||
transform-origin: 40px 40px;
|
||||
}
|
||||
|
||||
.lds-roller div:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 7.2px;
|
||||
height: 7.2px;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
background: currentColor;
|
||||
margin: -3.6px 0 0 -3.6px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
.lds-roller div:nth-child(1) { animation-delay: -0.036s; }
|
||||
.lds-roller div:nth-child(1):after { top: 62.62742px; left: 62.62742px; }
|
||||
.lds-roller div:nth-child(2) { animation-delay: -0.072s; }
|
||||
.lds-roller div:nth-child(2):after { top: 67.71281px; left: 56px; }
|
||||
.lds-roller div:nth-child(3) { animation-delay: -0.108s; }
|
||||
.lds-roller div:nth-child(3):after { top: 70.90963px; left: 48.28221px; }
|
||||
.lds-roller div:nth-child(4) { animation-delay: -0.144s; }
|
||||
.lds-roller div:nth-child(4):after { top: 72px; left: 40px; }
|
||||
.lds-roller div:nth-child(5) { animation-delay: -0.18s; }
|
||||
.lds-roller div:nth-child(5):after { top: 70.90963px; left: 31.71779px; }
|
||||
.lds-roller div:nth-child(6) { animation-delay: -0.216s; }
|
||||
.lds-roller div:nth-child(6):after { top: 67.71281px; left: 24px; }
|
||||
.lds-roller div:nth-child(7) { animation-delay: -0.252s; }
|
||||
.lds-roller div:nth-child(7):after { top: 62.62742px; left: 17.37258px; }
|
||||
.lds-roller div:nth-child(8) { animation-delay: -0.288s; }
|
||||
.lds-roller div:nth-child(8):after { top: 56px; left: 12.28719px; }
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
@keyframes lds-roller {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading-dots {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
/* Simple Loading Text */
|
||||
.loading-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.loading-dots span {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #007bff;
|
||||
animation: pulse 1.4s ease-in-out infinite both;
|
||||
.loading-text {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.loading-dots span:nth-child(1) {
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.loading-dots span:nth-child(2) {
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
.loading-dots span:nth-child(3) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
transform: scale(0.7);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
.loading-status {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* Legacy styles */
|
||||
.console-container {
|
||||
transition: all 0.5s ease-in-out;
|
||||
min-height: 500px;
|
||||
@@ -76,34 +88,6 @@
|
||||
transition: opacity 0.4s ease-in-out;
|
||||
}
|
||||
|
||||
.spinner-box {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.three-quarter-spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 3px solid #fb5b53;
|
||||
border-top: 3px solid transparent;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.5s linear 0s infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* User Console */
|
||||
.console-container {
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
@section('breadcrumb')
|
||||
@php
|
||||
$breadcrumbItems = [
|
||||
['label' => 'Modules'],
|
||||
['label' => 'Package vCenter'],
|
||||
['label' => 'Virtual Machine', 'route' => 'package.vm.index'],
|
||||
['label' => $vm->name ?? $vm->vm_id ?? 'Console', 'active' => true],
|
||||
];
|
||||
$breadcrumbItems = [
|
||||
['label' => 'Modules'],
|
||||
['label' => 'Package vCenter'],
|
||||
['label' => 'Virtual Machine', 'route' => 'package.vm.index'],
|
||||
['label' => $vm->name ?? $vm->vm_id ?? 'Console', 'active' => true],
|
||||
];
|
||||
@endphp
|
||||
<x-admin-breadcrumb :items="$breadcrumbItems" />
|
||||
@endsection
|
||||
@@ -24,81 +24,82 @@
|
||||
<!-- VM Info Card -->
|
||||
<div class="card card-outline card-secondary mb-3">
|
||||
<div class="card-header d-flex bg-white align-items-center justify-content-between">
|
||||
<h5 class="card-title">{{ $vm->name ?? 'VM Console' }} ({{ $vm->vm_id }})</h5>
|
||||
<h5 class="card-title mb-0">{{ $vm->name ?? 'VM Console' }} ({{ $vm->vm_id }})</h5>
|
||||
<div class="card-tools">
|
||||
<x-button-c-r-m route="package.vm.index" label="Tất cả VM"/>
|
||||
<x-button-crm type="button" variant="outline-info" size="sm" route="package.vm.index" icon="list">Tất cả
|
||||
VM</x-button-crm>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-2">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">Power State</small>
|
||||
<p class="mb-0">{{ $vm->power_state ?? 'N/A' }}</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">CPU</small>
|
||||
@if($vmStats && isset($vmStats['cpu']))
|
||||
<p class="mb-0">
|
||||
{{ $vmStats['cpu']['cores'] ?? $vm->cpu ?? 'N/A' }} vCore
|
||||
@if(isset($vmStats['cpu']['used_percent']))
|
||||
<span class="badge bg-{{ $vmStats['cpu']['used_percent'] > 80 ? 'danger' : 'success' }} ml-1">
|
||||
{{ $vmStats['cpu']['used_percent'] }}%
|
||||
</span>
|
||||
@endif
|
||||
</p>
|
||||
@else
|
||||
<p class="mb-0">{{ $vm->cpu ?? 'N/A' }} vCore</p>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">RAM</small>
|
||||
@if($vmStats && isset($vmStats['memory']))
|
||||
<p class="mb-0">
|
||||
{{ $vmStats['memory']['size_GB'] ?? round(($vm->ram_mb ?? 0) / 1024, 2) }} GB
|
||||
@if(isset($vmStats['memory']['used_GB']))
|
||||
<span class="badge bg-{{ $vmStats['memory']['usage_percent'] > 80 ? 'danger' : 'success' }} ml-1">
|
||||
{{ $vmStats['memory']['used_GB'] }} GB ({{ $vmStats['memory']['usage_percent'] }}%)
|
||||
</span>
|
||||
@endif
|
||||
</p>
|
||||
@else
|
||||
<p class="mb-0">{{ $vm->ram_mb ? round($vm->ram_mb / 1024, 2) : 'N/A' }} GB</p>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">Disk</small>
|
||||
@if($vmStats && isset($vmStats['disk']) && count($vmStats['disk']) > 0)
|
||||
<p class="mb-0">
|
||||
@foreach($vmStats['disk'] as $disk)
|
||||
{{ $disk['capacity_GB'] }} GB
|
||||
@endforeach
|
||||
</p>
|
||||
@else
|
||||
<p class="mb-0">N/A</p>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">Datacenter</small>
|
||||
<p class="mb-0">{{ $vm->datacenter->name ?? 'N/A' }}</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">vCenter</small>
|
||||
<p class="mb-0">
|
||||
@if($vm->datacenter && $vm->datacenter->vCenter)
|
||||
{{ $vm->datacenter->vCenter->host }}
|
||||
</div>
|
||||
<div class="card-body p-2">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">Power State</small>
|
||||
<p class="mb-0">{{ $vm->power_state ?? 'N/A' }}</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">CPU</small>
|
||||
@if($vmStats && isset($vmStats['cpu']))
|
||||
<p class="mb-0">
|
||||
{{ $vmStats['cpu']['cores'] ?? $vm->cpu ?? 'N/A' }} vCore
|
||||
@if(isset($vmStats['cpu']['used_percent']))
|
||||
<span class="badge bg-{{ $vmStats['cpu']['used_percent'] > 80 ? 'danger' : 'success' }} ml-1">
|
||||
{{ $vmStats['cpu']['used_percent'] }}%
|
||||
</span>
|
||||
@endif
|
||||
</p>
|
||||
@else
|
||||
N/A
|
||||
<p class="mb-0">{{ $vm->cpu ?? 'N/A' }} vCore</p>
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">RAM</small>
|
||||
@if($vmStats && isset($vmStats['memory']))
|
||||
<p class="mb-0">
|
||||
{{ $vmStats['memory']['size_GB'] ?? round(($vm->ram_mb ?? 0) / 1024, 2) }} GB
|
||||
@if(isset($vmStats['memory']['used_GB']))
|
||||
<span class="badge bg-{{ $vmStats['memory']['usage_percent'] > 80 ? 'danger' : 'success' }} ml-1">
|
||||
{{ $vmStats['memory']['used_GB'] }} GB ({{ $vmStats['memory']['usage_percent'] }}%)
|
||||
</span>
|
||||
@endif
|
||||
</p>
|
||||
@else
|
||||
<p class="mb-0">{{ $vm->ram_mb ? round($vm->ram_mb / 1024, 2) : 'N/A' }} GB</p>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">Disk</small>
|
||||
@if($vmStats && isset($vmStats['disk']) && count($vmStats['disk']) > 0)
|
||||
<p class="mb-0">
|
||||
@foreach($vmStats['disk'] as $disk)
|
||||
{{ $disk['capacity_GB'] }} GB
|
||||
@endforeach
|
||||
</p>
|
||||
@else
|
||||
<p class="mb-0">N/A</p>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">Datacenter</small>
|
||||
<p class="mb-0">{{ $vm->datacenter->name ?? 'N/A' }}</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<small class="text-muted">vCenter</small>
|
||||
<p class="mb-0">
|
||||
@if($vm->datacenter && $vm->datacenter->vCenter)
|
||||
{{ $vm->datacenter->vCenter->host }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Control Panel -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header bg-white">
|
||||
<h5 class="card-title fw-bold">Console Controls</h5>
|
||||
<!-- Control Panel -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header bg-white">
|
||||
<h5 class="card-title fw-bold mb-0">Console Controls</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
@@ -109,16 +110,16 @@
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label> </label>
|
||||
<div class="btn-group d-flex" role="group">
|
||||
<button onclick="enterFullScreen()" class="btn btn-primary btn-sm flex-fill">
|
||||
<i class="fas fa-expand"></i> Fullscreen
|
||||
</button>
|
||||
<button onclick="sendCAD()" class="btn btn-info btn-sm flex-fill">
|
||||
<i class="fas fa-keyboard"></i> Ctrl+Alt+Del
|
||||
</button>
|
||||
<button onclick="sendInputString()" class="btn btn-success btn-sm flex-fill">
|
||||
<i class="fas fa-paper-plane"></i> Send
|
||||
</button>
|
||||
<div class="btn-group d-flex gap-2" role="group">
|
||||
<x-button-c-r-m type="button" variant="primary" size="sm" icon="maximize" onclick="enterFullScreen()" class="flex-fill">
|
||||
Fullscreen
|
||||
</x-button-c-r-m>
|
||||
<x-button-c-r-m type="button" variant="info" size="sm" icon="keyboard" onclick="sendCAD()" class="flex-fill">
|
||||
Ctrl+Alt+Del
|
||||
</x-button-c-r-m>
|
||||
<x-button-c-r-m type="button" variant="success" size="sm" icon="send" onclick="sendInputString()" class="flex-fill">
|
||||
Send
|
||||
</x-button-c-r-m>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -130,22 +131,22 @@
|
||||
<div class="card-body p-0 position-relative">
|
||||
<!-- Loading State -->
|
||||
<div id="loadingState"
|
||||
class="loading-container d-flex align-items-center justify-content-center text-dark fade-transition"
|
||||
class="loading-container d-flex align-items-center justify-content-center fade-transition"
|
||||
style="height: 70vh;">
|
||||
<div class="text-center">
|
||||
<div class="spinner-box">
|
||||
<div class="three-quarter-spinner"></div>
|
||||
</div>
|
||||
<h5 class="mb-3">Connecting to vCenter...</h5>
|
||||
<p class="text-muted" id="loadingText">Initializing console</p>
|
||||
<div class="loading-dots justify-content-center">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<small class="text-muted" id="connectionStatus">Setting up session...</small>
|
||||
<div class="text-center" style="position: relative; z-index: 1; color: #3b82f6;">
|
||||
<div class="lds-roller mb-4">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
<h5 class="loading-title mb-2">Connecting to vCenter</h5>
|
||||
<p class="loading-text mb-1" id="loadingText">Initializing console</p>
|
||||
<small class="loading-status" id="connectionStatus">Setting up session...</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user