1- import React , { lazy , useEffect , useState } from 'react' ;
1+ import React , { lazy , memo } from 'react' ;
22import { ServerContext } from '@/state/server' ;
3- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' ;
4- import { faCircle , faHdd , faMemory , faMicrochip , faServer } from '@fortawesome/free-solid-svg-icons' ;
5- import { bytesToHuman , megabytesToHuman } from '@/helpers' ;
63import SuspenseSpinner from '@/components/elements/SuspenseSpinner' ;
7- import TitledGreyBox from '@/components/elements/TitledGreyBox' ;
84import Can from '@/components/elements/Can' ;
95import ContentContainer from '@/components/elements/ContentContainer' ;
106import tw from 'twin.macro' ;
11- import Button from '@/components/elements/Button' ;
12- import StopOrKillButton from '@/components/server/StopOrKillButton' ;
137import ServerContentBlock from '@/components/elements/ServerContentBlock' ;
8+ import ServerDetailsBlock from '@/components/server/ServerDetailsBlock' ;
9+ import isEqual from 'react-fast-compare' ;
10+ import PowerControls from '@/components/server/PowerControls' ;
1411
1512export type PowerAction = 'start' | 'stop' | 'restart' | 'kill' ;
1613
1714const ChunkedConsole = lazy ( ( ) => import ( /* webpackChunkName: "console" */ '@/components/server/Console' ) ) ;
1815const ChunkedStatGraphs = lazy ( ( ) => import ( /* webpackChunkName: "graphs" */ '@/components/server/StatGraphs' ) ) ;
1916
20- export default ( ) => {
21- const [ memory , setMemory ] = useState ( 0 ) ;
22- const [ cpu , setCpu ] = useState ( 0 ) ;
23- const [ disk , setDisk ] = useState ( 0 ) ;
24-
25- const name = ServerContext . useStoreState ( state => state . server . data ! . name ) ;
26- const limits = ServerContext . useStoreState ( state => state . server . data ! . limits ) ;
17+ const ServerConsole = ( ) => {
2718 const isInstalling = ServerContext . useStoreState ( state => state . server . data ! . isInstalling ) ;
28- const status = ServerContext . useStoreState ( state => state . status . value ) ;
29-
30- const connected = ServerContext . useStoreState ( state => state . socket . connected ) ;
31- const instance = ServerContext . useStoreState ( state => state . socket . instance ) ;
32-
33- const statsListener = ( data : string ) => {
34- let stats : any = { } ;
35- try {
36- stats = JSON . parse ( data ) ;
37- } catch ( e ) {
38- return ;
39- }
40-
41- setMemory ( stats . memory_bytes ) ;
42- setCpu ( stats . cpu_absolute ) ;
43- setDisk ( stats . disk_bytes ) ;
44- } ;
45-
46- const sendPowerCommand = ( command : PowerAction ) => {
47- instance && instance . send ( 'set state' , command ) ;
48- } ;
49-
50- useEffect ( ( ) => {
51- if ( ! connected || ! instance ) {
52- return ;
53- }
54-
55- instance . addListener ( 'stats' , statsListener ) ;
56- instance . send ( 'send stats' ) ;
57-
58- return ( ) => {
59- instance . removeListener ( 'stats' , statsListener ) ;
60- } ;
61- } , [ instance , connected ] ) ;
62-
63- const disklimit = limits . disk ? megabytesToHuman ( limits . disk ) : 'Unlimited' ;
64- const memorylimit = limits . memory ? megabytesToHuman ( limits . memory ) : 'Unlimited' ;
6519
6620 return (
6721 < ServerContentBlock title = { 'Console' } css = { tw `flex flex-wrap` } >
6822 < div css = { tw `w-full lg:w-1/4` } >
69- < TitledGreyBox css = { tw `break-all` } title = { name } icon = { faServer } >
70- < p css = { tw `text-xs uppercase` } >
71- < FontAwesomeIcon
72- icon = { faCircle }
73- fixedWidth
74- css = { [
75- tw `mr-1` ,
76- status === 'offline' ? tw `text-red-500` : ( status === 'running' ? tw `text-green-500` : tw `text-yellow-500` ) ,
77- ] }
78- />
79- { ! status ? 'Connecting...' : status }
80- </ p >
81- < p css = { tw `text-xs mt-2` } >
82- < FontAwesomeIcon icon = { faMicrochip } fixedWidth css = { tw `mr-1` } /> { cpu . toFixed ( 2 ) } %
83- </ p >
84- < p css = { tw `text-xs mt-2` } >
85- < FontAwesomeIcon icon = { faMemory } fixedWidth css = { tw `mr-1` } /> { bytesToHuman ( memory ) }
86- < span css = { tw `text-neutral-500` } > / { memorylimit } </ span >
87- </ p >
88- < p css = { tw `text-xs mt-2` } >
89- < FontAwesomeIcon icon = { faHdd } fixedWidth css = { tw `mr-1` } /> { bytesToHuman ( disk ) }
90- < span css = { tw `text-neutral-500` } > / { disklimit } </ span >
91- </ p >
92- </ TitledGreyBox >
23+ < ServerDetailsBlock />
9324 { ! isInstalling ?
9425 < Can action = { [ 'control.start' , 'control.stop' , 'control.restart' ] } matchAny >
95- < div css = { tw `shadow-md bg-neutral-700 rounded p-3 flex text-xs mt-4 justify-center` } >
96- < Can action = { 'control.start' } >
97- < Button
98- size = { 'xsmall' }
99- color = { 'green' }
100- isSecondary
101- css = { tw `mr-2` }
102- disabled = { status !== 'offline' }
103- onClick = { e => {
104- e . preventDefault ( ) ;
105- sendPowerCommand ( 'start' ) ;
106- } }
107- >
108- Start
109- </ Button >
110- </ Can >
111- < Can action = { 'control.restart' } >
112- < Button
113- size = { 'xsmall' }
114- isSecondary
115- css = { tw `mr-2` }
116- disabled = { ! status }
117- onClick = { e => {
118- e . preventDefault ( ) ;
119- sendPowerCommand ( 'restart' ) ;
120- } }
121- >
122- Restart
123- </ Button >
124- </ Can >
125- < Can action = { 'control.stop' } >
126- < StopOrKillButton onPress = { action => sendPowerCommand ( action ) } />
127- </ Can >
128- </ div >
26+ < PowerControls />
12927 </ Can >
13028 :
13129 < div css = { tw `mt-4 rounded bg-yellow-500 p-3` } >
@@ -147,3 +45,5 @@ export default () => {
14745 </ ServerContentBlock >
14846 ) ;
14947} ;
48+
49+ export default memo ( ServerConsole , isEqual ) ;
0 commit comments