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:
@@ -38,12 +38,7 @@
|
||||
localStorage.setItem('overview-notice-collapsed', this.isCollapsed);
|
||||
}
|
||||
}"
|
||||
x-init="
|
||||
isAdvancedView = localStorage.getItem('proxmox-view-mode') === 'advanced';
|
||||
window.addEventListener('proxmox-view-mode-changed', (e) => {
|
||||
isAdvancedView = e.detail.isAdvancedView;
|
||||
});
|
||||
"
|
||||
@proxmox-view-mode-changed.window="isAdvancedView = $event.detail.isAdvancedView"
|
||||
x-show="isAdvancedView"
|
||||
x-transition>
|
||||
<div class="flex items-start gap-3">
|
||||
@@ -103,7 +98,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"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
@@ -314,7 +309,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"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
@@ -470,7 +465,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="showHostnameEditModal = false; $wire.cancelEditingHostname()"
|
||||
@click.self="showHostnameEditModal = false; $wire.cancelEditingHostname()"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4">
|
||||
@@ -634,7 +629,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="showPasswordViewModal = false"
|
||||
@click.self="showPasswordViewModal = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;"
|
||||
x-data="{
|
||||
@@ -692,7 +687,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="showPasswordEditModal = false; $wire.cancelEditingPassword()"
|
||||
@click.self="showPasswordEditModal = false; $wire.cancelEditingPassword()"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4">
|
||||
@@ -796,7 +791,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;">
|
||||
@@ -894,7 +889,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"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
@@ -1096,7 +1091,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;">
|
||||
@@ -1163,7 +1158,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="showExportErrorModal = false"
|
||||
@click.self="showExportErrorModal = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-md bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
@@ -1269,7 +1264,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"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
@@ -1307,27 +1302,27 @@
|
||||
|
||||
|
||||
<div class="mt-2 border-l-4 bg-info/10 border border-info/30 p-3 rounded-md">
|
||||
<p class="text-sm dark:text-gray-100 font-bold leading-relaxed">
|
||||
<p class="text-sm text-base/90 font-bold leading-relaxed">
|
||||
Windows Server Networking (IPv4/IPv6 Setup):
|
||||
</p>
|
||||
<p class="text-sm dark:text-gray-200 italic leading-relaxed ">
|
||||
<p class="text-sm text-base/70 italic leading-relaxed ">
|
||||
Cloud-init does not automatically configure IPv4 or IPv6 networking on Windows Server installations. Please configure the addresses manually as assigned in the control panel of your installation.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-2 border-l-4 bg-info/10 border border-info/30 p-3 rounded-md">
|
||||
<p class="text-sm dark:text-gray-100 font-bold leading-relaxed">
|
||||
<p class="text-sm text-base/90 font-bold leading-relaxed">
|
||||
Windows Server Activation (Licensing):
|
||||
</p>
|
||||
<p class="text-sm dark:text-gray-100 italic leading-relaxed ">
|
||||
<p class="text-sm text-base/90 italic leading-relaxed ">
|
||||
No Windows Server license key is provided by Virtnet.bond. It is the responsibility of the account holder
|
||||
to provide and maintain active and compliant licensing with all Windows Server products.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-2 border-l-4 bg-info/10 border border-info/30 p-3 rounded-md">
|
||||
<p class="text-sm dark:text-gray-100 font-bold leading-relaxed">
|
||||
<p class="text-sm text-base/90 font-bold leading-relaxed">
|
||||
Periodic Licensing Audits and User Compliance:
|
||||
</p>
|
||||
<p class="text-sm dark:text-gray-200 italic leading-relaxed ">
|
||||
<p class="text-sm text-base/70 italic leading-relaxed ">
|
||||
Virtnet.bond reserves the right to perform periodic audits of Windows Server installations to ensure compliance with Microsoft's licensing terms. Non-compliant installations may be subject to suspension or termination. If you have any questions regarding licensing compliance, please contact our support team.
|
||||
</p>
|
||||
</div>
|
||||
@@ -1442,7 +1437,6 @@
|
||||
);
|
||||
|
||||
if (historyLength > 0) {
|
||||
console.log('Creating chart for interface:', interfaceId);
|
||||
requestAnimationFrame(() => {
|
||||
setTimeout(() => {
|
||||
if (!charts[interfaceId]) {
|
||||
@@ -1455,7 +1449,6 @@
|
||||
}
|
||||
|
||||
if (retries > 0) {
|
||||
console.log(`Chart data not ready for ${interfaceId}, retrying... (${retries} attempts left)`);
|
||||
setTimeout(() => attemptCreateChart(retries - 1, delay), delay);
|
||||
}
|
||||
};
|
||||
@@ -1594,15 +1587,6 @@
|
||||
let uploadRate = interfaceData.uploadRate ?? 0;
|
||||
|
||||
// Debug: Log interface data to verify each interface gets unique data
|
||||
console.log(`Updating interface ${interfaceId} (${interfaceData.id}):`, {
|
||||
downloadRate,
|
||||
uploadRate,
|
||||
totalIn: interfaceData.totalIn,
|
||||
totalOut: interfaceData.totalOut,
|
||||
hasHistory: !!interfaceData.history,
|
||||
historyLength: interfaceData.history?.download?.length || 0
|
||||
});
|
||||
|
||||
// Update peak rates
|
||||
if (!peakRates[interfaceId]) {
|
||||
peakRates[interfaceId] = { download: 0, upload: 0 };
|
||||
@@ -1651,7 +1635,6 @@
|
||||
interfaceData.history.upload?.length || 0
|
||||
);
|
||||
if (historyLength > 0) {
|
||||
console.log('Creating chart for', interfaceId, 'on data update (container was open)');
|
||||
setTimeout(() => createChart(interfaceId, interfaceData), 100);
|
||||
}
|
||||
}
|
||||
@@ -1800,15 +1783,6 @@
|
||||
});
|
||||
|
||||
// Debug logging
|
||||
console.log('Chart data for', interfaceId, {
|
||||
interfaceName: interfaceData.name,
|
||||
downloadData: downloadData,
|
||||
uploadData: uploadData,
|
||||
downloadMax: downloadData.length > 0 ? Math.max(...downloadData, 0) : 0,
|
||||
uploadMax: uploadData.length > 0 ? Math.max(...uploadData, 0) : 0,
|
||||
hasData: downloadData.some(v => v > 0) || uploadData.some(v => v > 0)
|
||||
});
|
||||
|
||||
// Calculate 95th percentile from combined traffic
|
||||
const combinedTraffic = downloadData.map((d, i) => d + (uploadData[i] || 0));
|
||||
const sortedTraffic = [...combinedTraffic].filter(v => v > 0).sort((a, b) => a - b);
|
||||
@@ -1818,14 +1792,6 @@
|
||||
p95Value = sortedTraffic[Math.min(p95Index, sortedTraffic.length - 1)];
|
||||
}
|
||||
const p95Data = Array(downloadData.length).fill(p95Value);
|
||||
|
||||
console.log('95th Percentile calculation:', {
|
||||
combinedTraffic: combinedTraffic,
|
||||
sortedTraffic: sortedTraffic,
|
||||
p95Value: p95Value,
|
||||
p95DataLength: p95Data.length
|
||||
});
|
||||
|
||||
// Create a local formatRate function that's guaranteed to be in scope
|
||||
const formatRateForChart = (bytesPerSec) => {
|
||||
if (typeof bytesPerSec !== 'number' || isNaN(bytesPerSec)) {
|
||||
@@ -1939,9 +1905,6 @@
|
||||
const poll = async () => {
|
||||
if (pollInFlight || !pollingEndpoint) return;
|
||||
pollInFlight = true;
|
||||
|
||||
console.log('Polling network data from:', pollingEndpoint);
|
||||
|
||||
try {
|
||||
const csrfElement = document.querySelector('meta[name="csrf-token"]');
|
||||
const csrfToken = csrfElement ? csrfElement.content : '';
|
||||
@@ -1955,13 +1918,8 @@
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
});
|
||||
|
||||
console.log('Network Traffic Response status:', response.status);
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('Network Traffic Data received:', data);
|
||||
|
||||
const container = document.getElementById('network-traffic-container');
|
||||
const wasEmpty = !networkData || !networkData.interfaces || networkData.interfaces.length === 0;
|
||||
const hasExistingInterfaces = container && container.querySelectorAll('.chart-toggle').length > 0;
|
||||
@@ -1983,7 +1941,6 @@
|
||||
// 3. No existing interfaces found in container
|
||||
if (data.interfaces && data.interfaces.length > 0) {
|
||||
if (showsPlaceholder || !hasExistingInterfaces || wasEmpty) {
|
||||
console.log('Rendering interfaces - showsPlaceholder:', showsPlaceholder, 'hasExistingInterfaces:', hasExistingInterfaces, 'wasEmpty:', wasEmpty);
|
||||
// Render immediately - no delay
|
||||
renderInterfaces();
|
||||
// Also update data immediately after render to ensure values are set
|
||||
@@ -2027,7 +1984,6 @@
|
||||
);
|
||||
|
||||
if (historyLength > 0) {
|
||||
console.log('Creating chart for interface:', interfaceId, 'after tab switch');
|
||||
requestAnimationFrame(() => {
|
||||
setTimeout(() => {
|
||||
if (!charts[interfaceId]) {
|
||||
@@ -2087,10 +2043,6 @@
|
||||
|
||||
const container = document.getElementById('network-traffic-container');
|
||||
pollingEndpoint = container?.dataset?.liveTrafficEndpoint || null;
|
||||
|
||||
console.log('Network Traffic Bootstrap: Container found:', !!container);
|
||||
console.log('Network Traffic Bootstrap: Endpoint:', pollingEndpoint);
|
||||
|
||||
if (pollingEndpoint && container) {
|
||||
// Check if container exists and has endpoint - be less strict about visibility
|
||||
// Sometimes container exists but offsetParent check fails initially
|
||||
@@ -2099,8 +2051,6 @@
|
||||
|
||||
if (isVisible || containerExists) {
|
||||
// Always poll immediately on bootstrap (don't wait for interval)
|
||||
console.log('Network Traffic: Polling immediately on bootstrap...');
|
||||
|
||||
// Poll immediately - don't wait
|
||||
poll();
|
||||
|
||||
@@ -2109,11 +2059,9 @@
|
||||
setTimeout(() => {
|
||||
if (!pollInterval) {
|
||||
pollInterval = setInterval(poll, 30000);
|
||||
console.log('Network Traffic: Polling interval set up (30 seconds)');
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
console.log('Network Traffic: Container not ready, will retry via visibility check');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2145,7 +2093,6 @@
|
||||
}
|
||||
} else {
|
||||
// Successfully bootstrapped, also try immediate poll as backup
|
||||
console.log('Network Traffic: Bootstrap successful, ensuring immediate poll...');
|
||||
}
|
||||
|
||||
// Re-initialize on Livewire lifecycle events (immediate)
|
||||
@@ -2208,12 +2155,6 @@
|
||||
);
|
||||
|
||||
if (historyLength > 0) {
|
||||
console.log('Creating chart for interface:', interfaceId, 'with data:', {
|
||||
id: interfaceData.id,
|
||||
name: interfaceData.name,
|
||||
historyLength: historyLength
|
||||
});
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setTimeout(() => {
|
||||
if (!charts[interfaceId]) {
|
||||
@@ -2226,7 +2167,6 @@
|
||||
}
|
||||
|
||||
if (retries > 0) {
|
||||
console.log(`Chart data not ready for ${interfaceId}, retrying... (${retries} attempts left)`);
|
||||
setTimeout(() => attemptCreateChart(retries - 1, delay), delay);
|
||||
} else {
|
||||
console.warn('Failed to create chart for', interfaceId, 'after multiple attempts');
|
||||
@@ -2256,7 +2196,6 @@
|
||||
// 1. No polling interval (not initialized), OR
|
||||
// 2. Shows placeholder (was reset)
|
||||
if (isVisible && hasEndpoint && (showsPlaceholder || !pollInterval)) {
|
||||
console.log('Network Traffic: Container needs initialization (placeholder:', showsPlaceholder, 'no interval:', !pollInterval, '), re-initializing...');
|
||||
bootstrap();
|
||||
}
|
||||
|
||||
@@ -2266,7 +2205,6 @@
|
||||
if (!pollingEndpoint) {
|
||||
pollingEndpoint = hasEndpoint;
|
||||
}
|
||||
console.log('Network Traffic: Container visible with endpoint but no polling active, polling immediately...');
|
||||
poll();
|
||||
setTimeout(() => {
|
||||
if (!pollInterval) {
|
||||
@@ -2281,7 +2219,6 @@
|
||||
|
||||
// Register cleanup function for Livewire navigation
|
||||
window.__networkTrafficCleanup = () => {
|
||||
console.log('Network Traffic: Cleaning up for navigation...');
|
||||
if (visibilityCheckInterval) {
|
||||
clearInterval(visibilityCheckInterval);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user