Refactor modal close behavior and improve styling
- Changed modal close event from `@click.away` to `@click.self` for better control over closing modals. - Updated various modal button styles for consistency and improved accessibility. - Adjusted transition durations for modal animations to enhance user experience. - Added aria-labels to close buttons for better screen reader support.
This commit is contained in:
@@ -50,7 +50,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -162,7 +162,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -251,7 +251,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -345,7 +345,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -442,7 +442,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -536,7 +536,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -632,7 +632,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -1054,7 +1054,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -1549,7 +1549,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -1968,7 +1968,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -2129,15 +2129,15 @@
|
||||
<tr class="hover:bg-background-secondary/50 transition-colors">
|
||||
<td class="py-3 px-4 text-sm whitespace-nowrap">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-hard-drive-line class="size-4" style="color: #9256b5" />
|
||||
<x-ri-hard-drive-line class="size-4 text-purple-500 dark:text-purple-400" />
|
||||
<span class="font-medium">Disk Read Rate</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm whitespace-nowrap">
|
||||
<span class="font-medium" style="color: #9256b5">{{ $this->formatBytes($diff['disk_read']['historical_rate']) }}/s</span>
|
||||
<span class="font-medium text-purple-500 dark:text-purple-400">{{ $this->formatBytes($diff['disk_read']['historical_rate']) }}/s</span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm whitespace-nowrap">
|
||||
<span class="font-medium" style="color: #9256b5">{{ $this->formatBytes($diff['disk_read']['current_rate']) }}/s</span>
|
||||
<span class="font-medium text-purple-500 dark:text-purple-400">{{ $this->formatBytes($diff['disk_read']['current_rate']) }}/s</span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm whitespace-nowrap">
|
||||
<span class="inline-flex items-center px-2 py-1 rounded-md text-xs font-semibold {{ $diff['disk_read']['percent_change'] > 0 ? 'bg-warning/20 text-warning' : ($diff['disk_read']['percent_change'] < 0 ? 'bg-success/20 text-success' : 'bg-base/20 text-base/70') }}">
|
||||
@@ -2150,15 +2150,15 @@
|
||||
<tr class="hover:bg-background-secondary/50 transition-colors">
|
||||
<td class="py-3 px-4 text-sm whitespace-nowrap">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-hard-drive-line class="size-4" style="color: #60496f" />
|
||||
<x-ri-hard-drive-line class="size-4 text-purple-700 dark:text-purple-300" />
|
||||
<span class="font-medium">Disk Write Rate</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm whitespace-nowrap">
|
||||
<span class="font-medium" style="color: #60496f">{{ $this->formatBytes($diff['disk_write']['historical_rate']) }}/s</span>
|
||||
<span class="font-medium text-purple-700 dark:text-purple-300">{{ $this->formatBytes($diff['disk_write']['historical_rate']) }}/s</span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm whitespace-nowrap">
|
||||
<span class="font-medium" style="color: #60496f">{{ $this->formatBytes($diff['disk_write']['current_rate']) }}/s</span>
|
||||
<span class="font-medium text-purple-700 dark:text-purple-300">{{ $this->formatBytes($diff['disk_write']['current_rate']) }}/s</span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm whitespace-nowrap">
|
||||
<span class="inline-flex items-center px-2 py-1 rounded-md text-xs font-semibold {{ $diff['disk_write']['percent_change'] > 0 ? 'bg-warning/20 text-warning' : ($diff['disk_write']['percent_change'] < 0 ? 'bg-success/20 text-success' : 'bg-base/20 text-base/70') }}">
|
||||
@@ -2289,7 +2289,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -3159,7 +3159,7 @@
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -3375,7 +3375,7 @@
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -3778,7 +3778,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@click.self="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -3868,7 +3868,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="$wire.closeClearStatisticsModal()"
|
||||
@click.self="$wire.closeClearStatisticsModal()"
|
||||
@keydown.escape.window="$wire.closeClearStatisticsModal()"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -3928,7 +3928,7 @@
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="$wire.closeExportInfoModal()"
|
||||
@click.self="$wire.closeExportInfoModal()"
|
||||
@keydown.escape.window="$wire.closeExportInfoModal()"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
@@ -5088,7 +5088,6 @@
|
||||
(!diskChartExpected || diskChartHasData);
|
||||
|
||||
if (allExpectedChartsHaveData) {
|
||||
console.log('All expected charts have received data.');
|
||||
try {
|
||||
window.dispatchEvent(new CustomEvent('proxmox-all-stats-loaded'));
|
||||
} catch (e) {}
|
||||
@@ -5103,8 +5102,6 @@
|
||||
}
|
||||
|
||||
chartRetryAttempts[chartType]++;
|
||||
console.log('Requesting ' + chartType + ' chart data (attempt ' + chartRetryAttempts[chartType] + ')');
|
||||
|
||||
try {
|
||||
// Dispatch individual chart event for more reliable loading
|
||||
Livewire.dispatch('proxmox:stats:' + chartType);
|
||||
@@ -5145,8 +5142,6 @@
|
||||
|
||||
// Request all chart data in parallel using individual events
|
||||
// This ensures each chart loads independently - if one fails, others still work
|
||||
console.log('Requesting all Proxmox stats (parallel individual requests)');
|
||||
|
||||
if (cpuChartExpected) {
|
||||
requestChartData('cpu');
|
||||
checkAndRetryChart('cpu', false, true);
|
||||
@@ -5274,9 +5269,6 @@
|
||||
// Get the current server ID from the DOM (dynamically)
|
||||
var serverIdElement = document.querySelector('[data-server-id]');
|
||||
var currentServerId = serverIdElement ? serverIdElement.getAttribute('data-server-id') : '{{ $server->id }}';
|
||||
|
||||
console.log('Setting up event listeners for server:', currentServerId);
|
||||
|
||||
var cpuCleanup = Livewire.on('proxmox:stats:' + currentServerId + ':cpu', function(eventData) {
|
||||
if (!cpuChart) {
|
||||
console.warn('CPU chart not initialized');
|
||||
@@ -5453,7 +5445,6 @@
|
||||
// Load Network Analysis after charts are initialized (non-blocking)
|
||||
function loadNetworkAnalysisData() {
|
||||
// Start the timeout FIRST before loading, so it's guaranteed to start
|
||||
console.log('Starting Network Analysis load process - timeout will begin');
|
||||
startNetworkAnalysisTimeout();
|
||||
|
||||
setTimeout(function() {
|
||||
@@ -5461,7 +5452,6 @@
|
||||
// Use a Livewire event instead of @this directly so that
|
||||
// the initial load is reliable even on first-ever visits.
|
||||
Livewire.dispatch('proxmox:network-analysis-load');
|
||||
console.log('Network Analysis load event dispatched');
|
||||
} catch (e) {
|
||||
console.warn('Failed to dispatch Network Analysis load event:', e);
|
||||
// Even if dispatch fails, timeout is already started
|
||||
@@ -5478,7 +5468,6 @@
|
||||
// Check if we've already refreshed once in this session for this server
|
||||
var hasAlreadyRefreshed = sessionStorage.getItem(refreshKey);
|
||||
if (hasAlreadyRefreshed === 'true') {
|
||||
console.log('Network Analysis timeout skipped - page has already been refreshed once in this session for server ' + serverId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5486,10 +5475,6 @@
|
||||
if (window.networkAnalysisTimeoutId) {
|
||||
clearTimeout(window.networkAnalysisTimeoutId);
|
||||
}
|
||||
|
||||
console.log('Network Analysis timeout started - page will refresh in 30 seconds if data does not load (one-time refresh only)');
|
||||
console.log('Timeout ID will be stored at: window.networkAnalysisTimeoutId');
|
||||
|
||||
// Simple timeout: refresh after 30 seconds unless we can confirm it loaded
|
||||
window.networkAnalysisTimeoutId = setTimeout(function() {
|
||||
console.warn('=== Network Analysis timeout callback FIRED (30 seconds elapsed) ===');
|
||||
@@ -5501,7 +5486,6 @@
|
||||
// Double-check we haven't already refreshed (in case of race conditions)
|
||||
var hasAlreadyRefreshedCheck = sessionStorage.getItem(refreshKey);
|
||||
if (hasAlreadyRefreshedCheck === 'true') {
|
||||
console.log('Network Analysis timeout - page was already refreshed for server ' + serverId + ', skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5522,9 +5506,6 @@
|
||||
var hasLoadingText = loadingTextElements.some(function(p) {
|
||||
return p && p.textContent && p.textContent.includes('Fetching data from Core Router');
|
||||
});
|
||||
|
||||
console.log('Loading check:', { isLoadingVisible: isLoadingVisible, hasLoadingText: hasLoadingText });
|
||||
|
||||
// If loading indicator is visible, definitely refresh (but only once)
|
||||
if (isLoadingVisible || hasLoadingText) {
|
||||
console.warn('Network Analysis timeout - loading indicator still visible, refreshing page NOW (one-time refresh) for server ' + serverId);
|
||||
@@ -5538,12 +5519,8 @@
|
||||
var hasError = networkAnalysisCard.querySelector('[class*="border-warning"]');
|
||||
var hasEmptyState = networkAnalysisCard.querySelector('.text-center.py-6');
|
||||
var hasTabs = networkAnalysisCard.querySelector('[x-data*="tab"]');
|
||||
|
||||
console.log('Content check:', { hasTable: !!hasTable, hasError: !!hasError, hasEmptyState: !!hasEmptyState, hasTabs: !!hasTabs });
|
||||
|
||||
// Only skip refresh if we have clear evidence it loaded (tabs + content)
|
||||
if ((hasTabs && (hasTable || hasError || hasEmptyState)) || hasError) {
|
||||
console.log('Network Analysis loaded successfully (found tabs and content), NOT refreshing');
|
||||
cancelNetworkAnalysisTimeout();
|
||||
// Clear the refresh flag since we loaded successfully
|
||||
sessionStorage.removeItem(refreshKey);
|
||||
@@ -5555,8 +5532,6 @@
|
||||
sessionStorage.setItem(refreshKey, 'true');
|
||||
window.location.reload();
|
||||
}, 30000); // 30 seconds
|
||||
|
||||
console.log('Timeout set with ID:', window.networkAnalysisTimeoutId);
|
||||
}
|
||||
|
||||
// Function to cancel the Network Analysis timeout
|
||||
@@ -5564,7 +5539,6 @@
|
||||
if (window.networkAnalysisTimeoutId) {
|
||||
clearTimeout(window.networkAnalysisTimeoutId);
|
||||
window.networkAnalysisTimeoutId = null;
|
||||
console.log('Network Analysis timeout cancelled - data has loaded');
|
||||
}
|
||||
// Clear the refresh flag since data loaded successfully (server-specific)
|
||||
var serverId = {{ $server->id ?? 0 }};
|
||||
@@ -5621,7 +5595,6 @@
|
||||
var serverId = {{ $server->id ?? 0 }};
|
||||
var refreshKey = 'networkAnalysisRefreshed_' + serverId;
|
||||
sessionStorage.removeItem(refreshKey);
|
||||
console.log('Network Analysis loaded successfully on page load, refresh flag cleared for server ' + serverId);
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
@@ -5652,15 +5625,11 @@
|
||||
document.addEventListener('network-analysis-502-retry', function(event) {
|
||||
var retryCount = (event.detail && event.detail.retryCount) ? event.detail.retryCount : 1;
|
||||
var delay = Math.min(2000 * retryCount, 5000); // Exponential backoff, max 5 seconds
|
||||
|
||||
console.log('Core Router API 502 error detected, retrying in ' + delay + 'ms (Attempt ' + retryCount + ')');
|
||||
|
||||
setTimeout(function() {
|
||||
try {
|
||||
// Dispatch the same event used for initial load so that
|
||||
// retries are decoupled from any specific @this instance.
|
||||
Livewire.dispatch('proxmox:network-analysis-load');
|
||||
console.log('Network Analysis retry event dispatched after 502 (delay ' + delay + 'ms)');
|
||||
} catch (e) {
|
||||
console.error('Failed to retry Network Analysis after 502 error:', e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user