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 ( - - - - - - - - - - - - {countries.length ? countries.map(country => ) : - - - - - } - -
{t('html.label.country')}{t('html.label.averagePing')}{t('html.label.bestPing')}{t('html.label.worstPing')}
{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 (