Implemented player list to server page

Holy moly was it a big fight to get DataTables to cooperate
This commit is contained in:
Aurora Lahtela 2022-06-05 21:38:12 +03:00
parent 71424fa2ec
commit df0c0fa8a5
11 changed files with 162 additions and 20 deletions

View File

@ -4,6 +4,7 @@
"private": true,
"proxy": "https://localhost:8804",
"dependencies": {
"@fortawesome/fontawesome-free": "^6.1.1",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-brands-svg-icons": "^6.1.1",
"@fortawesome/free-regular-svg-icons": "^6.1.1",
@ -17,6 +18,9 @@
"@testing-library/user-event": "^13.2.1",
"axios": "^0.26.1",
"bootstrap": "^5.1.3",
"datatables.net": "^1.12.1",
"datatables.net-bs5": "^1.12.1",
"datatables.net-responsive-bs5": "^2.3.0",
"highcharts": "^9.3.2",
"i18next": "^21.6.14",
"i18next-chained-backend": "^3.0.2",

View File

@ -24,6 +24,7 @@ import OnlineActivity from "./views/server/OnlineActivity";
import ServerSessions from "./views/server/ServerSessions";
import ServerPvpPve from "./views/server/ServerPvpPve";
import PlayerbaseOverview from "./views/server/PlayerbaseOverview";
import ServerPlayers from "./views/server/ServerPlayers";
const OverviewRedirect = () => {
return (<Navigate to={"overview"} replace={true}/>)
@ -72,7 +73,7 @@ function App() {
<Route path="pvppve" element={<ServerPvpPve/>}/>
<Route path="playerbase" element={<PlayerbaseOverview/>}/>
<Route path="retention" element={<></>}/>
<Route path="players" element={<></>}/>
<Route path="players" element={<ServerPlayers/>}/>
<Route path="geolocations" element={<></>}/>
<Route path="performance" element={<></>}/>
<Route path="plugins-overview" element={<></>}/>

View File

@ -0,0 +1,41 @@
import {useTranslation} from "react-i18next";
import {Card} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import React, {useEffect, useState} from "react";
import {faUsers} from "@fortawesome/free-solid-svg-icons";
import DataTablesTable from "../../table/DataTablesTable";
import {CardLoader} from "../../navigation/Loader";
const PlayerListCard = ({data}) => {
const {t} = useTranslation();
const [options, setOptions] = useState(undefined);
useEffect(() => {
for (const row of data.data) {
row.name = row.name.replace('../player/', '../../player/');
}
setOptions({
responsive: true,
deferRender: true,
columns: data.columns,
data: data?.data,
order: [[5, "desc"]]
});
}, [data])
if (!options) return <CardLoader/>
return (
<Card>
<Card.Header>
<h6 className="col-black">
<Fa icon={faUsers} className="col-black"/> {t('html.label.playerList')}
</h6>
</Card.Header>
<DataTablesTable id={"players-table"} options={options}/>
</Card>
)
}
export default PlayerListCard;

View File

@ -10,8 +10,8 @@ import {faGamepad, faUsers} from "@fortawesome/free-solid-svg-icons";
import {faClock} from "@fortawesome/free-regular-svg-icons";
const SessionInsightsCard = () => {
const {identifier} = useParams();
const {t} = useTranslation();
const {identifier} = useParams();
const {data, loadingError} = useDataRequest(fetchSessionOverview, [identifier]);

View File

@ -1,4 +1,4 @@
import React, {useEffect, useState} from "react";
import React, {useCallback, useEffect, useState} from "react";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import logo from '../../Flaticon_circle.png';
import {faArrowLeft, faDoorOpen, faDownload, faPalette, faQuestionCircle} from "@fortawesome/free-solid-svg-icons";
@ -208,11 +208,11 @@ const Sidebar = ({items, showBackButton}) => {
}
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const updateWidth = () => setWindowWidth(window.innerWidth);
const updateWidth = useCallback(() => setWindowWidth(window.innerWidth), []);
useEffect(() => {
window.addEventListener('resize', updateWidth);
return () => window.removeEventListener('resize', updateWidth);
}, []);
}, [updateWidth]);
const collapseSidebar = () => setSidebarExpanded(windowWidth > 1350);
useEffect(collapseSidebar, [windowWidth, currentTab, setSidebarExpanded]);

View File

@ -0,0 +1,33 @@
import React, {useEffect, useState} from 'react';
import DataTable from 'datatables.net'
import 'datatables.net-bs5'
import 'datatables.net-responsive-bs5'
import 'datatables.net-bs5/css/dataTables.bootstrap5.min.css';
import 'datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css';
const DataTablesTable = ({id, options}) => {
const [dataTable, setDataTable] = useState(null);
useEffect(() => {
if (dataTable) {
dataTable.destroy();
setDataTable(null);
}
const createdDataTable = new DataTable(`#${id}`, options);
setDataTable(createdDataTable);
return () => {
if (dataTable) {
dataTable.clear();
dataTable.destroy();
}
};
}, [id, options, dataTable]);
return (
<table id={id} className="table table-bordered table-striped" style={{width: "100%"}}/>
)
};
export default DataTablesTable

View File

@ -2,7 +2,8 @@ import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import '@fortawesome/fontawesome-free/css/all.min.css'
import {library} from '@fortawesome/fontawesome-svg-core';
import {fas} from '@fortawesome/free-solid-svg-icons';
@ -20,16 +21,4 @@ localeService.init().then(() => ReactDOM.render(
<App/>
</React.StrictMode>,
document.getElementById('root')
));
// ReactDOM.render(
// <React.StrictMode>
// <App/>
// </React.StrictMode>,
// document.getElementById('root')
// );
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
));

View File

@ -44,7 +44,7 @@ export const localeService = {
this.languageVersions = data.languageVersions;
} else {
this.defaultLanguage = 'en'
this.availableLanguages = [];
this.availableLanguages = {};
this.languageVersions = [];
}

View File

@ -42,6 +42,12 @@ export const fetchKills = async (identifier) => {
return doGetRequest(url);
}
export const fetchPlayers = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/players?server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}
export const fetchPlayersOnlineGraph = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/graph?type=playersOnline&server=${identifier}&timestamp=${timestamp}`;

View File

@ -0,0 +1,26 @@
import React from 'react';
import {useDataRequest} from "../../hooks/dataFetchHook";
import {useParams} from "react-router-dom";
import {fetchPlayers} from "../../service/serverService";
import ErrorView from "../ErrorView";
import {Col, Row} from "react-bootstrap-v5";
import PlayerListCard from "../../components/cards/common/PlayerListCard";
const ServerPlayers = () => {
const {identifier} = useParams();
const {data, loadingError} = useDataRequest(fetchPlayers, [identifier]);
if (!data) return <></>;
if (loadingError) return <ErrorView error={loadingError}/>
return (
<Row>
<Col md={12}>
<PlayerListCard data={data}/>
</Col>
</Row>
)
};
export default ServerPlayers

View File

@ -1153,6 +1153,11 @@
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz#7dc996042d21fc1ae850e3173b5c67b0549f9105"
integrity sha512-wVn5WJPirFTnzN6tR95abCx+ocH+3IFLXAgyavnf9hUmN0CfWoDjPT/BAWsUVwSlYYVBeCLJxaqi7ZGe4uSjBA==
"@fortawesome/fontawesome-free@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz#bf5d45611ab74890be386712a0e5d998c65ee2a1"
integrity sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg==
"@fortawesome/fontawesome-svg-core@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.1.tgz#3424ec6182515951816be9b11665d67efdce5b5f"
@ -3465,6 +3470,38 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
datatables.net-bs5@>=1.11.3, datatables.net-bs5@^1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/datatables.net-bs5/-/datatables.net-bs5-1.12.1.tgz#b05d4bcaed77f6b77df0b50eaf1d5ec8e5d476bd"
integrity sha512-CcQCImfmH4YZk7I0aC0kTiNPyfHJ2ueGgOh/kFB9KqsZD8bNJy2A88gC6hn9A7TbmmenOL+K3Q1ti7G8yqi8SQ==
dependencies:
datatables.net ">=1.11.3"
jquery ">=1.7"
datatables.net-responsive-bs5@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/datatables.net-responsive-bs5/-/datatables.net-responsive-bs5-2.3.0.tgz#f92b79b7d5995c8c6cdc31ab0a725c240bcec448"
integrity sha512-OVe2y+WGbZNqwu0clpzjPGg85Y+8KW8pVXVZJEKKyHW0GYAU3Ewhk0f3ZdS0B6Al9Q4v3Gt6OzupVwuY5Ck1pA==
dependencies:
datatables.net-bs5 ">=1.11.3"
datatables.net-responsive ">=2.2.9"
jquery ">=1.7"
datatables.net-responsive@>=2.2.9:
version "2.3.0"
resolved "https://registry.yarnpkg.com/datatables.net-responsive/-/datatables.net-responsive-2.3.0.tgz#2b8d894af5456f8c8a320eeac5e837a24d84e033"
integrity sha512-QA5QsD1sJQRQ7/IFi3rSd33O84f/Augz2KnaehjfuEANtK4KeC9Lbkut5tPuuMcK4jOpQPOOPYTbmfrt+tfh9w==
dependencies:
datatables.net ">=1.11.3"
jquery ">=1.7"
datatables.net@>=1.11.3, datatables.net@^1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.12.1.tgz#3e625e49a3341f605b0efb519fae94e37b278f24"
integrity sha512-e6XAMUoV41JdQPS/r9YRfRcmTPcCVvyZbWI+xog1Zg+kjVliMQbEkvWK5XFItmi64Cvwg+IqsZbTUJ1KSY3umA==
dependencies:
jquery ">=1.7"
debug@2.6.9, debug@^2.6.0, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -5634,6 +5671,11 @@ jest@^27.4.3:
import-local "^3.0.2"
jest-cli "^27.5.1"
jquery@>=1.7:
version "3.6.0"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470"
integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"