signal-batch/frontend/src/components/charts/LineChart.tsx
htlee 7852f840e4 feat: 쿼리 메트릭 수집 확장 + 대시보드 성능 차트 추가
- client IP 수집 (REST: X-Forwarded-For 체인, WS: 세션 속성)
- 응답 크기 추정 (uniqueVessels*200 + points*40)
- timeseries API (/api/monitoring/query-metrics/timeseries)
- Dashboard 쿼리 성능 차트 5종 (응답시간, 볼륨, 캐시경로, 응답크기, Top 클라이언트)
2026-03-10 11:15:00 +09:00

84 lines
2.1 KiB
TypeScript

import {
LineChart as RechartsLineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Legend,
} from 'recharts'
interface LineSeries {
dataKey: string
color: string
name?: string
}
interface LineChartProps {
data: Record<string, unknown>[]
series: LineSeries[]
xKey: string
height?: number
label?: string
yFormatter?: (value: number) => string
}
export default function LineChart({
data,
series,
xKey,
height = 240,
label,
yFormatter,
}: LineChartProps) {
return (
<div>
{label && <div className="mb-2 text-sm font-medium text-muted">{label}</div>}
<ResponsiveContainer width="100%" height={height}>
<RechartsLineChart data={data} margin={{ top: 4, right: 4, bottom: 4, left: 4 }}>
<CartesianGrid strokeDasharray="3 3" stroke="var(--sb-border)" />
<XAxis
dataKey={xKey}
tick={{ fontSize: 12, fill: 'var(--sb-text-muted)' }}
axisLine={{ stroke: 'var(--sb-border)' }}
tickLine={false}
/>
<YAxis
tick={{ fontSize: 12, fill: 'var(--sb-text-muted)' }}
axisLine={false}
tickLine={false}
tickFormatter={yFormatter}
/>
<Tooltip
contentStyle={{
backgroundColor: 'var(--sb-surface)',
border: '1px solid var(--sb-border)',
borderRadius: 'var(--sb-radius)',
fontSize: 12,
}}
formatter={yFormatter ? (v: number) => yFormatter(v) : undefined}
/>
{series.length > 1 && (
<Legend
wrapperStyle={{ fontSize: 12, color: 'var(--sb-text-muted)' }}
/>
)}
{series.map(s => (
<Line
key={s.dataKey}
type="monotone"
dataKey={s.dataKey}
stroke={s.color}
name={s.name ?? s.dataKey}
strokeWidth={2}
dot={false}
activeDot={{ r: 4 }}
/>
))}
</RechartsLineChart>
</ResponsiveContainer>
</div>
)
}