|
@@ -27,9 +27,18 @@
|
|
|
<i class="fas fa-shield-alt"></i> Stato Connessione VPN
|
|
<i class="fas fa-shield-alt"></i> Stato Connessione VPN
|
|
|
</h3>
|
|
</h3>
|
|
|
<div class="card-tools">
|
|
<div class="card-tools">
|
|
|
- <button type="button" class="btn btn-tool" wire:click="refreshStatus">
|
|
|
|
|
|
|
+ <button type="button"
|
|
|
|
|
+ class="btn btn-tool"
|
|
|
|
|
+ wire:click="refreshStatus(false)"
|
|
|
|
|
+ title="Aggiorna stato database">
|
|
|
<i class="fas fa-sync"></i>
|
|
<i class="fas fa-sync"></i>
|
|
|
</button>
|
|
</button>
|
|
|
|
|
+ <button type="button"
|
|
|
|
|
+ class="btn btn-tool"
|
|
|
|
|
+ wire:click="syncWithSystem"
|
|
|
|
|
+ title="Sincronizza con sistema">
|
|
|
|
|
+ <i class="fas fa-sync-alt"></i>
|
|
|
|
|
+ </button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="card-body">
|
|
<div class="card-body">
|
|
@@ -54,29 +63,80 @@
|
|
|
</div>
|
|
</div>
|
|
|
<div class="col-md-6">
|
|
<div class="col-md-6">
|
|
|
<div class="text-center">
|
|
<div class="text-center">
|
|
|
- <button type="button"
|
|
|
|
|
- class="btn btn-success btn-lg"
|
|
|
|
|
- wire:click="connectVpn"
|
|
|
|
|
- wire:loading.attr="disabled"
|
|
|
|
|
- wire:target="connectVpn">
|
|
|
|
|
- <span wire:loading.remove wire:target="connectVpn">
|
|
|
|
|
- <i class="fas fa-play"></i> Connetti VPN
|
|
|
|
|
- </span>
|
|
|
|
|
- <span wire:loading wire:target="connectVpn">
|
|
|
|
|
- <i class="fas fa-spinner fa-spin"></i> Connettendo...
|
|
|
|
|
- </span>
|
|
|
|
|
- </button>
|
|
|
|
|
|
|
+ @if($vpnStatus === 'connected')
|
|
|
|
|
+ <button type="button" class="btn btn-success btn-lg" disabled>
|
|
|
|
|
+ <i class="fas fa-check"></i> VPN Connessa
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <br><br>
|
|
|
|
|
+ <button type="button"
|
|
|
|
|
+ class="btn btn-warning btn-lg"
|
|
|
|
|
+ wire:click="disconnectVpn"
|
|
|
|
|
+ wire:loading.attr="disabled"
|
|
|
|
|
+ wire:target="disconnectVpn">
|
|
|
|
|
+ <span wire:loading.remove wire:target="disconnectVpn">
|
|
|
|
|
+ <i class="fas fa-stop"></i> Disconnetti VPN
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span wire:loading wire:target="disconnectVpn">
|
|
|
|
|
+ <i class="fas fa-spinner fa-spin"></i> Disconnettendo...
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ @elseif($vpnStatus === 'disconnected')
|
|
|
|
|
+ <button type="button"
|
|
|
|
|
+ class="btn btn-success btn-lg"
|
|
|
|
|
+ wire:click="connectVpn"
|
|
|
|
|
+ wire:loading.attr="disabled"
|
|
|
|
|
+ wire:target="connectVpn">
|
|
|
|
|
+ <span wire:loading.remove wire:target="connectVpn">
|
|
|
|
|
+ <i class="fas fa-play"></i> Connetti VPN
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span wire:loading wire:target="connectVpn">
|
|
|
|
|
+ <i class="fas fa-spinner fa-spin"></i> Connettendo...
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <br><br>
|
|
|
|
|
+ <button type="button" class="btn btn-secondary btn-lg" disabled>
|
|
|
|
|
+ <i class="fas fa-times"></i> VPN Disconnessa
|
|
|
|
|
+ </button>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <button type="button"
|
|
|
|
|
+ class="btn btn-success btn-lg"
|
|
|
|
|
+ wire:click="connectVpn"
|
|
|
|
|
+ wire:loading.attr="disabled"
|
|
|
|
|
+ wire:target="connectVpn">
|
|
|
|
|
+ <span wire:loading.remove wire:target="connectVpn">
|
|
|
|
|
+ <i class="fas fa-play"></i> Connetti VPN
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span wire:loading wire:target="connectVpn">
|
|
|
|
|
+ <i class="fas fa-spinner fa-spin"></i> Connettendo...
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <br><br>
|
|
|
|
|
+ <button type="button"
|
|
|
|
|
+ class="btn btn-warning btn-lg"
|
|
|
|
|
+ wire:click="disconnectVpn"
|
|
|
|
|
+ wire:loading.attr="disabled"
|
|
|
|
|
+ wire:target="disconnectVpn">
|
|
|
|
|
+ <span wire:loading.remove wire:target="disconnectVpn">
|
|
|
|
|
+ <i class="fas fa-stop"></i> Disconnetti VPN
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span wire:loading wire:target="disconnectVpn">
|
|
|
|
|
+ <i class="fas fa-spinner fa-spin"></i> Disconnettendo...
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ @endif
|
|
|
|
|
+
|
|
|
<br><br>
|
|
<br><br>
|
|
|
<button type="button"
|
|
<button type="button"
|
|
|
- class="btn btn-warning btn-lg"
|
|
|
|
|
- wire:click="disconnectVpn"
|
|
|
|
|
|
|
+ class="btn btn-info btn-sm"
|
|
|
|
|
+ wire:click="syncWithSystem"
|
|
|
wire:loading.attr="disabled"
|
|
wire:loading.attr="disabled"
|
|
|
- wire:target="disconnectVpn">
|
|
|
|
|
- <span wire:loading.remove wire:target="disconnectVpn">
|
|
|
|
|
- <i class="fas fa-stop"></i> Disconnetti VPN
|
|
|
|
|
|
|
+ wire:target="syncWithSystem"
|
|
|
|
|
+ title="Sincronizza stato con sistema">
|
|
|
|
|
+ <span wire:loading.remove wire:target="syncWithSystem">
|
|
|
|
|
+ <i class="fas fa-sync-alt"></i> Sincronizza
|
|
|
</span>
|
|
</span>
|
|
|
- <span wire:loading wire:target="disconnectVpn">
|
|
|
|
|
- <i class="fas fa-spinner fa-spin"></i> Disconnettendo...
|
|
|
|
|
|
|
+ <span wire:loading wire:target="syncWithSystem">
|
|
|
|
|
+ <i class="fas fa-spinner fa-spin"></i> Sincronizzando...
|
|
|
</span>
|
|
</span>
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
@@ -223,51 +283,166 @@
|
|
|
@push('scripts')
|
|
@push('scripts')
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
|
|
|
<script>
|
|
<script>
|
|
|
- // Listen for Livewire events
|
|
|
|
|
- document.addEventListener('livewire:load', function () {
|
|
|
|
|
- // Auto-refresh status every 30 seconds
|
|
|
|
|
- setInterval(function() {
|
|
|
|
|
- @this.call('refreshStatus');
|
|
|
|
|
- }, 30000);
|
|
|
|
|
|
|
+ let loadingTimeouts = {};
|
|
|
|
|
+
|
|
|
|
|
+ // Funzione per forzare il reset degli stati di loading
|
|
|
|
|
+ function forceResetLoadingStates() {
|
|
|
|
|
+ // Reset loading indicators
|
|
|
|
|
+ document.querySelectorAll('[wire\\:loading]').forEach(el => {
|
|
|
|
|
+ el.style.display = 'none';
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- // Update sidebar badge when status changes
|
|
|
|
|
- Livewire.on('vpnStatusUpdated', status => {
|
|
|
|
|
- updateSidebarBadge(status);
|
|
|
|
|
|
|
+ // Show normal buttons
|
|
|
|
|
+ document.querySelectorAll('[wire\\:loading\\.remove]').forEach(el => {
|
|
|
|
|
+ el.style.display = '';
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- // Show toast notifications
|
|
|
|
|
- Livewire.on('showToast', (type, message) => {
|
|
|
|
|
|
|
+ // Re-enable buttons (except permanently disabled ones)
|
|
|
|
|
+ document.querySelectorAll('button[disabled]').forEach(btn => {
|
|
|
|
|
+ if (!btn.classList.contains('permanently-disabled')) {
|
|
|
|
|
+ btn.removeAttribute('disabled');
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Clear all timeouts
|
|
|
|
|
+ Object.values(loadingTimeouts).forEach(timeout => clearTimeout(timeout));
|
|
|
|
|
+ loadingTimeouts = {};
|
|
|
|
|
+
|
|
|
|
|
+ console.log('Loading states forcefully reset');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Set timeout for each loading state
|
|
|
|
|
+ function setLoadingTimeout(target, duration = 8000) {
|
|
|
|
|
+ if (loadingTimeouts[target]) {
|
|
|
|
|
+ clearTimeout(loadingTimeouts[target]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ loadingTimeouts[target] = setTimeout(() => {
|
|
|
|
|
+ console.warn(`Loading timeout for ${target}, forcing reset`);
|
|
|
|
|
+ forceResetLoadingStates();
|
|
|
|
|
+
|
|
|
|
|
+ // Show error toast
|
|
|
if (typeof toastr !== 'undefined') {
|
|
if (typeof toastr !== 'undefined') {
|
|
|
- toastr[type](message);
|
|
|
|
|
|
|
+ toastr.error('Operazione completata (timeout raggiunto)');
|
|
|
}
|
|
}
|
|
|
|
|
+ }, duration);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Clear timeout when loading finishes
|
|
|
|
|
+ function clearLoadingTimeout(target) {
|
|
|
|
|
+ if (loadingTimeouts[target]) {
|
|
|
|
|
+ clearTimeout(loadingTimeouts[target]);
|
|
|
|
|
+ delete loadingTimeouts[target];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
+ // Livewire event listeners
|
|
|
|
|
+ window.addEventListener('livewire:load', function () {
|
|
|
|
|
+ console.log('Livewire loaded');
|
|
|
|
|
+
|
|
|
|
|
+ // Auto-refresh status every 30 seconds (only if not loading)
|
|
|
|
|
+ setInterval(function() {
|
|
|
|
|
+ if (Object.keys(loadingTimeouts).length === 0) {
|
|
|
|
|
+ @this.call('refreshStatus', false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 30000);
|
|
|
|
|
+
|
|
|
|
|
+ // Update sidebar badge when status changes
|
|
|
|
|
+ Livewire.on('vpnStatusUpdated', status => {
|
|
|
|
|
+ updateSidebarBadge(status);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Show toast notifications
|
|
|
|
|
+ Livewire.on('showToast', (type, message) => {
|
|
|
|
|
+ if (typeof toastr !== 'undefined') {
|
|
|
|
|
+ toastr[type](message);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ alert(type.toUpperCase() + ': ' + message);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Refresh status with delay
|
|
|
|
|
+ Livewire.on('refreshStatusDelayed', () => {
|
|
|
|
|
+ setTimeout(function() {
|
|
|
|
|
+ if (Object.keys(loadingTimeouts).length === 0) {
|
|
|
|
|
+ @this.call('refreshStatus', false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 3000);
|
|
|
|
|
+ });
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- // Refresh status with delay (after connect/disconnect commands)
|
|
|
|
|
- Livewire.on('refreshStatusDelayed', () => {
|
|
|
|
|
- setTimeout(function() {
|
|
|
|
|
- @this.call('refreshStatus');
|
|
|
|
|
- }, 3000);
|
|
|
|
|
|
|
+ // Track when loading starts
|
|
|
|
|
+ window.addEventListener('livewire:loading:start', function(event) {
|
|
|
|
|
+ const target = event.detail.target || 'unknown';
|
|
|
|
|
+ console.log('Loading started for:', target);
|
|
|
|
|
+ setLoadingTimeout(target);
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+ // Track when loading finishes
|
|
|
|
|
+ window.addEventListener('livewire:loading:finish', function(event) {
|
|
|
|
|
+ const target = event.detail.target || 'unknown';
|
|
|
|
|
+ console.log('Loading finished for:', target);
|
|
|
|
|
+ clearLoadingTimeout(target);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Force reset after 10 seconds on page load
|
|
|
|
|
+ setTimeout(forceResetLoadingStates, 10000);
|
|
|
|
|
+
|
|
|
|
|
+ // Initialize sidebar badge
|
|
|
|
|
+ const currentStatus = @json($vpnStatus ?? 'unknown');
|
|
|
|
|
+ updateSidebarBadge(currentStatus);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
function updateSidebarBadge(status) {
|
|
function updateSidebarBadge(status) {
|
|
|
const badge = document.getElementById('vpn-status-badge');
|
|
const badge = document.getElementById('vpn-status-badge');
|
|
|
if (badge) {
|
|
if (badge) {
|
|
|
- badge.className = ''; // Clear existing classes
|
|
|
|
|
- if (status === 'connected') {
|
|
|
|
|
- badge.className = 'badge badge-success right';
|
|
|
|
|
- badge.textContent = 'ON';
|
|
|
|
|
- } else if (status === 'disconnected') {
|
|
|
|
|
- badge.className = 'badge badge-danger right';
|
|
|
|
|
- badge.textContent = 'OFF';
|
|
|
|
|
- } else if (status === 'error') {
|
|
|
|
|
- badge.className = 'badge badge-danger right';
|
|
|
|
|
- badge.textContent = 'ERR';
|
|
|
|
|
- } else {
|
|
|
|
|
- badge.className = 'badge badge-warning right';
|
|
|
|
|
- badge.textContent = '?';
|
|
|
|
|
|
|
+ badge.className = '';
|
|
|
|
|
+ switch(status) {
|
|
|
|
|
+ case 'connected':
|
|
|
|
|
+ badge.className = 'badge badge-success right';
|
|
|
|
|
+ badge.textContent = 'ON';
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'disconnected':
|
|
|
|
|
+ badge.className = 'badge badge-danger right';
|
|
|
|
|
+ badge.textContent = 'OFF';
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'error':
|
|
|
|
|
+ badge.className = 'badge badge-danger right';
|
|
|
|
|
+ badge.textContent = 'ERR';
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ badge.className = 'badge badge-warning right';
|
|
|
|
|
+ badge.textContent = '?';
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // Emergency reset button (remove this in production)
|
|
|
|
|
+ function addEmergencyResetButton() {
|
|
|
|
|
+ if (document.getElementById('emergency-reset')) return;
|
|
|
|
|
+
|
|
|
|
|
+ const resetBtn = document.createElement('button');
|
|
|
|
|
+ resetBtn.id = 'emergency-reset';
|
|
|
|
|
+ resetBtn.innerHTML = '🔄 Reset Loading';
|
|
|
|
|
+ resetBtn.className = 'btn btn-danger btn-sm';
|
|
|
|
|
+ resetBtn.style.position = 'fixed';
|
|
|
|
|
+ resetBtn.style.top = '10px';
|
|
|
|
|
+ resetBtn.style.right = '10px';
|
|
|
|
|
+ resetBtn.style.zIndex = '9999';
|
|
|
|
|
+ resetBtn.onclick = forceResetLoadingStates;
|
|
|
|
|
+
|
|
|
|
|
+ document.body.appendChild(resetBtn);
|
|
|
|
|
+
|
|
|
|
|
+ // Auto-remove after 30 seconds
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ if (resetBtn.parentNode) {
|
|
|
|
|
+ resetBtn.parentNode.removeChild(resetBtn);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 30000);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Add emergency button if loading states persist
|
|
|
|
|
+ setTimeout(addEmergencyResetButton, 5000);
|
|
|
</script>
|
|
</script>
|
|
|
@endpush
|
|
@endpush
|