import { useState } from "react"; import { Link } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { downloadNeConfigSnapshot, fetchNeConfigSnapshotDetail, fetchNeConfigSnapshots, } from "../../services/api"; import { queryKeys } from "../../constants/queryKeys"; import { useI18n } from "../../i18n"; import { useToast } from "../../hooks/useToast"; import { pageCount } from "../../utils/display"; import { formatSystemTime } from "../../utils/time"; function fmtBytes(n: number): string { if (!n) return "0 B"; if (n < 1024) return `${n} B`; if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`; return `${(n / (1024 * 1024)).toFixed(2)} MB`; } export function NetworkConfigsPage() { const { t } = useI18n(); const { showOk, showError } = useToast(); const [page, setPage] = useState(1); const [keyword, setKeyword] = useState(""); const [source, setSource] = useState(""); const [vendor, setVendor] = useState(""); const [selected, setSelected] = useState<{ source: string; id: string } | null>(null); const [tab, setTab] = useState<"primary" | "alt">("primary"); const [exporting, setExporting] = useState(""); const listQuery = useQuery({ queryKey: queryKeys.networkConfigs(page, keyword, source, vendor), queryFn: () => fetchNeConfigSnapshots({ page, pageSize: 20, keyword, source, vendor }), staleTime: 5000, }); const detailQuery = useQuery({ queryKey: queryKeys.networkConfigDetail(selected?.source || "", selected?.id || ""), queryFn: () => fetchNeConfigSnapshotDetail(selected!.source, selected!.id, "both"), enabled: Boolean(selected), staleTime: 10000, }); const items = listQuery.data?.items ?? []; const total = Number(listQuery.data?.total || 0); const pages = pageCount(total, 20); const detail = detailQuery.data; const showAlt = Boolean(detail?.has_alt); const exportConfig = async ( src: string, id: string, field: "primary" | "alt" | "both", ) => { const key = `${src}:${id}:${field}`; setExporting(key); try { await downloadNeConfigSnapshot(src, id, field); showOk(t("networkConfigs.exportOk")); } catch (err) { showError(String(err)); } finally { setExporting(""); } }; return (

{t("networkConfigs.title")}

{ setKeyword(e.target.value); setPage(1); }} /> { setVendor(e.target.value); setPage(1); }} />
{listQuery.isLoading ?

{t("common.refreshing")}

: null} {items.map((row) => { const exportKey = `${row.source}:${row.target_id}:list`; return ( ); })} {!items.length && !listQuery.isLoading ? ( ) : null}
{t("networkConfigs.col.name")} IP {t("networkConfigs.col.vendor")} {t("networkConfigs.col.source")} {t("networkConfigs.col.size")} {t("networkConfigs.col.collected")}
{row.ne_name || row.target_id} {row.ne_ip} {row.vendor || "-"} {row.source} {fmtBytes(row.plain_size)} {row.collected_at ? formatSystemTime(row.collected_at) : "-"} WebCRT
{t("networkConfigs.empty")}
{t("common.pagerMeta", { total: String(total), page: String(page), pages: String(pages) })}
{selected ? (

{detail?.ne_name || selected.id}{" "} ({selected.source} / {detail?.ne_ip || "-"})

{showAlt ? ( ) : null}
{detailQuery.isLoading ?

{t("common.refreshing")}

: null} {showAlt ? (
) : null}