1
1
import React , { useEffect , useState } from "react" ;
2
2
import { Link } from "react-router-dom" ;
3
3
import useFetch from "use-http" ;
4
+ import Table from '@material-ui/core/Table' ;
5
+ import TableBody from '@material-ui/core/TableBody' ;
6
+ import TableCell from '@material-ui/core/TableCell' ;
7
+ import TableRow from '@material-ui/core/TableRow' ;
8
+ import LinearProgress from "@material-ui/core/LinearProgress" ;
4
9
import {
10
+ Box ,
5
11
Button ,
6
12
Card ,
7
13
CardActions ,
8
14
CardContent ,
9
- CardHeader ,
15
+ CardHeader , createMuiTheme ,
10
16
Divider ,
11
17
IconButton ,
12
18
InputAdornment ,
13
19
Menu ,
14
- MenuItem ,
20
+ MenuItem , MuiThemeProvider ,
15
21
TextField ,
16
- Tooltip
22
+ Tooltip , Typography , withStyles
17
23
} from "@material-ui/core" ;
18
- import { makeStyles , createStyles , useTheme , Theme } from "@material-ui/core/styles" ;
24
+ import {
25
+ makeStyles ,
26
+ createStyles ,
27
+ useTheme ,
28
+ Theme ,
29
+ lighten
30
+ } from "@material-ui/core/styles" ;
19
31
import { MoreVert , FileCopyRounded } from "@material-ui/icons" ;
20
32
21
33
import { Cell , PieChart , Pie , ResponsiveContainer , Sector } from "recharts" ;
22
34
import UserContext from "../../contexts/User" ;
23
35
import TeamsContext from '../../contexts/Teams' ;
24
- import { green , lightGreen , deepOrange } from "@material-ui/core/colors" ;
36
+ import {
37
+ green ,
38
+ lightGreen ,
39
+ deepOrange ,
40
+ red ,
41
+ yellow
42
+ } from "@material-ui/core/colors" ;
25
43
import copy from 'clipboard-copy'
26
44
import { checkObjIsEmpty , sumValues } from "../../utlities/ObjUtlities" ;
27
45
import { DLTSSnackbar } from "../CommonComponents/DLTSSnackbar" ;
46
+
47
+ import _ from "lodash" ;
48
+ import { type } from "os" ;
49
+ import useCheckIsDesktop from "../../utlities/layoutUtlities" ;
28
50
const useStyles = makeStyles ( ( theme : Theme ) => createStyles ( {
29
51
avatar : {
30
52
backgroundColor : theme . palette . secondary . main ,
@@ -48,6 +70,14 @@ const useStyles = makeStyles((theme: Theme) => createStyles({
48
70
} ,
49
71
container : {
50
72
margin : '0 auto' ,
73
+ } ,
74
+ tableTitle : {
75
+ display : "flex" ,
76
+ justifyContent : "center"
77
+ } ,
78
+ tableInfo : {
79
+ justifyContent : "space-between" ,
80
+ display : "flex"
51
81
}
52
82
} ) ) ;
53
83
@@ -242,6 +272,7 @@ const GPUCard: React.FC<{ cluster: string }> = ({ cluster }) => {
242
272
const name = typeof email === 'string' ? email . split ( '@' , 1 ) [ 0 ] : email ;
243
273
setDataStorage ( data . dataStorage ) ;
244
274
setWorkStorage ( `${ data . workStorage } /${ name } ` ) ;
275
+ return data ;
245
276
}
246
277
const fetchClusterStatusUrl = `/api` ;
247
278
const requestClusterStatus = useFetch ( fetchClusterStatusUrl ) ;
@@ -250,9 +281,71 @@ const GPUCard: React.FC<{ cluster: string }> = ({ cluster }) => {
250
281
const data = await requestClusterStatus . get ( `/teams/${ selectedTeam } /clusters/${ cluster } ` ) ;
251
282
return data ;
252
283
}
284
+ const [ nfsStorage , setNfsStorage ] = useState ( [ ] ) ;
253
285
useEffect ( ( ) => {
254
- fetchDirectories ( ) ;
255
- fetchClusterStatus ( ) . then ( ( res ) => {
286
+ fetchDirectories ( ) . then ( ( res ) => {
287
+ let fetchStorage = [ ] ;
288
+ let freeBytesSubPath = '/prometheus/api/v1/query?query=node_filesystem_free_bytes%7Bfstype%3D%27nfs4%27%7D' ;
289
+ let sizeBytesSubPath = '/prometheus/api/v1/query?query=node_filesystem_size_bytes%7Bfstype%3D%27nfs4%27%7D' ;
290
+ fetchStorage . push ( fetch ( `${ res [ 'prometheus' ] } ${ freeBytesSubPath } ` ) ) ;
291
+ fetchStorage . push ( fetch ( `${ res [ 'prometheus' ] } ${ sizeBytesSubPath } ` ) ) ;
292
+ let storageRes : any = [ ] ;
293
+ let tmpStorage : any = [ ] ;
294
+ Promise . all ( fetchStorage ) . then ( ( responses ) => {
295
+ responses . forEach ( async ( response : any ) => {
296
+ const res = await response . json ( ) ;
297
+ if ( res [ 'data' ] ) {
298
+ for ( let item of res [ 'data' ] [ "result" ] ) {
299
+ let tmp = { } as any ;
300
+ if ( item [ 'metric' ] [ '__name__' ] == "node_filesystem_size_bytes" ) {
301
+ let mountpointName = item [ 'metric' ] [ 'mountpoint' ]
302
+ let val = Math . floor ( item [ 'value' ] [ 1 ] / ( Math . pow ( 10 , 9 ) ) )
303
+ tmp [ 'mountpointName' ] = mountpointName ;
304
+ tmp [ 'total' ] = val ;
305
+ }
306
+ let tmpUsed = { } as any ;
307
+ //node_filesystem_free_bytes
308
+ if ( item [ 'metric' ] [ '__name__' ] == "node_filesystem_free_bytes" ) {
309
+ let mountpointName = item [ 'metric' ] [ 'mountpoint' ]
310
+ let val = Math . floor ( item [ 'value' ] [ 1 ] / ( Math . pow ( 10 , 9 ) ) )
311
+ tmpUsed [ 'mountpointName' ] = mountpointName ;
312
+ tmpUsed [ 'Free' ] = val ;
313
+ }
314
+ tmpStorage . push ( tmp )
315
+ tmpStorage . push ( tmpUsed )
316
+ }
317
+ }
318
+ //({ mountpointName: key, users: value })
319
+ storageRes = tmpStorage . filter ( ( store : any ) => ! checkObjIsEmpty ( store ) ) ;
320
+ let finalStorageRes : any = [ ] ;
321
+ if ( storageRes && storageRes . length > 0 ) {
322
+ finalStorageRes = _ . chain ( storageRes ) . groupBy ( 'mountpointName' ) . map ( ( value , key ) => {
323
+ let tmpTotal : any = value . filter ( ( item : any ) => item . hasOwnProperty ( 'total' ) ) ;
324
+ let tmpFree : any = value . filter ( ( item : any ) => item . hasOwnProperty ( 'Free' ) ) ;
325
+ let total = 0 ;
326
+ let used = 0 ;
327
+ if ( typeof tmpTotal [ 0 ] !== "undefined" && typeof tmpFree [ 0 ] !== "undefined" ) {
328
+ total = tmpTotal [ 0 ] [ "total" ] ;
329
+ used = tmpTotal [ 0 ] [ "total" ] - tmpFree [ 0 ] [ "Free" ]
330
+ }
331
+ return {
332
+ mountpointName : key , total :total , used : used
333
+ }
334
+ } ) . value ( ) ;
335
+ }
336
+ finalStorageRes . forEach ( ( item : any , i : number ) => {
337
+ if ( item [ "mountpointName" ] . indexOf ( "dlws/nfs" ) !== - 1 ) {
338
+ finalStorageRes . splice ( i , 1 ) ;
339
+ finalStorageRes . unshift ( item ) ;
340
+ }
341
+ } ) ;
342
+ setNfsStorage ( finalStorageRes . filter ( ( store : any ) => {
343
+ return store [ 'mountpointName' ] . indexOf ( selectedTeam ) !== - 1 || store [ 'mountpointName' ] . indexOf ( "dlws/nfs" ) !== - 1 ;
344
+ } ) ) ;
345
+ } ) ;
346
+ } ) ;
347
+ } ) ;
348
+ fetchClusterStatus ( ) . then ( ( res ) => {
256
349
const availableGpu = ! checkObjIsEmpty ( res [ 'gpu_avaliable' ] ) ? ( Number ) ( sumValues ( res [ 'gpu_avaliable' ] ) ) : 0 ;
257
350
setAvailable ( availableGpu ) ;
258
351
const usedGpu = ! checkObjIsEmpty ( res [ 'gpu_used' ] ) ? ( Number ) ( sumValues ( res [ 'gpu_used' ] ) ) : 0 ;
@@ -263,6 +356,50 @@ const GPUCard: React.FC<{ cluster: string }> = ({ cluster }) => {
263
356
setActivate ( true ) ;
264
357
} )
265
358
} , [ selectedTeam ] ) ;
359
+ const tableTheme = createMuiTheme ( {
360
+ overrides : {
361
+ MuiTableCell : {
362
+ root : {
363
+ paddingTop : 10 ,
364
+ paddingBottom : 10 ,
365
+ paddingLeft :2 ,
366
+ paddingRight :5 ,
367
+ }
368
+ }
369
+ }
370
+ } ) ;
371
+ const BorderLinearProgress = withStyles ( {
372
+ root : {
373
+ height : 10 ,
374
+ backgroundColor : lighten ( '#363636' , 0.5 ) ,
375
+ } ,
376
+ bar : {
377
+ borderRadius : 20 ,
378
+ backgroundColor : green [ 400 ] ,
379
+ } ,
380
+ } ) ( LinearProgress ) ;
381
+ const GenernalLinerProgress = withStyles ( {
382
+ root : {
383
+ height : 10 ,
384
+ backgroundColor : lighten ( '#363636' , 0.5 ) ,
385
+ } ,
386
+ bar : {
387
+ borderRadius : 20 ,
388
+ backgroundColor : yellow [ 800 ] ,
389
+ } ,
390
+ } ) ( LinearProgress ) ;
391
+ const FullBorderLinearProgress = withStyles ( {
392
+ root : {
393
+ height : 10 ,
394
+ backgroundColor : lighten ( '#363636' , 0.5 ) ,
395
+ } ,
396
+ bar : {
397
+ borderRadius : 20 ,
398
+ backgroundColor : red [ 400 ] ,
399
+ } ,
400
+ } ) ( LinearProgress ) ;
401
+ const theme = useTheme ( ) ;
402
+
266
403
return (
267
404
< Card >
268
405
< CardHeader
@@ -278,6 +415,41 @@ const GPUCard: React.FC<{ cluster: string }> = ({ cluster }) => {
278
415
/>
279
416
< CardContent className = { styles . chart } >
280
417
< Chart available = { available } used = { used } reserved = { reversed } isActive = { activate } />
418
+ < Divider />
419
+ < Typography variant = "h6" id = "tableTitle" className = { styles . tableTitle } >
420
+ { "Storage (GB)" }
421
+ </ Typography >
422
+ < Box minHeight = { 100 } style = { { overflow : 'auto' } } >
423
+ < MuiThemeProvider theme = { tableTheme } >
424
+ < Table >
425
+ < TableBody >
426
+ {
427
+ nfsStorage . map ( ( nfs : any , index : number ) => {
428
+ let nfsMountNames = nfs [ 'mountpointName' ] . split ( "/" ) ;
429
+ let mounName = "" ;
430
+ if ( nfs [ 'mountpointName' ] . indexOf ( "dlws" ) !== - 1 ) {
431
+ mounName = "/data" ;
432
+ } else {
433
+ nfsMountNames . splice ( 0 , nfsMountNames . length - 1 ) ;
434
+ mounName = "/" + nfsMountNames . join ( '/' ) ;
435
+ }
436
+ let value = nfs [ 'total' ] == 0 ? 0 : ( nfs [ 'used' ] / nfs [ 'total' ] ) * 100 ;
437
+ return (
438
+ < TableRow key = { index } >
439
+ < TableCell >
440
+ {
441
+ value < 80 ? < BorderLinearProgress value = { value } variant = { "determinate" } /> : value >= 80 && value < 90 ? < GenernalLinerProgress value = { value } variant = { "determinate" } /> : < FullBorderLinearProgress value = { value } variant = { "determinate" } />
442
+ }
443
+ < div className = { styles . tableInfo } > < span > { `${ mounName } ` } </ span > < span > { `(${ nfs [ 'used' ] } /${ nfs [ 'total' ] } ) ${ Math . floor ( value ) } % used` } </ span > </ div >
444
+ </ TableCell >
445
+ </ TableRow >
446
+ )
447
+ } )
448
+ }
449
+ </ TableBody >
450
+ </ Table >
451
+ </ MuiThemeProvider >
452
+ </ Box >
281
453
</ CardContent >
282
454
< CardActions >
283
455
< Button component = { Link }
0 commit comments