import React from "react";
import { Document, Page, Text, View } from "@react-pdf/renderer";
import { sharedStyles } from "./sharedPdfStyles";
interface AgentPdfDocumentProps {
data: any;
agentLabel: string;
agentUuid: string;
reportDateStr: string;
}
interface TableColumn {
header: string;
width: string;
align?: "center" | "right" | "left";
cell: (row: any) => string | number;
}
function formatBytes(bytes: number): string {
if (!bytes || bytes === 0) return "0 B";
const k = 1000;
const sizes = ["B", "KB", "MB", "GB", "TB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
}
function formatIndonesiaTime(dateStr: string | Date): string {
if (!dateStr) return "Never";
try {
const d = new Date(dateStr);
return d.toLocaleString("id-ID", {
timeZone: "Asia/Jakarta",
day: "2-digit",
month: "2-digit",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
}) + " WIB";
} catch (e) {
return String(dateStr);
}
}
function RenderPdfTable({ title, columns, data }: { title: string; columns: TableColumn[]; data: any[] }) {
return (
{title}
{columns.map((col, idx) => (
{col.header}
))}
{data.length === 0 ? (
No Data
) : (
data.map((row, rowIdx) => (
{columns.map((col, colIdx) => (
{col.cell(row)}
))}
))
)}
);
}
export default function AgentPdfDocument({
data,
agentLabel,
agentUuid,
reportDateStr,
}: AgentPdfDocumentProps) {
const summary = data.summary || {};
// Sort by total bandwidth (download + upload) descending for PDF export
const sortByBandwidth = (arr: any[]) =>
[...arr].sort((a, b) =>
((b.download ?? b.bytes_download ?? 0) + (b.upload ?? b.bytes_upload ?? 0)) -
((a.download ?? a.bytes_download ?? 0) + (a.upload ?? a.bytes_upload ?? 0))
);
const devices = sortByBandwidth(data.devices || []).slice(0, 50);
const flows = sortByBandwidth(data.flows || []).slice(0, 50);
const topApps = sortByBandwidth(data.top_apps || []).slice(0, 50);
const macBw = sortByBandwidth(data.mac_bandwidth || []).slice(0, 50);
// Security alerts: not sorted by bandwidth — keep original order
const insecure = (data.security?.insecure_protocols || []).slice(0, 50);
const reputation = (data.security?.ip_reputation || []).slice(0, 50);
const events = (data.events || []).slice(0, 50);
return (
{/* Header */}
Deep Package Inspection
Security & Traffic Analytics Dashboard
Network Agent Report
Generated at: {reportDateStr}
{/* Agent Info */}
Agent Identification
Agent Name
{agentLabel || "N/A"}
Agent UUID
{agentUuid || "N/A"}
Active Devices
{summary.total_devices ?? 0}
Active Flows
{summary.active_flows ?? 0}
{/* Bandwidth Usage */}
Bandwidth Metrics
TOTAL DOWNLOAD
{formatBytes(summary.bandwidth_down)}
TOTAL UPLOAD
{formatBytes(summary.bandwidth_up)}
{/* Top Apps */}
r.app_label || "Unknown" },
{ header: "Category", width: "20%", cell: (r) => r.category || "—" },
{ header: "Download", width: "20%", align: "right", cell: (r) => formatBytes(r.download) },
{ header: "Upload", width: "20%", align: "right", cell: (r) => formatBytes(r.upload) },
]}
/>
{/* Monitored Devices */}
r.ip_address || "N/A" },
{ header: "OS / Manufacturer", width: "28%", cell: (r) => r.os_label || r.manufacturer || "Unknown" },
{ header: "Download", width: "15%", align: "right", cell: (r) => formatBytes(r.download) },
{ header: "Upload", width: "15%", align: "right", cell: (r) => formatBytes(r.upload) },
{ header: "Last Seen", width: "20%", cell: (r) => r.last_seen ? formatIndonesiaTime(r.last_seen) : "Never" },
]}
/>
{/* Recent Network Flows */}
r.src_ip || "—" },
{ header: "Destination IP", width: "20%", cell: (r) => r.dst_ip || "—" },
{ header: "Port", width: "10%", align: "center", cell: (r) => r.dst_port || "—" },
{ header: "App / Protocol", width: "20%", cell: (r) => r.app_label || r.protocol || "Unknown" },
{ header: "Download", width: "15%", align: "right", cell: (r) => formatBytes(r.download) },
{ header: "Upload", width: "15%", align: "right", cell: (r) => formatBytes(r.upload) },
]}
/>
{/* Insecure Protocols */}
r.ip_address || "—" },
{ header: "Protocol", width: "15%", cell: (r) => r.protocol || "—" },
{ header: "Risk Level", width: "15%", cell: (r) => r.risk || "—" },
{ header: "Destination", width: "25%", cell: (r) => r.dst_ip ? `${r.dst_ip}:${r.dst_port ?? ""}` : "—" },
{ header: "Bytes Traced", width: "20%", align: "right", cell: (r) => formatBytes((r.download ?? 0) + (r.upload ?? 0)) },
]}
/>
{/* IP Reputation Log */}
r.ip_address || "—" },
{ header: "Local IP", width: "30%", cell: (r) => r.local_ip || "—" },
{ header: "Reputation", width: "20%", cell: (r) => r.reputation || "—" },
{ header: "Risk Score", width: "20%", align: "right", cell: (r) => r.score ?? "—" },
]}
/>
{/* Security Events */}
r.event_type || "—" },
{ header: "Severity", width: "15%", align: "center", cell: (r) => r.severity || "—" },
{ header: "IP Address", width: "20%", cell: (r) => r.ip_address || "—" },
{ header: "Description", width: "25%", cell: (r) => r.description || "—" },
{ header: "Event Time", width: "20%", cell: (r) => r.event_at ? formatIndonesiaTime(r.event_at) : "—" },
]}
/>
{/* MAC Bandwidth */}
r.mac_address || "—" },
{ header: "Manufacturer", width: "30%", cell: (r) => r.manufacturer || "Unknown" },
{ header: "Download", width: "20%", align: "right", cell: (r) => formatBytes(r.download) },
{ header: "Upload", width: "20%", align: "right", cell: (r) => formatBytes(r.upload) },
]}
/>
);
}