diff --git a/.helmignore b/.helmignore index f4ac0f7..1532758 100644 --- a/.helmignore +++ b/.helmignore @@ -2,3 +2,5 @@ node_modules/ .git/ lib/ src/ +dist/ +build/ diff --git a/Dockerfile b/Dockerfile index c578d05..86d3c6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,13 +4,15 @@ WORKDIR /dunemask/net/minecluster COPY package.json . COPY package-lock.json . RUN npm i -# Copy react build resources over +# Copy build resources over COPY public public COPY dist dist COPY src src +COPY lib lib +# Copy TSConfigs over COPY index.html . -COPY vite.config.js . -RUN npm run build:react -# Copy Backend resources over -COPY lib lib +COPY vite.config.ts . +COPY tsconfig.json . +COPY tsconfig.server.json . +RUN npm run package:full CMD ["npm","start"] diff --git a/lib/database/queries/server-queries.ts b/lib/database/queries/server-queries.ts index 95ef4cd..a4f65c5 100644 --- a/lib/database/queries/server-queries.ts +++ b/lib/database/queries/server-queries.ts @@ -7,6 +7,7 @@ import { updateWhereAllQuery, } from "../pg-query.js"; import ExpressClientError from "../../util/ExpressClientError.js"; +import { VERB } from "@mcl/logging"; const table = "servers"; const asExpressClientError = (e) => { @@ -17,9 +18,8 @@ const getMclName = (host, id) => `${host.toLowerCase().replaceAll(".", "-")}-${id}`; export async function checkAuthorization(serverId, cairoId) { - console.log( - `Checking Authorization for user ${cairoId} for serverId ${serverId}`, - ); + const msgLog = `Checking Authorization for user ${cairoId} for serverId ${serverId}`; + VERB("DEBUG", msgLog); if (!cairoId) return false; const q = selectWhereAllQuery(table, { id: serverId, diff --git a/src/components/overview/Overview.tsx b/src/components/overview/Overview.tsx index aa09aa3..d0548d3 100644 --- a/src/components/overview/Overview.tsx +++ b/src/components/overview/Overview.tsx @@ -11,6 +11,7 @@ export default function Overview(props) { useEffect(() => { if (systemLoading || !props.clusterMetrics) return; + if (!systemAvailable) return; setCpu((props.clusterMetrics.cpu / systemAvailable.cpu) * 100); setMemory((props.clusterMetrics.memory / systemAvailable.memory) * 100); }, [systemAvailable, props.clusterMetrics]); diff --git a/src/components/servers/BackupsDialog.tsx b/src/components/servers/BackupsDialog.tsx index 565d26a..c51cbde 100644 --- a/src/components/servers/BackupsDialog.tsx +++ b/src/components/servers/BackupsDialog.tsx @@ -36,7 +36,7 @@ export default function BackupDialog(props) { function normalizeLastModified(lastModified) { const d = new Date(Date.parse(lastModified)); - return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()} ${d.getHours()}:${d.getMinutes()}`; + return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()} ${d.getHours()}:${d.getMinutes()}`; } const downloadBackup = (backup) => diff --git a/src/components/servers/ServerCard.tsx b/src/components/servers/ServerCard.tsx index 80610c7..75ba3ea 100644 --- a/src/components/servers/ServerCard.tsx +++ b/src/components/servers/ServerCard.tsx @@ -16,7 +16,11 @@ import EditIcon from "@mui/icons-material/Edit"; import FolderIcon from "@mui/icons-material/Folder"; import BackupIcon from "@mui/icons-material/Backup"; import { Link } from "react-router-dom"; -import { useServerDelete, useServerStart, useServerStop } from "@mcl/api/clients/server"; +import { + useServerDelete, + useServerStart, + useServerStop, +} from "@mcl/api/clients/server"; export default function ServerCard(props) { const { server, openRcon, openBackups } = props; diff --git a/src/pages/CreateCoreOptions.tsx b/src/pages/CreateCoreOptions.tsx index 04ac06a..8b1142d 100644 --- a/src/pages/CreateCoreOptions.tsx +++ b/src/pages/CreateCoreOptions.tsx @@ -58,9 +58,8 @@ export default function CreateCoreOptions() { async function upsertSpec() { if (validateSpec() !== "validated") return; - createServer() - .then(() => nav("/")) - .catch(alert); + createServer(); + nav("/"); } function validateSpec() { diff --git a/src/pages/CreateOptionsFull.tsx b/src/pages/CreateOptionsFull.tsx index 70a6627..e600edb 100644 --- a/src/pages/CreateOptionsFull.tsx +++ b/src/pages/CreateOptionsFull.tsx @@ -6,11 +6,10 @@ import TextField from "@mui/material/TextField"; import Box from "@mui/material/Box"; 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 { useCreateServer, useVersionList } from "@mcl/api/clients/server"; +import { useServerCreate } from "@mcl/api/clients/server"; +import { useVersionList } from "@mcl/api/clients/misc"; const defaultServer = { version: "latest", @@ -29,7 +28,7 @@ export default function Create() { const nav = useNavigate(); const versionList = useVersionList(); const [versions, setVersions] = useState(["latest"]); - const createServer = useCreateServer(spec); + const createServer = useServerCreate(spec); const updateSpec = (attr, val) => { const s = { ...spec }; s[attr] = val; @@ -91,9 +90,8 @@ export default function Create() { async function upsertSpec() { if (validateSpec() !== "validated") return; - createServer(spec) - .then(() => nav("/")) - .catch(alert); + createServer(spec); + nav("/"); } function validateSpec() { diff --git a/src/util/api/clients/files.ts b/src/util/api/clients/files.ts index 29a0e62..82b6826 100644 --- a/src/util/api/clients/files.ts +++ b/src/util/api/clients/files.ts @@ -14,11 +14,11 @@ export const createServerFolder = (serverId: string, path: string) => json: { id: serverId, path }, }); -export const uploadServerItem = (body:FormData) => +export const uploadServerItem = (body: FormData) => mclAuthenticatedApiRequest({ subPath: "/files/upload", body, - }) + }); export const deleteServerItem = ( serverId: string, diff --git a/src/util/api/clients/server.ts b/src/util/api/clients/server.ts index f67ba8e..3fb610c 100644 --- a/src/util/api/clients/server.ts +++ b/src/util/api/clients/server.ts @@ -1,8 +1,7 @@ -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query"; import { mclAuthenticatedApiRequest, useMutator } from "../requests"; // ===== API Utils ===== - const useInstanceControl = (apiRequest: (args: any) => Promise) => useMutator(apiRequest, ["server-instances"]); @@ -56,11 +55,13 @@ export const requestServerDelete = (serverId: string) => method: "DELETE", }); -export const requestServerCreate = (serverSpec: any) => - mclAuthenticatedApiRequest({ +export const requestServerCreate = (serverSpec: any) => { + console.log("requestServerCreate being called"); + return mclAuthenticatedApiRequest({ subPath: "/server/create", json: serverSpec, }); +}; export const requestServerModify = (serverSpec: any) => mclAuthenticatedApiRequest({ @@ -70,10 +71,10 @@ export const requestServerModify = (serverSpec: any) => export const getServerBlueprint = (serverId: string) => mclAuthenticatedApiRequest({ - subPath: "/server/blueprint", - json: { id: serverId }, - jsonify: true - }) + subPath: "/server/blueprint", + json: { id: serverId }, + jsonify: true, + }); // ===== API Queries ===== @@ -117,6 +118,6 @@ export const useServerModify = (spec: any) => export const useBlueprint = (serverId: string) => useQuery({ - queryKey: [`server-blueprint-${serverId}`], - queryFn: ()=>getServerBlueprint(serverId), - }) + queryKey: [`server-blueprint-${serverId}`], + queryFn: () => getServerBlueprint(serverId), + }); diff --git a/src/util/api/requests.ts b/src/util/api/requests.ts index 75c4a6b..0409ed5 100644 --- a/src/util/api/requests.ts +++ b/src/util/api/requests.ts @@ -1,7 +1,4 @@ -import { - useMutation, - useQueryClient, -} from "@tanstack/react-query"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { cairoAuthHeader } from "./auth"; declare interface ApiRequestArgs { @@ -10,20 +7,21 @@ declare interface ApiRequestArgs { json?: object | undefined; method?: string; jsonify?: boolean; - extraHeaders?: object; + extraHeaders?: HeadersInit; handleErrors?: boolean; } async function apiRequest(apiRequestArgs: ApiRequestArgs) { const { subPath, json, body, method, jsonify, extraHeaders, handleErrors } = apiRequestArgs; - const headers = extraHeaders ?? {}; + const headers: HeadersInit = extraHeaders ?? {}; const requestMethod = method ?? !!json ? "POST" : "GET"; const requestBody = body ?? !!json ? JSON.stringify(json) : undefined; if (!!json) headers["Content-Type"] = "application/json"; return fetch(`/api${subPath}`, { method: requestMethod, - body: requestBody + body: requestBody, + headers, }).then((res) => { if (res.status >= 300 && handleErrors) throw Error(res.statusText); if (jsonify) return res.json(); @@ -44,13 +42,14 @@ export async function mclApiRequest(apiRequestArgs: ApiRequestArgs) { return apiRequest(apiRequestArgs); } -export const useMutator = async ( - apiRequest: (args: any) => Promise, +export const useMutator = ( + apiRequest: (args?: any) => Promise, invalidate: string[], ) => { const qc = useQueryClient(); - useMutation({ - mutationFn: apiRequest, - onSuccess: () => qc.invalidateQueries({ queryKey: invalidate }), - }); + const mutate = async (...args: any) => + apiRequest(...args).then(() => + qc.invalidateQueries({ queryKey: invalidate }), + ); + return mutate; };