// API Configuration const API_BASE_URL = '/api/v1'; const STATUS_ENDPOINTS = { overall: `${API_BASE_URL}/status`, services: `${API_BASE_URL}/status/services`, metrics: `${API_BASE_URL}/status/metrics`, incidents: `${API_BASE_URL}/status/incidents`, maintenance: `${API_BASE_URL}/status/maintenance`, uptime: `${API_BASE_URL}/status/uptime`, subscribe: `${API_BASE_URL}/status/subscribe` }; // Global state let statusData = { overall: null, services: [], metrics: null, incidents: [], maintenance: [], uptime: [] }; let updateInterval = null; let charts = {}; // DOM Elements const elements = { overallStatus: document.getElementById('overallStatus'), overallStatusIcon: document.getElementById('overallStatusIcon'), overallStatusText: document.getElementById('overallStatusText'), overallStatusDescription: document.getElementById('overallStatusDescription'), lastUpdated: document.getElementById('lastUpdated'), refreshBtn: document.getElementById('refreshBtn'), servicesList: document.getElementById('servicesList'), incidentsList: document.getElementById('incidentsList'), maintenanceList: document.getElementById('maintenanceList'), noIncidents: document.getElementById('noIncidents'), noMaintenance: document.getElementById('noMaintenance'), uptimeCalendar: document.getElementById('uptimeCalendar'), subscribeForm: document.getElementById('subscribeForm'), toast: document.getElementById('toast') }; // Utility Functions const formatDate = (date) => { return new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' }).format(new Date(date)); }; const formatDuration = (minutes) => { if (minutes < 60) return `${minutes}m`; const hours = Math.floor(minutes / 60); const mins = minutes % 60; return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`; }; const getStatusColor = (status) => { const colors = { operational: '#10b981', degraded: '#f59e0b', down: '#ef4444', maintenance: '#6366f1' }; return colors[status] || colors.operational; }; const getStatusIcon = (status) => { const icons = { operational: '🟢', degraded: '🟡', down: '🔴', maintenance: '🔵' }; return icons[status] || icons.operational; }; const showToast = (message, type = 'success') => { const toast = elements.toast; const toastMessage = toast.querySelector('.toast-message'); const toastIcon = toast.querySelector('.toast-icon'); toastMessage.textContent = message; if (type === 'success') { toast.style.background = 'var(--success)'; toastIcon.textContent = '✓'; } else { toast.style.background = 'var(--error)'; toastIcon.textContent = '✕'; } toast.classList.add('show'); setTimeout(() => { toast.classList.remove('show'); }, 4000); }; // Mock Data Generation (for demonstration) const generateMockData = () => { const services = [ { id: 'api', name: 'API Gateway', description: 'Core API services', icon: '🔗' }, { id: 'web', name: 'Web Application', description: 'TaskFlow web interface', icon: '🌐' }, { id: 'auth', name: 'Authentication', description: 'User authentication service', icon: '🔐' }, { id: 'database', name: 'Database', description: 'Primary database cluster', icon: '🗄️' }, { id: 'storage', name: 'File Storage', description: 'Document and file storage', icon: '📁' }, { id: 'notifications', name: 'Notifications', description: 'Email and push notifications', icon: '📧' }, { id: 'search', name: 'Search Service', description: 'Full-text search functionality', icon: '🔍' }, { id: 'analytics', name: 'Analytics', description: 'Usage analytics and reporting', icon: '📊' } ]; const statuses = ['operational', 'operational', 'operational', 'degraded', 'operational']; const responseTimeBase = 150; return { overall: { status: 'operational', description: 'All systems are operating normally', uptime: 99.95, responseTime: 245, activeIncidents: 0, scheduledMaintenance: 0 }, services: services.map(service => ({ ...service, status: statuses[Math.floor(Math.random() * statuses.length)], responseTime: responseTimeBase + Math.floor(Math.random() * 200), uptime: 99.5 + Math.random() * 0.5 })), metrics: { uptime: 99.95, responseTime: 245, requestVolume: 1250000, errorRate: 0.02 }, incidents: [ { id: '1', title: 'Intermittent API Timeouts', description: 'Some users may experience slow response times when accessing the API. Our team is investigating the issue.', status: 'investigating', severity: 'minor', startTime: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), affectedServices: ['api', 'web'] } ], maintenance: [ { id: '1', title: 'Database Maintenance Window', description: 'Scheduled maintenance to upgrade database servers. Brief service interruptions may occur.', startTime: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), endTime: new Date(Date.now() + 24 * 60 * 60 * 1000 + 2 * 60 * 60 * 1000).toISOString(), affectedServices: ['database', 'api'] } ], uptime: generateUptimeData() }; }; const generateUptimeData = () => { const data = []; const now = new Date(); for (let i = 89; i >= 0; i--) { const date = new Date(now); date.setDate(date.getDate() - i); let uptime = 100; if (Math.random() < 0.05) { // 5% chance of issues uptime = 95 + Math.random() * 5; } data.push({ date: date.toISOString().split('T')[0], uptime: uptime }); } return data; }; const generateChartData = (type, range) => { const points = range === '1h' ? 60 : range === '6h' ? 72 : range === '24h' ? 144 : 168; const interval = range === '1h' ? 1 : range === '6h' ? 5 : range === '24h' ? 10 : 60; const data = []; const now = new Date(); for (let i = points - 1; i >= 0; i--) { const time = new Date(now.getTime() - i * interval * 60 * 1000); if (type === 'responseTime') { const baseTime = 200; const variation = Math.sin(i / 10) * 50 + Math.random() * 100; data.push({ time: time.toISOString(), value: Math.max(50, baseTime + variation) }); } else if (type === 'volume') { const baseVolume = 1000; const variation = Math.sin(i / 20) * 300 + Math.random() * 200; data.push({ time: time.toISOString(), value: Math.max(100, baseVolume + variation) }); } } return data; }; // API Functions (with mock data fallback) const fetchStatusData = async (endpoint, mockData = null) => { try { const response = await fetch(endpoint, { method: 'GET', headers: { 'Accept': 'application/json', } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.warn(`API call failed for ${endpoint}, using mock data:`, error.message); return mockData; } }; const fetchAllStatusData = async () => { const mockData = generateMockData(); try { const [overall, services, metrics, incidents, maintenance, uptime] = await Promise.all([ fetchStatusData(STATUS_ENDPOINTS.overall, mockData.overall), fetchStatusData(STATUS_ENDPOINTS.services, mockData.services), fetchStatusData(STATUS_ENDPOINTS.metrics, mockData.metrics), fetchStatusData(STATUS_ENDPOINTS.incidents, mockData.incidents), fetchStatusData(STATUS_ENDPOINTS.maintenance, mockData.maintenance), fetchStatusData(STATUS_ENDPOINTS.uptime, mockData.uptime) ]); statusData = { overall, services, metrics, incidents, maintenance, uptime }; return statusData; } catch (error) { console.error('Failed to fetch status data:', error); statusData = mockData; return statusData; } }; // UI Update Functions const updateOverallStatus = (data) => { const { status, description } = data; elements.overallStatusIcon.textContent = getStatusIcon(status); elements.overallStatusText.textContent = status.charAt(0).toUpperCase() + status.slice(1); elements.overallStatusText.className = `status-label ${status}`; elements.overallStatusDescription.textContent = description; // Update metrics document.getElementById('uptimeMetric').textContent = `${data.uptime}%`; document.getElementById('responseTimeMetric').textContent = `${data.responseTime}ms`; document.getElementById('incidentsMetric').textContent = data.activeIncidents; document.getElementById('maintenanceMetric').textContent = data.scheduledMaintenance; // Update metric statuses const responseTimeStatus = data.responseTime < 300 ? 'operational' : data.responseTime < 500 ? 'degraded' : 'down'; document.getElementById('responseTimeStatus').textContent = responseTimeStatus === 'operational' ? 'Good' : responseTimeStatus === 'degraded' ? 'Slow' : 'Poor'; document.getElementById('responseTimeStatus').className = `metric-status ${responseTimeStatus}`; document.getElementById('incidentsStatus').textContent = data.activeIncidents === 0 ? 'None' : `${data.activeIncidents} Active`; document.getElementById('incidentsStatus').className = `metric-status ${data.activeIncidents === 0 ? 'operational' : 'down'}`; document.getElementById('maintenanceStatus').textContent = data.scheduledMaintenance === 0 ? 'None' : `${data.scheduledMaintenance} Scheduled`; document.getElementById('maintenanceStatus').className = `metric-status ${data.scheduledMaintenance === 0 ? 'operational' : 'maintenance'}`; }; const updateServicesList = (services) => { const servicesList = elements.servicesList; servicesList.innerHTML = ''; services.forEach(service => { const serviceItem = document.createElement('div'); serviceItem.className = 'service-item'; serviceItem.innerHTML = `
${service.description}