Implemented player ping graph on Frontend BETA player page

Affects issues:
- Close #2258
This commit is contained in:
Aurora Lahtela 2022-05-21 09:25:27 +03:00
parent 52b8afe6cb
commit f36f1202fc
5 changed files with 127 additions and 17 deletions

View File

@ -24,6 +24,7 @@ import com.djrapitops.plan.delivery.formatting.Formatter;
import com.djrapitops.plan.delivery.formatting.Formatters;
import com.djrapitops.plan.delivery.rendering.html.Html;
import com.djrapitops.plan.delivery.rendering.json.graphs.Graphs;
import com.djrapitops.plan.delivery.rendering.json.graphs.line.PingGraph;
import com.djrapitops.plan.delivery.rendering.json.graphs.pie.WorldPie;
import com.djrapitops.plan.extension.implementation.results.ExtensionData;
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionPlayerDataQuery;
@ -46,6 +47,7 @@ import com.djrapitops.plan.storage.database.queries.containers.PlayerContainerQu
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
import com.djrapitops.plan.utilities.comparators.DateHolderRecentComparator;
import com.djrapitops.plan.utilities.java.Lists;
import com.djrapitops.plan.utilities.java.Maps;
import org.apache.commons.text.StringEscapeUtils;
import javax.inject.Inject;
@ -131,11 +133,26 @@ public class PlayerJSONCreator {
data.put("calendar_series", graphs.calendar().playerCalendar(player).getEntries());
data.put("server_pie_series", graphs.pie().serverPreferencePie(serverNames, worldTimesPerServer).getSlices());
data.put("server_pie_colors", pieColors);
data.put("ping_graph", createPingGraphJson(player));
data.put("first_day", 1); // Monday
data.put("extensions", playerExtensionData(playerUUID));
return data;
}
private Map<String, Object> createPingGraphJson(PlayerContainer player) {
PingGraph pingGraph = graphs.line().pingGraph(player.getUnsafe(PlayerKeys.PING));
return Maps.builder(String.class, Object.class)
.put("min_ping_series", pingGraph.getMinGraph().getPoints())
.put("avg_ping_series", pingGraph.getAvgGraph().getPoints())
.put("max_ping_series", pingGraph.getMaxGraph().getPoints())
.put("colors", Maps.builder(String.class, String.class)
.put("min", theme.getValue(ThemeVal.GRAPH_MIN_PING))
.put("avg", theme.getValue(ThemeVal.GRAPH_AVG_PING))
.put("max", theme.getValue(ThemeVal.GRAPH_MAX_PING))
.build())
.build();
}
private Map<String, Object> createOnlineActivityJSONMap(SessionsMutator sessionsMutator) {
long now = System.currentTimeMillis();
long monthAgo = now - TimeUnit.DAYS.toMillis(30L);

View File

@ -0,0 +1,55 @@
import React, {useEffect} from "react";
import {useTranslation} from "react-i18next";
import {useTheme} from "../../hooks/themeHook";
import Highcharts from "highcharts/highstock";
import {linegraphButtons, tooltip} from "../../util/graphs";
const PingGraph = ({data}) => {
const {t} = useTranslation();
const {graphTheming} = useTheme();
useEffect(() => {
const avgPingSeries = {
name: t('html.label.averagePing'),
type: 'spline',
tooltip: tooltip.twoDecimals,
data: data.avg_ping_series,
color: data.colors.avg
}
const maxPingSeries = {
name: t('html.label.maxPing'),
type: 'spline',
tooltip: tooltip.twoDecimals,
data: data.max_ping_series,
color: data.colors.max
}
const minPingSeries = {
name: t('html.label.minPing'),
type: 'spline',
tooltip: tooltip.twoDecimals,
data: data.min_ping_series,
color: data.colors.min
}
Highcharts.setOptions(graphTheming);
Highcharts.stockChart("ping-graph", {
rangeSelector: {
selected: 2,
buttons: linegraphButtons
},
yAxis: {
softMax: 2,
softMin: 0
},
title: {text: ''},
series: [avgPingSeries, maxPingSeries, minPingSeries]
})
}, [data, graphTheming, t])
return (
<div className="chart-area" id="ping-graph">
<span className="loader"/>
</div>
)
}
export default PingGraph

View File

@ -18,21 +18,30 @@ export const doSomeGetRequest = async (url, statusOptions) => {
}
}
} catch (e) {
for (const statusOption of statusOptions) {
if (e.response.status === statusOption.status) {
return {
data: undefined,
error: statusOption.get(response, e)
};
}
}
console.error(e);
if (e.response !== undefined) {
for (const statusOption of statusOptions) {
if (e.response.status === statusOption.status) {
return {
data: undefined,
error: statusOption.get(response, e)
};
}
}
return {
data: undefined,
error: {
message: e.message,
url,
data: e.response.data
}
};
}
return {
data: undefined,
error: {
message: e.message,
url,
data: e.response.data
url
}
};
}

View File

@ -38,10 +38,15 @@ export const localeService = {
init: async function () {
try {
const {data} = await fetchAvailableLocales();
this.defaultLanguage = data.defaultLanguage;
this.availableLanguages = data.languages;
this.languageVersions = data.languageVersions;
if (data !== undefined) {
this.defaultLanguage = data.defaultLanguage;
this.availableLanguages = data.languages;
this.languageVersions = data.languageVersions;
} else {
this.defaultLanguage = 'en'
this.availableLanguages = [];
this.languageVersions = [];
}
this.clientLocale = window.localStorage.getItem("locale");
if (!this.clientLocale) {

View File

@ -1,13 +1,32 @@
import React from "react";
import {Card, Col, Row} from "react-bootstrap-v5";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faCalendar, faHandPointer} from "@fortawesome/free-regular-svg-icons";
import {faHandPointer} from "@fortawesome/free-regular-svg-icons";
import Scrollable from "../components/Scrollable";
import {faNetworkWired} from "@fortawesome/free-solid-svg-icons";
import {faNetworkWired, faSignal} from "@fortawesome/free-solid-svg-icons";
import ServerPie from "../components/graphs/ServerPie";
import ServerAccordion from "../components/accordion/ServerAccordion";
import {usePlayer} from "./PlayerPage";
import {useTranslation} from "react-i18next";
import PingGraph from "../components/graphs/PingGraph";
const PingGraphCard = ({player}) => {
const {t} = useTranslation();
const hasPingData = Boolean(player.ping_graph.avg_ping_series.length);
return (
<Card>
<Card.Header>
<h6 className="col-black" style={{width: '100%'}}>
<Fa icon={faSignal} className="col-amber"/> {t('html.label.ping')}
</h6>
</Card.Header>
{hasPingData && <PingGraph data={player.ping_graph}/>}
{!hasPingData && <Card.Body><p>{t('generic.noData')}</p></Card.Body>}
</Card>
)
}
const ServersCard = ({player}) => {
const {t} = useTranslation();
@ -15,7 +34,7 @@ const ServersCard = ({player}) => {
<Card>
<Card.Header>
<h6 className="col-black" style={{width: '100%'}}>
<Fa icon={faCalendar} className="col-teal"/> {t('html.label.recentSessions')}
<Fa icon={faNetworkWired} className="col-light-green"/> {t('html.label.servers')}
<span className="float-end">
<Fa icon={faHandPointer}/> <small>{t('html.text.clickToExpand')}</small>
</span>
@ -50,6 +69,11 @@ const PlayerServers = () => {
const {player} = usePlayer();
return (
<section className="player_sessions">
<Row>
<Col lg={12}>
<PingGraphCard player={player}/>
</Col>
</Row>
<Row>
<Col lg={8}>
<ServersCard player={player}/>