@@ -147,3 +45,5 @@ export default () => {
);
};
+
+export default memo(ServerConsole, isEqual);
diff --git a/resources/scripts/components/server/ServerDetailsBlock.tsx b/resources/scripts/components/server/ServerDetailsBlock.tsx
new file mode 100644
index 000000000..563dedf76
--- /dev/null
+++ b/resources/scripts/components/server/ServerDetailsBlock.tsx
@@ -0,0 +1,83 @@
+import React, { useEffect, useState } from 'react';
+import tw from 'twin.macro';
+import { faCircle, faHdd, faMemory, faMicrochip, faServer } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { bytesToHuman, megabytesToHuman } from '@/helpers';
+import TitledGreyBox from '@/components/elements/TitledGreyBox';
+import { ServerContext } from '@/state/server';
+
+interface Stats {
+ memory: number;
+ cpu: number;
+ disk: number;
+}
+
+const ServerDetailsBlock = () => {
+ const [ stats, setStats ] = useState
({ memory: 0, cpu: 0, disk: 0 });
+
+ const connected = ServerContext.useStoreState(state => state.socket.connected);
+ const instance = ServerContext.useStoreState(state => state.socket.instance);
+
+ const statsListener = (data: string) => {
+ let stats: any = {};
+ try {
+ stats = JSON.parse(data);
+ } catch (e) {
+ return;
+ }
+
+ setStats({
+ memory: stats.memory_bytes,
+ cpu: stats.cpu_absolute,
+ disk: stats.disk_bytes,
+ });
+ };
+
+ useEffect(() => {
+ if (!connected || !instance) {
+ return;
+ }
+
+ instance.addListener('stats', statsListener);
+ instance.send('send stats');
+
+ return () => {
+ instance.removeListener('stats', statsListener);
+ };
+ }, [ instance, connected ]);
+
+ const name = ServerContext.useStoreState(state => state.server.data!.name);
+ const limits = ServerContext.useStoreState(state => state.server.data!.limits);
+
+ const disklimit = limits.disk ? megabytesToHuman(limits.disk) : 'Unlimited';
+ const memorylimit = limits.memory ? megabytesToHuman(limits.memory) : 'Unlimited';
+
+ return (
+
+
+
+ {!status ? 'Connecting...' : status}
+
+
+ {stats.cpu.toFixed(2)}%
+
+
+ {bytesToHuman(stats.memory)}
+ / {memorylimit}
+
+
+ {bytesToHuman(stats.disk)}
+ / {disklimit}
+
+
+ );
+};
+
+export default ServerDetailsBlock;
diff --git a/resources/scripts/routers/ServerRouter.tsx b/resources/scripts/routers/ServerRouter.tsx
index b830a3c7a..a90ff652b 100644
--- a/resources/scripts/routers/ServerRouter.tsx
+++ b/resources/scripts/routers/ServerRouter.tsx
@@ -30,7 +30,7 @@ import StartupContainer from '@/components/server/startup/StartupContainer';
import requireServerPermission from '@/hoc/requireServerPermission';
const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>) => {
- const { rootAdmin } = useStoreState(state => state.user.data!);
+ const rootAdmin = useStoreState(state => state.user.data!.rootAdmin);
const [ error, setError ] = useState('');
const [ installing, setInstalling ] = useState(false);