mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-27 09:00:28 +08:00
Fix some issues in server sorting
- Removed the need for switch statements by giving sort options properties - Added serverUUID to /v1/network/servers endpoint data
This commit is contained in:
parent
9654e4a8d3
commit
b8258a38a6
@ -217,6 +217,7 @@ public class JSONFactory {
|
|||||||
ServerUUID serverUUID = entry.getKey();
|
ServerUUID serverUUID = entry.getKey();
|
||||||
Map<String, Object> server = new HashMap<>();
|
Map<String, Object> server = new HashMap<>();
|
||||||
server.put("name", entry.getValue().getIdentifiableName());
|
server.put("name", entry.getValue().getIdentifiableName());
|
||||||
|
server.put("serverUUID", entry.getValue().getUuid().toString());
|
||||||
|
|
||||||
Optional<DateObj<Integer>> recentPeak = db.query(TPSQueries.fetchPeakPlayerCount(serverUUID, now - TimeUnit.DAYS.toMillis(2L)));
|
Optional<DateObj<Integer>> recentPeak = db.query(TPSQueries.fetchPeakPlayerCount(serverUUID, now - TimeUnit.DAYS.toMillis(2L)));
|
||||||
Optional<DateObj<Integer>> allTimePeak = db.query(TPSQueries.fetchAllTimePeakPlayerCount(serverUUID));
|
Optional<DateObj<Integer>> allTimePeak = db.query(TPSQueries.fetchAllTimePeakPlayerCount(serverUUID));
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
import React, {useCallback, useState} from 'react';
|
import React, {useCallback, useState} from 'react';
|
||||||
import {Card, Dropdown} from "react-bootstrap-v5";
|
import {Card, Dropdown} from "react-bootstrap-v5";
|
||||||
import ServersTable, {ServerSortOption} from "../../table/ServersTable";
|
import ServersTable, {ServerSortOption} from "../../table/ServersTable";
|
||||||
import {
|
import {faNetworkWired} from "@fortawesome/free-solid-svg-icons";
|
||||||
faNetworkWired,
|
|
||||||
faSort,
|
|
||||||
faSortAlphaDown,
|
|
||||||
faSortAlphaUp,
|
|
||||||
faSortNumericDown,
|
|
||||||
faSortNumericUp
|
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
||||||
import DropdownToggle from "react-bootstrap-v5/lib/esm/DropdownToggle";
|
import DropdownToggle from "react-bootstrap-v5/lib/esm/DropdownToggle";
|
||||||
@ -21,33 +14,20 @@ const SortDropDown = ({sortBy, sortReversed, setSortBy}) => {
|
|||||||
const sortOptions = Object.values(ServerSortOption);
|
const sortOptions = Object.values(ServerSortOption);
|
||||||
|
|
||||||
const getSortIcon = useCallback(() => {
|
const getSortIcon = useCallback(() => {
|
||||||
switch (sortBy) {
|
return sortReversed ? sortBy.iconDesc : sortBy.iconAsc;
|
||||||
case ServerSortOption.ALPHABETICAL:
|
}, [sortBy, sortReversed]);
|
||||||
return sortReversed ? faSortAlphaUp : faSortAlphaDown;
|
|
||||||
case ServerSortOption.PLAYERS_ONLINE:
|
|
||||||
// case ServerSortOption.DOWNTIME:
|
|
||||||
case ServerSortOption.AVERAGE_TPS:
|
|
||||||
case ServerSortOption.LOW_TPS_SPIKES:
|
|
||||||
case ServerSortOption.NEW_PLAYERS:
|
|
||||||
case ServerSortOption.UNIQUE_PLAYERS:
|
|
||||||
case ServerSortOption.REGISTERED_PLAYERS:
|
|
||||||
return sortReversed ? faSortNumericDown : faSortNumericUp;
|
|
||||||
default:
|
|
||||||
return faSort;
|
|
||||||
}
|
|
||||||
}, [sortBy, sortReversed])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown className="float-end">
|
<Dropdown className="float-end" style={{position: "absolute", right: "0.5rem"}}>
|
||||||
<DropdownToggle variant=''>
|
<DropdownToggle variant=''>
|
||||||
<Fa icon={getSortIcon()}/> {t(sortBy)}
|
<Fa icon={getSortIcon()}/> {t(sortBy.label)}
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
|
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<h6 className="dropdown-header">{t('html.label.sortBy')}</h6>
|
<h6 className="dropdown-header">{t('html.label.sortBy')}</h6>
|
||||||
{sortOptions.map((option, i) => (
|
{sortOptions.map((option, i) => (
|
||||||
<DropdownItem key={i} onClick={() => setSortBy(option)}>
|
<DropdownItem key={i} onClick={() => setSortBy(option)}>
|
||||||
{t(option)}
|
{t(option.label)}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
))}
|
))}
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
||||||
import {faCaretSquareRight, faLineChart, faLink, faServer, faUser, faUsers} from "@fortawesome/free-solid-svg-icons";
|
import {
|
||||||
|
faCaretSquareRight,
|
||||||
|
faLineChart,
|
||||||
|
faLink,
|
||||||
|
faServer,
|
||||||
|
faSortAlphaDown,
|
||||||
|
faSortAlphaUp,
|
||||||
|
faSortNumericDown,
|
||||||
|
faSortNumericUp,
|
||||||
|
faUser,
|
||||||
|
faUsers
|
||||||
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import {useTheme} from "../../hooks/themeHook";
|
import {useTheme} from "../../hooks/themeHook";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import Scrollable from "../Scrollable";
|
import Scrollable from "../Scrollable";
|
||||||
import {NavLink} from "react-router-dom";
|
import {NavLink} from "react-router-dom";
|
||||||
import {calculateSum} from "../../util/calculation";
|
|
||||||
|
|
||||||
const ServerRow = ({server, onQuickView}) => {
|
const ServerRow = ({server, onQuickView}) => {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
@ -13,7 +23,8 @@ const ServerRow = ({server, onQuickView}) => {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{server.name}</td>
|
<td>{server.name}</td>
|
||||||
<td className="p-1">
|
<td className="p-1">
|
||||||
<NavLink to={"/server/" + encodeURIComponent(server.name)}
|
<NavLink to={"/server/" + encodeURIComponent(server.serverUUID)}
|
||||||
|
title={t('html.label.serverAnalysis') + ': ' + server.name}
|
||||||
className={'btn bg-transparent col-light-green'}><Fa
|
className={'btn bg-transparent col-light-green'}><Fa
|
||||||
icon={faLink}/> {t('html.label.serverAnalysis')}
|
icon={faLink}/> {t('html.label.serverAnalysis')}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
@ -32,6 +43,7 @@ const ServerRow = ({server, onQuickView}) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sortKeepOrder = () => 0;
|
||||||
const sortBySometimesNumericProperty = (propertyName) => (a, b) => {
|
const sortBySometimesNumericProperty = (propertyName) => (a, b) => {
|
||||||
if (typeof (a[propertyName]) === 'number' && typeof (b[propertyName]) === 'number') return a[propertyName] - b[propertyName];
|
if (typeof (a[propertyName]) === 'number' && typeof (b[propertyName]) === 'number') return a[propertyName] - b[propertyName];
|
||||||
if (typeof (a[propertyName]) === 'number') return 1;
|
if (typeof (a[propertyName]) === 'number') return 1;
|
||||||
@ -40,24 +52,7 @@ const sortBySometimesNumericProperty = (propertyName) => (a, b) => {
|
|||||||
}
|
}
|
||||||
const sortByNumericProperty = (propertyName) => (a, b) => b[propertyName] - a[propertyName]; // Biggest first
|
const sortByNumericProperty = (propertyName) => (a, b) => b[propertyName] - a[propertyName]; // Biggest first
|
||||||
const sortBeforeReverse = (servers, sortBy) => {
|
const sortBeforeReverse = (servers, sortBy) => {
|
||||||
const sorting = [...servers];
|
return [...servers].sort(sortBy.sortFunction);
|
||||||
switch (sortBy) {
|
|
||||||
case ServerSortOption.PLAYERS_ONLINE:
|
|
||||||
return sorting.sort(sortBySometimesNumericProperty('online'));
|
|
||||||
case ServerSortOption.AVERAGE_TPS:
|
|
||||||
return sorting.sort(sortBySometimesNumericProperty('avg_tps'));
|
|
||||||
case ServerSortOption.UNIQUE_PLAYERS:
|
|
||||||
return sorting.sort(sortByNumericProperty('unique_players'));
|
|
||||||
case ServerSortOption.NEW_PLAYERS:
|
|
||||||
return sorting.sort(sortByNumericProperty('new_players'));
|
|
||||||
case ServerSortOption.REGISTERED_PLAYERS:
|
|
||||||
return sorting.sort(sortByNumericProperty('players'));
|
|
||||||
// case ServerSortOption.DOWNTIME:
|
|
||||||
// return servers.sort(sortByNumericProperty('downtime_raw'));
|
|
||||||
case ServerSortOption.ALPHABETICAL:
|
|
||||||
default:
|
|
||||||
return sorting;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const reverse = (array) => {
|
const reverse = (array) => {
|
||||||
@ -72,15 +67,54 @@ const sort = (servers, sortBy, sortReversed) => {
|
|||||||
return sortReversed ? reverse(sortBeforeReverse(servers, sortBy)) : sortBeforeReverse(servers, sortBy);
|
return sortReversed ? reverse(sortBeforeReverse(servers, sortBy)) : sortBeforeReverse(servers, sortBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SortOptionIcon = {
|
||||||
|
LETTERS: {
|
||||||
|
iconAsc: faSortAlphaDown,
|
||||||
|
iconDesc: faSortAlphaUp
|
||||||
|
},
|
||||||
|
NUMBERS: {
|
||||||
|
iconAsc: faSortNumericUp,
|
||||||
|
iconDesc: faSortNumericDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const ServerSortOption = {
|
export const ServerSortOption = {
|
||||||
ALPHABETICAL: 'html.label.alphabetical',
|
ALPHABETICAL: {
|
||||||
AVERAGE_TPS: 'html.label.averageTps7days',
|
label: 'html.label.alphabetical',
|
||||||
|
sortFunction: sortKeepOrder,
|
||||||
|
...SortOptionIcon.LETTERS
|
||||||
|
},
|
||||||
|
AVERAGE_TPS: {
|
||||||
|
label: 'html.label.averageTps7days',
|
||||||
|
sortFunction: sortBySometimesNumericProperty('avg_tps'),
|
||||||
|
...SortOptionIcon.NUMBERS
|
||||||
|
},
|
||||||
// DOWNTIME: 'html.label.downtime',
|
// DOWNTIME: 'html.label.downtime',
|
||||||
LOW_TPS_SPIKES: 'html.label.lowTpsSpikes7days',
|
LOW_TPS_SPIKES: {
|
||||||
NEW_PLAYERS: 'html.label.newPlayers7days',
|
label: 'html.label.lowTpsSpikes7days',
|
||||||
PLAYERS_ONLINE: 'html.label.playersOnlineNow',
|
sortFunction: sortByNumericProperty('low_tps_spikes'),
|
||||||
REGISTERED_PLAYERS: 'html.label.registeredPlayers',
|
...SortOptionIcon.NUMBERS
|
||||||
UNIQUE_PLAYERS: 'html.label.uniquePlayers7days',
|
},
|
||||||
|
NEW_PLAYERS: {
|
||||||
|
label: 'html.label.newPlayers7days',
|
||||||
|
sortFunction: sortByNumericProperty('new_players'),
|
||||||
|
...SortOptionIcon.NUMBERS
|
||||||
|
},
|
||||||
|
PLAYERS_ONLINE: {
|
||||||
|
label: 'html.label.playersOnlineNow',
|
||||||
|
sortFunction: sortBySometimesNumericProperty('online'),
|
||||||
|
...SortOptionIcon.NUMBERS
|
||||||
|
},
|
||||||
|
REGISTERED_PLAYERS: {
|
||||||
|
label: 'html.label.registeredPlayers',
|
||||||
|
sortFunction: sortByNumericProperty('players'),
|
||||||
|
...SortOptionIcon.NUMBERS
|
||||||
|
},
|
||||||
|
UNIQUE_PLAYERS: {
|
||||||
|
label: 'html.label.uniquePlayers7days',
|
||||||
|
sortFunction: sortByNumericProperty('unique_players'),
|
||||||
|
...SortOptionIcon.NUMBERS
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServersTable = ({servers, onSelect, sortBy, sortReversed}) => {
|
const ServersTable = ({servers, onSelect, sortBy, sortReversed}) => {
|
||||||
@ -111,14 +145,6 @@ const ServersTable = ({servers, onSelect, sortBy, sortReversed}) => {
|
|||||||
<td>-</td>
|
<td>-</td>
|
||||||
</tr>}
|
</tr>}
|
||||||
</tbody>
|
</tbody>
|
||||||
{sortedServers.length && <tfoot>
|
|
||||||
<tr>
|
|
||||||
<td><b>{t('html.label.total')}</b></td>
|
|
||||||
<td></td>
|
|
||||||
<td>{calculateSum(servers.map(s => s.players))}</td>
|
|
||||||
<td>{calculateSum(servers.map(s => s.online))}</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>}
|
|
||||||
</table>
|
</table>
|
||||||
</Scrollable>
|
</Scrollable>
|
||||||
)
|
)
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
export const calculateSum = array => {
|
|
||||||
let sum = 0;
|
|
||||||
for (let item of array) {
|
|
||||||
if (typeof (item) === "number") sum += item;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user