(feature) Update UI & Resource Availability

This commit is contained in:
Elijah Dunemask 2023-03-15 15:20:08 +00:00
parent 11d8229eb5
commit 929193d272
44 changed files with 4747 additions and 27 deletions

152
src/pages/Create.jsx Normal file
View file

@ -0,0 +1,152 @@
import { useState, useEffect } from "react";
import TextField from "@mui/material/TextField";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
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 { useCreateServer, useVersionList } from "@mcl/queries";
const defaultServer = {
version: "latest",
name: "example",
serverType: "VANILLA",
difficulty: "easy",
maxPlayers: "20",
gamemode: "survival",
memory: "1024",
motd: "Minecluster Server Hosting",
};
export default function Create() {
const [spec, setSpec] = useState(defaultServer);
const versionList = useVersionList();
const [versions, setVersions] = useState(["latest"]);
const createServer = useCreateServer(spec);
const updateSpec = (attr, val) => {
const s = { ...spec };
s[attr] = val;
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);
function upsertSpec() {
if (validateSpec() !== "validated") return;
createServer(spec);
}
function validateSpec() {
console.log("TODO CREATE VALIDATION");
if (!spec.name) return alertValidationError("Name not included");
if (!spec.version) return alertValidationError("Version cannot be blank");
if (!spec.url) return alertValidationError("Url cannot be blank");
return "validated";
}
function alertValidationError(reason) {
alert(`Could not validate spec because: ${reason}`);
}
return (
<Box className="create">
<FormControl fullWidth>
<TextField
label="Name"
onChange={coreUpdate("name")}
defaultValue={spec.name}
required
/>
<TextField label="URL" onChange={coreUpdate("url")} required />
<TextField
label="Version"
onChange={coreUpdate("version")}
value={spec.version}
select
required
SelectProps={{ MenuProps: { sx: { maxHeight: "12rem" } } }}
>
{versions.map((v, k) => (
<MenuItem value={v} key={k}>
{v}
</MenuItem>
))}
</TextField>
<TextField
label="Server Type"
onChange={coreUpdate("serverType")}
value={spec.serverType}
select
required
>
<MenuItem value={"VANILLA"}>Vanilla</MenuItem>
<MenuItem value={"FABRIC"}>Fabric</MenuItem>
<MenuItem value={"PAPER"}>Paper</MenuItem>
<MenuItem value={"SPIGOT"}>Spigot</MenuItem>
</TextField>
<TextField
label="Difficulty"
onChange={coreUpdate("difficulty")}
value={spec.difficulty}
select
required
>
<MenuItem value={"peaceful"}>Peaceful</MenuItem>
<MenuItem value={"easy"}>Easy</MenuItem>
<MenuItem value={"medium"}>Medium</MenuItem>
<MenuItem value={"hard"}>Hard</MenuItem>
</TextField>
<TextField label="Whitelist" onChange={coreUpdate("whitelist")} />
<TextField label="Ops" onChange={coreUpdate("ops")} />
<TextField label="Icon" onChange={coreUpdate("icon")} required />
<TextField
label="Max Players"
onChange={coreUpdate("maxPlayers")}
defaultValue={spec.maxPlayers}
required
/>
<TextField
label="Gamemode"
onChange={coreUpdate("gamemode")}
value={spec.gamemode}
select
required
>
<MenuItem value={"survival"}>Survival</MenuItem>
<MenuItem value={"creative"}>Creative</MenuItem>
<MenuItem value={"adventure"}>Adventure</MenuItem>
<MenuItem value={"spectator"}>Spectator</MenuItem>
</TextField>
<TextField label="Seed" onChange={coreUpdate("seed")} />
<TextField label="Modpack" onChange={coreUpdate("modpack")} />
<TextField
label="Memory"
onChange={coreUpdate("memory")}
defaultValue={spec.memory}
required
/>
<TextField
label="MOTD"
onChange={coreUpdate("motd")}
defaultValue={spec.motd}
required
/>
<Button onClick={upsertSpec} variant="contained">
Create
</Button>
</FormControl>
</Box>
);
}

51
src/pages/Home.jsx Normal file
View file

@ -0,0 +1,51 @@
import { useState, useEffect } from "react";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import ServerCard from "../servers/ServerCard.jsx";
import RconDialog, { useRconDialog } from "../servers/RconDialog.jsx";
import Overview from "../overview/Overview.jsx";
import "@mcl/css/server-card.css";
import "@mcl/css/overview.css";
import { useServerInstances } from "@mcl/queries";
export default function Home() {
const [server, setServer] = useState();
const [servers, setServers] = useState([]);
const [rdOpen, rconToggle] = useRconDialog();
const { isLoading, data: serversData } = useServerInstances();
const { servers: serverInstances, clusterMetrics } = serversData ?? {};
useEffect(() => {
if (!serverInstances) return;
serverInstances.sort((a, b) => a.name.localeCompare(b.name));
setServers(serverInstances);
}, [serverInstances]);
const openRcon = (s) => () => {
setServer(s);
rconToggle();
};
return (
<Box className="home">
<Overview clusterMetrics={clusterMetrics} />
{!isLoading && servers.length === 0 && (
<Box display="flex" alignItems="center" justifyContent="center">
<Typography variant="h4" sx={{ textAlign: "center" }}>
No servers found!
</Typography>
</Box>
)}
<Box className="servers">
{!isLoading &&
servers.map((s, k) => (
<ServerCard key={k} server={s} openRcon={openRcon(s.name)} />
))}
</Box>
<RconDialog
keepMounted
open={rdOpen}
dialogToggle={rconToggle}
serverName={server}
/>
</Box>
);
}