import { useMemo, useRef, useState, useCallback } from "react"; import { useLockFn } from "ahooks"; import { Box, Button, IconButton, MenuItem } from "@mui/material"; import { Virtuoso } from "react-virtuoso"; import { useTranslation } from "react-i18next"; import { TableChartRounded, TableRowsRounded, PlayCircleOutlineRounded, PauseCircleOutlineRounded, } from "@mui/icons-material"; import { closeAllConnections } from "@/services/api"; import { useConnectionSetting } from "@/services/states"; import { BaseEmpty, BasePage } from "@/components/base"; import { ConnectionItem } from "@/components/connection/connection-item"; import { ConnectionTable } from "@/components/connection/connection-table"; import { ConnectionDetail, ConnectionDetailRef, } from "@/components/connection/connection-detail"; import parseTraffic from "@/utils/parse-traffic"; import { BaseSearchBox, type SearchState, } from "@/components/base/base-search-box"; import { BaseStyledSelect } from "@/components/base/base-styled-select"; import { useTheme } from "@mui/material/styles"; import { useVisibility } from "@/hooks/use-visibility"; import { useAppData } from "@/providers/app-data-provider"; const initConn: IConnections = { uploadTotal: 0, downloadTotal: 0, connections: [], }; type OrderFunc = (list: IConnectionsItem[]) => IConnectionsItem[]; const ConnectionsPage = () => { const { t } = useTranslation(); const pageVisible = useVisibility(); const theme = useTheme(); const isDark = theme.palette.mode === "dark"; const [match, setMatch] = useState(() => (_: string) => true); const [curOrderOpt, setOrderOpt] = useState("Default"); // 使用全局数据 const { connections } = useAppData(); const [setting, setSetting] = useConnectionSetting(); const isTableLayout = setting.layout === "table"; const orderOpts: Record = { Default: (list) => list.sort( (a, b) => new Date(b.start || "0").getTime()! - new Date(a.start || "0").getTime()!, ), "Upload Speed": (list) => list.sort((a, b) => b.curUpload! - a.curUpload!), "Download Speed": (list) => list.sort((a, b) => b.curDownload! - a.curDownload!), }; const [isPaused, setIsPaused] = useState(false); const [frozenData, setFrozenData] = useState(null); // 使用全局连接数据 const displayData = useMemo(() => { if (!pageVisible) return initConn; if (isPaused) { return frozenData ?? { uploadTotal: connections.uploadTotal, downloadTotal: connections.downloadTotal, connections: connections.data }; } return { uploadTotal: connections.uploadTotal, downloadTotal: connections.downloadTotal, connections: connections.data }; }, [isPaused, frozenData, connections, pageVisible]); const [filterConn] = useMemo(() => { const orderFunc = orderOpts[curOrderOpt]; let conns = displayData.connections.filter((conn) => { const { host, destinationIP, process } = conn.metadata; return ( match(host || "") || match(destinationIP || "") || match(process || "") ); }); if (orderFunc) conns = orderFunc(conns); return [conns]; }, [displayData, match, curOrderOpt]); const onCloseAll = useLockFn(closeAllConnections); const detailRef = useRef(null!); const handleSearch = useCallback((match: (content: string) => boolean) => { setMatch(() => match); }, []); const handlePauseToggle = useCallback(() => { setIsPaused((prev) => { if (!prev) { setFrozenData({ uploadTotal: connections.uploadTotal, downloadTotal: connections.downloadTotal, connections: connections.data }); } else { setFrozenData(null); } return !prev; }); }, [connections]); return ( {t("Connections")}} contentStyle={{ height: "100%", display: "flex", flexDirection: "column", overflow: "auto", borderRadius: "8px", }} header={ {t("Downloaded")}: {parseTraffic(displayData.downloadTotal)} {t("Uploaded")}: {parseTraffic(displayData.uploadTotal)} setSetting((o) => o?.layout !== "table" ? { ...o, layout: "table" } : { ...o, layout: "list" }, ) } > {isTableLayout ? ( ) : ( )} {isPaused ? ( ) : ( )} } > {!isTableLayout && ( setOrderOpt(e.target.value)} > {Object.keys(orderOpts).map((opt) => ( {t(opt)} ))} )} {filterConn.length === 0 ? ( ) : isTableLayout ? ( detailRef.current?.open(detail)} /> ) : ( ( detailRef.current?.open(item)} /> )} /> )} ); }; export default ConnectionsPage;