diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java
index e6071393b..c2c2afe39 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java
@@ -320,9 +320,9 @@ public class JSONFactory {
tableEntries.add(Maps.builder(String.class, Object.class)
.put("country", geolocation)
- .put("avg_ping", formatters.decimals().apply(ping.getAverage()) + " ms")
- .put("min_ping", ping.getMin() + " ms")
- .put("max_ping", ping.getMax() + " ms")
+ .put("avg_ping", ping.getAverage())
+ .put("min_ping", ping.getMin())
+ .put("max_ping", ping.getMax())
.build());
}
return tableEntries;
diff --git a/Plan/react/dashboard/src/components/table/DataTablesTable.jsx b/Plan/react/dashboard/src/components/table/DataTablesTable.jsx
index b20119bd6..3d460e485 100644
--- a/Plan/react/dashboard/src/components/table/DataTablesTable.jsx
+++ b/Plan/react/dashboard/src/components/table/DataTablesTable.jsx
@@ -104,7 +104,7 @@ const ExportMenu = ({matchingData}) => {
filename: "data-" + new Date().toISOString().replaceAll(":", '').substring(0, 17)
});
const csvOutput = generateCsv(csvConfig)(rows);
- await download(csvConfig)(csvOutput);
+ download(csvConfig)(csvOutput);
setGenerating(false)
}, [matchingData, setGenerating])
@@ -125,7 +125,7 @@ const ExportMenu = ({matchingData}) => {
)
}
-const DataTablesTable = ({id, rowKeyFunction, options, colorClass}) => {
+const DataTablesTable = ({id, rowKeyFunction, options, colorClass, expandComponent}) => {
const {t} = useTranslation();
const {nightModeEnabled} = useTheme();
@@ -158,7 +158,7 @@ const DataTablesTable = ({id, rowKeyFunction, options, colorClass}) => {
const visibleColumns = visibleColumnIndexes.map(i => columns[i]);
const invisibleColumns = columns.filter((c, i) => !visibleColumnIndexes.includes(i));
- const [selectedPaginationCount, setSelectedPaginationCount] = useState(0)
+ const [selectedPaginationCount, setSelectedPaginationCount] = useState(options.paginationCount || 0)
const paginationCountOptions = ["10", "25", "100"];
const paginationCount = Number(paginationCountOptions[selectedPaginationCount]);
@@ -233,7 +233,7 @@ const DataTablesTable = ({id, rowKeyFunction, options, colorClass}) => {
return () => window.removeEventListener('resize', onResize);
}, [onResize]);
- const someColumnsHidden = columns.length !== visibleColumns.length;
+ const someColumnsHidden = expandComponent || columns.length !== visibleColumns.length;
return (
@@ -306,6 +306,7 @@ const DataTablesTable = ({id, rowKeyFunction, options, colorClass}) => {
{expandedRows.includes(rowKeyFunction(row, null)) &&
+ {expandComponent && expandComponent({row})}
{invisibleColumns.map(column => {
if (column.data._ !== undefined) {
return
diff --git a/Plan/react/dashboard/src/components/table/PingTable.jsx b/Plan/react/dashboard/src/components/table/PingTable.jsx
index 00f0adc79..e13590cc1 100644
--- a/Plan/react/dashboard/src/components/table/PingTable.jsx
+++ b/Plan/react/dashboard/src/components/table/PingTable.jsx
@@ -1,44 +1,53 @@
import React from "react";
-import {useTheme} from "../../hooks/themeHook";
import {useTranslation} from "react-i18next";
-import Scrollable from "../Scrollable";
-
-const PingRow = ({country}) => {
- return (
- |
- {country.country} |
- {country.avg_ping} |
- {country.min_ping} |
- {country.max_ping} |
-
- );
-}
+import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
+import {faGlobe, faSignal} from "@fortawesome/free-solid-svg-icons";
+import {formatDecimals} from "../../util/formatters.js";
+import {usePreferences} from "../../hooks/preferencesHook.jsx";
+import DataTablesTable from "./DataTablesTable.jsx";
const PingTable = ({countries}) => {
const {t} = useTranslation();
- const {nightModeEnabled} = useTheme();
+ const {preferencesLoaded, decimalFormat} = usePreferences();
+
+ const columns = [{
+ title: <>
{t('html.label.country')}>,
+ data: "country"
+ }, {
+ title: <> {t('html.label.averagePing')}>,
+ data: {_: "pingAverage", display: "pingAverageFormatted"}
+ }, {
+ title: <> {t('html.label.bestPing')}>,
+ data: {_: "pingMin", display: "pingMinFormatted"}
+ }, {
+ title: <> {t('html.label.worstPing')}>,
+ data: {_: "pingMax", display: "pingMaxFormatted"}
+ }];
+
+ const rows = countries.map(country => {
+ return {
+ country: country.country,
+ pingAverage: country.avg_ping,
+ pingAverageFormatted: formatDecimals(country.avg_ping, decimalFormat) + " ms",
+ pingMax: country.max_ping,
+ pingMaxFormatted: country.max_ping + " ms",
+ pingMin: country.min_ping,
+ pingMinFormatted: country.min_ping + " ms"
+ };
+ });
+ const options = {
+ responsive: true,
+ deferRender: true,
+ columns: columns,
+ data: rows,
+ paginationCount: 2,
+ order: [[0, "desc"]]
+ }
+
+ if (!preferencesLoaded) return <>>;
return (
-
-
-
-
- {t('html.label.country')} |
- {t('html.label.averagePing')} |
- {t('html.label.bestPing')} |
- {t('html.label.worstPing')} |
-
-
-
- {countries.length ? countries.map(country => ) :
- {t('generic.noData')} |
- - |
- - |
- - |
-
}
-
-
-
+
)
};
diff --git a/Plan/react/dashboard/src/components/table/PlayerTable.jsx b/Plan/react/dashboard/src/components/table/PlayerTable.jsx
index 74a0fe6d3..13d0ab062 100644
--- a/Plan/react/dashboard/src/components/table/PlayerTable.jsx
+++ b/Plan/react/dashboard/src/components/table/PlayerTable.jsx
@@ -106,9 +106,9 @@ const PlayerTable = ({data, orderBy}) => {
pingAverage: player.pingAverage,
pingAverageFormatted: formatDecimals(player.pingAverage, decimalFormat) + "ms",
pingMax: player.pingMax,
- pingMaxFormatted: formatDecimals(player.pingMax, decimalFormat) + "ms",
+ pingMaxFormatted: player.pingMax + "ms",
pingMin: player.pingMin,
- pingMinFormatted: formatDecimals(player.pingMin, decimalFormat) + "ms"
+ pingMinFormatted: player.pingMin + "ms"
};
data.extensionDescriptors.forEach(descriptor => {
row[descriptor.name] = ;
diff --git a/Plan/react/dashboard/src/hooks/dataFetchHook.js b/Plan/react/dashboard/src/hooks/dataFetchHook.js
index e255518fd..f0f2bec3f 100644
--- a/Plan/react/dashboard/src/hooks/dataFetchHook.js
+++ b/Plan/react/dashboard/src/hooks/dataFetchHook.js
@@ -1,4 +1,4 @@
-import {useEffect, useState} from "react";
+import {useEffect, useMemo, useState} from "react";
import {useNavigation} from "./navigationHook";
import {useDataStore} from "./datastoreHook";
import {useMetadata} from "./metadataHook";
@@ -23,7 +23,7 @@ export const useDataRequest = (fetchMethod, parameters, shouldRequest) => {
const timestamp = json.timestamp;
if (!staticSite && timestamp) {
// Data has timestamp, the data may come from cache
- const acceptedTimestamp = timestamp + (refreshBarrierMs ? refreshBarrierMs : 15000);
+ const acceptedTimestamp = timestamp + (refreshBarrierMs || 15000);
if (acceptedTimestamp < updateRequested) {
// Request again, received data was too old
setTimeout(() => {
@@ -66,5 +66,7 @@ export const useDataRequest = (fetchMethod, parameters, shouldRequest) => {
}, [fetchMethod, parameters.length, ...parameters, updateRequested, refreshBarrierMs, shouldRequest])
/* eslint-enable react-hooks/exhaustive-deps */
- return {data, loadingError};
+ return useMemo(() => {
+ return {data, loadingError}
+ }, [data, loadingError]);
}
\ No newline at end of file
diff --git a/Plan/react/dashboard/src/views/server/ServerGeolocations.jsx b/Plan/react/dashboard/src/views/server/ServerGeolocations.jsx
index 11dfa2898..fc6b4acf9 100644
--- a/Plan/react/dashboard/src/views/server/ServerGeolocations.jsx
+++ b/Plan/react/dashboard/src/views/server/ServerGeolocations.jsx
@@ -12,7 +12,7 @@ const ServerGeolocations = () => {
const seeGeolocations = hasPermission('page.server.geolocations.map');
const seePing = hasPermission('page.server.geolocations.ping.per.country');
const {data, loadingError} = useDataRequest(fetchGeolocations, [identifier], seeGeolocations);
- const {pingData, pingLoadingError} = useDataRequest(fetchPingTable, [identifier], seePing);
+ const {data: pingData, loadingError: pingLoadingError} = useDataRequest(fetchPingTable, [identifier], seePing);
return (