connection-table.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import dayjs from "dayjs";
  2. import { useMemo, useState } from "react";
  3. import { DataGrid, GridColDef } from "@mui/x-data-grid";
  4. import { useThemeMode } from "@/services/states";
  5. import { truncateStr } from "@/utils/truncate-str";
  6. import parseTraffic from "@/utils/parse-traffic";
  7. import { t } from "i18next";
  8. interface Props {
  9. connections: IConnectionsItem[];
  10. onShowDetail: (data: IConnectionsItem) => void;
  11. }
  12. export const ConnectionTable = (props: Props) => {
  13. const { connections, onShowDetail } = props;
  14. const mode = useThemeMode();
  15. const isDark = mode === "light" ? false : true;
  16. const backgroundColor = isDark ? "#282A36" : "#ffffff";
  17. const [columnVisible, setColumnVisible] = useState<
  18. Partial<Record<keyof IConnectionsItem, boolean>>
  19. >({});
  20. const [columns] = useState<GridColDef[]>([
  21. { field: "host", headerName: t("Host"), flex: 220, minWidth: 220 },
  22. {
  23. field: "download",
  24. headerName: t("Downloaded"),
  25. width: 88,
  26. align: "right",
  27. headerAlign: "right",
  28. valueFormatter: (value: number) => parseTraffic(value).join(" "),
  29. },
  30. {
  31. field: "upload",
  32. headerName: t("Uploaded"),
  33. width: 88,
  34. align: "right",
  35. headerAlign: "right",
  36. valueFormatter: (value: number) => parseTraffic(value).join(" "),
  37. },
  38. {
  39. field: "dlSpeed",
  40. headerName: t("DL Speed"),
  41. width: 88,
  42. align: "right",
  43. headerAlign: "right",
  44. valueFormatter: (value: number) => parseTraffic(value).join(" ") + "/s",
  45. },
  46. {
  47. field: "ulSpeed",
  48. headerName: t("UL Speed"),
  49. width: 88,
  50. align: "right",
  51. headerAlign: "right",
  52. valueFormatter: (value: number) => parseTraffic(value).join(" ") + "/s",
  53. },
  54. { field: "chains", headerName: t("Chains"), flex: 360, minWidth: 360 },
  55. { field: "rule", headerName: t("Rule"), flex: 300, minWidth: 250 },
  56. { field: "process", headerName: t("Process"), flex: 240, minWidth: 120 },
  57. {
  58. field: "time",
  59. headerName: t("Time"),
  60. flex: 120,
  61. minWidth: 100,
  62. align: "right",
  63. headerAlign: "right",
  64. sortComparator: (v1: string, v2: string) =>
  65. new Date(v2).getTime() - new Date(v1).getTime(),
  66. valueFormatter: (value: number) => dayjs(value).fromNow(),
  67. },
  68. { field: "source", headerName: t("Source"), flex: 200, minWidth: 130 },
  69. {
  70. field: "destinationIP",
  71. headerName: t("Destination IP"),
  72. flex: 200,
  73. minWidth: 130,
  74. },
  75. { field: "type", headerName: t("Type"), flex: 160, minWidth: 100 },
  76. ]);
  77. const connRows = useMemo(() => {
  78. return connections.map((each) => {
  79. const { metadata, rulePayload } = each;
  80. const chains = [...each.chains].reverse().join(" / ");
  81. const rule = rulePayload ? `${each.rule}(${rulePayload})` : each.rule;
  82. return {
  83. id: each.id,
  84. host: metadata.host
  85. ? `${metadata.host}:${metadata.destinationPort}`
  86. : `${metadata.destinationIP}:${metadata.destinationPort}`,
  87. download: each.download,
  88. upload: each.upload,
  89. dlSpeed: each.curDownload,
  90. ulSpeed: each.curUpload,
  91. chains,
  92. rule,
  93. process: truncateStr(metadata.process || metadata.processPath),
  94. time: each.start,
  95. source: `${metadata.sourceIP}:${metadata.sourcePort}`,
  96. destinationIP: metadata.destinationIP,
  97. type: `${metadata.type}(${metadata.network})`,
  98. connectionData: each,
  99. };
  100. });
  101. }, [connections]);
  102. return (
  103. <DataGrid
  104. hideFooter
  105. rows={connRows}
  106. columns={columns}
  107. onRowClick={(e) => onShowDetail(e.row.connectionData)}
  108. density="compact"
  109. sx={{
  110. border: "none",
  111. "div:focus": { outline: "none !important" },
  112. "& div[aria-rowindex]": {
  113. backgroundColor: `${backgroundColor} !important`,
  114. },
  115. }}
  116. columnVisibilityModel={columnVisible}
  117. onColumnVisibilityModelChange={(e) => setColumnVisible(e)}
  118. />
  119. );
  120. };