mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-04-01 17:35:49 +02:00
Implemented query page server selector
This commit is contained in:
parent
1c3cfbfe4b
commit
900ce7c49c
@ -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)."),
|
||||
|
@ -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')}
|
||||
|
@ -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
|
||||
};
|
@ -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
|
Loading…
Reference in New Issue
Block a user