Implemented query page server selector

This commit is contained in:
Aurora Lahtela 2022-10-16 11:07:11 +03:00
parent 1c3cfbfe4b
commit 900ce7c49c
4 changed files with 63 additions and 7 deletions

View File

@ -297,6 +297,10 @@ public enum HtmlLang implements Lang {
QUERY_SHOW_VIEW("html.query.label.view", "Show a view"),
QUERY("html.query.title.text", "Query<"),
QUERY_MAKE_ANOTHER("html.query.label.makeAnother", "Make another query"),
QUERY_SERVERS_ALL("html.query.label.servers.all", "using data of all servers"),
QUERY_SERVERS_SINGLE("html.query.label.servers.single", "using data of 1 server"),
QUERY_SERVERS_TWO("html.query.label.servers.two", "using data of 2 servers"),
QUERY_SERVERS_MANY("html.query.label.servers.many", "using data of {number} servers"),
WARNING_NO_GAME_SERVERS("html.description.noGameServers", "Some data requires Plan to be installed on game servers."),
WARNING_NO_GEOLOCATIONS("html.description.noGeolocations", "Geolocation gathering needs to be enabled in the config (Accept GeoLite2 EULA)."),

View File

@ -11,6 +11,8 @@ import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faSearch} from "@fortawesome/free-solid-svg-icons";
import PlayersOnlineGraph from "../../graphs/PlayersOnlineGraph";
import Highcharts from "highcharts/highstock";
import MultiSelect from "../../input/MultiSelect";
import CollapseWithButton from "../../layout/CollapseWithButton";
const parseTime = (dateString, timeString) => {
const d = dateString.match(
@ -31,10 +33,15 @@ const parseTime = (dateString, timeString) => {
const QueryOptionsCard = () => {
const {t} = useTranslation();
// View state
const [fromDate, setFromDate] = useState(undefined);
const [fromTime, setFromTime] = useState(undefined);
const [toDate, setToDate] = useState(undefined);
const [toTime, setToTime] = useState(undefined);
const [selectedServers, setSelectedServers] = useState([]);
// View state handling
const [invalidFields, setInvalidFields] = useState([]);
const setAsInvalid = id => setInvalidFields([...invalidFields, id]);
const setAsValid = id => setInvalidFields(invalidFields.filter(invalid => id !== invalid));
@ -58,7 +65,7 @@ const QueryOptionsCard = () => {
useEffect(updateExtremes, [invalidFields]);
const onSetExtremes = useCallback((event) => {
if (event && (event.trigger === "navigator" || event.trigger === 'rangeSelectorButton')) {
if (event) {
const afterDate = Highcharts.dateFormat('%d/%m/%Y', event.min);
const afterTime = Highcharts.dateFormat('%H:%M', event.min);
const beforeDate = Highcharts.dateFormat('%d/%m/%Y', event.max);
@ -70,6 +77,7 @@ const QueryOptionsCard = () => {
}
}, [setFromTime, setFromDate, setToTime, setToDate]);
// View & filter data
const {data: options, loadingError} = useDataRequest(fetchFilters, []);
const [graphData, setGraphData] = useState(undefined);
useEffect(() => {
@ -78,6 +86,20 @@ const QueryOptionsCard = () => {
}
}, [options, setGraphData]);
const getServerSelectorMessage = () => {
const selected = selectedServers.length;
const available = options.view.servers.length;
if (selected === 0 || selected === available) {
return t('query.label.servers.all');
} else if (selected === 1) {
return t('query.label.servers.single');
} else if (selected === 2) {
return t('query.label.servers.two');
} else {
return t('query.label.servers.many').replace('{number}', selected);
}
}
if (loadingError) return <ErrorViewCard error={loadingError}/>
if (!options) return (<Card>
<Card.Body>
@ -145,6 +167,16 @@ const QueryOptionsCard = () => {
/>
</Col>
</Row>
<Row>
<Col md={12}>
<CollapseWithButton title={getServerSelectorMessage()}>
<MultiSelect options={view.servers.map(server => server.serverName)}
selectedIndexes={selectedServers}
setSelectedIndexes={setSelectedServers}/>
</CollapseWithButton>
</Col>
</Row>
<hr/>
</Card.Body>
<button id={"query-button"} className={"btn bg-plan m-2"} disabled={Boolean(invalidFields.length)}>
<FontAwesomeIcon icon={faSearch}/> {t('html.query.performQuery')}

View File

@ -4,12 +4,13 @@ import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import DropdownMenu from "react-bootstrap-v5/lib/esm/DropdownMenu";
import DropdownItem from "react-bootstrap-v5/lib/esm/DropdownItem";
import {useTranslation} from "react-i18next";
import {Dropdown} from "react-bootstrap-v5";
const BasicDropdown = ({selected, optionList, onChange, optionLabelMapper, icon, title}) => {
export const DropDownWithOptions = ({selected, optionList, onChange, optionLabelMapper, icon, title}) => {
const {t} = useTranslation();
return (
<BasicDropdown className="float-end" style={{position: "absolute", right: "0.5rem"}} title={t(title)}>
<Dropdown className="float-end" style={{position: "absolute", right: "0.5rem"}} title={t(title)}>
<DropdownToggle variant=''>
<Fa icon={icon}/> {t(optionLabelMapper ? optionLabelMapper(selected) : selected)}
</DropdownToggle>
@ -22,8 +23,6 @@ const BasicDropdown = ({selected, optionList, onChange, optionLabelMapper, icon,
</DropdownItem>
))}
</DropdownMenu>
</BasicDropdown>
</Dropdown>
)
};
export default BasicDropdown
};

View File

@ -0,0 +1,21 @@
import React, {useState} from 'react';
const CollapseWithButton = ({title, children}) => {
const [collapsed, setCollapsed] = useState(true);
const toggle = () => {
setCollapsed(!collapsed);
}
return (
<>
<button className={"btn dropdown-toggle " + (collapsed ? "collapsed" : "")}
onClick={toggle}>{title}</button>
<div className={"collapse " + (collapsed ? '' : "show")}>
{children}
</div>
</>
)
};
export default CollapseWithButton