/**
* ClusterStatusCard — reusable component showing Rook-Ceph cluster health.
* Displays CephCluster health, phase, capacity, version, and daemon pod counts.
*/
import {
NameValueTable,
PercentageBar,
SectionBox,
StatusLabel,
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
import React from 'react';
import type { CephCluster, RookCephPod } from '../api/k8s';
import {
formatAge,
formatBytes,
getPodImage,
getPodRestarts,
healthToStatus,
isPodReady,
phaseToStatus,
} from '../api/k8s';
interface ClusterStatusCardProps {
cephClusters: CephCluster[];
operatorPods: RookCephPod[];
monPods: RookCephPod[];
osdPods: RookCephPod[];
mgrPods: RookCephPod[];
csiRbdPods: RookCephPod[];
csiCephfsPods: RookCephPod[];
}
function PodStatusBadge({ pod }: { pod: RookCephPod }) {
const ready = isPodReady(pod);
const phase = pod.status?.phase ?? 'Unknown';
return {phase};
}
function PodSummaryRow({ pods, label }: { pods: RookCephPod[]; label: string }) {
const ready = pods.filter(isPodReady).length;
const total = pods.length;
const status =
total === 0 ? 'error' : ready === total ? 'success' : ready > 0 ? 'warning' : 'error';
return {
name: label,
value: (
{total === 0 ? 'None found' : `${ready}/${total} ready`}
),
};
}
export default function ClusterStatusCard({
cephClusters,
operatorPods,
monPods,
osdPods,
mgrPods,
csiRbdPods,
csiCephfsPods,
}: ClusterStatusCardProps) {
return (
<>
{cephClusters.map(cluster => {
const health = cluster.status?.ceph?.health;
const phase = cluster.status?.phase;
const capacity = cluster.status?.ceph?.capacity;
const version = cluster.status?.version?.version ?? '—';
const bytesTotal = capacity?.bytesTotal ?? 0;
const bytesUsed = capacity?.bytesUsed ?? 0;
const bytesAvail = capacity?.bytesAvailable ?? 0;
const usedPct = bytesTotal > 0 ? Math.round((bytesUsed / bytesTotal) * 100) : 0;
return (
{health ?? 'Unknown'}
),
},
{
name: 'Phase',
value: (
{phase ?? 'Unknown'}
),
},
...(cluster.status?.message
? [{ name: 'Message', value: cluster.status.message }]
: []),
{ name: 'Ceph Version', value: version },
{ name: 'Namespace', value: cluster.metadata.namespace ?? '—' },
{ name: 'Age', value: formatAge(cluster.metadata.creationTimestamp) },
]}
/>
{bytesTotal > 0 && (
80
? 'var(--mui-palette-error-main, #f44336)'
: 'var(--mui-palette-primary-main, #1976d2)',
},
{
name: 'Free',
value: bytesAvail,
fill: 'var(--mui-palette-action-disabledBackground, #e0e0e0)',
},
]}
total={bytesTotal}
/>
)}
);
})}
>
);
}
export function PodDetailRows({ pods, label }: { pods: RookCephPod[]; label: string }) {
if (pods.length === 0) {
return (
No pods found },
]}
/>
);
}
return (
{pods.map(pod => (
},
{ name: 'Restarts', value: String(getPodRestarts(pod)) },
{ name: 'Image', value: getPodImage(pod) },
{ name: 'Age', value: formatAge(pod.metadata.creationTimestamp) },
]}
/>
))}
);
}