import { useEffect, useMemo, useState } from "react"; import { api, type PortEntry, type PortList, type PortScanResult } from "../api/client"; import { sortItems, type SortDirection } from "../hooks/useSortable"; import { usePagination } from "../hooks/usePagination"; import { formatDateTime } from "../utils/date"; import { downloadCsv } from "../utils/csv"; import { readableError } from "../utils/errors"; import Pagination from "./Pagination"; import SortableTh from "./SortableTh"; const PRESETS: { key: string; label: string; from: number; to: number }[] = [ { key: "well-known", label: "1–1024 (well-known)", from: 1, to: 1024 }, { key: "common", label: "1–10000 (most services)", from: 1, to: 10000 }, { key: "high1", label: "10001–30000", from: 10001, to: 30000 }, { key: "high2", label: "30001–50000", from: 30001, to: 50000 }, { key: "high3", label: "50001–65535", from: 50001, to: 65535 }, { key: "custom", label: "Custom range…", from: 8000, to: 8999 }, ]; const MAX_SHOWN_RANGES = 24; interface NoteForm { editingId: number | null; port: string; protocol: "tcp" | "udp"; label: string; comment: string; } function rangeText([from, to]: [number, number]) { return from === to ? String(from) : `${from}–${to}`; } function StatusBadges({ entry }: { entry: PortEntry }) { if (entry.state === "reserved") return Reserved; return (
| Actions | }|||||
|---|---|---|---|---|---|
{p.port}
|
{p.protocol} |
|
{p.label ?? —}
{p.agent?.process && {p.agent.process} }
|
{p.comment ?? "—"} | {canEdit && (
{(p.label || p.comment) && (
)}
|
)}