diff --git a/src/components/connection/connection-item.tsx b/src/components/connection/connection-item.tsx index e6379df..3ec7583 100644 --- a/src/components/connection/connection-item.tsx +++ b/src/components/connection/connection-item.tsx @@ -4,6 +4,7 @@ import { styled, ListItem, IconButton, ListItemText } from "@mui/material"; import { CloseRounded } from "@mui/icons-material"; import { ApiType } from "../../services/types"; import { deleteConnection } from "../../services/api"; +import parseTraffic from "../../utils/parse-traffic"; const Tag = styled("span")(({ theme }) => ({ display: "inline-block", @@ -23,32 +24,39 @@ interface Props { const ConnectionItem = (props: Props) => { const { value } = props; - const onDelete = useLockFn(async () => deleteConnection(value.id)); + const { id, metadata, chains, start, curUpload, curDownload } = value; + + const onDelete = useLockFn(async () => deleteConnection(id)); + const showTraffic = curUpload! > 1024 || curDownload! > 1024; return ( + } > - {value.metadata.network} + {metadata.network} - {value.metadata.type} + {metadata.type} - {value.chains.length > 0 && ( - {value.chains[value.chains.length - 1]} + {chains.length > 0 && {chains[value.chains.length - 1]}} + + {dayjs(start).fromNow()} + + {showTraffic && ( + + {parseTraffic(curUpload!)} / {parseTraffic(curDownload!)} + )} - - {dayjs(value.start).fromNow()} } /> diff --git a/src/pages/connections.tsx b/src/pages/connections.tsx index f949de7..1cc6f76 100644 --- a/src/pages/connections.tsx +++ b/src/pages/connections.tsx @@ -1,6 +1,6 @@ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useLockFn } from "ahooks"; -import { Button, Paper } from "@mui/material"; +import { Box, Button, Paper, TextField } from "@mui/material"; import { Virtuoso } from "react-virtuoso"; import { useTranslation } from "react-i18next"; import { ApiType } from "../services/types"; @@ -8,12 +8,20 @@ import { closeAllConnections, getInfomation } from "../services/api"; import BasePage from "../components/base/base-page"; import ConnectionItem from "../components/connection/connection-item"; -const ConnectionsPage = () => { - const initConn = { uploadTotal: 0, downloadTotal: 0, connections: [] }; +const initConn = { uploadTotal: 0, downloadTotal: 0, connections: [] }; +const ConnectionsPage = () => { const { t } = useTranslation(); + + const [filterText, setFilterText] = useState(""); const [connData, setConnData] = useState(initConn); + const filterConn = useMemo(() => { + return connData.connections.filter((conn) => + (conn.metadata.host || conn.metadata.destinationIP)?.includes(filterText) + ); + }, [connData, filterText]); + useEffect(() => { let ws: WebSocket | null = null; @@ -23,32 +31,35 @@ const ConnectionsPage = () => { ws.addEventListener("message", (event) => { const data = JSON.parse(event.data) as ApiType.Connections; + + // 与前一次connections的展示顺序尽量保持一致 setConnData((old) => { const oldConn = old.connections; - const oldList = oldConn.map((each) => each.id); const maxLen = data.connections.length; const connections: typeof oldConn = []; - // 与前一次连接的顺序尽量保持一致 - data.connections - .filter((each) => { - const index = oldList.indexOf(each.id); + const rest = data.connections.filter((each) => { + const index = oldConn.findIndex((o) => o.id === each.id); - if (index >= 0 && index < maxLen) { - connections[index] = each; - return false; - } - return true; - }) - .forEach((each) => { - for (let i = 0; i < maxLen; ++i) { - if (!connections[i]) { - connections[i] = each; - return; - } - } - }); + if (index >= 0 && index < maxLen) { + const old = oldConn[index]; + each.curUpload = each.upload - old.upload; + each.curDownload = each.download - old.download; + + connections[index] = each; + return false; + } + return true; + }); + + for (let i = 0; i < maxLen; ++i) { + if (!connections[i] && rest.length > 0) { + connections[i] = rest.shift()!; + connections[i].curUpload = 0; + connections[i].curDownload = 0; + } + } return { ...data, connections }; }); @@ -76,11 +87,48 @@ const ConnectionsPage = () => { } > - } - /> + + {/* */} + + setFilterText(e.target.value)} + sx={{ input: { py: 0.65, px: 1.25 } }} + /> + + + + } + /> + ); diff --git a/src/services/types.ts b/src/services/types.ts index 50b81fc..4858679 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -65,6 +65,8 @@ export namespace ApiType { chains: string[]; rule: string; rulePayload: string; + curUpload?: number; // calculate + curDownload?: number; // calculate } export interface Connections {