Implement rest of Performance tab (graphs) in React

Adds all graphs and their respective tabs.
Extra:
- Zero baselined charts where it made sense
- Increased performance graph card height to improve readability

Affects issues:
- Close #2270
This commit is contained in:
Aurora Lahtela 2022-08-20 15:53:34 +03:00
parent cc217b5ccd
commit a43a2ae581
13 changed files with 679 additions and 21 deletions

View File

@ -94,7 +94,9 @@ public enum HtmlLang implements Lang {
TITLE_AS_NUMBERS("html.label.asNumbers", "as Numbers"),
LABEL_AVG_TPS("html.label.averageTps", "Average TPS"),
LABEL_AVG_PLAYERS("html.label.averagePlayers", "Average Players"),
LABEL_CPU("html.label.cpuUsage", "CPU Usage"),
LABEL_AVG_CPU("html.label.averageCpuUsage", "Average CPU Usage"),
LABEL_RAM("html.label.ramUsage", "RAM Usage"),
LABEL_AVG_RAM("html.label.averageRamUsage", "Average RAM Usage"),
LABEL_AVG_ENTITIES("html.label.averageEntities", "Average Entities"),
LABEL_AVG_CHUNKS("html.label.averageChunks", "Average Chunks"),

View File

@ -1,6 +1,6 @@
import {useParams} from "react-router-dom";
import {useDataRequest} from "../../../../hooks/dataFetchHook";
import {fetchOptimizedPerformance} from "../../../../service/serverService";
import {fetchOptimizedPerformance, fetchPingGraph} from "../../../../service/serverService";
import {ErrorViewBody} from "../../../../views/ErrorView";
import {useTranslation} from "react-i18next";
import {Card} from "react-bootstrap-v5";
@ -8,13 +8,54 @@ import CardTabs from "../../../CardTabs";
import {faGears, faHdd, faMap, faMicrochip, faSignal, faTachometerAlt} from "@fortawesome/free-solid-svg-icons";
import React, {useEffect, useState} from "react";
import {ChartLoader} from "../../../navigation/Loader";
import AllPerformanceGraph from "../../../graphs/performance/AllPerformanceGraph";
import TpsPerformanceGraph from "../../../graphs/performance/TpsPerformanceGraph";
import CpuRamPerformanceGraph from "../../../graphs/performance/CpuRamPerformanceGraph";
import WorldPerformanceGraph from "../../../graphs/performance/WorldPerformanceGraph";
import DiskPerformanceGraph from "../../../graphs/performance/DiskPerformanceGraph";
import PingGraph from "../../../graphs/performance/PingGraph";
const PunchCardTab = ({data, loadingError}) => {
const AllGraphTab = ({data, dataSeries, loadingError}) => {
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!data) return <ChartLoader/>;
if (!dataSeries) return <ChartLoader style={{height: "450px"}}/>;
return <ChartLoader/>
return <AllPerformanceGraph id="server-performance-all-chart" data={data} dataSeries={dataSeries}/>
}
const TpsGraphTab = ({data, dataSeries, loadingError}) => {
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!dataSeries) return <ChartLoader style={{height: "450px"}}/>;
return <TpsPerformanceGraph id="server-performance-tps-chart" data={data} dataSeries={dataSeries}/>
}
const CpuRamGraphTab = ({data, dataSeries, loadingError}) => {
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!dataSeries) return <ChartLoader style={{height: "450px"}}/>;
return <CpuRamPerformanceGraph id="server-performance-cpuram-chart" data={data} dataSeries={dataSeries}/>
}
const WorldGraphTab = ({data, dataSeries, loadingError}) => {
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!dataSeries) return <ChartLoader style={{height: "450px"}}/>;
return <WorldPerformanceGraph id="server-performance-world-chart" data={data} dataSeries={dataSeries}/>
}
const DiskGraphTab = ({data, dataSeries, loadingError}) => {
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!dataSeries) return <ChartLoader style={{height: "450px"}}/>;
return <DiskPerformanceGraph id="server-performance-disk-chart" data={data} dataSeries={dataSeries}/>
}
const PingGraphTab = ({identifier}) => {
const {data, loadingError} = useDataRequest(fetchPingGraph, [identifier]);
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!data) return <ChartLoader style={{height: "450px"}}/>;
return <PingGraph id="server-performance-ping-chart" data={data}/>;
}
function mapToDataSeries(performanceData) {
@ -63,30 +104,30 @@ const PerformanceGraphsCard = () => {
useEffect(() => {
if (data) {
mapToDataSeries(data).then(parsed => setParsedData(parsed))
mapToDataSeries(data.values).then(parsed => setParsedData(parsed))
}
}, [data]);
}, [data, setParsedData]);
return <Card>
<CardTabs tabs={[
{
name: t('html.label.all'), icon: faGears, color: 'blue-grey', href: 'all',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
element: <AllGraphTab data={data} dataSeries={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.tps'), icon: faTachometerAlt, color: 'red', href: 'tps',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
element: <TpsGraphTab data={data} dataSeries={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.cpuRam'), icon: faMicrochip, color: 'light-green', href: 'cpu-ram',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
element: <CpuRamGraphTab data={data} dataSeries={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.world'), icon: faMap, color: 'purple', href: 'world-load',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
element: <WorldGraphTab data={data} dataSeries={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.ping'), icon: faSignal, color: 'amber', href: 'ping',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
element: <PingGraphTab identifier={identifier}/>
}, {
name: t('html.label.diskSpace'), icon: faHdd, color: 'green', href: 'disk',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
element: <DiskGraphTab data={data} dataSeries={parsedData} loadingError={loadingError}/>
},
]}/>
</Card>

View File

@ -3,7 +3,7 @@ import {useTranslation} from "react-i18next";
import {tooltip} from "../../util/graphs";
import LineGraph from "./LineGraph";
const PingGraph = ({data}) => {
const PlayerPingGraph = ({data}) => {
const {t} = useTranslation();
const [series, setSeries] = useState([]);
@ -37,4 +37,4 @@ const PingGraph = ({data}) => {
)
}
export default PingGraph
export default PlayerPingGraph

View File

@ -0,0 +1,182 @@
import React, {useCallback, useEffect} from 'react';
import {linegraphButtons, tooltip} from "../../../util/graphs";
import Highcharts from "highcharts/highstock";
import NoDataDisplay from "highcharts/modules/no-data-to-display"
import {useTranslation} from "react-i18next";
import {useTheme} from "../../../hooks/themeHook";
import {withReducedSaturation} from "../../../util/colors";
const yAxis = [
{
labels: {
formatter: function () {
return this.value + ' P';
}
},
softMin: 0,
softMax: 2
}, {
opposite: true,
labels: {
formatter: function () {
return this.value + ' TPS';
}
},
softMin: 0,
softMax: 20
}, {
opposite: true,
labels: {
formatter: function () {
return this.value + '%';
}
},
softMin: 0,
softMax: 100
}, {
labels: {
formatter: function () {
return this.value + ' MB';
}
},
softMin: 0
}, {
opposite: true,
labels: {
formatter: function () {
return this.value + ' E';
}
},
softMin: 0,
softMax: 2
}, {
labels: {
formatter: function () {
return this.value + ' C';
}
},
softMin: 0
}
]
const AllPerformanceGraph = ({id, data, dataSeries}) => {
const {t} = useTranslation();
const {graphTheming, nightModeEnabled} = useTheme();
const onResize = useCallback(() => {
let chartElement = document.getElementById(id);
let chartId = chartElement?.getAttribute('data-highcharts-chart');
const chart = chartId !== undefined ? Highcharts.charts[chartId] : undefined;
if (chart && chart.yAxis && chart.yAxis.length) {
const newWidth = window.innerWidth
chart.yAxis[0].update({labels: {enabled: newWidth >= 900}});
chart.yAxis[1].update({labels: {enabled: newWidth >= 900}});
chart.yAxis[2].update({labels: {enabled: newWidth >= 1000}});
chart.yAxis[3].update({labels: {enabled: newWidth >= 1000}});
chart.yAxis[4].update({labels: {enabled: newWidth >= 1400}});
chart.yAxis[5].update({labels: {enabled: newWidth >= 1400}});
}
}, [id])
useEffect(() => {
window.addEventListener("resize", onResize);
return () => {
window.removeEventListener("resize", onResize);
}
}, [onResize])
useEffect(() => {
const zones = {
tps: [{
value: data.zones.tpsThresholdMed,
color: nightModeEnabled ? withReducedSaturation(data.colors.low) : data.colors.low
}, {
value: data.zones.tpsThresholdHigh,
color: nightModeEnabled ? withReducedSaturation(data.colors.med) : data.colors.med
}, {
value: 30,
color: nightModeEnabled ? withReducedSaturation(data.colors.high) : data.colors.high
}]
};
const spline = 'spline'
const series = {
playersOnline: {
name: t('html.label.playersOnline'),
type: 'areaspline',
tooltip: tooltip.zeroDecimals,
data: dataSeries.playersOnline,
color: nightModeEnabled ? withReducedSaturation(data.colors.playersOnline) : data.colors.playersOnline,
yAxis: 0
}, tps: {
name: t('html.label.tps'),
type: spline,
color: nightModeEnabled ? withReducedSaturation(data.colors.high) : data.colors.high,
zones: zones.tps,
tooltip: tooltip.twoDecimals,
data: dataSeries.tps,
yAxis: 1
}, cpu: {
name: t('html.label.cpu'),
type: spline,
tooltip: tooltip.twoDecimals,
data: dataSeries.cpu,
color: nightModeEnabled ? withReducedSaturation(data.colors.cpu) : data.colors.cpu,
yAxis: 2
}, ram: {
name: t('html.label.ram'),
type: spline,
tooltip: tooltip.zeroDecimals,
data: dataSeries.ram,
color: nightModeEnabled ? withReducedSaturation(data.colors.ram) : data.colors.ram,
yAxis: 3
}, entities: {
name: t('html.label.loadedEntities'),
type: spline,
tooltip: tooltip.zeroDecimals,
data: dataSeries.entities,
color: nightModeEnabled ? withReducedSaturation(data.colors.entities) : data.colors.entities,
yAxis: 4
}, chunks: {
name: t('html.label.loadedChunks'),
type: spline,
tooltip: tooltip.zeroDecimals,
data: dataSeries.chunks,
color: nightModeEnabled ? withReducedSaturation(data.colors.chunks) : data.colors.chunks,
yAxis: 5
}
};
NoDataDisplay(Highcharts);
Highcharts.setOptions({lang: {noData: t('html.label.noDataToDisplay')}})
Highcharts.setOptions(graphTheming);
Highcharts.stockChart(id, {
rangeSelector: {
selected: 2,
buttons: linegraphButtons
},
yAxis,
title: {text: ''},
plotOptions: {
areaspline: {
fillOpacity: 0.4
}
},
legend: {
enabled: true
},
series: [series.playersOnline, series.tps, series.cpu, series.ram, series.entities, series.chunks]
});
}, [data, dataSeries, graphTheming, nightModeEnabled, id, t])
return (
<div className="chart-area" style={{height: "450px"}} id={id}>
<span className="loader"/>
</div>
)
};
export default AllPerformanceGraph

View File

@ -0,0 +1,94 @@
import React, {useEffect} from 'react';
import {linegraphButtons, tooltip} from "../../../util/graphs";
import Highcharts from "highcharts/highstock";
import NoDataDisplay from "highcharts/modules/no-data-to-display"
import {useTranslation} from "react-i18next";
import {useTheme} from "../../../hooks/themeHook";
import {withReducedSaturation} from "../../../util/colors";
const CpuRamPerformanceGraph = ({id, data, dataSeries}) => {
const {t} = useTranslation();
const {graphTheming, nightModeEnabled} = useTheme();
useEffect(() => {
const spline = 'spline'
const series = {
playersOnline: {
name: t('html.label.playersOnline'),
type: 'areaspline',
tooltip: tooltip.zeroDecimals,
data: dataSeries.playersOnline,
color: nightModeEnabled ? withReducedSaturation(data.colors.playersOnline) : data.colors.playersOnline,
yAxis: 0
}, cpu: {
name: t('html.label.cpu'),
type: spline,
tooltip: tooltip.twoDecimals,
data: dataSeries.cpu,
color: nightModeEnabled ? withReducedSaturation(data.colors.cpu) : data.colors.cpu,
yAxis: 1
}, ram: {
name: t('html.label.ram'),
type: spline,
tooltip: tooltip.zeroDecimals,
data: dataSeries.ram,
color: nightModeEnabled ? withReducedSaturation(data.colors.ram) : data.colors.ram,
yAxis: 2
}
};
NoDataDisplay(Highcharts);
Highcharts.setOptions({lang: {noData: t('html.label.noDataToDisplay')}})
Highcharts.setOptions(graphTheming);
Highcharts.stockChart(id, {
rangeSelector: {
selected: 1, // TODO Sync range selectors state
buttons: linegraphButtons
},
yAxis: [{
labels: {
formatter: function () {
return this.value + ' ' + t('html.unit.players')
}
},
softMin: 0,
softMax: 2
}, {
labels: {
formatter: function () {
return this.value + ' %'
}
},
softMin: 0,
softMax: 100
}, {
labels: {
formatter: function () {
return this.value + ' MB'
}
},
softMin: 0
}],
title: {text: ''},
plotOptions: {
areaspline: {
fillOpacity: 0.4
}
},
legend: {
enabled: true
},
series: [series.playersOnline, series.cpu, series.ram]
});
}, [data, dataSeries, graphTheming, nightModeEnabled, id, t])
return (
<div className="chart-area" style={{height: "450px"}} id={id}>
<span className="loader"/>
</div>
)
};
export default CpuRamPerformanceGraph

View File

@ -0,0 +1,75 @@
import React, {useEffect} from 'react';
import {linegraphButtons, tooltip} from "../../../util/graphs";
import Highcharts from "highcharts/highstock";
import NoDataDisplay from "highcharts/modules/no-data-to-display"
import {useTranslation} from "react-i18next";
import {useTheme} from "../../../hooks/themeHook";
import {withReducedSaturation} from "../../../util/colors";
const DiskPerformanceGraph = ({id, data, dataSeries}) => {
const {t} = useTranslation();
const {graphTheming, nightModeEnabled} = useTheme();
useEffect(() => {
const zones = {
disk: [{
value: data.zones.diskThresholdMed,
color: nightModeEnabled ? withReducedSaturation(data.colors.low) : data.colors.low
}, {
value: data.zones.diskThresholdHigh,
color: nightModeEnabled ? withReducedSaturation(data.colors.med) : data.colors.med
}, {
value: Number.MAX_VALUE,
color: nightModeEnabled ? withReducedSaturation(data.colors.high) : data.colors.high
}]
};
const series = {
disk: {
name: t('html.label.disk'),
type: 'areaspline',
color: nightModeEnabled ? withReducedSaturation(data.colors.high) : data.colors.high,
zones: zones.disk,
tooltip: tooltip.zeroDecimals,
data: dataSeries.disk
}
};
NoDataDisplay(Highcharts);
Highcharts.setOptions({lang: {noData: t('html.label.noDataToDisplay')}})
Highcharts.setOptions(graphTheming);
Highcharts.stockChart(id, {
rangeSelector: {
selected: 2,
buttons: linegraphButtons
},
yAxis: {
labels: {
formatter: function () {
return this.value + ' MB';
}
},
softMin: 0
},
title: {text: ''},
plotOptions: {
areaspline: {
fillOpacity: 0.4
}
},
legend: {
enabled: true
},
series: [series.disk]
});
}, [data, dataSeries, graphTheming, nightModeEnabled, id, t])
return (
<div className="chart-area" style={{height: "450px"}} id={id}>
<span className="loader"/>
</div>
)
};
export default DiskPerformanceGraph

View File

@ -0,0 +1,72 @@
import React, {useEffect} from 'react';
import {linegraphButtons, tooltip} from "../../../util/graphs";
import Highcharts from "highcharts/highstock";
import NoDataDisplay from "highcharts/modules/no-data-to-display"
import {useTranslation} from "react-i18next";
import {useTheme} from "../../../hooks/themeHook";
import {withReducedSaturation} from "../../../util/colors";
const PingGraph = ({id, data}) => {
const {t} = useTranslation();
const {graphTheming, nightModeEnabled} = useTheme();
useEffect(() => {
const spline = 'spline'
const series = {
avgPing: {
name: t('html.label.averagePing'),
type: spline,
tooltip: tooltip.twoDecimals,
data: data.avg_ping_series,
color: nightModeEnabled ? withReducedSaturation(data.colors.avg) : data.colors.avg,
},
maxPing: {
name: t('html.label.worstPing'),
type: spline,
tooltip: tooltip.zeroDecimals,
data: data.max_ping_series,
color: nightModeEnabled ? withReducedSaturation(data.colors.max) : data.colors.max,
},
minPing: {
name: t('html.label.bestPing'),
type: spline,
tooltip: tooltip.zeroDecimals,
data: data.min_ping_series,
color: nightModeEnabled ? withReducedSaturation(data.colors.min) : data.colors.min,
}
};
NoDataDisplay(Highcharts);
Highcharts.setOptions({lang: {noData: t('html.label.noDataToDisplay')}})
Highcharts.setOptions(graphTheming);
Highcharts.stockChart(id, {
rangeSelector: {
selected: 2,
buttons: linegraphButtons
},
yAxis: {
labels: {
formatter: function () {
return this.value + ' ms'
}
},
softMin: 0
},
title: {text: ''},
legend: {
enabled: true
},
series: [series.avgPing, series.maxPing, series.minPing]
});
}, [data, graphTheming, nightModeEnabled, id, t])
return (
<div className="chart-area" style={{height: "450px"}} id={id}>
<span className="loader"/>
</div>
)
};
export default PingGraph

View File

@ -0,0 +1,91 @@
import React, {useEffect} from 'react';
import {linegraphButtons, tooltip} from "../../../util/graphs";
import Highcharts from "highcharts/highstock";
import NoDataDisplay from "highcharts/modules/no-data-to-display"
import {useTranslation} from "react-i18next";
import {useTheme} from "../../../hooks/themeHook";
import {withReducedSaturation} from "../../../util/colors";
const TpsPerformanceGraph = ({id, data, dataSeries}) => {
const {t} = useTranslation();
const {graphTheming, nightModeEnabled} = useTheme();
useEffect(() => {
const zones = {
tps: [{
value: data.zones.tpsThresholdMed,
color: nightModeEnabled ? withReducedSaturation(data.colors.low) : data.colors.low
}, {
value: data.zones.tpsThresholdHigh,
color: nightModeEnabled ? withReducedSaturation(data.colors.med) : data.colors.med
}, {
value: 30,
color: nightModeEnabled ? withReducedSaturation(data.colors.high) : data.colors.high
}]
};
const spline = 'spline'
const series = {
playersOnline: {
name: t('html.label.playersOnline'),
type: 'areaspline',
tooltip: tooltip.zeroDecimals,
data: dataSeries.playersOnline,
color: nightModeEnabled ? withReducedSaturation(data.colors.playersOnline) : data.colors.playersOnline,
yAxis: 0
}, tps: {
name: t('html.label.tps'),
type: spline,
color: nightModeEnabled ? withReducedSaturation(data.colors.high) : data.colors.high,
zones: zones.tps,
tooltip: tooltip.twoDecimals,
data: dataSeries.tps,
yAxis: 1
}
};
NoDataDisplay(Highcharts);
Highcharts.setOptions({lang: {noData: t('html.label.noDataToDisplay')}})
Highcharts.setOptions(graphTheming);
Highcharts.stockChart(id, {
rangeSelector: {
selected: 1,
buttons: linegraphButtons
},
yAxis: [{
labels: {
formatter: function () {
return this.value + ' ' + t('html.unit.players')
}
},
softMin: 0,
softMax: 2
}, {
labels: {
formatter: function () {
return this.value + ' ' + t('html.label.tps')
}
}
}],
title: {text: ''},
plotOptions: {
areaspline: {
fillOpacity: 0.4
}
},
legend: {
enabled: true
},
series: [series.playersOnline, series.tps]
});
}, [data, dataSeries, graphTheming, nightModeEnabled, id, t])
return (
<div className="chart-area" style={{height: "450px"}} id={id}>
<span className="loader"/>
</div>
)
};
export default TpsPerformanceGraph

View File

@ -0,0 +1,93 @@
import React, {useEffect} from 'react';
import {linegraphButtons, tooltip} from "../../../util/graphs";
import Highcharts from "highcharts/highstock";
import NoDataDisplay from "highcharts/modules/no-data-to-display"
import {useTranslation} from "react-i18next";
import {useTheme} from "../../../hooks/themeHook";
import {withReducedSaturation} from "../../../util/colors";
const WorldPerformanceGraph = ({id, data, dataSeries}) => {
const {t} = useTranslation();
const {graphTheming, nightModeEnabled} = useTheme();
useEffect(() => {
const spline = 'spline'
const series = {
playersOnline: {
name: t('html.label.playersOnline'),
type: 'areaspline',
tooltip: tooltip.zeroDecimals,
data: dataSeries.playersOnline,
color: nightModeEnabled ? withReducedSaturation(data.colors.playersOnline) : data.colors.playersOnline,
yAxis: 0
}, entities: {
name: t('html.label.loadedEntities'),
type: spline,
tooltip: tooltip.zeroDecimals,
data: dataSeries.entities,
color: nightModeEnabled ? withReducedSaturation(data.colors.entities) : data.colors.entities,
yAxis: 1
}, chunks: {
name: t('html.label.loadedChunks'),
type: spline,
tooltip: tooltip.zeroDecimals,
data: dataSeries.chunks,
color: nightModeEnabled ? withReducedSaturation(data.colors.chunks) : data.colors.chunks,
yAxis: 2
}
};
NoDataDisplay(Highcharts);
Highcharts.setOptions({lang: {noData: t('html.label.noDataToDisplay')}})
Highcharts.setOptions(graphTheming);
Highcharts.stockChart(id, {
rangeSelector: {
selected: 2,
buttons: linegraphButtons
},
yAxis: [{
labels: {
formatter: function () {
return this.value + ' ' + t('html.unit.players')
}
},
softMin: 0,
softMax: 2
}, {
labels: {
formatter: function () {
return this.value + ' ' + t('html.label.entities')
}
},
softMin: 0,
}, {
labels: {
formatter: function () {
return this.value + ' ' + t('html.unit.chunks')
}
},
softMin: 0,
}],
title: {text: ''},
plotOptions: {
areaspline: {
fillOpacity: 0.4
}
},
legend: {
enabled: true
},
series: [series.playersOnline, series.entities, series.chunks]
});
}, [data, dataSeries, graphTheming, nightModeEnabled, id, t])
return (
<div className="chart-area" style={{height: "450px"}} id={id}>
<span className="loader"/>
</div>
)
};
export default WorldPerformanceGraph

View File

@ -14,8 +14,8 @@ export const CardLoader = () => {
)
}
export const ChartLoader = () => {
return <div className="chart-area loading">
export const ChartLoader = ({style}) => {
return <div className="chart-area loading" style={style}>
<Loader/>
</div>
}

View File

@ -19,8 +19,10 @@ export const NavigationContextProvider = ({children}) => {
const finishUpdate = useCallback((date, formatted) => {
// TODO Logic to retry if received data is too old
setLastUpdate({date, formatted});
setUpdating(false);
if (date) {
setLastUpdate({date, formatted});
setUpdating(false);
}
}, [setLastUpdate, setUpdating]);
const toggleSidebar = useCallback(() => {

View File

@ -119,3 +119,9 @@ export const fetchOptimizedPerformance = async (identifier) => {
const url = `/v1/graph?type=optimizedPerformance&server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}
export const fetchPingGraph = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/graph?type=aggregatedPing&server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}

View File

@ -8,7 +8,7 @@ import ServerPie from "../../components/graphs/ServerPie";
import ServerAccordion from "../../components/accordion/ServerAccordion";
import {usePlayer} from "../layout/PlayerPage";
import {useTranslation} from "react-i18next";
import PingGraph from "../../components/graphs/PingGraph";
import PlayerPingGraph from "../../components/graphs/PlayerPingGraph";
import LoadIn from "../../components/animation/LoadIn";
const PingGraphCard = ({player}) => {
@ -23,7 +23,7 @@ const PingGraphCard = ({player}) => {
<Fa icon={faSignal} className="col-amber"/> {t('html.label.ping')}
</h6>
</Card.Header>
{hasPingData && <PingGraph data={player.ping_graph}/>}
{hasPingData && <PlayerPingGraph data={player.ping_graph}/>}
{!hasPingData && <Card.Body><p>{t('generic.noData')}</p></Card.Body>}
</Card>
)