11import React , { useEffect , useState } from 'react' ;
2- import tw , { TwStyle } from 'twin.macro' ;
32import {
4- faArrowCircleDown ,
5- faArrowCircleUp ,
6- faCircle ,
7- faEthernet ,
3+ faClock ,
4+ faCloudDownloadAlt ,
5+ faCloudUploadAlt ,
86 faHdd ,
97 faMemory ,
108 faMicrochip ,
11- faServer ,
9+ faWifi ,
1210} from '@fortawesome/free-solid-svg-icons' ;
13- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' ;
1411import { bytesToHuman , formatIp , megabytesToHuman } from '@/helpers' ;
15- import TitledGreyBox from '@/components/elements/TitledGreyBox' ;
1612import { ServerContext } from '@/state/server' ;
17- import CopyOnClick from '@/components/elements/CopyOnClick' ;
1813import { SocketEvent , SocketRequest } from '@/components/server/events' ;
1914import UptimeDuration from '@/components/server/UptimeDuration' ;
15+ import StatBlock from '@/components/server/console/StatBlock' ;
16+ import useWebsocketEvent from '@/plugins/useWebsocketEvent' ;
2017
2118type Stats = Record < 'memory' | 'cpu' | 'disk' | 'uptime' | 'rx' | 'tx' , number > ;
2219
23- function statusToColor ( status : string | null , installing : boolean ) : TwStyle {
24- if ( installing ) {
25- status = '' ;
26- }
20+ interface DetailBlockProps {
21+ className ?: string ;
22+ }
23+
24+ const getBackgroundColor = ( value : number , max : number | null ) : string | undefined => {
25+ const delta = ! max ? 0 : ( value / max ) ;
2726
28- switch ( status ) {
29- case 'offline' :
30- return tw `text-red-500` ;
31- case 'running' :
32- return tw `text-green-500` ;
33- default :
34- return tw `text-yellow-500` ;
27+ if ( delta > 0.8 ) {
28+ if ( delta > 0.9 ) {
29+ return 'bg-red-500' ;
30+ }
31+ return 'bg-yellow-500' ;
3532 }
36- }
3733
38- const ServerDetailsBlock = ( ) => {
34+ return undefined ;
35+ } ;
36+
37+ const ServerDetailsBlock = ( { className } : DetailBlockProps ) => {
3938 const [ stats , setStats ] = useState < Stats > ( { memory : 0 , cpu : 0 , disk : 0 , uptime : 0 , tx : 0 , rx : 0 } ) ;
4039
4140 const status = ServerContext . useStoreState ( state => state . status . value ) ;
4241 const connected = ServerContext . useStoreState ( state => state . socket . connected ) ;
4342 const instance = ServerContext . useStoreState ( state => state . socket . instance ) ;
43+ const limits = ServerContext . useStoreState ( state => state . server . data ! . limits ) ;
44+ const allocation = ServerContext . useStoreState ( state => {
45+ const match = state . server . data ! . allocations . find ( allocation => allocation . isDefault ) ;
46+
47+ return ! match ? 'n/a' : `${ match . alias || formatIp ( match . ip ) } :${ match . port } ` ;
48+ } ) ;
4449
45- const statsListener = ( data : string ) => {
50+ useEffect ( ( ) => {
51+ if ( ! connected || ! instance ) {
52+ return ;
53+ }
54+
55+ instance . send ( SocketRequest . SEND_STATS ) ;
56+ } , [ instance , connected ] ) ;
57+
58+ useWebsocketEvent ( SocketEvent . STATS , ( data ) => {
4659 let stats : any = { } ;
4760 try {
4861 stats = JSON . parse ( data ) ;
@@ -58,75 +71,92 @@ const ServerDetailsBlock = () => {
5871 rx : stats . network . rx_bytes ,
5972 uptime : stats . uptime || 0 ,
6073 } ) ;
61- } ;
62-
63- useEffect ( ( ) => {
64- if ( ! connected || ! instance ) {
65- return ;
66- }
67-
68- instance . addListener ( SocketEvent . STATS , statsListener ) ;
69- instance . send ( SocketRequest . SEND_STATS ) ;
70-
71- return ( ) => {
72- instance . removeListener ( SocketEvent . STATS , statsListener ) ;
73- } ;
74- } , [ instance , connected ] ) ;
75-
76- const name = ServerContext . useStoreState ( state => state . server . data ! . name ) ;
77- const isInstalling = ServerContext . useStoreState ( state => state . server . data ! . isInstalling ) ;
78- const isTransferring = ServerContext . useStoreState ( state => state . server . data ! . isTransferring ) ;
79- const limits = ServerContext . useStoreState ( state => state . server . data ! . limits ) ;
80- const primaryAllocation = ServerContext . useStoreState ( state => state . server . data ! . allocations . filter ( alloc => alloc . isDefault ) . map (
81- allocation => ( allocation . alias || formatIp ( allocation . ip ) ) + ':' + allocation . port ,
82- ) ) . toString ( ) ;
83-
84- const diskLimit = limits . disk ? megabytesToHuman ( limits . disk ) : 'Unlimited' ;
85- const memoryLimit = limits . memory ? megabytesToHuman ( limits . memory ) : 'Unlimited' ;
86- const cpuLimit = limits . cpu ? limits . cpu + '%' : 'Unlimited' ;
74+ } ) ;
8775
8876 return (
89- < TitledGreyBox css = { tw `break-words` } title = { name } icon = { faServer } >
90- < p css = { tw `text-xs uppercase` } >
91- < FontAwesomeIcon
92- icon = { faCircle }
93- fixedWidth
94- css = { [
95- tw `mr-1` ,
96- statusToColor ( status , isInstalling || isTransferring ) ,
97- ] }
98- />
99- { ! status ? 'Connecting...' : ( isInstalling ? 'Installing' : ( isTransferring ) ? 'Transferring' : status ) }
100- { stats . uptime > 0 &&
101- < span css = { tw `ml-2 lowercase` } >
102- (< UptimeDuration uptime = { stats . uptime / 1000 } /> )
103- </ span >
77+ < div className = { className } >
78+ < StatBlock
79+ icon = { faClock }
80+ title = { 'Uptime' }
81+ color = { getBackgroundColor ( status === 'running' ? 0 : ( status !== 'offline' ? 9 : 10 ) , 10 ) }
82+ >
83+ { stats . uptime > 0 ?
84+ < UptimeDuration uptime = { stats . uptime / 1000 } />
85+ :
86+ 'Offline'
87+ }
88+ </ StatBlock >
89+ < StatBlock
90+ icon = { faMicrochip }
91+ title = { 'CPU' }
92+ color = { getBackgroundColor ( stats . cpu , limits . cpu ) }
93+ description = { limits . memory
94+ ? `This server is allowed to use up to ${ limits . cpu } % of the host's available CPU resources.`
95+ : 'No CPU limit has been configured for this server.'
96+ }
97+ >
98+ { status === 'offline' ?
99+ < span className = { 'text-gray-400' } > Offline</ span >
100+ :
101+ `${ stats . cpu . toFixed ( 2 ) } %`
102+ }
103+ </ StatBlock >
104+ < StatBlock
105+ icon = { faMemory }
106+ title = { 'Memory' }
107+ color = { getBackgroundColor ( stats . memory / 1024 , limits . memory * 1024 ) }
108+ description = { limits . memory
109+ ? `This server is allowed to use up to ${ megabytesToHuman ( limits . memory ) } of memory.`
110+ : 'No memory limit has been configured for this server.'
111+ }
112+ >
113+ { status === 'offline' ?
114+ < span className = { 'text-gray-400' } > Offline</ span >
115+ :
116+ bytesToHuman ( stats . memory )
117+ }
118+ </ StatBlock >
119+ < StatBlock
120+ icon = { faHdd }
121+ title = { 'Disk' }
122+ color = { getBackgroundColor ( stats . disk / 1024 , limits . disk * 1024 ) }
123+ description = { limits . disk
124+ ? `This server is allowed to use up to ${ megabytesToHuman ( limits . disk ) } of disk space.`
125+ : 'No disk space limit has been configured for this server.'
126+ }
127+ >
128+ { bytesToHuman ( stats . disk ) }
129+ </ StatBlock >
130+ < StatBlock
131+ icon = { faCloudDownloadAlt }
132+ title = { 'Network (Inbound)' }
133+ description = { 'The total amount of network traffic that your server has recieved since it was started.' }
134+ >
135+ { status === 'offline' ?
136+ < span className = { 'text-gray-400' } > Offline</ span >
137+ :
138+ bytesToHuman ( stats . tx )
139+ }
140+ </ StatBlock >
141+ < StatBlock
142+ icon = { faCloudUploadAlt }
143+ title = { 'Network (Outbound)' }
144+ description = { 'The total amount of traffic your server has sent across the internet since it was started.' }
145+ >
146+ { status === 'offline' ?
147+ < span className = { 'text-gray-400' } > Offline</ span >
148+ :
149+ bytesToHuman ( stats . rx )
104150 }
105- </ p >
106- < CopyOnClick text = { primaryAllocation } >
107- < p css = { tw `text-xs mt-2` } >
108- < FontAwesomeIcon icon = { faEthernet } fixedWidth css = { tw `mr-1` } />
109- < code css = { tw `ml-1` } > { primaryAllocation } </ code >
110- </ p >
111- </ CopyOnClick >
112- < p css = { tw `text-xs mt-2` } >
113- < FontAwesomeIcon icon = { faMicrochip } fixedWidth css = { tw `mr-1` } /> { stats . cpu . toFixed ( 2 ) } %
114- < span css = { tw `text-neutral-500` } > / { cpuLimit } </ span >
115- </ p >
116- < p css = { tw `text-xs mt-2` } >
117- < FontAwesomeIcon icon = { faMemory } fixedWidth css = { tw `mr-1` } /> { bytesToHuman ( stats . memory ) }
118- < span css = { tw `text-neutral-500` } > / { memoryLimit } </ span >
119- </ p >
120- < p css = { tw `text-xs mt-2` } >
121- < FontAwesomeIcon icon = { faHdd } fixedWidth css = { tw `mr-1` } /> { bytesToHuman ( stats . disk ) }
122- < span css = { tw `text-neutral-500` } > / { diskLimit } </ span >
123- </ p >
124- < p css = { tw `text-xs mt-2` } >
125- < FontAwesomeIcon icon = { faEthernet } fixedWidth css = { tw `mr-1` } />
126- < FontAwesomeIcon icon = { faArrowCircleUp } fixedWidth css = { tw `mr-1` } /> { bytesToHuman ( stats . tx ) }
127- < FontAwesomeIcon icon = { faArrowCircleDown } fixedWidth css = { tw `mx-1` } /> { bytesToHuman ( stats . rx ) }
128- </ p >
129- </ TitledGreyBox >
151+ </ StatBlock >
152+ < StatBlock
153+ icon = { faWifi }
154+ title = { 'Address' }
155+ description = { `You can connect to your server at: ${ allocation } ` }
156+ >
157+ { allocation }
158+ </ StatBlock >
159+ </ div >
130160 ) ;
131161} ;
132162
0 commit comments