/** * Health View Data Builder * * Transforms health DTO data into UI-ready view models. * This layer isolates the UI from API churn by providing a stable interface * between the API layer and the presentation layer. */ import type { HealthViewData, HealthStatus, HealthMetrics, HealthComponent, HealthAlert } from '@/lib/view-data/HealthViewData'; import { HealthStatusDisplay } from '@/lib/display-objects/HealthStatusDisplay'; import { HealthMetricDisplay } from '@/lib/display-objects/HealthMetricDisplay'; import { HealthComponentDisplay } from '@/lib/display-objects/HealthComponentDisplay'; import { HealthAlertDisplay } from '@/lib/display-objects/HealthAlertDisplay'; export interface HealthDTO { status: 'ok' | 'degraded' | 'error' | 'unknown'; timestamp: string; uptime?: number; responseTime?: number; errorRate?: number; lastCheck?: string; checksPassed?: number; checksFailed?: number; components?: Array<{ name: string; status: 'ok' | 'degraded' | 'error' | 'unknown'; lastCheck?: string; responseTime?: number; errorRate?: number; }>; alerts?: Array<{ id: string; type: 'critical' | 'warning' | 'info'; title: string; message: string; timestamp: string; }>; } export class HealthViewDataBuilder { static build(dto: HealthDTO): HealthViewData { const now = new Date(); const lastUpdated = dto.timestamp || now.toISOString(); // Build overall status const overallStatus: HealthStatus = { status: dto.status, timestamp: dto.timestamp, formattedTimestamp: HealthStatusDisplay.formatTimestamp(dto.timestamp), relativeTime: HealthStatusDisplay.formatRelativeTime(dto.timestamp), statusLabel: HealthStatusDisplay.formatStatusLabel(dto.status), statusColor: HealthStatusDisplay.formatStatusColor(dto.status), statusIcon: HealthStatusDisplay.formatStatusIcon(dto.status), }; // Build metrics const metrics: HealthMetrics = { uptime: HealthMetricDisplay.formatUptime(dto.uptime), responseTime: HealthMetricDisplay.formatResponseTime(dto.responseTime), errorRate: HealthMetricDisplay.formatErrorRate(dto.errorRate), lastCheck: dto.lastCheck || lastUpdated, formattedLastCheck: HealthMetricDisplay.formatTimestamp(dto.lastCheck || lastUpdated), checksPassed: dto.checksPassed || 0, checksFailed: dto.checksFailed || 0, totalChecks: (dto.checksPassed || 0) + (dto.checksFailed || 0), successRate: HealthMetricDisplay.formatSuccessRate(dto.checksPassed, dto.checksFailed), }; // Build components const components: HealthComponent[] = (dto.components || []).map((component) => ({ name: component.name, status: component.status, statusLabel: HealthComponentDisplay.formatStatusLabel(component.status), statusColor: HealthComponentDisplay.formatStatusColor(component.status), statusIcon: HealthComponentDisplay.formatStatusIcon(component.status), lastCheck: component.lastCheck || lastUpdated, formattedLastCheck: HealthComponentDisplay.formatTimestamp(component.lastCheck || lastUpdated), responseTime: HealthMetricDisplay.formatResponseTime(component.responseTime), errorRate: HealthMetricDisplay.formatErrorRate(component.errorRate), })); // Build alerts const alerts: HealthAlert[] = (dto.alerts || []).map((alert) => ({ id: alert.id, type: alert.type, title: alert.title, message: alert.message, timestamp: alert.timestamp, formattedTimestamp: HealthAlertDisplay.formatTimestamp(alert.timestamp), relativeTime: HealthAlertDisplay.formatRelativeTime(alert.timestamp), severity: HealthAlertDisplay.formatSeverity(alert.type), severityColor: HealthAlertDisplay.formatSeverityColor(alert.type), })); // Calculate derived fields const hasAlerts = alerts.length > 0; const hasDegradedComponents = components.some((c) => c.status === 'degraded'); const hasErrorComponents = components.some((c) => c.status === 'error'); return { overallStatus, metrics, components, alerts, hasAlerts, hasDegradedComponents, hasErrorComponents, lastUpdated, formattedLastUpdated: HealthStatusDisplay.formatTimestamp(lastUpdated), }; } }