Network sessions tab implemented in React

This commit is contained in:
Aurora Lahtela 2022-09-10 09:38:25 +03:00
parent b8258a38a6
commit adc4162217
12 changed files with 95 additions and 19 deletions

View File

@ -108,7 +108,7 @@ public enum HtmlLang implements Lang {
LABEL_AVG_ENTITIES("html.label.averageEntities", "Average Entities"),
LABEL_AVG_CHUNKS("html.label.averageChunks", "Average Chunks"),
LABEL_LOW_TPS("html.label.lowTpsSpikes", "Low TPS Spikes"),
LABEL_LOW_TPS_7_DAYS("html.label.lowTpsSpikes", "Low TPS Spikes (7 days)"),
LABEL_LOW_TPS_7_DAYS("html.label.lowTpsSpikes7days", "Low TPS Spikes (7 days)"),
LABEL_DOWNTIME("html.label.downtime", "Downtime"),
// Sessions tab #tab-sessions-overview
TITLE_RECENT_SESSIONS("html.label.recentSessions", "Recent Sessions"),

View File

@ -37,6 +37,7 @@ const ServerJoinAddresses = React.lazy(() => import("./views/server/ServerJoinAd
const NetworkPage = React.lazy(() => import("./views/layout/NetworkPage"));
const NetworkOverview = React.lazy(() => import("./views/network/NetworkOverview"));
const NetworkServers = React.lazy(() => import("./views/network/NetworkServers"));
const NetworkSessions = React.lazy(() => import("./views/network/NetworkSessions"));
const PlayersPage = React.lazy(() => import("./views/layout/PlayersPage"));
const AllPlayers = React.lazy(() => import("./views/players/AllPlayers"));
@ -119,6 +120,7 @@ function App() {
<Route path="" element={<Lazy><OverviewRedirect/></Lazy>}/>
<Route path="overview" element={<Lazy><NetworkOverview/></Lazy>}/>
<Route path="serversOverview" element={<Lazy><NetworkServers/></Lazy>}/>
<Route path="sessions" element={<Lazy><NetworkSessions/></Lazy>}/>
<Route path="players" element={<Lazy><AllPlayers/></Lazy>}/>
<Route path="plugins-overview" element={<Lazy><ServerPluginData/></Lazy>}/>
<Route path="plugins/:plugin" element={<Lazy><ServerWidePluginData/></Lazy>}/>

View File

@ -0,0 +1,28 @@
import {Card} from "react-bootstrap-v5";
import React from "react";
import {CardLoader} from "../../navigation/Loader";
import ServerPie from "../../graphs/ServerPie";
import {faNetworkWired} from "@fortawesome/free-solid-svg-icons";
import CardHeader from "../CardHeader";
import {useDataRequest} from "../../../hooks/dataFetchHook";
import {fetchServerPie} from "../../../service/networkService";
import {ErrorViewCard} from "../../../views/ErrorView";
const ServerPieCard = () => {
const {data, loadingError} = useDataRequest(fetchServerPie, []);
if (!data) return <CardLoader/>;
if (loadingError) return <ErrorViewCard error={loadingError}/>;
const series = data.server_pie_series_30d;
const colors = data.server_pie_colors;
return (
<Card>
<CardHeader icon={faNetworkWired} color={'teal'} label={'html.label.serverPlaytime30days'}/>
<ServerPie series={series} colors={colors}/>
</Card>
)
}
export default ServerPieCard;

View File

@ -1,6 +1,5 @@
import React from "react";
import InsightsFor30DaysCard from "../../common/InsightsFor30DaysCard";
import {useParams} from "react-router-dom";
import {useDataRequest} from "../../../../hooks/dataFetchHook";
import {fetchSessionOverview} from "../../../../service/serverService";
import {ErrorViewCard} from "../../../../views/ErrorView";
@ -8,29 +7,35 @@ import Datapoint from "../../../Datapoint";
import {useTranslation} from "react-i18next";
import {faGamepad, faUsers} from "@fortawesome/free-solid-svg-icons";
import {faClock} from "@fortawesome/free-regular-svg-icons";
import {fetchNetworkSessionsOverview} from "../../../../service/networkService";
const SessionInsightsCard = () => {
const SessionInsightsCard = ({identifier}) => {
const {t} = useTranslation();
const {identifier} = useParams();
const {data, loadingError} = useDataRequest(fetchSessionOverview, [identifier]);
const {
data,
loadingError
} = useDataRequest(identifier ? fetchSessionOverview : fetchNetworkSessionsOverview, [identifier]);
if (loadingError) return <ErrorViewCard error={loadingError}/>
const insights = data?.insights;
return (
<InsightsFor30DaysCard>
<Datapoint name={t('html.label.mostActiveGamemode')} icon={faGamepad} color="teal" bold
value={data?.insights.most_active_gamemode}
valueLabel={data?.insights.most_active_gamemode_perc}
value={insights?.most_active_gamemode}
valueLabel={insights?.most_active_gamemode_perc}
/>
<Datapoint name={t('html.label.serverOccupied')} icon={faUsers} color="teal"
value={'~' + data?.insights.server_occupied} valueLabel={data?.insights.server_occupied_perc}
value={insights?.server_occupied ? '~' + insights.server_occupied : undefined}
valueLabel={insights?.server_occupied_perc}
/>
<Datapoint name={t('html.label.playtime')} icon={faClock} color="green"
value={data?.insights.total_playtime}
value={insights?.total_playtime}
/>
<Datapoint name={t('html.label.afkTime')} icon={faClock} color="grey"
value={data?.insights.afk_time} valueLabel={data?.insights.afk_time_perc}
value={insights?.afk_time} valueLabel={insights?.afk_time_perc}
/>
</InsightsFor30DaysCard>
)

View File

@ -1,14 +1,10 @@
import React from "react";
import {useParams} from "react-router-dom";
import {useDataRequest} from "../../../../hooks/dataFetchHook";
import {fetchSessions} from "../../../../service/serverService";
import {ErrorViewCard} from "../../../../views/ErrorView";
import RecentSessionsCard from "../../common/RecentSessionsCard";
const ServerRecentSessionsCard = () => {
const {identifier} = useParams();
const ServerRecentSessionsCard = ({identifier}) => {
const {data, loadingError} = useDataRequest(fetchSessions, [identifier])
if (loadingError) return <ErrorViewCard error={loadingError}/>

View File

@ -5,6 +5,7 @@ import {withReducedSaturation} from "../../util/colors";
import Highcharts from 'highcharts/highmaps.js';
import map from '@highcharts/map-collection/custom/world.geo.json';
import Accessibility from "highcharts/modules/accessibility";
import NoDataDisplay from "highcharts/modules/no-data-to-display";
const GeolocationWorldMap = ({series, colors}) => {
const {t} = useTranslation();
@ -19,8 +20,10 @@ const GeolocationWorldMap = ({series, colors}) => {
joinBy: ['iso-a3', 'code']
};
NoDataDisplay(Highcharts);
Accessibility(Highcharts);
Highcharts.setOptions(graphTheming);
Highcharts.setOptions({lang: {noData: t('html.label.noDataToDisplay')}});
Highcharts.mapChart('countryWorldMap', {
chart: {
animation: true

View File

@ -5,6 +5,7 @@ import {formatTimeAmount} from '../../util/formatters'
import {useTheme} from "../../hooks/themeHook";
import {withReducedSaturation} from "../../util/colors";
import {useTranslation} from "react-i18next";
import NoDataDisplay from "highcharts/modules/no-data-to-display";
import Accessibility from "highcharts/modules/accessibility";
const ServerPie = ({colors, series}) => {
@ -21,8 +22,10 @@ const ServerPie = ({colors, series}) => {
data: series
};
NoDataDisplay(Highcharts);
Accessibility(Highcharts);
Highcharts.setOptions(graphTheming);
Highcharts.setOptions({lang: {noData: t('html.label.noDataToDisplay')}});
Highcharts.chart('server-pie', {
chart: {
backgroundColor: 'transparent',

View File

@ -51,7 +51,7 @@ export const useDataRequest = (fetchMethod, parameters) => {
console.warn(error);
datastore.finishUpdate(fetchMethod)
setLoadingError(error);
finishUpdate(new Date().getTime(), "Error", datastore.isSomethingUpdating());
finishUpdate(new Date().getTime(), "Error: " + error, datastore.isSomethingUpdating());
}
};

View File

@ -8,4 +8,14 @@ export const fetchNetworkOverview = async (updateRequested) => {
export const fetchServersOverview = async (updateRequested) => {
const url = `/v1/network/servers?timestamp=${updateRequested}`;
return doGetRequest(url);
}
export const fetchServerPie = async (timestamp) => {
const url = `/v1/graph?type=serverPie&timestamp=${timestamp}`;
return doGetRequest(url);
}
export const fetchNetworkSessionsOverview = async (timestamp) => {
const url = `/v1/network/sessionsOverview?timestamp=${timestamp}`;
return doGetRequest(url);
}

View File

@ -42,7 +42,8 @@ export const fetchExtensionData = async (timestamp, identifier) => {
}
export const fetchSessions = async (timestamp, identifier) => {
const url = `/v1/sessions?server=${identifier}&timestamp=${timestamp}`;
const url = identifier ? `/v1/sessions?server=${identifier}&timestamp=${timestamp}` :
`/v1/sessions?timestamp=${timestamp}`;
return doGetRequest(url);
}

View File

@ -0,0 +1,26 @@
import {Col, Row} from "react-bootstrap-v5";
import React from "react";
import ServerRecentSessionsCard from "../../components/cards/server/tables/ServerRecentSessionsCard";
import SessionInsightsCard from "../../components/cards/server/insights/SessionInsightsCard";
import LoadIn from "../../components/animation/LoadIn";
import ServerPieCard from "../../components/cards/common/ServerPieCard";
const NetworkSessions = () => {
return (
<LoadIn>
<section className="server_sessions">
<Row>
<Col lg={8}>
<ServerRecentSessionsCard identifier={undefined}/>
</Col>
<Col lg={4}>
<ServerPieCard/>
<SessionInsightsCard identifier={undefined}/>
</Col>
</Row>
</section>
</LoadIn>
)
}
export default NetworkSessions;

View File

@ -4,18 +4,20 @@ import ServerWorldPieCard from "../../components/cards/server/graphs/ServerWorld
import ServerRecentSessionsCard from "../../components/cards/server/tables/ServerRecentSessionsCard";
import SessionInsightsCard from "../../components/cards/server/insights/SessionInsightsCard";
import LoadIn from "../../components/animation/LoadIn";
import {useParams} from "react-router-dom";
const ServerSessions = () => {
const {identifier} = useParams();
return (
<LoadIn>
<section className="server_sessions">
<Row>
<Col lg={8}>
<ServerRecentSessionsCard/>
<ServerRecentSessionsCard identifier={identifier}/>
</Col>
<Col lg={4}>
<ServerWorldPieCard/>
<SessionInsightsCard/>
<SessionInsightsCard identifier={identifier}/>
</Col>
</Row>
</section>