import { useMemo, useState } from "react";
import { Unplug, Search } from "lucide-react";
import { useTranslation } from "react-i18next";
import type { ServerMetrics, ListeningPort } from "@/main-axios";
import { MetricCard } from "@/components/metric-card";
import { Select2 } from "@/components/select2";
function formatAddress(addr: string) {
return addr === "0.0.0.0" || addr === "*" || addr === "::" ? "*" : addr;
}
function PortRow({ port }: { port: ListeningPort }) {
return (
{port.localPort}
{port.protocol.toUpperCase()}
{port.process ?? (port.pid ? `PID:${port.pid}` : "—")}
{formatAddress(port.localAddress)}
);
}
export function PortsCard({ metrics }: { metrics: ServerMetrics | null }) {
const { t } = useTranslation();
const [query, setQuery] = useState("");
const [proto, setProto] = useState<"all" | "tcp" | "udp">("all");
const ports = useMemo(() => metrics?.ports?.ports ?? [], [metrics]);
const filtered = useMemo(() => {
const q = query.toLowerCase();
return ports.filter((p) => {
if (proto !== "all" && p.protocol.toLowerCase() !== proto) return false;
if (!q) return true;
return (
String(p.localPort).includes(q) ||
(p.process ?? "").toLowerCase().includes(q) ||
String(p.pid ?? "").includes(q) ||
p.localAddress.toLowerCase().includes(q)
);
});
}, [ports, query, proto]);
return (
}
scroll
>
{t("hostMetrics.ports.port")}
{t("hostMetrics.ports.protocol")}
{t("hostMetrics.ports.process")}
{t("hostMetrics.ports.address")}
{filtered.length === 0 ? (
{t("hostMetrics.ports.noData")}
) : (
filtered.map((port, i) => (
))
)}
);
}