[STYLING] Adjusted formatting for options
This commit is contained in:
parent
b45bfed63c
commit
2da6278ae7
12 changed files with 443 additions and 128 deletions
|
@ -3,6 +3,7 @@ import k8s from "@kubernetes/client-node";
|
||||||
import { Rcon as RconClient } from "rcon-client";
|
import { Rcon as RconClient } from "rcon-client";
|
||||||
import stream from "stream";
|
import stream from "stream";
|
||||||
import { ERR, WARN } from "../../util/logging.js";
|
import { ERR, WARN } from "../../util/logging.js";
|
||||||
|
import { getServerEntry } from "../../database/queries/server-queries.js";
|
||||||
|
|
||||||
// Kubernetes Configuration
|
// Kubernetes Configuration
|
||||||
const kc = new k8s.KubeConfig();
|
const kc = new k8s.KubeConfig();
|
||||||
|
@ -12,8 +13,9 @@ const namespace = process.env.MCL_SERVER_NAMESPACE;
|
||||||
|
|
||||||
// Retrieves logs from the minecraft server container
|
// Retrieves logs from the minecraft server container
|
||||||
export async function webConsoleLogs(socket) {
|
export async function webConsoleLogs(socket) {
|
||||||
const { serverName } = socket.mcs;
|
const { serverId } = socket.mcs;
|
||||||
const podName = `mcl-${serverName}`;
|
const server = await getServerEntry(serverId);
|
||||||
|
const podName = `mcl-${server.mclName}`;
|
||||||
const containerName = `${podName}-server`;
|
const containerName = `${podName}-server`;
|
||||||
const podResponse = await k8sCore.listNamespacedPod(namespace);
|
const podResponse = await k8sCore.listNamespacedPod(namespace);
|
||||||
const pods = podResponse.body.items.map((vp1) => vp1.metadata.name);
|
const pods = podResponse.body.items.map((vp1) => vp1.metadata.name);
|
||||||
|
@ -41,14 +43,15 @@ export async function webConsoleLogs(socket) {
|
||||||
export async function webConsoleRcon(socket) {
|
export async function webConsoleRcon(socket) {
|
||||||
if (socket.rconClient)
|
if (socket.rconClient)
|
||||||
return VERB("RCON", "Socket already connected to RCON");
|
return VERB("RCON", "Socket already connected to RCON");
|
||||||
const rconSecret = `mcl-${socket.mcs.serverName}-rcon-secret`;
|
const { serverId } = socket.mcs;
|
||||||
|
const server = await getServerEntry(serverId);
|
||||||
|
const rconSecret = `mcl-${server.mclName}-rcon-secret`;
|
||||||
const rconRes = await k8sCore.readNamespacedSecret(rconSecret, namespace);
|
const rconRes = await k8sCore.readNamespacedSecret(rconSecret, namespace);
|
||||||
const rconPassword = Buffer.from(
|
const rconPassword = Buffer.from(
|
||||||
rconRes.body.data["rcon-password"],
|
rconRes.body.data["rcon-password"],
|
||||||
"base64",
|
"base64",
|
||||||
).toString("utf8");
|
).toString("utf8");
|
||||||
const { serverName } = socket.mcs;
|
const rconHost = `mcl-${server.mclName}-rcon.${namespace}.svc.cluster.local`;
|
||||||
const rconHost = `mcl-${serverName}-rcon.${namespace}.svc.cluster.local`;
|
|
||||||
const rcon = new RconClient({
|
const rcon = new RconClient({
|
||||||
host: rconHost,
|
host: rconHost,
|
||||||
port: 25575,
|
port: 25575,
|
||||||
|
|
|
@ -18,7 +18,7 @@ async function rconSend(socket, m) {
|
||||||
|
|
||||||
const socketConnect = async (io, socket) => {
|
const socketConnect = async (io, socket) => {
|
||||||
VERB("WS", "Websocket connecting");
|
VERB("WS", "Websocket connecting");
|
||||||
socket.mcs = { serverName: socket.handshake.query.serverName };
|
socket.mcs = { serverId: socket.handshake.query.serverId };
|
||||||
try {
|
try {
|
||||||
await webConsoleLogs(socket);
|
await webConsoleLogs(socket);
|
||||||
await webConsoleRcon(socket);
|
await webConsoleRcon(socket);
|
||||||
|
|
304
package-lock.json
generated
304
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -28,12 +28,15 @@
|
||||||
"@mui/material": "^5.14.20",
|
"@mui/material": "^5.14.20",
|
||||||
"@tanstack/react-query": "^5.12.2",
|
"@tanstack/react-query": "^5.12.2",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
|
"chonky": "^2.3.2",
|
||||||
|
"chonky-icon-fontawesome": "^2.3.2",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"nodemon": "^3.0.2",
|
"nodemon": "^3.0.2",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^6.20.1",
|
"react-router-dom": "^6.20.1",
|
||||||
|
"react-toastify": "^9.1.3",
|
||||||
"socket.io-client": "^4.7.2",
|
"socket.io-client": "^4.7.2",
|
||||||
"vite": "^5.0.7"
|
"vite": "^5.0.7"
|
||||||
},
|
},
|
||||||
|
@ -43,8 +46,6 @@
|
||||||
"basic-ftp": "^5.0.4",
|
"basic-ftp": "^5.0.4",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
"chonky": "^2.3.2",
|
|
||||||
"chonky-icon-fontawesome": "^2.3.2",
|
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"figlet": "^1.7.0",
|
"figlet": "^1.7.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
|
|
@ -40,10 +40,16 @@ export default function MineclusterFiles(props) {
|
||||||
|
|
||||||
const updateFiles = () => {
|
const updateFiles = () => {
|
||||||
const dir = dirStack.join("/");
|
const dir = dirStack.join("/");
|
||||||
getServerFiles(serverId, dir).then((f) => {
|
getServerFiles(serverId, dir)
|
||||||
|
.then((f) => {
|
||||||
const files = f.map((fi) => ({ ...fi, id: `${dir}/${fi.name}` }));
|
const files = f.map((fi) => ({ ...fi, id: `${dir}/${fi.name}` }));
|
||||||
setFiles(files ?? []);
|
setFiles(files ?? []);
|
||||||
});
|
})
|
||||||
|
.catch(() =>
|
||||||
|
console.error(
|
||||||
|
"Couldn't update files, server likely hasn't started yet",
|
||||||
|
),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
26
src/components/server-options/CpuOption.jsx
Normal file
26
src/components/server-options/CpuOption.jsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
|
||||||
|
const maxCpuSupported = 8;
|
||||||
|
export const cpuOptions = new Array(2 * maxCpuSupported)
|
||||||
|
.fill(0)
|
||||||
|
.map((v, i) => (i + 1) * 0.5);
|
||||||
|
|
||||||
|
export default function CpuOption(props) {
|
||||||
|
const { value, onChange } = props;
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
label="CPU"
|
||||||
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
select
|
||||||
|
required
|
||||||
|
SelectProps={{ MenuProps: { sx: { maxHeight: "20rem" } } }}
|
||||||
|
disabled // TODO: Enable on backend support
|
||||||
|
>
|
||||||
|
{cpuOptions.map((o, i) => (
|
||||||
|
<MenuItem value={o} key={i}>{`${o} CPU`}</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
);
|
||||||
|
}
|
14
src/components/server-options/HostOption.jsx
Normal file
14
src/components/server-options/HostOption.jsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
export default function HostOption(props) {
|
||||||
|
const { onChange } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
label="Host"
|
||||||
|
onChange={onChange}
|
||||||
|
helperText="Example: host.mydomain.com"
|
||||||
|
FormHelperTextProps={{ sx: { ml: 0 } }}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
24
src/components/server-options/MemoryOption.jsx
Normal file
24
src/components/server-options/MemoryOption.jsx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
const maxMemSupported = 10;
|
||||||
|
export const memoryOptions = new Array(2 * maxMemSupported)
|
||||||
|
.fill(0)
|
||||||
|
.map((v, i) => (i + 1) * 512);
|
||||||
|
|
||||||
|
export default function Option(props) {
|
||||||
|
const { value, onChange } = props;
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
label="Memory"
|
||||||
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
select
|
||||||
|
required
|
||||||
|
SelectProps={{ MenuProps: { sx: { maxHeight: "20rem" } } }}
|
||||||
|
>
|
||||||
|
{memoryOptions.map((o, i) => (
|
||||||
|
<MenuItem value={o} key={i}>{`${o / 1024} Gi`}</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
);
|
||||||
|
}
|
14
src/components/server-options/NameOption.jsx
Normal file
14
src/components/server-options/NameOption.jsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
export default function NameOption(props) {
|
||||||
|
const { onChange } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
label="Name"
|
||||||
|
onChange={onChange}
|
||||||
|
helperText="Example: My Survival World"
|
||||||
|
FormHelperTextProps={{ sx: { ml: 0 } }}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
25
src/components/server-options/ServerTypeOption.jsx
Normal file
25
src/components/server-options/ServerTypeOption.jsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
|
||||||
|
const displayOption = (o) => o.charAt(0) + o.toLowerCase().slice(1);
|
||||||
|
|
||||||
|
export const serverTypeOptions = ["VANILLA", "FABRIC", "PAPER", "SPIGOT"];
|
||||||
|
export default function ServerTypeOption(props) {
|
||||||
|
const { value, onChange } = props;
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
label="Memory"
|
||||||
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
select
|
||||||
|
required
|
||||||
|
SelectProps={{ MenuProps: { sx: { maxHeight: "20rem" } } }}
|
||||||
|
>
|
||||||
|
{serverTypeOptions.map((o, i) => (
|
||||||
|
<MenuItem value={o} key={i}>
|
||||||
|
{displayOption(o)}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
);
|
||||||
|
}
|
37
src/components/server-options/VersionOption.jsx
Normal file
37
src/components/server-options/VersionOption.jsx
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
import { useVersionList } from "@mcl/queries";
|
||||||
|
|
||||||
|
export default function VersionOption(props) {
|
||||||
|
const { value, onChange } = props;
|
||||||
|
const versionList = useVersionList();
|
||||||
|
const [versions, setVersions] = useState(["latest"]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!versionList.data) return;
|
||||||
|
setVersions([
|
||||||
|
"latest",
|
||||||
|
...versionList.data.versions
|
||||||
|
.filter(({ type: releaseType }) => releaseType === "release")
|
||||||
|
.map(({ id }) => id),
|
||||||
|
]);
|
||||||
|
}, [versionList.data]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
label="Version"
|
||||||
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
select
|
||||||
|
required
|
||||||
|
SelectProps={{ MenuProps: { sx: { maxHeight: "20rem" } } }}
|
||||||
|
>
|
||||||
|
{versions.map((v, k) => (
|
||||||
|
<MenuItem value={v} key={k}>
|
||||||
|
{v}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,27 +1,37 @@
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import Autocomplete from "@mui/material/Autocomplete";
|
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Chip from "@mui/material/Chip";
|
|
||||||
import Select from "@mui/material/Select";
|
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
|
||||||
import InputLabel from "@mui/material/InputLabel";
|
|
||||||
import FormControl from "@mui/material/FormControl";
|
import FormControl from "@mui/material/FormControl";
|
||||||
import { useCreateServer, useVersionList } from "@mcl/queries";
|
import { useCreateServer } from "@mcl/queries";
|
||||||
|
|
||||||
|
import NameOption from "@mcl/components/server-options/NameOption.jsx";
|
||||||
|
import HostOption from "@mcl/components/server-options/HostOption.jsx";
|
||||||
|
|
||||||
|
import VersionOption from "@mcl/components/server-options/VersionOption.jsx";
|
||||||
|
|
||||||
|
import ServerTypeOption, {
|
||||||
|
serverTypeOptions,
|
||||||
|
} from "@mcl/components/server-options/ServerTypeOption.jsx";
|
||||||
|
|
||||||
|
import CpuOption, {
|
||||||
|
cpuOptions,
|
||||||
|
} from "@mcl/components/server-options/CpuOption.jsx";
|
||||||
|
import MemoryOption, {
|
||||||
|
memoryOptions,
|
||||||
|
} from "@mcl/components/server-options/MemoryOption.jsx";
|
||||||
|
|
||||||
const defaultServer = {
|
const defaultServer = {
|
||||||
version: "latest",
|
version: "latest",
|
||||||
serverType: "VANILLA",
|
serverType: serverTypeOptions[0],
|
||||||
memory: "512",
|
cpu: cpuOptions[0],
|
||||||
|
memory: memoryOptions[2], // 1.5GB
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Create() {
|
export default function Create() {
|
||||||
const [spec, setSpec] = useState(defaultServer);
|
const [spec, setSpec] = useState(defaultServer);
|
||||||
const nav = useNavigate();
|
const nav = useNavigate();
|
||||||
const versionList = useVersionList();
|
|
||||||
const [versions, setVersions] = useState(["latest"]);
|
|
||||||
const createServer = useCreateServer(spec);
|
const createServer = useCreateServer(spec);
|
||||||
|
|
||||||
const updateSpec = (attr, val) => {
|
const updateSpec = (attr, val) => {
|
||||||
|
@ -30,16 +40,6 @@ export default function Create() {
|
||||||
setSpec(s);
|
setSpec(s);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!versionList.data) return;
|
|
||||||
setVersions([
|
|
||||||
"latest",
|
|
||||||
...versionList.data.versions
|
|
||||||
.filter(({ type: releaseType }) => releaseType === "release")
|
|
||||||
.map(({ id }) => id),
|
|
||||||
]);
|
|
||||||
}, [versionList.data]);
|
|
||||||
|
|
||||||
const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value);
|
const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value);
|
||||||
|
|
||||||
async function upsertSpec() {
|
async function upsertSpec() {
|
||||||
|
@ -67,54 +67,15 @@ export default function Create() {
|
||||||
sx={{ width: "100%", maxWidth: "600px", margin: "auto" }}
|
sx={{ width: "100%", maxWidth: "600px", margin: "auto" }}
|
||||||
>
|
>
|
||||||
<FormControl fullWidth sx={{ mt: "2rem", display: "flex", gap: ".5rem" }}>
|
<FormControl fullWidth sx={{ mt: "2rem", display: "flex", gap: ".5rem" }}>
|
||||||
<TextField
|
<NameOption onChange={coreUpdate("name")} />
|
||||||
label="Name"
|
<HostOption onChange={coreUpdate("host")} />
|
||||||
onChange={coreUpdate("name")}
|
<VersionOption value={spec.version} onChange={coreUpdate("version")} />
|
||||||
helperText="Example: My Survival World"
|
<ServerTypeOption
|
||||||
defaultValue={spec.name}
|
|
||||||
FormHelperTextProps={{ sx: { ml: 0 } }}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="Host"
|
|
||||||
onChange={coreUpdate("host")}
|
|
||||||
helperText="Example: host.mydomain.com"
|
|
||||||
FormHelperTextProps={{ sx: { ml: 0 } }}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="Version"
|
|
||||||
onChange={coreUpdate("version")}
|
|
||||||
value={spec.version}
|
|
||||||
select
|
|
||||||
required
|
|
||||||
SelectProps={{ MenuProps: { sx: { maxHeight: "20rem" } } }}
|
|
||||||
>
|
|
||||||
{versions.map((v, k) => (
|
|
||||||
<MenuItem value={v} key={k}>
|
|
||||||
{v}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</TextField>
|
|
||||||
<TextField
|
|
||||||
label="Server Type"
|
|
||||||
onChange={coreUpdate("serverType")}
|
|
||||||
value={spec.serverType}
|
value={spec.serverType}
|
||||||
select
|
onChange={coreUpdate("serverType")}
|
||||||
required
|
|
||||||
>
|
|
||||||
<MenuItem value={"VANILLA"}>Vanilla</MenuItem>
|
|
||||||
<MenuItem value={"FABRIC"}>Fabric</MenuItem>
|
|
||||||
<MenuItem value={"PAPER"}>Paper</MenuItem>
|
|
||||||
<MenuItem value={"SPIGOT"}>Spigot</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
label="Memory"
|
|
||||||
onChange={coreUpdate("memory")}
|
|
||||||
defaultValue={spec.memory}
|
|
||||||
required
|
|
||||||
/>
|
/>
|
||||||
|
<CpuOption value={spec.cpu} onChange={coreUpdate("cpu")} />
|
||||||
|
<MemoryOption value={spec.memory} onChange={coreUpdate("memory")} />
|
||||||
<Button onClick={upsertSpec} variant="contained">
|
<Button onClick={upsertSpec} variant="contained">
|
||||||
Create
|
Create
|
||||||
</Button>
|
</Button>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue