245 lines
7.8 KiB
TypeScript
245 lines
7.8 KiB
TypeScript
import React, { Suspense, useMemo } from 'react';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
Typography,
|
|
Box,
|
|
Tooltip as MuiTooltip,
|
|
} from '@mui/material';
|
|
import { motion } from 'framer-motion';
|
|
import { AlertTriangle, CheckCircle, AlertCircle } from 'lucide-react';
|
|
import {
|
|
LazyPieChart,
|
|
Pie,
|
|
Cell,
|
|
ResponsiveContainer,
|
|
ChartLoadingFallback
|
|
} from '../../utils/lazyRecharts';
|
|
import { SystemHealth } from '../../types/monitoring';
|
|
|
|
interface ErrorRateGaugeProps {
|
|
systemHealth: SystemHealth | null;
|
|
terminalTheme?: boolean;
|
|
terminalColors?: any;
|
|
}
|
|
|
|
/**
|
|
* ErrorRateGauge - Semi-circular gauge showing API error rate
|
|
*
|
|
* Visual gauge with:
|
|
* - Green (0-5%): Healthy
|
|
* - Yellow (5-10%): Warning
|
|
* - Red (>10%): Critical
|
|
*/
|
|
const ErrorRateGauge: React.FC<ErrorRateGaugeProps> = ({
|
|
systemHealth,
|
|
terminalTheme = false,
|
|
terminalColors
|
|
}) => {
|
|
const errorRate = systemHealth?.error_rate || 0;
|
|
const recentRequests = systemHealth?.recent_requests || 0;
|
|
const recentErrors = systemHealth?.recent_errors || 0;
|
|
|
|
// Determine status and color
|
|
const { status, color, icon } = useMemo(() => {
|
|
if (errorRate <= 5) {
|
|
return {
|
|
status: 'Healthy',
|
|
color: terminalTheme ? (terminalColors?.success || '#22c55e') : '#22c55e',
|
|
icon: <CheckCircle size={20} color="#22c55e" />
|
|
};
|
|
} else if (errorRate <= 10) {
|
|
return {
|
|
status: 'Warning',
|
|
color: terminalTheme ? (terminalColors?.warning || '#f59e0b') : '#f59e0b',
|
|
icon: <AlertCircle size={20} color="#f59e0b" />
|
|
};
|
|
} else {
|
|
return {
|
|
status: 'Critical',
|
|
color: terminalTheme ? (terminalColors?.error || '#ef4444') : '#ef4444',
|
|
icon: <AlertTriangle size={20} color="#ef4444" />
|
|
};
|
|
}
|
|
}, [errorRate, terminalTheme, terminalColors]);
|
|
|
|
// Data for semi-circular gauge (using Pie chart)
|
|
const gaugeData = [
|
|
{ name: 'Errors', value: errorRate, fill: color },
|
|
{ name: 'Success', value: Math.max(0, 100 - errorRate), fill: 'rgba(255,255,255,0.1)' }
|
|
];
|
|
|
|
return (
|
|
<motion.div
|
|
initial={{ opacity: 0, scale: 0.9 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
transition={{ duration: 0.4 }}
|
|
>
|
|
<Card
|
|
sx={{
|
|
height: '100%',
|
|
background: terminalTheme
|
|
? (terminalColors?.background || 'rgba(0,0,0,0.8)')
|
|
: 'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
|
backdropFilter: 'blur(10px)',
|
|
border: `1px solid ${terminalTheme
|
|
? (terminalColors?.border || 'rgba(255,255,255,0.1)')
|
|
: 'rgba(255,255,255,0.1)'}`,
|
|
borderRadius: 3,
|
|
}}
|
|
>
|
|
<CardContent>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
|
{icon}
|
|
<Typography variant="h6" sx={{ fontWeight: 'bold', color: terminalTheme ? terminalColors?.text : '#ffffff' }}>
|
|
Error Rate Gauge
|
|
</Typography>
|
|
</Box>
|
|
|
|
<Box sx={{ position: 'relative', height: 200, mb: 2 }}>
|
|
<Suspense fallback={<ChartLoadingFallback />}>
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<LazyPieChart>
|
|
<Pie
|
|
data={gaugeData}
|
|
cx="50%"
|
|
cy="80%"
|
|
startAngle={180}
|
|
endAngle={0}
|
|
innerRadius={60}
|
|
outerRadius={80}
|
|
dataKey="value"
|
|
animationDuration={1000}
|
|
animationBegin={0}
|
|
>
|
|
<Cell fill={color} />
|
|
<Cell fill={terminalTheme
|
|
? (terminalColors?.backgroundLight || 'rgba(255,255,255,0.1)')
|
|
: 'rgba(255,255,255,0.1)'}
|
|
/>
|
|
</Pie>
|
|
</LazyPieChart>
|
|
</ResponsiveContainer>
|
|
</Suspense>
|
|
|
|
{/* Center value display */}
|
|
<Box
|
|
sx={{
|
|
position: 'absolute',
|
|
top: '50%',
|
|
left: '50%',
|
|
transform: 'translate(-50%, -50%)',
|
|
textAlign: 'center',
|
|
mt: 2
|
|
}}
|
|
>
|
|
<Typography
|
|
variant="h3"
|
|
sx={{
|
|
fontWeight: 800,
|
|
color: color,
|
|
textShadow: terminalTheme ? 'none' : '0 2px 8px rgba(0,0,0,0.3)'
|
|
}}
|
|
>
|
|
{errorRate.toFixed(1)}%
|
|
</Typography>
|
|
<Typography
|
|
variant="caption"
|
|
sx={{
|
|
color: terminalTheme
|
|
? (terminalColors?.textSecondary || 'rgba(255,255,255,0.7)')
|
|
: 'rgba(255,255,255,0.7)',
|
|
fontSize: '0.7rem',
|
|
textTransform: 'uppercase',
|
|
letterSpacing: '1px'
|
|
}}
|
|
>
|
|
Error Rate
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Stats */}
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-around', gap: 2 }}>
|
|
<MuiTooltip title="Total API requests in the last 5 minutes">
|
|
<Box sx={{ textAlign: 'center' }}>
|
|
<Typography
|
|
variant="h6"
|
|
sx={{
|
|
fontWeight: 'bold',
|
|
color: terminalTheme ? terminalColors?.text : '#ffffff'
|
|
}}
|
|
>
|
|
{recentRequests.toLocaleString()}
|
|
</Typography>
|
|
<Typography
|
|
variant="caption"
|
|
sx={{
|
|
color: terminalTheme
|
|
? (terminalColors?.textSecondary || 'rgba(255,255,255,0.7)')
|
|
: 'rgba(255,255,255,0.7)',
|
|
fontSize: '0.7rem'
|
|
}}
|
|
>
|
|
Requests
|
|
</Typography>
|
|
</Box>
|
|
</MuiTooltip>
|
|
<MuiTooltip title="Failed requests in the last 5 minutes">
|
|
<Box sx={{ textAlign: 'center' }}>
|
|
<Typography
|
|
variant="h6"
|
|
sx={{
|
|
fontWeight: 'bold',
|
|
color: color
|
|
}}
|
|
>
|
|
{recentErrors.toLocaleString()}
|
|
</Typography>
|
|
<Typography
|
|
variant="caption"
|
|
sx={{
|
|
color: terminalTheme
|
|
? (terminalColors?.textSecondary || 'rgba(255,255,255,0.7)')
|
|
: 'rgba(255,255,255,0.7)',
|
|
fontSize: '0.7rem'
|
|
}}
|
|
>
|
|
Errors
|
|
</Typography>
|
|
</Box>
|
|
</MuiTooltip>
|
|
<MuiTooltip title="System health status">
|
|
<Box sx={{ textAlign: 'center' }}>
|
|
<Typography
|
|
variant="h6"
|
|
sx={{
|
|
fontWeight: 'bold',
|
|
color: color,
|
|
textTransform: 'capitalize'
|
|
}}
|
|
>
|
|
{status}
|
|
</Typography>
|
|
<Typography
|
|
variant="caption"
|
|
sx={{
|
|
color: terminalTheme
|
|
? (terminalColors?.textSecondary || 'rgba(255,255,255,0.7)')
|
|
: 'rgba(255,255,255,0.7)',
|
|
fontSize: '0.7rem'
|
|
}}
|
|
>
|
|
Status
|
|
</Typography>
|
|
</Box>
|
|
</MuiTooltip>
|
|
</Box>
|
|
</CardContent>
|
|
</Card>
|
|
</motion.div>
|
|
);
|
|
};
|
|
|
|
export default ErrorRateGauge;
|