diff --git a/src/components/connection/connection-table.tsx b/src/components/connection/connection-table.tsx index 143bf9f6..03832f0a 100644 --- a/src/components/connection/connection-table.tsx +++ b/src/components/connection/connection-table.tsx @@ -3,6 +3,7 @@ import { useMemo, useState } from "react"; import { DataGrid, GridColDef } from "@mui/x-data-grid"; import { truncateStr } from "@/utils/truncate-str"; import parseTraffic from "@/utils/parse-traffic"; +import { sortWithUnit, sortStringTime } from "@/utils/custom-comparator"; interface Props { connections: IConnectionsItem[]; @@ -24,6 +25,7 @@ export const ConnectionTable = (props: Props) => { width: 88, align: "right", headerAlign: "right", + sortComparator: sortWithUnit, }, { field: "upload", @@ -31,6 +33,7 @@ export const ConnectionTable = (props: Props) => { width: 88, align: "right", headerAlign: "right", + sortComparator: sortWithUnit, }, { field: "dlSpeed", @@ -38,6 +41,7 @@ export const ConnectionTable = (props: Props) => { width: 88, align: "right", headerAlign: "right", + sortComparator: sortWithUnit, }, { field: "ulSpeed", @@ -45,6 +49,7 @@ export const ConnectionTable = (props: Props) => { width: 88, align: "right", headerAlign: "right", + sortComparator: sortWithUnit, }, { field: "chains", headerName: "Chains", flex: 360, minWidth: 360 }, { field: "rule", headerName: "Rule", flex: 300, minWidth: 250 }, @@ -56,6 +61,7 @@ export const ConnectionTable = (props: Props) => { minWidth: 100, align: "right", headerAlign: "right", + sortComparator: sortStringTime, }, { field: "source", headerName: "Source", flex: 200, minWidth: 130 }, { @@ -72,7 +78,6 @@ export const ConnectionTable = (props: Props) => { const { metadata, rulePayload } = each; const chains = [...each.chains].reverse().join(" / "); const rule = rulePayload ? `${each.rule}(${rulePayload})` : each.rule; - return { id: each.id, host: metadata.host diff --git a/src/pages/connections.tsx b/src/pages/connections.tsx index 39510a78..3df4be21 100644 --- a/src/pages/connections.tsx +++ b/src/pages/connections.tsx @@ -24,6 +24,7 @@ import { ConnectionDetail, ConnectionDetailRef, } from "@/components/connection/connection-detail"; +import parseTraffic from "@/utils/parse-traffic"; const initConn = { uploadTotal: 0, downloadTotal: 0, connections: [] }; @@ -48,14 +49,20 @@ const ConnectionsPage = () => { list.sort((a, b) => b.curDownload! - a.curDownload!), }; - const filterConn = useMemo(() => { + const [filterConn, download, upload] = useMemo(() => { const orderFunc = orderOpts[curOrderOpt]; - const connections = connData.connections.filter((conn) => + let connections = connData.connections.filter((conn) => (conn.metadata.host || conn.metadata.destinationIP)?.includes(filterText) ); - if (orderFunc) return orderFunc(connections); - return connections; + if (orderFunc) connections = orderFunc(connections); + let download = 0; + let upload = 0; + connections.forEach((x) => { + download += x.download; + upload += x.upload; + }); + return [connections, download, upload]; }, [connData, filterText, curOrderOpt]); const { connect, disconnect } = useWebsocket( @@ -119,6 +126,8 @@ const ConnectionsPage = () => { contentStyle={{ height: "100%" }} header={ + Download: {parseTraffic(download)} + Upload: {parseTraffic(upload)} { placeholder={t("Filter conditions")} value={filterText} onChange={(e) => setFilterText(e.target.value)} - sx={{ input: { py: 0.65, px: 1.25 } }} /> diff --git a/src/utils/custom-comparator.ts b/src/utils/custom-comparator.ts new file mode 100644 index 00000000..2972e39d --- /dev/null +++ b/src/utils/custom-comparator.ts @@ -0,0 +1,38 @@ +import { GridComparatorFn } from "@mui/x-data-grid"; + +const UNITS = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; +const unitMap = new Map(); +unitMap.set("分钟前", 60); +unitMap.set("小时前", 60 * 60); +unitMap.set("天前", 60 * 60 * 24); +unitMap.set("个月前", 60 * 60 * 24 * 30); +unitMap.set("年前", 60 * 60 * 24 * 30 * 12); + +export const sortWithUnit: GridComparatorFn = (v1, v2) => { + const [ret1, unit1] = v1.split(" "); + const [ret2, unit2] = v2.split(" "); + let value1 = + parseFloat(ret1) * + Math.pow(1024, UNITS.indexOf(unit1.replace("/s", "").trim())); + let value2 = + parseFloat(ret2) * + Math.pow(1024, UNITS.indexOf(unit2.replace("/s", "").trim())); + return value1 - value2; +}; + +export const sortStringTime: GridComparatorFn = (v1, v2) => { + if (v1 === "几秒前") { + return -1; + } + if (v2 === "几秒前") { + return 1; + } + + const matches1 = v1.match(/[0-9]+/); + const num1 = matches1 !== null ? parseInt(matches1[0]) : 0; + const matches2 = v2.match(/[0-9]+/); + const num2 = matches2 !== null ? parseInt(matches2[0]) : 0; + const unit1 = unitMap.get(v1.replace(num1.toString(), "").trim()) || 0; + const unit2 = unitMap.get(v2.replace(num2.toString(), "").trim()) || 0; + return num1 * unit1 - num2 * unit2; +};