mirror of
https://github.com/hubHarmony/servii-frontend.git
synced 2024-11-18 05:40:31 +00:00
Merge pull request #22 from hubHarmony/newdetails
New Server details form
This commit is contained in:
commit
d6709163ee
9
package-lock.json
generated
9
package-lock.json
generated
@ -19,6 +19,7 @@
|
|||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"react-icons": "^5.3.0",
|
||||||
"react-router-dom": "^6.24.0",
|
"react-router-dom": "^6.24.0",
|
||||||
"react-toastify": "^10.0.5",
|
"react-toastify": "^10.0.5",
|
||||||
"sass": "^1.77.6",
|
"sass": "^1.77.6",
|
||||||
@ -9754,6 +9755,14 @@
|
|||||||
"react": ">=16.3.0"
|
"react": ">=16.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-icons": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"react-icons": "^5.3.0",
|
||||||
"react-router-dom": "^6.24.0",
|
"react-router-dom": "^6.24.0",
|
||||||
"react-toastify": "^10.0.5",
|
"react-toastify": "^10.0.5",
|
||||||
"sass": "^1.77.6",
|
"sass": "^1.77.6",
|
||||||
|
@ -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>
|
||||||
|
@ -10,26 +10,10 @@ import spigot from '../../assets/frameworks/spigot.png';
|
|||||||
import paper from '../../assets/frameworks/paper.png';
|
import paper from '../../assets/frameworks/paper.png';
|
||||||
|
|
||||||
const versions = {
|
const versions = {
|
||||||
vanilla: ['1.21', '1.20', '1.19'],
|
vanilla:[ "1.21.1", "1.21", "1.20.6", "1.20.5", "1.20.4", "1.20.2", "1.20.1", "1.19.4", "1.19.3", "1.19.2", "1.19.1", "1.18.2", "1.18.1", "1.17.1", "1.16.5", "1.16.4", "1.16.3", "1.16.2", "1.16.1", "1.15.2", "1.15.1", "1.14.4", "1.14.3", "1.14.2", "1.14.1", "1.13.2", "1.13.1", "1.12.2", "1.12.1", "1.11.2", "1.10.2", "1.9.4"],
|
||||||
bukkit: [
|
bukkit: [ "1.20.6", "1.20.4", "1.20.2", "1.20.1", "1.19.4", "1.19.3", "1.19.2", "1.19.1", "1.18.2", "1.17.5", "1.17.4", "1.17.3", "1.17.2", "1.17.0", "1.16.5", "1.16.4", "1.16.3", "1.16.2", "1.16.1", "1.16.0", "1.15.5", "1.15.4", "1.15.3", "1.15.2", "1.15.1", "1.15.0", "1.14.5", "1.14.4", "1.14.3", "1.14.2", "1.14.1", "1.14.0", "1.13.5", "1.13.4", "1.13.3", "1.13.2", "1.13.1", "1.13.0", "1.12.5", "1.12.4", "1.12.3", "1.12.2", "1.12.1", "1.12.0", "1.11.5", "1.11.4", "1.11.3", "1.11.2", "1.11.1", "1.11.0", "1.10.5", "1.10.4", "1.10.3", "1.10.2", "1.10.1", "1.10.0", "1.9.5", "1.9.4", "1.9.3", "1.9.2", "1.9.1", "1.9.0", "1.8.5", "1.8.4", "1.8.3", "1.8.2", "1.8.1", "1.8.0", "1.7.5", "1.7.4", "1.7.3", "1.7.2", "1.7.1", "1.7.0", "1.6.5", "1.6.4", "1.6.3", "1.6.2", "1.6.1", "1.6.0", "1.5.5", "1.5.4", "1.5.3", "1.5.2", "1.5.1", "1.5.0", "1.4.5", "1.4.4", "1.4.3", "1.4.2", "1.4.1", "1.4.0", "1.3.5", "1.3.4", "1.3.3", "1.3.2", "1.3.1", "1.3.0", "1.2.5", "1.2.4", "1.2.3", "1.2.2", "1.2.1", "1.2.0", "1.1.5", "1.1.4", "1.1.3", "1.1.2", "1.1.1", "1.1.0", "1.0.5", "1.0.4", "1.0.3", "1.0.2", "1.0.1", "1.0.0"],
|
||||||
'1.15.0', '1.15.1', '1.15.2', '1.15.3', '1.15.4', '1.15.5',
|
spigot: [ "1.21", "1.20.6", "1.20.4", "1.20.2", "1.20.1", "1.19.4", "1.19.3", "1.19.2", "1.19.1", "1.18.2", "1.18.1", "1.17.1", "1.16.5", "1.16.4", "1.16.3", "1.16.2", "1.16.1", "1.15.2", "1.15.1", "1.14.4", "1.14.3", "1.14.2", "1.14.1", "1.13.2", "1.13.1", "1.12.2", "1.12.1", "1.11.2", "1.11.1", "1.10.2", "1.9.4", "1.9.2", "1.8.8", "1.8.7", "1.8.6", "1.8.5", "1.8.4", "1.8.3", "1.7.10", "1.7.9", "1.7.8", "1.7.5", "1.7.2", "1.6.4", "1.6.2", "1.5.2", "1.5.1", "1.4.7", "1.4.6"],
|
||||||
'1.16.0', '1.16.1', '1.16.2', '1.16.3', '1.16.4', '1.16.5',
|
paper: [ "1.21.1", "1.21", "1.20.6", "1.20.5", "1.20.4", "1.20.2", "1.20.1", "1.19.4", "1.19.3", "1.19.2", "1.19.1", "1.18.2", "1.18.1", "1.17.1", "1.16.5", "1.16.4", "1.16.3", "1.16.2", "1.16.1", "1.15.2", "1.15.1", "1.14.4", "1.14.3", "1.14.2", "1.14.1", "1.13.2", "1.13.1", "1.12.2", "1.12.1", "1.11.2", "1.10.2", "1.9.4"]
|
||||||
'1.17.0', '1.17.1', '1.17.2', '1.17.3', '1.17.4', '1.17.5',
|
|
||||||
'1.18.1', '1.18.2',
|
|
||||||
'1.19.1', '1.19.2', '1.19.3', '1.19.4',
|
|
||||||
'1.20.1', '1.20.2', '1.20.4', '1.20.6'
|
|
||||||
],
|
|
||||||
spigot: ['1.21', '1.20'],
|
|
||||||
paper: [
|
|
||||||
'1.13.1', '1.13.2',
|
|
||||||
'1.14.1', '1.14.2', '1.14.3', '1.14.4',
|
|
||||||
'1.15.1', '1.15.2',
|
|
||||||
'1.16.1', '1.16.2', '1.16.3', '1.16.4', '1.16.5',
|
|
||||||
'1.17.1',
|
|
||||||
'1.18.1', '1.18.2',
|
|
||||||
'1.19.1', '1.19.2', '1.19.3', '1.19.4',
|
|
||||||
'1.20.1', '1.20.2', '1.20.4', '1.20.5', '1.20.6'
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noServers }) => {
|
const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noServers }) => {
|
||||||
@ -37,7 +21,7 @@ const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noSer
|
|||||||
const [subdomainInput, setSubdomainInput] = useState('');
|
const [subdomainInput, setSubdomainInput] = useState('');
|
||||||
const [serverName, setServerName] = useState('');
|
const [serverName, setServerName] = useState('');
|
||||||
const [serverVersion, setServerVersion] = useState();
|
const [serverVersion, setServerVersion] = useState();
|
||||||
const [selectedFramework, setSelectedFramework] = useState("vanilla");
|
const [selectedFramework, setSelectedFramework] = useState("paper");
|
||||||
|
|
||||||
const loadSubdomain = async () => {
|
const loadSubdomain = async () => {
|
||||||
try {
|
try {
|
||||||
@ -69,11 +53,13 @@ const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noSer
|
|||||||
|
|
||||||
const handleCreateServer = async () => {
|
const handleCreateServer = async () => {
|
||||||
try {
|
try {
|
||||||
await onCreateServer(serverName, serverVersion, selectedFramework);
|
const frameworkToSend = selectedFramework === 'vanilla' ? 'paper' : selectedFramework;
|
||||||
|
await onCreateServer(serverName, serverVersion, frameworkToSend);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating server:', error);
|
console.error('Error creating server:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const validateInput = (input) => {
|
const validateInput = (input) => {
|
||||||
return input.replace(/[^a-zA-Z]/g, '');
|
return input.replace(/[^a-zA-Z]/g, '');
|
||||||
@ -124,6 +110,7 @@ const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noSer
|
|||||||
|
|
||||||
<div className={styles.subtitle}>Sélection du framework</div>
|
<div className={styles.subtitle}>Sélection du framework</div>
|
||||||
<div className={styles.carreContainer}>
|
<div className={styles.carreContainer}>
|
||||||
|
<div className={styles.carreWrapper}>
|
||||||
<img
|
<img
|
||||||
className={`${styles.carre} ${selectedFramework === 'vanilla' ? styles.selected : ''}`}
|
className={`${styles.carre} ${selectedFramework === 'vanilla' ? styles.selected : ''}`}
|
||||||
src={vanilla}
|
src={vanilla}
|
||||||
@ -133,6 +120,9 @@ const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noSer
|
|||||||
setServerVersion('');
|
setServerVersion('');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.carreWrapper}>
|
||||||
<img
|
<img
|
||||||
className={`${styles.carre} ${selectedFramework === 'bukkit' ? styles.selected : ''}`}
|
className={`${styles.carre} ${selectedFramework === 'bukkit' ? styles.selected : ''}`}
|
||||||
src={bukkit}
|
src={bukkit}
|
||||||
@ -142,6 +132,9 @@ const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noSer
|
|||||||
setServerVersion('');
|
setServerVersion('');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.carreWrapper}>
|
||||||
<img
|
<img
|
||||||
className={`${styles.carre} ${selectedFramework === 'spigot' ? styles.selected : ''}`}
|
className={`${styles.carre} ${selectedFramework === 'spigot' ? styles.selected : ''}`}
|
||||||
src={spigot}
|
src={spigot}
|
||||||
@ -151,8 +144,11 @@ const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noSer
|
|||||||
setServerVersion('');
|
setServerVersion('');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.carreWrapper}>
|
||||||
<img
|
<img
|
||||||
className={`${styles.carre} ${selectedFramework === 'paper' ? styles.selected : ''}`}
|
className={`${styles.carre} ${styles.adviced} ${selectedFramework === 'paper' ? styles.selected : ''}`}
|
||||||
src={paper}
|
src={paper}
|
||||||
alt="Paper Logo"
|
alt="Paper Logo"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -160,8 +156,9 @@ const CreateServer = ({ user, onCreateServer, onSubdomainUpdate, onCancel, noSer
|
|||||||
setServerVersion('');
|
setServerVersion('');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<label className={styles.recommendationLabel}>Recommandé</label> {}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.subtitle}>Sélection de la version</div>
|
<div className={styles.subtitle}>Sélection de la version</div>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
|
@ -139,7 +139,13 @@
|
|||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 5rem;
|
height: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carreWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carre {
|
.carre {
|
||||||
@ -160,6 +166,17 @@
|
|||||||
transform: scale(1.2);
|
transform: scale(1.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.adviced {
|
||||||
|
border: 2px solid violet;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recommendationLabel {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: violet;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ const Navbar = ({ user }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('User data:', user);
|
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -9,6 +9,7 @@ import PropTypes from "prop-types";
|
|||||||
|
|
||||||
const ServerCard = ({ status, version, name, framework, onRunClick, onStopClick, onDeleteClick , countPlayers , maxPlayers}) => {
|
const ServerCard = ({ status, version, name, framework, onRunClick, onStopClick, onDeleteClick , countPlayers , maxPlayers}) => {
|
||||||
|
|
||||||
|
|
||||||
const getFrameworkSource = () => {
|
const getFrameworkSource = () => {
|
||||||
switch (framework) {
|
switch (framework) {
|
||||||
case "bukkit":
|
case "bukkit":
|
||||||
@ -50,7 +51,10 @@ 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}
|
||||||
|
state={{ status }}>
|
||||||
<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} />
|
||||||
|
@ -88,9 +88,7 @@ const DashboardPage = ({ user }) => {
|
|||||||
const handleCopyAddress = () => {
|
const handleCopyAddress = () => {
|
||||||
const address = `${subdomain}.servii.fr`;
|
const address = `${subdomain}.servii.fr`;
|
||||||
navigator.clipboard.writeText(address)
|
navigator.clipboard.writeText(address)
|
||||||
.then(() => {
|
|
||||||
console.log('Address copied to clipboard');
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
133
src/pages/ServerConsole/ServerConsole.jsx
Normal file
133
src/pages/ServerConsole/ServerConsole.jsx
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { useEffect, useState, useRef } from 'react';
|
||||||
|
import { useParams, useNavigate, useLocation } from 'react-router-dom';
|
||||||
|
import { FaExclamationCircle } from 'react-icons/fa';
|
||||||
|
import styles from './ServerConsole.module.scss';
|
||||||
|
import serviiApi from "../../service/api.tsx";
|
||||||
|
import Loading from '../Loading/loading.jsx';
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
const ServerConsole = ({ user }) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { serverName } = useParams();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
const [logs, setLogs] = useState('');
|
||||||
|
const [message, setMessage] = useState('');
|
||||||
|
const location = useLocation();
|
||||||
|
const status = location.state?.status;
|
||||||
|
|
||||||
|
const logsEndRef = useRef(null);
|
||||||
|
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
logsEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchServerLogs = async () => {
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await serviiApi.fetchLogs(serverName);
|
||||||
|
if (response.return_code === 200) {
|
||||||
|
let logString = response.message;
|
||||||
|
logString = logString.slice(1, -1);
|
||||||
|
logString = logString.replace(/\\n/g, '\n');
|
||||||
|
logString = logString.replace(/\\\"/g, '"');
|
||||||
|
logString = logString.replace(/, ?/g, '');
|
||||||
|
logString = logString.replace(/"{2,}/g, '');
|
||||||
|
logString = logString.replace(/'{2,}/g, '');
|
||||||
|
logString = logString.trim();
|
||||||
|
setLogs(logString);
|
||||||
|
} else {
|
||||||
|
setError(`Erreur lors de la récupération des logs: ${response.message}`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError(`Erreur: ${err.message}`);
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchServerLogs();
|
||||||
|
}, [serverName]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
}, [logs]);
|
||||||
|
|
||||||
|
const handleSendMessage = async () => {
|
||||||
|
if (message.trim() === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await serviiApi.command(message, serverName);
|
||||||
|
setMessage('');
|
||||||
|
fetchServerLogs();
|
||||||
|
} catch (err) {
|
||||||
|
setError(`Erreur lors de l'envoi de la commande : ${err.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className={styles.serverDetailsContainer}>
|
||||||
|
<div className={styles.error}>
|
||||||
|
<h1>{error}</h1>
|
||||||
|
<button onClick={() => navigate('/dashboard')}>Retour au Dashboard</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.containerConsole}>
|
||||||
|
<div className={styles.header}>
|
||||||
|
Console {status ? '(En marche)' : '(Arrêté)'}
|
||||||
|
</div>
|
||||||
|
<div className={styles.logContainer}>
|
||||||
|
{status ? (
|
||||||
|
<>
|
||||||
|
<pre className={styles.logs}>
|
||||||
|
{logs}
|
||||||
|
</pre>
|
||||||
|
<div ref={logsEndRef} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className={styles.offline}>
|
||||||
|
<FaExclamationCircle style={{ marginRight: '.6rem' }} />
|
||||||
|
<span>Serveur hors ligne</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.chatInputContainer}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className={styles.chatInput}
|
||||||
|
value={message}
|
||||||
|
onChange={(e) => setMessage(e.target.value)}
|
||||||
|
placeholder="Écrire un message..."
|
||||||
|
/>
|
||||||
|
<button className={styles.sendButton} onClick={handleSendMessage}>
|
||||||
|
Envoyer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ServerConsole.propTypes = {
|
||||||
|
user: PropTypes.oneOfType([
|
||||||
|
PropTypes.shape({
|
||||||
|
uid: PropTypes.string.isRequired,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServerConsole;
|
99
src/pages/ServerConsole/ServerConsole.module.scss
Normal file
99
src/pages/ServerConsole/ServerConsole.module.scss
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: var(--navbar-height);
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.containerConsole {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #100D25;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 50rem;
|
||||||
|
height: 38rem;
|
||||||
|
overflow: hidden;
|
||||||
|
border: .1rem solid #343947;
|
||||||
|
padding: 0;
|
||||||
|
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.5);
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logContainer {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 6rem);
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs {
|
||||||
|
font-family: 'Courier New', Courier, monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #ffffff;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatInputContainer {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: #1D1836;
|
||||||
|
border-top: .1rem solid #343947;
|
||||||
|
border-left: .1rem solid #343947;
|
||||||
|
border-right: .1rem solid #343947;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatInput {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: .1rem solid #343947;
|
||||||
|
background-color: #2C2A3E;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sendButton {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
background-color: #3E3B59;
|
||||||
|
color: #ffffff;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sendButton:hover {
|
||||||
|
background-color: #5A567E;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.offline {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
@ -1,155 +1,101 @@
|
|||||||
import { useEffect, 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 ServerConsole from '../ServerConsole/ServerConsole';
|
||||||
|
// import ServerHistory from '../ServerHistory/ServerHistory';
|
||||||
|
// import ServerPlayers from '../ServerPlayers/ServerPlayers';
|
||||||
|
// import ServerWorlds from '../ServerWorlds/ServerWorlds';
|
||||||
|
// import ServerBackups from '../ServerBackups/ServerBackups';
|
||||||
|
// import ServerAccess from '../ServerAccess/ServerAccess';
|
||||||
import styles from './ServerDetails.module.scss';
|
import styles from './ServerDetails.module.scss';
|
||||||
import serviiApi from "../../service/api.tsx";
|
|
||||||
import Loading from '../Loading/loading';
|
|
||||||
import PropTypes from "prop-types";
|
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';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
|
||||||
const ServerDetails = ({ user }) => {
|
const ServerDetails = ({ user }) => {
|
||||||
const { serverName } = useParams();
|
const { serverName } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [server, setServer] = useState(null);
|
const location = useLocation();
|
||||||
const [loading, setLoading] = useState(true);
|
const status = location.state?.status;
|
||||||
const [error, setError] = useState(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchServer = async () => {
|
|
||||||
try {
|
|
||||||
const ApiResponse = await serviiApi.fetchServers();
|
|
||||||
const data = ApiResponse.message;
|
|
||||||
const foundServer = data.find(server => server.name === serverName);
|
|
||||||
|
|
||||||
if (foundServer) {
|
|
||||||
setServer(foundServer);
|
|
||||||
} else {
|
|
||||||
setError('Server not found');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching server:', error);
|
|
||||||
setError('Error fetching server');
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchServer();
|
|
||||||
}, [serverName]);
|
|
||||||
|
|
||||||
const validateInput = (input) => {
|
|
||||||
return input.replace(/[^a-zA-Z]/g, '');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (e) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
const validatedValue = name === 'motd' ? validateInput(value) : value;
|
|
||||||
setServer({ ...server, [name]: validatedValue });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSave = async () => {
|
|
||||||
try {
|
|
||||||
const props = [
|
|
||||||
['max-players', server.maxPlayers.toString()],
|
|
||||||
['motd', server.motd],
|
|
||||||
['difficulty', server.difficulty],
|
|
||||||
['enable-command-block', server.enableCommandBlock.toString()],
|
|
||||||
['gamemode', server.gamemode.toString()],
|
|
||||||
['hardcore', server.hardcore.toString()],
|
|
||||||
['online-mode', server.onlineMode.toString()],
|
|
||||||
['pvp', server.pvp.toString()]
|
|
||||||
];
|
|
||||||
|
|
||||||
await serviiApi.updateProperties(server.name, props);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error updating server:', error);
|
|
||||||
alert('Error updating server');
|
|
||||||
}
|
|
||||||
handleQuit();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleQuit = () => {
|
const handleQuit = () => {
|
||||||
navigate('/dashboard');
|
navigate('/dashboard');
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return <Loading />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<div className={styles.serverDetailsContainer}>
|
|
||||||
<Navbar user={user} />
|
|
||||||
<div className={styles.error}>
|
|
||||||
<h1>{error}</h1>
|
|
||||||
<button onClick={() => navigate('/dashboard')}>Retour au Dashboard</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.serverDetailsContainer}>
|
<>
|
||||||
<Navbar user={user} />
|
<Navbar user={user} />
|
||||||
<div className={styles.details}>
|
<div className={styles.container}>
|
||||||
<h1>Détails du serveur {server.name}</h1>
|
<div className={styles.sidebar}>
|
||||||
<div className={styles.formGroup}>
|
<div className={styles.userinfo}>
|
||||||
<label htmlFor="difficulty">Difficultée:</label>
|
<div className={styles.user}>
|
||||||
<select id="difficulty" name="difficulty" value={server.difficulty} onChange={handleChange}>
|
<p>{user.displayName}</p>
|
||||||
<option value="easy">Facile</option>
|
|
||||||
<option value="normal">Normal</option>
|
|
||||||
<option value="hard">Difficile</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label htmlFor="enableCommandBlock">Activation des commandes block:</label>
|
|
||||||
<select id="enableCommandBlock" name="enableCommandBlock" value={server.enableCommandBlock} onChange={handleChange}>
|
|
||||||
<option value="true">Activé</option>
|
|
||||||
<option value="false">Désactivé</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label htmlFor="gamemode">Gamemode:</label>
|
|
||||||
<select id="gamemode" name="gamemode" value={server.gamemode} onChange={handleChange}>
|
|
||||||
<option value="survival">Survie</option>
|
|
||||||
<option value="creative">Créatif</option>
|
|
||||||
<option value="adventure">Aventure</option>
|
|
||||||
<option value="spectator">Spectateur</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label htmlFor="hardcore">Hardcore:</label>
|
|
||||||
<select id="hardcore" name="hardcore" value={server.hardcore} onChange={handleChange}>
|
|
||||||
<option value="true">Activé</option>
|
|
||||||
<option value="false">Désactivé</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label htmlFor="maxPlayers">Max de joueurs:</label>
|
|
||||||
<input type="number" id="maxPlayers" name="maxPlayers" value={server.maxPlayers} onChange={handleChange} />
|
|
||||||
</div>
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label htmlFor="motd">Description du serveur:</label>
|
|
||||||
<input type="text" id="motd" name="motd" value={server.motd} onChange={handleChange} />
|
|
||||||
</div>
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label htmlFor="onlineMode">Mode en ligne:</label>
|
|
||||||
<select id="onlineMode" name="onlineMode" value={server.onlineMode} onChange={handleChange}>
|
|
||||||
<option value="true">Activé</option>
|
|
||||||
<option value="false">Désactivé</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label htmlFor="pvp">PVP:</label>
|
|
||||||
<select id="pvp" name="pvp" value={server.pvp} onChange={handleChange}>
|
|
||||||
<option value="true">Activé</option>
|
|
||||||
<option value="false">Désactivé</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<button className={styles.saveButton} onClick={handleSave}>Sauvegarder et quitter</button>
|
|
||||||
<button className={styles.quitButton} onClick={handleQuit}>Retour</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={styles.menu}>
|
||||||
|
<NavLink
|
||||||
|
to={`/server/${serverName}/options`}
|
||||||
|
className={({ isActive }) => isActive ? `${styles.menuItem} ${styles.active}` : styles.menuItem}>
|
||||||
|
<FaCogs /> Propriétés
|
||||||
|
</NavLink>
|
||||||
|
|
||||||
|
<NavLink
|
||||||
|
state={{ status }}
|
||||||
|
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>
|
||||||
|
<button className={styles.BackButton} onClick={handleQuit}>Retour</button>
|
||||||
|
</div>
|
||||||
|
<div className={styles.serverDetailsContainer}>
|
||||||
|
<Routes>
|
||||||
|
<Route path="options" element={<ServerProperties user={user} status={status} />} />
|
||||||
|
<Route path="console" element={<ServerConsole user={user} status={status} />} />
|
||||||
|
<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>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -162,4 +108,5 @@ ServerDetails.propTypes = {
|
|||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ServerDetails;
|
export default ServerDetails;
|
||||||
|
@ -1,133 +1,114 @@
|
|||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
min-height: calc(100vh - var(--navbar-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 20rem;
|
||||||
|
background-color: #100D25;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
padding-left: 0rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: fixed;
|
||||||
|
height: calc(100vh - var(--navbar-height));
|
||||||
|
top: var(--navbar-height);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuItem {
|
||||||
|
display: flex;
|
||||||
|
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: #1D1836;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuItem:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.user {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user p {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user small {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #9CA3AF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.menuItem:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuItem svg {
|
||||||
|
margin-right: 1rem;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BackButton {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 0.70rem 1.5rem;
|
||||||
|
background-color: #1D1836;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 20rem;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.serverDetailsContainer {
|
.serverDetailsContainer {
|
||||||
padding-top: var(--navbar-height);
|
margin-top: var(--navbar-height);
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 20rem;
|
||||||
|
padding-top: 1rem;
|
||||||
background-color: var(--main-bg-color);
|
background-color: var(--main-bg-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.details {
|
|
||||||
margin-top: 5rem;
|
.navbar {
|
||||||
padding: 3rem;
|
position: fixed;
|
||||||
padding-top: 0;
|
top: 0;
|
||||||
background-color: var(--card-bg-color);
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 60rem;
|
height: var(--navbar-height);
|
||||||
border-radius: 1.5rem;
|
background-color: var(--navbar-bg-color);
|
||||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
z-index: 1000;
|
||||||
box-sizing: border-box;
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.formGroup {
|
.userinfo {
|
||||||
margin-bottom: 2.5rem;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
|
||||||
|
|
||||||
.formGroup label {
|
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
font-size: 1.4rem;
|
|
||||||
color: var(--label-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.formGroup input,
|
|
||||||
.formGroup select {
|
|
||||||
width: 100%;
|
|
||||||
padding: 1.2rem;
|
|
||||||
height: auto;
|
|
||||||
background-color: var(--input-bg-color);
|
|
||||||
border: 1px solid var(--input-border-color);
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
color: var(--text-color);
|
|
||||||
font-size: 1.2rem;
|
|
||||||
line-height: 1.5rem;
|
|
||||||
box-sizing: border-box;
|
|
||||||
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formGroup input:focus,
|
|
||||||
.formGroup select:focus {
|
|
||||||
border-color: var(--focus-border-color);
|
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Chrome- styles */
|
|
||||||
@supports (-webkit-appearance: none) {
|
|
||||||
.formGroup select {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
background-image: url('data:image/svg+xml;utf8,<svg fill="%23ddd" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/></svg>');
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: right 1.2rem center;
|
|
||||||
background-size: 1rem;
|
|
||||||
padding-right: 3rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.saveButton,
|
|
||||||
.quitButton {
|
|
||||||
padding: 1.2rem 2.5rem;
|
|
||||||
color: var(--button-text-color);
|
|
||||||
border: none;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.3s ease, transform 0.3s ease;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.saveButton {
|
|
||||||
background-color: #05a771;
|
|
||||||
}
|
|
||||||
|
|
||||||
.saveButton:hover {
|
|
||||||
background-color: #05a77183;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quitButton {
|
|
||||||
background-color: gray;
|
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.error {
|
|
||||||
color: var(--error-color);
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.details h1 {
|
|
||||||
font-size: 2.5rem;
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
color: var(--header-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.details {
|
|
||||||
width: 90%;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formGroup input,
|
|
||||||
.formGroup select {
|
|
||||||
height: auto;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.saveButton,
|
|
||||||
.quitButton {
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.details h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
156
src/pages/ServerProperties/ServerProperties.jsx
Normal file
156
src/pages/ServerProperties/ServerProperties.jsx
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
|
import styles from './ServerProperties.module.scss';
|
||||||
|
import serviiApi from "../../service/api.tsx";
|
||||||
|
import Loading from '../Loading/loading';
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
const ServerProprieties = ({ user }) => {
|
||||||
|
const { serverName } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [server, setServer] = useState(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchServer = async () => {
|
||||||
|
try {
|
||||||
|
const ApiResponse = await serviiApi.fetchServers();
|
||||||
|
const data = ApiResponse.message;
|
||||||
|
const foundServer = data.find(server => server.name === serverName);
|
||||||
|
|
||||||
|
if (foundServer) {
|
||||||
|
setServer(foundServer);
|
||||||
|
} else {
|
||||||
|
setError('Server not found');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching server:', error);
|
||||||
|
setError('Error fetching server');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchServer();
|
||||||
|
}, [serverName]);
|
||||||
|
|
||||||
|
const validateInput = (input) => {
|
||||||
|
return input.replace(/[^a-zA-Z]/g, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
const validatedValue = name === 'motd' ? validateInput(value) : value;
|
||||||
|
setServer({ ...server, [name]: validatedValue });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
try {
|
||||||
|
const props = [
|
||||||
|
['max-players', server.maxPlayers.toString()],
|
||||||
|
['motd', server.motd],
|
||||||
|
['difficulty', server.difficulty],
|
||||||
|
['enable-command-block', server.enableCommandBlock.toString()],
|
||||||
|
['gamemode', server.gamemode.toString()],
|
||||||
|
['hardcore', server.hardcore.toString()],
|
||||||
|
['online-mode', server.onlineMode.toString()],
|
||||||
|
['pvp', server.pvp.toString()]
|
||||||
|
];
|
||||||
|
|
||||||
|
await serviiApi.updateProperties(server.name, props);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating server:', error);
|
||||||
|
alert('Error updating server');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className={styles.serverDetailsContainer}>
|
||||||
|
<div className={styles.error}>
|
||||||
|
<h1>{error}</h1>
|
||||||
|
<button onClick={() => navigate('/dashboard')}>Retour au Dashboard</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.serverDetailsContainer}>
|
||||||
|
<div className={styles.details}>
|
||||||
|
<h1>Propriétés du serveur {server.name}</h1>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="difficulty">Difficultée:</label>
|
||||||
|
<select id="difficulty" name="difficulty" value={server.difficulty} onChange={handleChange}>
|
||||||
|
<option value="easy">Facile</option>
|
||||||
|
<option value="normal">Normal</option>
|
||||||
|
<option value="hard">Difficile</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="enableCommandBlock">Activation des commandes block:</label>
|
||||||
|
<select id="enableCommandBlock" name="enableCommandBlock" value={server.enableCommandBlock} onChange={handleChange}>
|
||||||
|
<option value="true">Activé</option>
|
||||||
|
<option value="false">Désactivé</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="gamemode">Gamemode:</label>
|
||||||
|
<select id="gamemode" name="gamemode" value={server.gamemode} onChange={handleChange}>
|
||||||
|
<option value="survival">Survie</option>
|
||||||
|
<option value="creative">Créatif</option>
|
||||||
|
<option value="adventure">Aventure</option>
|
||||||
|
<option value="spectator">Spectateur</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="hardcore">Hardcore:</label>
|
||||||
|
<select id="hardcore" name="hardcore" value={server.hardcore} onChange={handleChange}>
|
||||||
|
<option value="true">Activé</option>
|
||||||
|
<option value="false">Désactivé</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="maxPlayers">Max de joueurs:</label>
|
||||||
|
<input type="number" id="maxPlayers" name="maxPlayers" value={server.maxPlayers} onChange={handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="motd">Description du serveur:</label>
|
||||||
|
<input type="text" id="motd" name="motd" value={server.motd} onChange={handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="onlineMode">Mode en ligne:</label>
|
||||||
|
<select id="onlineMode" name="onlineMode" value={server.onlineMode} onChange={handleChange}>
|
||||||
|
<option value="true">Activé</option>
|
||||||
|
<option value="false">Désactivé</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="pvp">PVP:</label>
|
||||||
|
<select id="pvp" name="pvp" value={server.pvp} onChange={handleChange}>
|
||||||
|
<option value="true">Activé</option>
|
||||||
|
<option value="false">Désactivé</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button className={styles.saveButton} onClick={handleSave}>Sauvegarder</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ServerProprieties.propTypes = {
|
||||||
|
user: PropTypes.oneOfType([
|
||||||
|
PropTypes.shape({
|
||||||
|
uid: PropTypes.string.isRequired,
|
||||||
|
displayName: PropTypes.string,
|
||||||
|
email: PropTypes.string,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServerProprieties;
|
133
src/pages/ServerProperties/ServerProperties.module.scss
Normal file
133
src/pages/ServerProperties/ServerProperties.module.scss
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
.serverDetailsContainer {
|
||||||
|
padding-top: var(--navbar-height);
|
||||||
|
background-color: var(--main-bg-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--text-color);
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
padding: 3rem;
|
||||||
|
padding-top: 0;
|
||||||
|
background-color: var(--card-bg-color);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 60rem;
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formGroup {
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formGroup label {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
color: var(--label-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.formGroup input,
|
||||||
|
.formGroup select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 1.2rem;
|
||||||
|
height: auto;
|
||||||
|
background-color: var(--input-bg-color);
|
||||||
|
border: 1px solid var(--input-border-color);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formGroup input:focus,
|
||||||
|
.formGroup select:focus {
|
||||||
|
border-color: var(--focus-border-color);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chrome- styles */
|
||||||
|
@supports (-webkit-appearance: none) {
|
||||||
|
.formGroup select {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url('data:image/svg+xml;utf8,<svg fill="%23ddd" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/></svg>');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 1.2rem center;
|
||||||
|
background-size: 1rem;
|
||||||
|
padding-right: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.saveButton,
|
||||||
|
.quitButton {
|
||||||
|
padding: 1.2rem 2.5rem;
|
||||||
|
color: var(--button-text-color);
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease, transform 0.3s ease;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.saveButton {
|
||||||
|
background-color: #05a771;
|
||||||
|
}
|
||||||
|
|
||||||
|
.saveButton:hover {
|
||||||
|
background-color: #05a77183;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quitButton {
|
||||||
|
background-color: gray;
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: var(--error-color);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
color: var(--header-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.details {
|
||||||
|
width: 90%;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formGroup input,
|
||||||
|
.formGroup select {
|
||||||
|
height: auto;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.saveButton,
|
||||||
|
.quitButton {
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -47,8 +47,15 @@ enum serviiRequest {
|
|||||||
serverStop = 'ServerStop',
|
serverStop = 'ServerStop',
|
||||||
updateProperty = 'UpdateProperties',
|
updateProperty = 'UpdateProperties',
|
||||||
command = 'Command',
|
command = 'Command',
|
||||||
|
fetchLogs = 'FetchLogs',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const nonToastableCalls: string[] = [
|
||||||
|
serviiRequest.fetchServers,
|
||||||
|
serviiRequest.fetchLogs,
|
||||||
|
];
|
||||||
|
|
||||||
class serviiApi {
|
class serviiApi {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
@ -65,13 +72,14 @@ 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 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!nonToastableCalls.includes(endpoint)) {
|
||||||
|
|
||||||
let toastType: 'success' | 'error' | 'info';
|
let toastType: 'success' | 'error' | 'info';
|
||||||
let toastColor: string;
|
|
||||||
|
|
||||||
if (status >= 200 && status < 300) {
|
if (status >= 200 && status < 300) {
|
||||||
toastType = 'success';
|
toastType = 'success';
|
||||||
@ -92,6 +100,7 @@ class serviiApi {
|
|||||||
theme: "light",
|
theme: "light",
|
||||||
transition: Bounce,
|
transition: Bounce,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return { return_code: status, message: json.message };
|
return { return_code: status, message: json.message };
|
||||||
}
|
}
|
||||||
@ -114,6 +123,11 @@ class serviiApi {
|
|||||||
return this.call(serviiRequest.fetchServers, payload);
|
return this.call(serviiRequest.fetchServers, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async fetchLogs(name: string): Promise<ApiResponse> {
|
||||||
|
const payload: ServerRequest = { token: this.token(), name: name };
|
||||||
|
return this.call(serviiRequest.fetchLogs, payload);
|
||||||
|
}
|
||||||
|
|
||||||
public static async accountCreate(): Promise<ApiResponse> {
|
public static async accountCreate(): Promise<ApiResponse> {
|
||||||
const payload: BaseRequest = { token: this.token() };
|
const payload: BaseRequest = { token: this.token() };
|
||||||
return this.call(serviiRequest.accountCreate, payload);
|
return this.call(serviiRequest.accountCreate, payload);
|
||||||
@ -150,7 +164,7 @@ 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> {
|
||||||
|
Loading…
Reference in New Issue
Block a user