+ fetching log in console

This commit is contained in:
AntoninoP 2024-08-15 18:17:43 +02:00
parent bd62b5d77f
commit 76272696f3
7 changed files with 202 additions and 88 deletions

View File

@ -33,7 +33,8 @@ const App = () => {
<Routes> <Routes>
<Route path="/login" element={user ? <Navigate to="/dashboard" /> : <LoginPage />} /> <Route path="/login" element={user ? <Navigate to="/dashboard" /> : <LoginPage />} />
<Route path="/dashboard" element={user ? <DashboardPage user={user} /> : <Navigate to="/login" />} /> <Route path="/dashboard" element={user ? <DashboardPage user={user} /> : <Navigate to="/login" />} />
<Route path="/server/:serverName" element={user ? <ServerDetails user={user} /> : <Navigate to="/login" />} /> <Route path="/createServer" element={<Navigate />} />
<Route path="/server/:serverName/*" element={user ? <ServerDetails user={user} /> : <Navigate to="/login" />} />
<Route path="/" element={<Navigate to={user ? "/dashboard" : "/login"} />} /> <Route path="/" element={<Navigate to={user ? "/dashboard" : "/login"} />} />
<Route path="*" element={<NotFoundPage />} /> <Route path="*" element={<NotFoundPage />} />
</Routes> </Routes>

View File

@ -50,7 +50,7 @@ const ServerCard = ({ status, version, name, framework, onRunClick, onStopClick,
}; };
return ( return (
<Link to={`/server/${name}`} className={styles.serverCard}> <Link to={`/server/${name}/options`} className={styles.serverCard}>
<div className={styles.header}> <div className={styles.header}>
<div className={styles.serverInfo}> <div className={styles.serverInfo}>
<img src={getFrameworkSource()} alt={`${name} Icon`} className={styles.frameworkIcon} /> <img src={getFrameworkSource()} alt={`${name} Icon`} className={styles.frameworkIcon} />

View File

@ -7,11 +7,38 @@ import PropTypes from "prop-types";
const ServerConsole = ({ user }) => { const ServerConsole = ({ user }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const { serverName } = useParams();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [logs, setLogs] = useState(''); const [logs, setLogs] = useState('');
useEffect(() => {
const fetchServerLogs = async () => {
setLoading(true);
setError(null);
try {
const response = await serviiApi.fetchLogs(serverName);
if (response.return_code === 200) {
// Nettoyer la chaîne de caractères en supprimant les [ ] et en remplaçant les \\n
let logString = response.message;
logString = logString.slice(1, -1); // Supprime les crochets [ ] au début et à la fin
logString = logString.replace(/\\n/g, '\n'); // Remplace les \\n par de véritables sauts de ligne
logString = logString.replace(/\\\"/g, '"'); // Supprime les échappements de guillemets
setLogs(logString);
} else {
setError(`Erreur lors de la récupération des logs: ${response.message}`);
}
} catch (err) {
setError(`Erreur: ${err.message}`);
} finally {
setLoading(false);
}
};
fetchServerLogs();
}, [serverName]);
if (loading) { if (loading) {
return <Loading />; return <Loading />;
} }
@ -30,6 +57,7 @@ const ServerConsole = ({ user }) => {
return ( return (
<div className={styles.container}> <div className={styles.container}>
<div className={styles.containerConsole}> <div className={styles.containerConsole}>
<div className={styles.header}>Console</div>
<h1>Console</h1> <h1>Console</h1>
<div className={styles.logContainer}> <div className={styles.logContainer}>
<pre className={styles.logs}> <pre className={styles.logs}>

View File

@ -1,19 +1,56 @@
/* Container for the entire console section */
.container { .container {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
margin-top: var(--navbar-height); margin-top: var(--navbar-height);
width: 60rem; width: 100%;
height: 90%; height: calc(100vh - var(--navbar-height) - 2rem);
margin-bottom: 1rem; margin-bottom: 1rem;
} overflow: hidden;
}
.containerConsole { .containerConsole {
display: flex; display: flex;
justify-content: center; justify-content: flex-start;
align-items: center; align-items: flex-start;
background-color: red; flex-direction: column;
width: 50rem; background-color: #100D25;
height: 100%; width: 100%;
overflow: auto; max-width: 50rem;
} height: 100%;
overflow-y: auto;
border: .1rem solid #343947;
padding: 1rem;
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.5);
}
.header {
display: flex;
justify-content: flex-start;
align-items: center;
background-color: #1D1836;
width: 100%;
height: 3rem;
font-size: 1rem;
font-weight: 500;
border-bottom: .1rem solid #343947;
}
.logs {
font-family: 'Courier New', Courier, monospace;
font-size: 0.9rem;
color: #ffffff;
white-space: pre-wrap;
line-height: 1.5;
}
.sidebar {
overflow: hidden;
}
.logContainer {
width: 100%;
height: calc(100% - 3rem);
overflow-y: auto;
}

View File

@ -1,73 +1,91 @@
import { useState } from 'react'; import { useParams, useNavigate, Route, Routes, Link } from 'react-router-dom';
import { useParams, useNavigate } from 'react-router-dom';
import Navbar from '../../components/navbar/Navbar'; import Navbar from '../../components/navbar/Navbar';
import ServerProperties from '../ServerProperties/ServerProperties'; import ServerProperties from '../ServerProperties/ServerProperties';
import styles from './ServerDetails.module.scss';
import PropTypes from "prop-types";
import { FaServer, FaCogs, FaUserFriends, FaGlobe, FaHistory, FaClipboardList, FaSave, FaLock } from 'react-icons/fa';
import ServerConsole from '../ServerConsole/ServerConsole'; import ServerConsole from '../ServerConsole/ServerConsole';
// import ServerHistory from '../ServerHistory/ServerHistory'; // import ServerHistory from '../ServerHistory/ServerHistory';
// import ServerPlayers from '../ServerPlayers/ServerPlayers'; // import ServerPlayers from '../ServerPlayers/ServerPlayers';
// import ServerWorlds from '../ServerWorlds/ServerWorlds'; // import ServerWorlds from '../ServerWorlds/ServerWorlds';
// import ServerBackups from '../ServerBackups/ServerBackups'; // import ServerBackups from '../ServerBackups/ServerBackups';
// import ServerAccess from '../ServerAccess/ServerAccess'; // import ServerAccess from '../ServerAccess/ServerAccess';
import styles from './ServerDetails.module.scss';
import PropTypes from "prop-types";
import { FaServer, FaCogs, FaUserFriends, FaGlobe, FaHistory, FaClipboardList, FaSave, FaLock } from 'react-icons/fa';
import NotFoundPage from '../NotFoundPage/NotFoundPage';
import { NavLink } from 'react-router-dom';
const ServerDetails = ({ user }) => { const ServerDetails = ({ user }) => {
const { serverName } = useParams(); const { serverName } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
const [selectedMenu, setSelectedMenu] = useState('');
const handleQuit = () => { const handleQuit = () => {
navigate('/dashboard'); navigate('/dashboard');
}; };
const renderContent = () => {
switch (selectedMenu) {
case 'options':
return <ServerProperties user={user} />;
case 'console':
return <ServerConsole user={user} />;
case 'history':
return <h2>Cette fonctionnalité sera prochainement disponible.</h2>; // <ServerHistory user={user} />
case 'players':
return <h2>Cette fonctionnalité sera prochainement disponible.</h2>; // <ServerPlayers user={user} />
case 'worlds':
return <h2>Cette fonctionnalité sera prochainement disponible.</h2>; // <ServerWorlds user={user} />
case 'backups':
return <h2>Cette fonctionnalité sera prochainement disponible.</h2>; // <ServerBackups user={user} />
case 'access':
return <h2>Cette fonctionnalité sera prochainement disponible.</h2>; // <ServerAccess user={user} />
default:
return <h1>{serverName || 'Server name not available'}</h1>;
}
};
return ( return (
<> <>
<Navbar user={user} /> <Navbar user={user} />
<div className={styles.container}> <div className={styles.container}>
<div className={styles.sidebar}> <div className={styles.sidebar}>
<div className={styles.logo}> <div className={styles.userinfo}>
<img src="/path/to/logo.png" alt="Logo" /> <div className={styles.user}>
</div> <p>{user.displayName}</p>
<div className={styles.user}> </div>
<p>{user.displayName}</p>
<small>{user.email}</small>
</div> </div>
<div className={styles.menu}> <div className={styles.menu}>
<a onClick={handleQuit}><div className={styles.menuItem}><FaServer /> Mes serveurs</div></a> <NavLink
<a onClick={() => setSelectedMenu('options')}><div className={styles.menuItem}><FaCogs /> Propriétés</div></a> to={`/server/${serverName}/options`}
<a onClick={() => setSelectedMenu('console')}><div className={styles.menuItem}><FaClipboardList /> Console</div></a> className={({ isActive }) => isActive ? `${styles.menuItem} ${styles.active}` : styles.menuItem}>
<a onClick={() => setSelectedMenu('history')}><div className={styles.menuItem}><FaHistory /> Historique</div></a> <FaCogs /> Propriétés
<a onClick={() => setSelectedMenu('players')}><div className={styles.menuItem}><FaUserFriends /> Joueurs</div></a> </NavLink>
<a onClick={() => setSelectedMenu('worlds')}><div className={styles.menuItem}><FaGlobe /> Mondes</div></a>
<a onClick={() => setSelectedMenu('backups')}><div className={styles.menuItem}><FaSave /> Sauvegardes</div></a> <NavLink
<a onClick={() => setSelectedMenu('access')}><div className={styles.menuItem}><FaLock /> Accès</div></a> to={`/server/${serverName}/console`}
className={({ isActive }) => isActive ? `${styles.menuItem} ${styles.active}` : styles.menuItem}>
<FaClipboardList /> Console
</NavLink>
<NavLink
to={`/server/${serverName}/history`}
className={({ isActive }) => isActive ? `${styles.menuItem} ${styles.active}` : styles.menuItem}>
<FaHistory /> Historique
</NavLink>
<NavLink
to={`/server/${serverName}/players`}
className={({ isActive }) => isActive ? `${styles.menuItem} ${styles.active}` : styles.menuItem}>
<FaUserFriends /> Joueurs
</NavLink>
<NavLink
to={`/server/${serverName}/worlds`}
className={({ isActive }) => isActive ? `${styles.menuItem} ${styles.active}` : styles.menuItem}>
<FaGlobe /> Mondes
</NavLink>
<NavLink
to={`/server/${serverName}/backups`}
className={({ isActive }) => isActive ? `${styles.menuItem} ${styles.active}` : styles.menuItem}>
<FaSave /> Sauvegardes
</NavLink>
<NavLink
to={`/server/${serverName}/access`}
className={({ isActive }) => isActive ? `${styles.menuItem} ${styles.active}` : styles.menuItem}>
<FaLock /> Accès
</NavLink>
</div> </div>
<button className={styles.logoutButton} onClick={handleQuit}>Se déconnecter</button>
</div> </div>
<div className={styles.serverDetailsContainer}> <div className={styles.serverDetailsContainer}>
{renderContent()} <Routes>
<Route path="options" element={<ServerProperties user={user} />} />
<Route path="console" element={<ServerConsole user={user} />} />
<Route path="history" element={<h2>Cette fonctionnalité sera prochainement disponible.</h2>} />
<Route path="players" element={<h2>Cette fonctionnalité sera prochainement disponible.</h2>} />
<Route path="worlds" element={<h2>Cette fonctionnalité sera prochainement disponible.</h2>} />
<Route path="backups" element={<h2>Cette fonctionnalité sera prochainement disponible.</h2>} />
<Route path="access" element={<h2>Cette fonctionnalité sera prochainement disponible.</h2>} />
<Route path="*" element={<NotFoundPage/>} />
</Routes>
</div> </div>
</div> </div>
</> </>

View File

@ -1,24 +1,43 @@
.container { .container {
display: flex; display: flex;
min-height: 100vh; min-height: 100vh;
margin-top: var(--navbar-height);
} }
.sidebar { .sidebar {
width: 20rem; width: 20rem;
background-color: #100D25; background-color: #100D25;
padding: 2rem; padding: 2rem 1rem;
padding-left: 0rem;
box-sizing: border-box; box-sizing: border-box;
position: fixed; position: fixed;
height: 100vh; height: calc(100vh - var(--navbar-height));
top: 0; top: var(--navbar-height);
color: white; color: white;
} }
.logo img { .menuItem {
width: 150px; display: flex;
margin-bottom: 2rem; align-items: center;
padding: 0.7rem 1rem ;
margin: .5rem 0rem;
padding-right: 0rem;
font-size: 1.5rem;
cursor: pointer;
color: #D1D5DB;
text-decoration: none;
width: 100%;
&.active {
background-color: red;
color: white;
}
} }
.menuItem:hover {
color: white;
}
.user { .user {
margin-bottom: 2rem; margin-bottom: 2rem;
} }
@ -38,18 +57,9 @@
flex-direction: column; flex-direction: column;
} }
.menuItem {
display: flex;
align-items: center;
padding: 1rem 0;
font-size: 1.5rem;
cursor: pointer;
color: #D1D5DB;
text-decoration: none;
}
.menuItem:hover { .menuItem:hover {
color: white; color: white;
} }
.menuItem svg { .menuItem svg {
@ -60,7 +70,7 @@
.logoutButton { .logoutButton {
margin-top: 2rem; margin-top: 2rem;
padding: 0.75rem 1.5rem; padding: 0.75rem 1.5rem;
background-color: #EF4444; background-color: #EF4444;
border: none; border: none;
color: white; color: white;
cursor: pointer; cursor: pointer;
@ -73,9 +83,9 @@
} }
.serverDetailsContainer { .serverDetailsContainer {
flex: 1; flex: 1;
margin-left: 20rem; margin-left: 20rem;
padding-top: var(--navbar-height); padding-top: 2rem;
background-color: var(--main-bg-color); background-color: var(--main-bg-color);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -87,8 +97,18 @@
.navbar { .navbar {
position: fixed; position: fixed;
top: 0; top: 0;
width: 100%; left: 0;
height: var(--navbar-height); width: 100%;
height: var(--navbar-height);
background-color: var(--navbar-bg-color); background-color: var(--navbar-bg-color);
z-index: 1000; z-index: 1000;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
} }
.userinfo {
display: flex;
align-items: start;
justify-content: center;
flex-direction: column;
margin-left: 1rem;
}

View File

@ -36,6 +36,10 @@ interface CommandRequest extends BaseRequest {
name: string; name: string;
} }
interface FetchLogsRequest extends BaseRequest {
name: string;
}
enum serviiRequest { enum serviiRequest {
setSubdomain = 'SetSubdomain', setSubdomain = 'SetSubdomain',
fetchServers = 'FetchServers', fetchServers = 'FetchServers',
@ -47,6 +51,7 @@ enum serviiRequest {
serverStop = 'ServerStop', serverStop = 'ServerStop',
updateProperty = 'UpdateProperties', updateProperty = 'UpdateProperties',
command = 'Command', command = 'Command',
fetchLogs = 'FetchLogs',
} }
class serviiApi { class serviiApi {
@ -65,7 +70,7 @@ class serviiApi {
if (json.message === undefined) { if (json.message === undefined) {
if (!(endpoint === serviiRequest.fetchServers)) { if (!(endpoint === serviiRequest.fetchServers)) {
return { return_code: status, message: "Couldn't find an available API, we're sorry for the inconvenience." }; return { return_code: status, message: "Couldn't find an available API" };
} }
return { return_code: status, message: json }; return { return_code: status, message: json };
} }
@ -150,13 +155,18 @@ class serviiApi {
name: name, name: name,
props: props, props: props,
}; };
return this.call(serviiRequest.updateProperty, payload); // Correct usage here return this.call(serviiRequest.updateProperty, payload);
} }
public static async command(command: string, name: string): Promise<ApiResponse> { public static async command(command: string, name: string): Promise<ApiResponse> {
const payload: CommandRequest = { token: this.token(), command: command, name: name }; const payload: CommandRequest = { token: this.token(), command: command, name: name };
return this.call(serviiRequest.command, payload); return this.call(serviiRequest.command, payload);
} }
public static async fetchLogs(name: string): Promise<ApiResponse> {
const payload: FetchLogsRequest = { token: this.token(), name: name };
return this.call(serviiRequest.fetchLogs, payload);
}
} }
export default serviiApi; export default serviiApi;