NodeListView.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import { FC, useState, useEffect } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import { Theme } from '@mui/material';
  4. import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
  5. import AttuGrid from '@/components/grid/Grid';
  6. import { ColDefinitionsType } from '@/components/grid/Types';
  7. import { useNavigationHook } from '@/hooks';
  8. import { ALL_ROUTER_TYPES } from '@/router/Types';
  9. import MiniTopo from './MiniTopology';
  10. import { getByteString, formatByteSize } from '@/utils';
  11. import DataCard from './DataCard';
  12. import { usePaginationHook } from '@/hooks';
  13. import { getLabelDisplayedRows } from '@/pages/search/Utils';
  14. import { NodeListViewProps, Node } from './Types';
  15. import { makeStyles } from '@mui/styles';
  16. const getStyles = makeStyles((theme: Theme) => ({
  17. root: {
  18. overflow: 'hidden',
  19. padding: '0 16px',
  20. display: 'flex',
  21. flexDirection: 'column',
  22. border: `1px solid ${theme.palette.divider}`,
  23. },
  24. childCloseBtnContainer: {
  25. border: 0,
  26. backgroundColor: theme.palette.background.paper,
  27. cursor: 'pointer',
  28. width: '100%',
  29. height: '28px',
  30. },
  31. childCloseBtn: {
  32. border: 0,
  33. backgroundColor: theme.palette.background.paper,
  34. color: theme.palette.text.primary,
  35. width: '100%',
  36. },
  37. gridContainer: {
  38. height: `calc(100vh - 120px)`,
  39. display: 'flex',
  40. gap: 8,
  41. },
  42. leftContainer: {
  43. height: '100%',
  44. width: '70%',
  45. },
  46. rightContainer: {
  47. width: '30%',
  48. overflow: 'scroll',
  49. },
  50. dataCard: {},
  51. }));
  52. type GridNode = {
  53. id: string;
  54. ip: string;
  55. cpuCore: number;
  56. cpuUsage: number;
  57. disk: number;
  58. diskUsage: number;
  59. memUsage: number;
  60. name: string;
  61. node: Node;
  62. };
  63. const NodeListView: FC<NodeListViewProps> = props => {
  64. useNavigationHook(ALL_ROUTER_TYPES.SYSTEM);
  65. const { t } = useTranslation('systemView');
  66. const { t: commonTrans } = useTranslation();
  67. const capacityTrans: { [key in string]: string } = commonTrans('capacity');
  68. const gridTrans = commonTrans('grid');
  69. const classes = getStyles();
  70. const [selectedChildNode, setSelectedChildNode] = useState<GridNode[]>([]);
  71. const [rows, setRows] = useState<any[]>([]);
  72. const { selectedCord, childNodes, setCord, setShowChildView } = props;
  73. const colDefinitions: ColDefinitionsType[] = [
  74. {
  75. id: 'name',
  76. label: t('thName'),
  77. disablePadding: true,
  78. sortBy: 'name',
  79. sortType: 'string',
  80. },
  81. {
  82. id: 'ip',
  83. label: t('thIP'),
  84. disablePadding: true,
  85. notSort: true,
  86. needCopy: true,
  87. },
  88. {
  89. id: 'cpuCore',
  90. label: t('thCPUCount'),
  91. disablePadding: true,
  92. },
  93. {
  94. id: 'cpuUsage',
  95. label: t('thCPUUsage'),
  96. formatter(_, cellData) {
  97. // -> 0.00%
  98. return `${cellData.toFixed(2)}%`;
  99. },
  100. disablePadding: true,
  101. },
  102. {
  103. id: 'diskUsage',
  104. label: t('thDiskUsage'),
  105. disablePadding: true,
  106. notSort: true,
  107. formatter(rowData) {
  108. return getByteString(rowData.diskUsage, rowData.disk, capacityTrans);
  109. },
  110. },
  111. {
  112. id: 'memUsage',
  113. label: t('thMemUsage'),
  114. disablePadding: true,
  115. formatter(_, cellData) {
  116. const memUsage = formatByteSize(cellData, capacityTrans);
  117. return `${memUsage.value}${memUsage.unit}`;
  118. },
  119. },
  120. ];
  121. const {
  122. pageSize,
  123. handlePageSize,
  124. currentPage,
  125. handleCurrentPage,
  126. total,
  127. data,
  128. order,
  129. orderBy,
  130. handleGridSort,
  131. } = usePaginationHook(rows);
  132. useEffect(() => {
  133. if (selectedCord) {
  134. const connectedTypes = selectedCord.connected.map(
  135. node => node.target_type
  136. );
  137. const newRows: any[] = [];
  138. childNodes.forEach(node => {
  139. if (connectedTypes.includes(node.infos.type)) {
  140. const dataRow = {
  141. _id: `${node?.identifier}-${node?.infos?.type}`,
  142. id: node?.identifier,
  143. ip: node?.infos?.hardware_infos.ip,
  144. cpuCore: node?.infos?.hardware_infos.cpu_core_count,
  145. cpuUsage: node?.infos?.hardware_infos.cpu_core_usage,
  146. disk: node?.infos?.hardware_infos.disk,
  147. diskUsage: node?.infos?.hardware_infos.disk_usage,
  148. memUsage: node?.infos?.hardware_infos.memory_usage,
  149. name: node?.infos?.name,
  150. node: node,
  151. };
  152. newRows.push(dataRow);
  153. }
  154. });
  155. // create mock rows 100 times to test pagination
  156. // const mockRows: any = [...newRows];
  157. // for (let i = 0; i < 100; i++) {
  158. // mockRows.push({
  159. // ...newRows[0],
  160. // id: 'mock' + i,
  161. // memUsage: i * 1000 * Math.floor(Math.random() * 100000000),
  162. // });
  163. // }
  164. setRows(newRows);
  165. // make first row selected
  166. if (newRows.length > 0) {
  167. setSelectedChildNode([newRows[0]]);
  168. }
  169. }
  170. }, [selectedCord, childNodes]);
  171. const handlePageChange = (e: any, page: number) => {
  172. handleCurrentPage(page);
  173. };
  174. const handleSelectChange = (value: GridNode[]) => {
  175. // only select one row, filter out the rest
  176. if (value.length > 1) {
  177. value = [value[value.length - 1]];
  178. }
  179. setSelectedChildNode(value);
  180. };
  181. const infoNode = selectedChildNode[0] && selectedChildNode[0].node;
  182. return (
  183. <div className={classes.root}>
  184. <button
  185. className={classes.childCloseBtnContainer}
  186. onClick={() => setShowChildView(false)}
  187. >
  188. <KeyboardArrowDown className={classes.childCloseBtn} />
  189. </button>
  190. <div className={classes.gridContainer}>
  191. <div className={classes.leftContainer}>
  192. <AttuGrid
  193. toolbarConfigs={[]}
  194. colDefinitions={colDefinitions}
  195. rows={data}
  196. rowCount={total}
  197. primaryKey="_id"
  198. page={currentPage}
  199. onPageChange={handlePageChange}
  200. rowsPerPage={pageSize}
  201. setRowsPerPage={handlePageSize}
  202. isLoading={false}
  203. order={order}
  204. orderBy={orderBy}
  205. handleSort={handleGridSort}
  206. openCheckBox={false}
  207. selected={selectedChildNode}
  208. setSelected={handleSelectChange}
  209. labelDisplayedRows={getLabelDisplayedRows(
  210. gridTrans[data.length > 1 ? 'nodes' : 'node']
  211. )}
  212. />
  213. </div>
  214. <div className={classes.rightContainer}>
  215. {infoNode && (
  216. <>
  217. <MiniTopo
  218. selectedCord={selectedCord}
  219. setCord={setCord}
  220. selectedChildNode={infoNode}
  221. setShowChildView={setShowChildView}
  222. />
  223. <DataCard
  224. className={classes.dataCard}
  225. node={infoNode}
  226. extend={true}
  227. />
  228. </>
  229. )}
  230. </div>
  231. </div>
  232. </div>
  233. );
  234. };
  235. export default NodeListView;