Implement smart loading system with intelligent timeout and graceful error handling
This commit is contained in:
@@ -1730,6 +1730,15 @@
|
|||||||
overcommitByNamespace: false
|
overcommitByNamespace: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Smart loading system
|
||||||
|
let loadingProgress = {
|
||||||
|
lastActivity: Date.now(),
|
||||||
|
timeoutId: null,
|
||||||
|
isActive: false,
|
||||||
|
progressSteps: 0,
|
||||||
|
totalSteps: 3
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize the application
|
// Initialize the application
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
@@ -1849,6 +1858,58 @@
|
|||||||
}
|
}
|
||||||
console.log(`Loading progress: ${progress}% (${loaded}/${total})`);
|
console.log(`Loading progress: ${progress}% (${loaded}/${total})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Smart loading system functions
|
||||||
|
function resetLoadingTimeout() {
|
||||||
|
loadingProgress.lastActivity = Date.now();
|
||||||
|
if (loadingProgress.timeoutId) {
|
||||||
|
clearTimeout(loadingProgress.timeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timeout only if no activity for 30 seconds
|
||||||
|
loadingProgress.timeoutId = setTimeout(() => {
|
||||||
|
if (loadingProgress.isActive) {
|
||||||
|
console.log('Loading timeout - no activity for 30 seconds');
|
||||||
|
hideFullscreenLoading();
|
||||||
|
showError('metrics-grid', 'Request timeout - API stopped responding');
|
||||||
|
}
|
||||||
|
}, 30000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSmartProgress(step, message = '') {
|
||||||
|
loadingProgress.progressSteps = step;
|
||||||
|
loadingProgress.lastActivity = Date.now();
|
||||||
|
|
||||||
|
// Update progress bar
|
||||||
|
const progress = Math.round((step / loadingProgress.totalSteps) * 100);
|
||||||
|
const progressBar = document.getElementById('loading-progress');
|
||||||
|
if (progressBar) {
|
||||||
|
progressBar.style.width = progress + '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update status message if provided
|
||||||
|
if (message) {
|
||||||
|
console.log(`Loading progress: ${progress}% - ${message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset timeout since we have activity
|
||||||
|
resetLoadingTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startSmartLoading() {
|
||||||
|
loadingProgress.isActive = true;
|
||||||
|
loadingProgress.progressSteps = 0;
|
||||||
|
loadingProgress.lastActivity = Date.now();
|
||||||
|
resetLoadingTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopSmartLoading() {
|
||||||
|
loadingProgress.isActive = false;
|
||||||
|
if (loadingProgress.timeoutId) {
|
||||||
|
clearTimeout(loadingProgress.timeoutId);
|
||||||
|
loadingProgress.timeoutId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setupNavigation() {
|
function setupNavigation() {
|
||||||
// Sidebar navigation
|
// Sidebar navigation
|
||||||
@@ -1917,67 +1978,52 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadWorkloadScanner() {
|
async function loadWorkloadScanner() {
|
||||||
let loadingModal = null;
|
|
||||||
let timeoutId = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Show fullscreen loading modal
|
// Show fullscreen loading modal
|
||||||
loadingModal = showFullscreenLoading(
|
showFullscreenLoading(
|
||||||
'Analyzing Cluster Resources',
|
'Analyzing Cluster Resources',
|
||||||
'Please wait while we analyze your cluster resources and generate insights... This may take up to 60 seconds for large clusters.'
|
'Please wait while we analyze your cluster resources and generate insights... This may take up to 60 seconds for large clusters.'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set timeout for loading (60 seconds)
|
// Start smart loading system
|
||||||
timeoutId = setTimeout(() => {
|
startSmartLoading();
|
||||||
hideFullscreenLoading();
|
|
||||||
showError('metrics-grid', 'Request timeout - API is taking too long to respond');
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
// Load cluster status with timeout
|
// Step 1: Load cluster status
|
||||||
const controller = new AbortController();
|
updateSmartProgress(0, 'Connecting to OpenShift API...');
|
||||||
const timeoutController = setTimeout(() => controller.abort(), 50000);
|
|
||||||
|
|
||||||
const clusterResponse = await fetch('/api/v1/cluster/status', {
|
|
||||||
signal: controller.signal
|
|
||||||
});
|
|
||||||
clearTimeout(timeoutController);
|
|
||||||
|
|
||||||
|
const clusterResponse = await fetch('/api/v1/cluster/status');
|
||||||
if (!clusterResponse.ok) {
|
if (!clusterResponse.ok) {
|
||||||
throw new Error(`HTTP error! status: ${clusterResponse.status}`);
|
throw new Error(`HTTP error! status: ${clusterResponse.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const clusterData = await clusterResponse.json();
|
const clusterData = await clusterResponse.json();
|
||||||
|
updateSmartProgress(1, 'Cluster data loaded successfully');
|
||||||
// Update progress
|
|
||||||
updateLoadingProgress(1, 3);
|
|
||||||
|
|
||||||
// Update metrics cards
|
// Update metrics cards
|
||||||
updateMetricsCards(clusterData);
|
updateMetricsCards(clusterData);
|
||||||
|
|
||||||
// Update progress
|
// Step 2: Load dashboard charts
|
||||||
updateLoadingProgress(2, 3);
|
updateSmartProgress(2, 'Loading dashboard charts...');
|
||||||
|
|
||||||
// Load dashboard charts with loading states
|
|
||||||
await loadDashboardCharts();
|
await loadDashboardCharts();
|
||||||
|
|
||||||
// Update progress
|
// Step 3: Complete
|
||||||
updateLoadingProgress(3, 3);
|
updateSmartProgress(3, 'Analysis complete');
|
||||||
|
|
||||||
currentData = { cluster: clusterData };
|
currentData = { cluster: clusterData };
|
||||||
|
|
||||||
// Clear timeout and hide loading modal
|
// Stop smart loading and hide modal
|
||||||
clearTimeout(timeoutId);
|
stopSmartLoading();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
hideFullscreenLoading();
|
hideFullscreenLoading();
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading workload scanner data:', error);
|
console.error('Error loading workload scanner data:', error);
|
||||||
if (timeoutId) clearTimeout(timeoutId);
|
stopSmartLoading();
|
||||||
hideFullscreenLoading();
|
hideFullscreenLoading();
|
||||||
|
|
||||||
if (error.name === 'AbortError') {
|
if (error.name === 'AbortError') {
|
||||||
showError('metrics-grid', 'Request timeout - API is taking too long to respond');
|
showError('metrics-grid', 'Request timeout - API stopped responding');
|
||||||
} else {
|
} else {
|
||||||
showError('metrics-grid', 'Failed to load cluster data: ' + error.message);
|
showError('metrics-grid', 'Failed to load cluster data: ' + error.message);
|
||||||
}
|
}
|
||||||
@@ -2125,16 +2171,45 @@
|
|||||||
// Dashboard Charts Functions
|
// Dashboard Charts Functions
|
||||||
async function loadDashboardCharts() {
|
async function loadDashboardCharts() {
|
||||||
try {
|
try {
|
||||||
// Load all charts in parallel
|
// Load all charts in parallel with individual error handling
|
||||||
await Promise.all([
|
const chartPromises = [
|
||||||
loadResourceUtilizationTrend(),
|
loadResourceUtilizationTrend().catch(err => {
|
||||||
loadNamespaceDistribution(),
|
console.warn('Resource utilization trend failed:', err);
|
||||||
loadIssuesTimeline(),
|
return null;
|
||||||
loadTopWorkloads(),
|
}),
|
||||||
loadOvercommitByNamespace()
|
loadNamespaceDistribution().catch(err => {
|
||||||
]);
|
console.warn('Namespace distribution failed:', err);
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
loadIssuesTimeline().catch(err => {
|
||||||
|
console.warn('Issues timeline failed:', err);
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
loadTopWorkloads().catch(err => {
|
||||||
|
console.warn('Top workloads failed:', err);
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
loadOvercommitByNamespace().catch(err => {
|
||||||
|
console.warn('Overcommit by namespace failed:', err);
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
console.log('All dashboard charts loaded successfully');
|
// Wait for all charts to complete (or fail gracefully)
|
||||||
|
await Promise.allSettled(chartPromises);
|
||||||
|
|
||||||
|
// Update progress for each successful chart
|
||||||
|
let successCount = 0;
|
||||||
|
chartPromises.forEach((promise, index) => {
|
||||||
|
promise.then(result => {
|
||||||
|
if (result !== null) {
|
||||||
|
successCount++;
|
||||||
|
updateSmartProgress(2, `Loaded ${successCount}/5 charts successfully`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Dashboard charts loading completed');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading dashboard charts:', error);
|
console.error('Error loading dashboard charts:', error);
|
||||||
}
|
}
|
||||||
@@ -2143,8 +2218,14 @@
|
|||||||
// 1. Resource Utilization Trend (24h)
|
// 1. Resource Utilization Trend (24h)
|
||||||
async function loadResourceUtilizationTrend() {
|
async function loadResourceUtilizationTrend() {
|
||||||
try {
|
try {
|
||||||
|
// Update progress
|
||||||
|
updateSmartProgress(2, 'Loading resource utilization trend...');
|
||||||
|
|
||||||
// Use real Prometheus data from historical analysis
|
// Use real Prometheus data from historical analysis
|
||||||
const response = await fetch('/api/v1/optimized/historical/summary');
|
const response = await fetch('/api/v1/optimized/historical/summary');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
// Create trend data from real cluster metrics
|
// Create trend data from real cluster metrics
|
||||||
@@ -2272,7 +2353,13 @@
|
|||||||
// 2. Namespace Resource Distribution
|
// 2. Namespace Resource Distribution
|
||||||
async function loadNamespaceDistribution() {
|
async function loadNamespaceDistribution() {
|
||||||
try {
|
try {
|
||||||
|
// Update progress
|
||||||
|
updateSmartProgress(2, 'Loading namespace distribution...');
|
||||||
|
|
||||||
const response = await fetch('/api/v1/namespace-distribution');
|
const response = await fetch('/api/v1/namespace-distribution');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
// Pass data directly to chart function (no mapping needed)
|
// Pass data directly to chart function (no mapping needed)
|
||||||
|
|||||||
Reference in New Issue
Block a user