45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
/**
|
|
* Port Table — top ports by traffic
|
|
* Ball Studios <https://git.balls.studio>
|
|
*/
|
|
|
|
import React from 'react';
|
|
|
|
interface Port {
|
|
port: number;
|
|
protocol: string;
|
|
rx_bytes: number;
|
|
tx_bytes: number;
|
|
}
|
|
|
|
function fmt(bytes: number): string {
|
|
if (bytes < 1024) return `${bytes} B`;
|
|
if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
return `${(bytes / 1048576).toFixed(2)} MB`;
|
|
}
|
|
|
|
export default function PortTable({ ports }: { ports: Port[] }) {
|
|
if (!ports.length) {
|
|
return <div className='addon-empty'>Port-level data requires iptables collection (disabled by default).</div>;
|
|
}
|
|
return (
|
|
<table className='addon-table'>
|
|
<thead>
|
|
<tr>
|
|
<th>Port</th><th>Proto</th><th>⬇ Inbound</th><th>⬆ Outbound</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{ports.map(p => (
|
|
<tr key={`${p.port}-${p.protocol}`}>
|
|
<td>{p.port}</td>
|
|
<td><span className={`addon-badge ${p.protocol}`}>{p.protocol.toUpperCase()}</span></td>
|
|
<td>{fmt(p.rx_bytes)}</td>
|
|
<td>{fmt(p.tx_bytes)}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
);
|
|
}
|