refactor: enhance network traffic loading placeholder and error handling
This commit is contained in:
@@ -772,11 +772,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Live Network Traffic & Notes Row -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
|
||||
<!-- Live Network Traffic -->
|
||||
<div wire:ignore class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4 h-full w-full mt-0">
|
||||
<div wire:ignore class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="text-base font-semibold flex items-center gap-2">
|
||||
@@ -836,23 +838,18 @@
|
||||
|
||||
<!-- Network Traffic Sections -->
|
||||
<div id="network-traffic-container" data-live-traffic-endpoint="{{ route('proxmox.server.live-traffic', $server) }}">
|
||||
<div class="bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<div class="w-4 h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse"></div>
|
||||
<div class="w-24 h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse"></div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="h-3 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-3/4"></div>
|
||||
<div class="h-2 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-full"></div>
|
||||
<div class="h-3 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-2/3"></div>
|
||||
<div class="h-2 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-full"></div>
|
||||
</div>
|
||||
<!-- Initial placeholder - will be replaced with actual data on first load -->
|
||||
<div class="text-center py-6 text-gray-500 dark:text-gray-400 text-sm" id="network-traffic-placeholder">
|
||||
<svg class="w-8 h-8 mx-auto mb-2 animate-spin text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
Connecting to network monitor...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notes Section -->
|
||||
<div id="notes-section" class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4 h-full flex flex-col mt-0" x-data="{ showExportErrorModal: false }" x-cloak>
|
||||
<div id="notes-section" class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4 flex flex-col" x-data="{ showExportErrorModal: false }" x-cloak>
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="text-base font-semibold">Notes</h2>
|
||||
@@ -966,7 +963,7 @@
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@once
|
||||
@@ -1212,11 +1209,11 @@
|
||||
|
||||
if (networkData.interfaces.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-6 text-center">
|
||||
<svg class="w-10 h-10 mx-auto text-gray-300 dark:text-gray-600 mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div class="text-center py-6 text-gray-500 dark:text-gray-400 text-sm">
|
||||
<svg class="w-8 h-8 mx-auto mb-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">No network data available</p>
|
||||
No network interfaces detected
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
@@ -1516,10 +1513,10 @@
|
||||
const wasEmpty = !networkData || !networkData.interfaces || networkData.interfaces.length === 0;
|
||||
const hasExistingInterfaces = container && container.querySelectorAll('.chart-toggle').length > 0;
|
||||
|
||||
// Check if container shows the loading placeholder (skeleton loader)
|
||||
// Check if container shows the initial placeholder
|
||||
const showsPlaceholder = container && (
|
||||
container.querySelector('.animate-pulse') !== null ||
|
||||
container.querySelector('.border-dashed') !== null
|
||||
container.querySelector('#network-traffic-placeholder') !== null ||
|
||||
container.querySelector('.animate-spin') !== null
|
||||
);
|
||||
|
||||
networkData = data;
|
||||
@@ -1527,13 +1524,13 @@
|
||||
// Store globally for export access
|
||||
window.networkTrafficData = data;
|
||||
|
||||
// Render interfaces if:
|
||||
// 1. This is the first load (wasEmpty && no existing interfaces), OR
|
||||
// 2. Container shows placeholder (was reset by tab switch), OR
|
||||
// 3. No existing interfaces found in container
|
||||
// Render interfaces only if:
|
||||
// 1. This is the first load (showing placeholder), OR
|
||||
// 2. No existing interfaces found in container
|
||||
// Never re-render once we have data - just update values
|
||||
if (data.interfaces && data.interfaces.length > 0) {
|
||||
if (showsPlaceholder || !hasExistingInterfaces || wasEmpty) {
|
||||
console.log('Rendering interfaces - showsPlaceholder:', showsPlaceholder, 'hasExistingInterfaces:', hasExistingInterfaces, 'wasEmpty:', wasEmpty);
|
||||
if (showsPlaceholder || !hasExistingInterfaces) {
|
||||
console.log('Rendering interfaces - showsPlaceholder:', showsPlaceholder, 'hasExistingInterfaces:', hasExistingInterfaces);
|
||||
// Render immediately - no delay
|
||||
renderInterfaces();
|
||||
// Also update data immediately after render to ensure values are set
|
||||
@@ -1611,17 +1608,20 @@
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch live traffic data:', error);
|
||||
const container = document.getElementById('network-traffic-container');
|
||||
// Only show error if there's no existing network data (initial load failed)
|
||||
// Keep existing content if we already have data (refresh failed)
|
||||
const hasExistingContent = container && container.querySelectorAll('.chart-toggle').length > 0;
|
||||
if (container && !hasExistingContent) {
|
||||
// Only show error if still showing initial placeholder (no data loaded yet)
|
||||
// Never replace existing network data with error state
|
||||
const showsPlaceholder = container && (
|
||||
container.querySelector('#network-traffic-placeholder') !== null ||
|
||||
container.querySelector('.animate-spin') !== null
|
||||
);
|
||||
if (container && showsPlaceholder) {
|
||||
container.innerHTML = `
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-6 text-center">
|
||||
<svg class="w-10 h-10 mx-auto text-red-400 mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div class="text-center py-6 text-gray-500 dark:text-gray-400 text-sm">
|
||||
<svg class="w-8 h-8 mx-auto mb-2 text-red-400" 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"></path>
|
||||
</svg>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Failed to load network data</p>
|
||||
<p class="text-xs text-gray-400 dark:text-gray-500 mt-1">${error.message}</p>
|
||||
Failed to load network data
|
||||
<p class="text-xs text-gray-400 mt-1">${error.message}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user