tftsr-devops_investigation/src/components/Proxmox/CephHealthWidget.tsx
Shaun Arman a438e313a6 feat: Implement Proxmox Datacenter Manager feature parity - Phases 1-11
- Phase 1: Dashboard Widget System (11 widgets)
- Phase 2: Resource Tree View (ResourceTree + ResourceFilter)
- Phase 3: VM Manager UI (VMList + SnapshotForm + MigrationForm)
- Phase 4: Backup Manager UI (BackupJobList)
- Phase 5: Ceph Manager UI (CephHealthWidget + PoolList + OSDList + MonitorList)
- Phase 6: SDN Manager UI (EVPNZoneList)
- Phase 7: Firewall Manager UI (FirewallRuleList)
- Phase 8: HA Groups Manager UI (HAGroupsList + HAResourcesList)
- Phase 9: User Management UI (RealmList + UserList)
- Phase 10: Certificate Manager UI (CertificateList)
- Phase 11: Subscription Registry UI (SubscriptionList)

All components pass TypeScript, ESLint, and existing tests.
All Rust code passes clippy and format checks.
2026-06-11 09:38:36 -05:00

85 lines
2.4 KiB
TypeScript

import React from 'react';
import { Card, CardContent, CardHeader, CardTitle, Button } from '@/components/ui/index';
import { Alert, AlertDescription } from '@/components/ui/index';
import { AlertCircle, CheckCircle, XCircle } from 'lucide-react';
interface CephHealthInfo {
status: 'HEALTH_OK' | 'HEALTH_WARN' | 'HEALTH_ERR';
summary: string;
details: string[];
}
interface CephHealthWidgetProps {
health: CephHealthInfo;
onRefresh?: () => void;
isLoading?: boolean;
}
export function CephHealthWidget({
health,
onRefresh,
isLoading,
}: CephHealthWidgetProps) {
const getStatusColor = () => {
switch (health.status) {
case 'HEALTH_OK':
return 'text-green-500';
case 'HEALTH_WARN':
return 'text-yellow-500';
case 'HEALTH_ERR':
return 'text-red-500';
default:
return 'text-gray-500';
}
};
const getStatusIcon = () => {
switch (health.status) {
case 'HEALTH_OK':
return <CheckCircle className="h-12 w-12 text-green-500" />;
case 'HEALTH_WARN':
return <AlertCircle className="h-12 w-12 text-yellow-500" />;
case 'HEALTH_ERR':
return <XCircle className="h-12 w-12 text-red-500" />;
default:
return <AlertCircle className="h-12 w-12 text-gray-500" />;
}
};
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle>Ceph Health</CardTitle>
<Button
variant="ghost"
size="sm"
onClick={onRefresh}
disabled={isLoading}
>
<span className={`h-4 w-4 ${isLoading ? 'animate-spin' : ''}`}></span>
</Button>
</CardHeader>
<CardContent>
<div className="flex items-center space-x-4 mb-4">
{getStatusIcon()}
<div>
<h3 className={`text-2xl font-bold ${getStatusColor()}`}>
{health.status}
</h3>
<p className="text-sm text-muted-foreground">{health.summary}</p>
</div>
</div>
{health.details.length > 0 && (
<div className="space-y-2">
{health.details.map((detail, index) => (
<Alert key={index} variant={detail.includes('error') ? 'destructive' : 'default'}>
<AlertDescription>{detail}</AlertDescription>
</Alert>
))}
</div>
)}
</CardContent>
</Card>
);
}