120 lines
4.4 KiB
TypeScript
120 lines
4.4 KiB
TypeScript
/**
|
|
* 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;
|
|
}>;
|
|
}
|
|
|
|
import { ViewDataBuilder } from "../../contracts/builders/ViewDataBuilder";
|
|
|
|
export class HealthViewDataBuilder implements ViewDataBuilder<any, any> {
|
|
build(input: any): any {
|
|
return HealthViewDataBuilder.build(input);
|
|
}
|
|
|
|
static build(
|
|
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),
|
|
};
|
|
}
|
|
}
|