feat: add disk avg/min to node table, add NAS/Ingress/Istio detail tables
CI/CD / build-and-push (push) Successful in 1m27s
Details
CI/CD / build-and-push (push) Successful in 1m27s
Details
- NodeTable: disk now shows avg, max, min (was max only) - NasTable: mountpoint-based avg/max/min - NetworkTable: RX/TX avg/max/min for Ingress and Istio Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ba52cb31c1
commit
57dcad38ff
|
|
@ -7,6 +7,8 @@ import SummaryCards from '@/components/report/SummaryCards';
|
|||
import TimeSeriesChart from '@/components/charts/TimeSeriesChart';
|
||||
import NetworkChart from '@/components/charts/NetworkChart';
|
||||
import NodeTable from '@/components/report/NodeTable';
|
||||
import NasTable from '@/components/report/NasTable';
|
||||
import NetworkTable from '@/components/report/NetworkTable';
|
||||
import AlertSection from '@/components/report/AlertSection';
|
||||
import ErrorBoundary from '@/components/ErrorBoundary';
|
||||
|
||||
|
|
@ -180,6 +182,29 @@ export default function Home() {
|
|||
</div>
|
||||
</ErrorBoundary>
|
||||
|
||||
{data.metrics.nas && data.metrics.nas.length > 0 && (
|
||||
<ErrorBoundary fallback="NAS 상세 오류">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-800 mb-3">NAS 사용률 상세</h2>
|
||||
<NasTable nas={data.metrics.nas} />
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
|
||||
<ErrorBoundary fallback="Ingress 상세 오류">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-800 mb-3">Ingress Network 상세</h2>
|
||||
<NetworkTable title="Ingress" data={data.metrics.ingress} />
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
|
||||
<ErrorBoundary fallback="Istio 상세 오류">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-800 mb-3">Istio Network 상세</h2>
|
||||
<NetworkTable title="Istio" data={data.metrics.istio} />
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
|
||||
<ErrorBoundary fallback="AlertSection 오류">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-800 mb-3">주의 구간</h2>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
'use client';
|
||||
|
||||
import type { MetricInstance } from '@/types/metrics';
|
||||
import { formatPercent } from '@/lib/formatters';
|
||||
|
||||
interface NasTableProps {
|
||||
nas: MetricInstance[];
|
||||
}
|
||||
|
||||
export default function NasTable({ nas }: NasTableProps) {
|
||||
if (!nas || nas.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full bg-white rounded-lg shadow">
|
||||
<thead>
|
||||
<tr className="bg-gray-50 border-b">
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Mountpoint</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">Avg</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">Max</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">Min</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
{nas.map((inst) => (
|
||||
<tr key={inst.instance} className="hover:bg-gray-50">
|
||||
<td className="px-4 py-3 text-sm font-medium">{inst.instance || '-'}</td>
|
||||
<td className="px-4 py-3 text-sm text-right">{formatPercent(inst.stats.avg)}</td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium">{formatPercent(inst.stats.max)}</td>
|
||||
<td className="px-4 py-3 text-sm text-right text-gray-400">{formatPercent(inst.stats.min)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
'use client';
|
||||
|
||||
import type { NetworkMetrics } from '@/types/metrics';
|
||||
import { formatBytesPerSec } from '@/lib/formatters';
|
||||
|
||||
interface NetworkTableProps {
|
||||
title: string;
|
||||
data: NetworkMetrics;
|
||||
}
|
||||
|
||||
export default function NetworkTable({ title, data }: NetworkTableProps) {
|
||||
const hasData = data.receive.length > 0 || data.transmit.length > 0;
|
||||
if (!hasData) return null;
|
||||
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full bg-white rounded-lg shadow">
|
||||
<thead>
|
||||
<tr className="bg-gray-50 border-b">
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">{title}</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">Avg</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">Max</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">Min</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
{data.receive.map((inst, idx) => (
|
||||
<tr key={`rx-${idx}`} className="hover:bg-gray-50">
|
||||
<td className="px-4 py-3 text-sm font-medium">
|
||||
<span className="inline-block px-2 py-0.5 rounded text-xs bg-blue-100 text-blue-700 mr-2">RX</span>
|
||||
{inst.instance || 'total'}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm text-right">{formatBytesPerSec(inst.stats.avg)}</td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium">{formatBytesPerSec(inst.stats.max)}</td>
|
||||
<td className="px-4 py-3 text-sm text-right text-gray-400">{formatBytesPerSec(inst.stats.min)}</td>
|
||||
</tr>
|
||||
))}
|
||||
{data.transmit.map((inst, idx) => (
|
||||
<tr key={`tx-${idx}`} className="hover:bg-gray-50">
|
||||
<td className="px-4 py-3 text-sm font-medium">
|
||||
<span className="inline-block px-2 py-0.5 rounded text-xs bg-green-100 text-green-700 mr-2">TX</span>
|
||||
{inst.instance || 'total'}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm text-right">{formatBytesPerSec(inst.stats.avg)}</td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium">{formatBytesPerSec(inst.stats.max)}</td>
|
||||
<td className="px-4 py-3 text-sm text-right text-gray-400">{formatBytesPerSec(inst.stats.min)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -31,7 +31,9 @@ export default function NodeTable({ nodes, cpu, memory, disk }: NodeTableProps)
|
|||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">MEM avg</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">MEM max</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">MEM min</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">DISK avg</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">DISK max</th>
|
||||
<th className="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">DISK min</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
|
|
@ -70,9 +72,13 @@ export default function NodeTable({ nodes, cpu, memory, disk }: NodeTableProps)
|
|||
<td className="px-4 py-3 text-sm text-right text-gray-400">
|
||||
{memStats ? formatPercent(memStats.min) : '-'}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm text-right">{diskStats ? formatPercent(diskStats.avg) : '-'}</td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium">
|
||||
{diskStats ? formatPercent(diskStats.max) : '-'}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm text-right text-gray-400">
|
||||
{diskStats ? formatPercent(diskStats.min) : '-'}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
Loading…
Reference in New Issue