Files
Sankofa/portal/src/components/dashboard/SystemHealthTile.tsx
defiQUG 9daf1fd378 Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements
- Add comprehensive database migrations (001-024) for schema evolution
- Enhance API schema with expanded type definitions and resolvers
- Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth
- Implement new services: AI optimization, billing, blockchain, compliance, marketplace
- Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage)
- Update Crossplane provider with enhanced VM management capabilities
- Add comprehensive test suite for API endpoints and services
- Update frontend components with improved GraphQL subscriptions and real-time updates
- Enhance security configurations and headers (CSP, CORS, etc.)
- Update documentation and configuration files
- Add new CI/CD workflows and validation scripts
- Implement design system improvements and UI enhancements
2025-12-12 18:01:35 -08:00

174 lines
7.1 KiB
TypeScript

'use client';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
import { Activity, CheckCircle, AlertCircle, XCircle, Globe, Server } from 'lucide-react';
import { useSystemHealth } from '@/hooks/useDashboardData';
export function SystemHealthTile() {
const { data, loading, error } = useSystemHealth();
// Calculate health data from API response
const healthData = data ? {
regions: {
total: data.sites?.length || 0,
healthy: data.sites?.filter((s: any) => s.status === 'ACTIVE').length || 0,
warning: data.sites?.filter((s: any) => s.status === 'MAINTENANCE').length || 0,
critical: data.sites?.filter((s: any) => s.status === 'INACTIVE').length || 0,
},
clusters: {
total: data.resources?.length || 0,
healthy: data.resources?.filter((r: any) => r.status === 'RUNNING').length || 0,
warning: data.resources?.filter((r: any) => r.status === 'PROVISIONING').length || 0,
critical: data.resources?.filter((r: any) => r.status === 'ERROR').length || 0,
},
nodes: {
total: data.resources?.length || 0,
healthy: data.resources?.filter((r: any) => r.status === 'RUNNING').length || 0,
warning: data.resources?.filter((r: any) => r.status === 'PROVISIONING').length || 0,
critical: data.resources?.filter((r: any) => r.status === 'ERROR').length || 0,
},
} : {
regions: { total: 0, healthy: 0, warning: 0, critical: 0 },
clusters: { total: 0, healthy: 0, warning: 0, critical: 0 },
nodes: { total: 0, healthy: 0, warning: 0, critical: 0 },
};
if (loading) {
return (
<Card className="bg-gray-800 border-gray-700">
<CardHeader>
<CardTitle className="text-white flex items-center gap-2">
<Activity className="h-5 w-5 text-orange-500" />
System Health Overview
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-center text-gray-400 py-4">Loading...</div>
</CardContent>
</Card>
);
}
if (error) {
return (
<Card className="bg-gray-800 border-gray-700">
<CardHeader>
<CardTitle className="text-white flex items-center gap-2">
<Activity className="h-5 w-5 text-orange-500" />
System Health Overview
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-center text-red-400 py-4">Error loading health data</div>
</CardContent>
</Card>
);
}
const overallHealth = healthData.regions.healthy / healthData.regions.total > 0.95 ? 'healthy' :
healthData.regions.healthy / healthData.regions.total > 0.85 ? 'warning' : 'critical';
return (
<Card className="bg-gray-800 border-gray-700">
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle className="text-white flex items-center gap-2">
<Activity className="h-5 w-5 text-orange-500" />
System Health Overview
</CardTitle>
<div className={`px-3 py-1 rounded-full text-xs font-semibold ${
overallHealth === 'healthy' ? 'bg-green-500/20 text-green-400' :
overallHealth === 'warning' ? 'bg-yellow-500/20 text-yellow-400' :
'bg-red-500/20 text-red-400'
}`}>
{overallHealth === 'healthy' ? 'Healthy' : overallHealth === 'warning' ? 'Warning' : 'Critical'}
</div>
</div>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex items-center justify-between p-3 bg-gray-900 rounded-lg">
<div className="flex items-center gap-3">
<Globe className="h-5 w-5 text-blue-400" />
<div>
<p className="text-sm text-gray-400">Regions</p>
<p className="text-lg font-semibold text-white">{healthData.regions.total}</p>
</div>
</div>
<div className="flex gap-2">
<div className="flex items-center gap-1 text-green-400">
<CheckCircle className="h-4 w-4" />
<span className="text-sm">{healthData.regions.healthy}</span>
</div>
{healthData.regions.warning > 0 && (
<div className="flex items-center gap-1 text-yellow-400">
<AlertCircle className="h-4 w-4" />
<span className="text-sm">{healthData.regions.warning}</span>
</div>
)}
{healthData.regions.critical > 0 && (
<div className="flex items-center gap-1 text-red-400">
<XCircle className="h-4 w-4" />
<span className="text-sm">{healthData.regions.critical}</span>
</div>
)}
</div>
</div>
<div className="flex items-center justify-between p-3 bg-gray-900 rounded-lg">
<div className="flex items-center gap-3">
<Server className="h-5 w-5 text-purple-400" />
<div>
<p className="text-sm text-gray-400">Clusters</p>
<p className="text-lg font-semibold text-white">{healthData.clusters.total}</p>
</div>
</div>
<div className="flex gap-2">
<div className="flex items-center gap-1 text-green-400">
<CheckCircle className="h-4 w-4" />
<span className="text-sm">{healthData.clusters.healthy}</span>
</div>
{healthData.clusters.warning > 0 && (
<div className="flex items-center gap-1 text-yellow-400">
<AlertCircle className="h-4 w-4" />
<span className="text-sm">{healthData.clusters.warning}</span>
</div>
)}
</div>
</div>
<div className="flex items-center justify-between p-3 bg-gray-900 rounded-lg">
<div className="flex items-center gap-3">
<Activity className="h-5 w-5 text-cyan-400" />
<div>
<p className="text-sm text-gray-400">Nodes</p>
<p className="text-lg font-semibold text-white">{healthData.nodes.total}</p>
</div>
</div>
<div className="flex gap-2">
<div className="flex items-center gap-1 text-green-400">
<CheckCircle className="h-4 w-4" />
<span className="text-sm">{healthData.nodes.healthy}</span>
</div>
{healthData.nodes.warning > 0 && (
<div className="flex items-center gap-1 text-yellow-400">
<AlertCircle className="h-4 w-4" />
<span className="text-sm">{healthData.nodes.warning}</span>
</div>
)}
{healthData.nodes.critical > 0 && (
<div className="flex items-center gap-1 text-red-400">
<XCircle className="h-4 w-4" />
<span className="text-sm">{healthData.nodes.critical}</span>
</div>
)}
</div>
</div>
</div>
</CardContent>
</Card>
);
}