From bfd0bf921ae179230ce1fa7784d810d3a40fe86a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 13:10:00 +0000 Subject: [PATCH 1/3] Initial plan From 4bfcfed2b9fee206c0a161011cd6d85b4548ca15 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 13:15:10 +0000 Subject: [PATCH 2/3] Add server control functionality to admin dashboard Co-authored-by: maxonary <62939182+maxonary@users.noreply.github.com> --- frontend/src/components/Dashboard.tsx | 104 +++++++++++++++++++++++++- frontend/src/styles/Minecraft.css | 8 +- 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/Dashboard.tsx b/frontend/src/components/Dashboard.tsx index 8e63f3e..caaf1dc 100644 --- a/frontend/src/components/Dashboard.tsx +++ b/frontend/src/components/Dashboard.tsx @@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom"; import { copyToClipboard } from "../utils/clipboardUtils"; import UserTable from "./UserTable"; import Button from "./Button"; -import { apiJwt, setAuthToken } from "../api"; +import { apiJwt, setAuthToken, api, apiStatus } from "../api"; import "../styles/Minecraft.css"; import TitleImage from "./TitleImage"; @@ -36,9 +36,78 @@ function Dashboard() { const [invitationCode, setInvitationCode] = useState(null); const [isCopied, setIsCopied] = useState(false); const [error, setError] = useState(null); + const [serverStatus, setServerStatus] = useState(""); const invitationCodeRef = useRef(null); + // Function to fetch server status + const fetchServerStatus = () => { + // Try backend API status endpoint first, fallback to direct status service + api.get('/api/status') + .then(response => setServerStatus(response.data.status)) + .catch(() => { + // Fallback to direct status service if backend proxy is unavailable + if (process.env.REACT_APP_STATUS_API_URL) { + apiStatus.get('/status') + .then(response => setServerStatus(response.data.status)) + .catch(() => { + setServerStatus("Error fetching status"); + }); + } else { + setServerStatus("Error fetching status"); + } + }); + }; + + const startClick = () => { + console.log('WakeUp'); + // Try backend API wakeup endpoint first, fallback to direct status service + api.post('/api/status/wakeup', {}) + .then((response) => { + console.log('WakeUp Success', response); + // Update status immediately after wake-up attempt + fetchServerStatus(); + }) + .catch(() => { + // Fallback to direct status service if backend proxy is unavailable + if (process.env.REACT_APP_STATUS_API_URL) { + apiStatus.post('/wakeup', {}) + .then((response) => { + console.log('WakeUp Success (direct)', response); + // Update status immediately after wake-up attempt + fetchServerStatus(); + }) + .catch((error) => { + console.log('WakeUp Error', error); + }); + } else { + console.log('WakeUp Error: No status service URL configured'); + } + }); + }; + + const getTexts = (status: string) => { + let emoji = '❌' + let buttonText = status; + switch (status) { + case 'Running': + emoji = '🟩' + buttonText = 'Server is running' + break; + case 'Sleeping': + emoji = '🟥' + buttonText = "Wake Up Server" + break; + case 'Starting': + emoji = '🟧' + buttonText = '...Waiting...' + break; + } + return { emoji, buttonText }; + }; + + const serverStatusLink = process.env.REACT_APP_SERVER_STATUS_URL; + const generateCode = async () => { try { const response = await apiJwt.post("/api/invitation/generate-invitation-code"); @@ -72,6 +141,19 @@ function Dashboard() { useEffect(() => { const url = window.location.host; document.title = `Admin Dashboard - ${url}`; + + // Fetch status immediately + fetchServerStatus(); + + // Set up polling to fetch status every 5 seconds + const statusInterval = setInterval(() => { + fetchServerStatus(); + }, 5000); // Poll every 5 seconds + + // Cleanup interval on unmount + return () => { + clearInterval(statusInterval); + }; }, []); return ( @@ -94,6 +176,17 @@ function Dashboard() { /> )} +
+ {serverStatusLink && ( + + + )} ); diff --git a/frontend/src/styles/Minecraft.css b/frontend/src/styles/Minecraft.css index a31124d..d650f48 100644 --- a/frontend/src/styles/Minecraft.css +++ b/frontend/src/styles/Minecraft.css @@ -135,17 +135,21 @@ grid-gap: 8px; display: grid; justify-content: center; grid-template-columns: var(--btn-size) calc(var(--btn-size) * 10) var(--btn-size); - grid-template-rows: repeat(2, var(--btn-size)) 16px var(--btn-size); + grid-template-rows: repeat(3, var(--btn-size)) 16px var(--btn-size); grid-template-areas: '. first .' '. second .' + '. third .' + '. . .' + 'lang fourth .' ; grid-gap: 8px; } -.menu-dashboard :nth-child(1) {grid-area: first;} +.menu-dashboard .server-status-btn {grid-area: first;} .menu-dashboard .double {grid-area: second;} .menu-dashboard .double :nth-child(1) {grid-area: left;} .menu-dashboard .double :nth-child(2) {grid-area: right;} +.menu-dashboard .lang {grid-area: lang;} .title { align-items: center; From be628dc79d04ce5d655d650337efc502a3d5aa39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 13:16:56 +0000 Subject: [PATCH 3/3] Fix nested button HTML structure and clean up CSS grid layout Co-authored-by: maxonary <62939182+maxonary@users.noreply.github.com> --- frontend/src/components/Dashboard.tsx | 12 +++++------- frontend/src/styles/Minecraft.css | 3 +-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/Dashboard.tsx b/frontend/src/components/Dashboard.tsx index caaf1dc..abe9150 100644 --- a/frontend/src/components/Dashboard.tsx +++ b/frontend/src/components/Dashboard.tsx @@ -200,13 +200,11 @@ function Dashboard() { {serverStatusLink && ( - - +
+ + {getTexts(serverStatus).emoji} + +
)} diff --git a/frontend/src/styles/Minecraft.css b/frontend/src/styles/Minecraft.css index d650f48..2ecab3d 100644 --- a/frontend/src/styles/Minecraft.css +++ b/frontend/src/styles/Minecraft.css @@ -135,11 +135,10 @@ grid-gap: 8px; display: grid; justify-content: center; grid-template-columns: var(--btn-size) calc(var(--btn-size) * 10) var(--btn-size); - grid-template-rows: repeat(3, var(--btn-size)) 16px var(--btn-size); + grid-template-rows: repeat(2, var(--btn-size)) 16px var(--btn-size); grid-template-areas: '. first .' '. second .' - '. third .' '. . .' 'lang fourth .' ;