import { ref, computed } from 'vue' import { useAuthStore } from '~/stores/auth' // Types export interface HealthMetrics { total_assets: number total_organizations: number critical_alerts_24h: number system_status: 'healthy' | 'degraded' | 'critical' uptime_percentage: number response_time_ms: number database_connections: number active_users: number last_updated: string } export interface SystemAlert { id: string severity: 'info' | 'warning' | 'critical' title: string description: string timestamp: string component: string resolved: boolean } export interface HealthMonitorState { metrics: HealthMetrics | null alerts: SystemAlert[] loading: boolean error: string | null lastUpdated: Date | null } // Mock data for development/testing const generateMockMetrics = (): HealthMetrics => { return { total_assets: Math.floor(Math.random() * 10000) + 5000, total_organizations: Math.floor(Math.random() * 500) + 100, critical_alerts_24h: Math.floor(Math.random() * 10), system_status: Math.random() > 0.8 ? 'degraded' : Math.random() > 0.95 ? 'critical' : 'healthy', uptime_percentage: 99.5 + (Math.random() * 0.5 - 0.25), // 99.25% - 99.75% response_time_ms: Math.floor(Math.random() * 100) + 50, database_connections: Math.floor(Math.random() * 50) + 10, active_users: Math.floor(Math.random() * 1000) + 500, last_updated: new Date().toISOString() } } const generateMockAlerts = (count: number = 5): SystemAlert[] => { const severities: SystemAlert['severity'][] = ['info', 'warning', 'critical'] const components = ['Database', 'API Gateway', 'Redis', 'PostgreSQL', 'Docker', 'Network', 'Authentication', 'File Storage'] const titles = [ 'High memory usage detected', 'Database connection pool exhausted', 'API response time above threshold', 'Redis cache miss rate increased', 'Disk space running low', 'Network latency spike', 'Authentication service slow response', 'Backup job failed' ] const alerts: SystemAlert[] = [] for (let i = 0; i < count; i++) { const severity = severities[Math.floor(Math.random() * severities.length)] const isResolved = Math.random() > 0.7 alerts.push({ id: `alert_${Date.now()}_${i}`, severity, title: titles[Math.floor(Math.random() * titles.length)], description: `Detailed description of the ${severity} alert in the ${components[Math.floor(Math.random() * components.length)]} component.`, timestamp: new Date(Date.now() - Math.random() * 24 * 60 * 60 * 1000).toISOString(), // Within last 24 hours component: components[Math.floor(Math.random() * components.length)], resolved: isResolved }) } return alerts } // API Service class HealthMonitorApiService { private baseUrl = 'http://localhost:8000/api/v1/admin' // Should come from environment config private delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) // Get health metrics async getHealthMetrics(): Promise { // In a real implementation, this would call the actual API // const response = await fetch(`${this.baseUrl}/health-monitor`, { // headers: this.getAuthHeaders() // }) // // if (!response.ok) { // throw new Error(`HTTP ${response.status}: ${response.statusText}`) // } // // return await response.json() await this.delay(800) // Simulate network delay // For now, return mock data return generateMockMetrics() } // Get system alerts async getSystemAlerts(options?: { severity?: SystemAlert['severity'] resolved?: boolean limit?: number }): Promise { await this.delay(500) let alerts = generateMockAlerts(10) if (options?.severity) { alerts = alerts.filter(alert => alert.severity === options.severity) } if (options?.resolved !== undefined) { alerts = alerts.filter(alert => alert.resolved === options.resolved) } if (options?.limit) { alerts = alerts.slice(0, options.limit) } return alerts } // Get auth headers (for real API calls) private getAuthHeaders(): Record { const authStore = useAuthStore() const headers: Record = { 'Content-Type': 'application/json' } if (authStore.token) { headers['Authorization'] = `Bearer ${authStore.token}` } // Add geographical scope headers if (authStore.getScopeId) { headers['X-Scope-Id'] = authStore.getScopeId.toString() } if (authStore.getRegionCode) { headers['X-Region-Code'] = authStore.getRegionCode } if (authStore.getScopeLevel) { headers['X-Scope-Level'] = authStore.getScopeLevel } return headers } } // Composable export const useHealthMonitor = () => { const state = ref({ metrics: null, alerts: [], loading: false, error: null, lastUpdated: null }) const apiService = new HealthMonitorApiService() // Computed properties const systemStatusColor = computed(() => { if (!state.value.metrics) return 'grey' switch (state.value.metrics.system_status) { case 'healthy': return 'green' case 'degraded': return 'orange' case 'critical': return 'red' default: return 'grey' } }) const systemStatusIcon = computed(() => { if (!state.value.metrics) return 'mdi-help-circle' switch (state.value.metrics.system_status) { case 'healthy': return 'mdi-check-circle' case 'degraded': return 'mdi-alert-circle' case 'critical': return 'mdi-alert-octagon' default: return 'mdi-help-circle' } }) const criticalAlerts = computed(() => { return state.value.alerts.filter(alert => alert.severity === 'critical' && !alert.resolved) }) const warningAlerts = computed(() => { return state.value.alerts.filter(alert => alert.severity === 'warning' && !alert.resolved) }) const formattedUptime = computed(() => { if (!state.value.metrics) return 'N/A' return `${state.value.metrics.uptime_percentage.toFixed(2)}%` }) const formattedResponseTime = computed(() => { if (!state.value.metrics) return 'N/A' return `${state.value.metrics.response_time_ms}ms` }) // Actions const fetchHealthMetrics = async () => { state.value.loading = true state.value.error = null try { const metrics = await apiService.getHealthMetrics() state.value.metrics = metrics state.value.lastUpdated = new Date() } catch (error) { state.value.error = error instanceof Error ? error.message : 'Failed to fetch health metrics' console.error('Error fetching health metrics:', error) // Fallback to mock data state.value.metrics = generateMockMetrics() } finally { state.value.loading = false } } const fetchSystemAlerts = async (options?: { severity?: SystemAlert['severity'] resolved?: boolean limit?: number }) => { state.value.loading = true state.value.error = null try { const alerts = await apiService.getSystemAlerts(options) state.value.alerts = alerts } catch (error) { state.value.error = error instanceof Error ? error.message : 'Failed to fetch system alerts' console.error('Error fetching system alerts:', error) // Fallback to mock data state.value.alerts = generateMockAlerts(5) } finally { state.value.loading = false } } const refreshAll = async () => { await Promise.all([ fetchHealthMetrics(), fetchSystemAlerts() ]) } const markAlertAsResolved = async (alertId: string) => { // In a real implementation, this would call an API endpoint // await apiService.resolveAlert(alertId) // Update local state const alertIndex = state.value.alerts.findIndex(alert => alert.id === alertId) if (alertIndex !== -1) { state.value.alerts[alertIndex].resolved = true } } const dismissAlert = (alertId: string) => { // Remove alert from local state (frontend only) state.value.alerts = state.value.alerts.filter(alert => alert.id !== alertId) } // Initialize const initialize = () => { refreshAll() } return { // State state: computed(() => state.value), metrics: computed(() => state.value.metrics), alerts: computed(() => state.value.alerts), loading: computed(() => state.value.loading), error: computed(() => state.value.error), lastUpdated: computed(() => state.value.lastUpdated), // Computed systemStatusColor, systemStatusIcon, criticalAlerts, warningAlerts, formattedUptime, formattedResponseTime, // Actions fetchHealthMetrics, fetchSystemAlerts, refreshAll, markAlertAsResolved, dismissAlert, initialize, // Helper functions getAlertColor: (severity: SystemAlert['severity']) => { switch (severity) { case 'info': return 'blue' case 'warning': return 'orange' case 'critical': return 'red' default: return 'grey' } }, getAlertIcon: (severity: SystemAlert['severity']) => { switch (severity) { case 'info': return 'mdi-information' case 'warning': return 'mdi-alert' case 'critical': return 'mdi-alert-circle' default: return 'mdi-help-circle' } }, formatTimestamp: (timestamp: string) => { const date = new Date(timestamp) return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) } } } export default useHealthMonitor