feat(statsPage): cleaned RequestInterface cmp

parent d18eda98
......@@ -3,7 +3,7 @@ import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/styles";
import Divider from "@material-ui/core/Divider";
import { withPaddedPaper } from "./shared";
import SqlInterface from "../stats/RequestSQLHandler";
import RequestInterface from "../stats/RequestInterface";
import DatasetSelector from "../stats/DatasetSelector";
import DatasetDescriptor from "../stats/DatasetDescriptor";
import {
......@@ -53,7 +53,7 @@ function PageStats() {
/>
<Divider className={classes.spacer} />
<div className={classes.requestInterface}>
<SqlInterface />
<RequestInterface />
</div>
</>
);
......
import React, { useCallback, useEffect, useState } from "react";
import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/styles";
import Divider from "@material-ui/core/Divider";
import ExpansionPanel from "@material-ui/core/ExpansionPanel";
import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
import {
currentDatasetData,
currentDatasetName,
executeSqlRequest,
getDatasetExampleRequests,
getRequestFromUrl,
setRequestInUrl,
} from "./utils";
import ExampleRequests from "./ExampleRequests";
import useOnBeforeComponentMount from "../../hooks/useOnBeforeComponentMount";
import SqlEditor from "./SqlEditor";
import RequestResults from "./RequestResults";
const useStyles = makeStyles((theme) => ({
fullWidth: {
width: "100%",
},
spacer: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
},
}));
const requestFromUrl = getRequestFromUrl();
const exampleRequests = getDatasetExampleRequests(currentDatasetName);
const isPredefinedRequest =
exampleRequests.filter((el) => el.request === requestFromUrl).length === 1;
function RequestInterface() {
const classes = useStyles();
const [sqlRequest, setSqlRequest] = useState(requestFromUrl);
const [requestError, setRequestError] = useState("");
const [requestResults, setRequestResults] = useState([]);
useEffect(() => {
setRequestResults([]);
}, [sqlRequest]);
const performRequest = useCallback((request) => {
// make sure to update the sql request in the text area
setSqlRequest(request);
setRequestError("");
setRequestResults([]);
executeSqlRequest(request)
.then((res) => {
setRequestResults(res);
setRequestInUrl(request);
})
.catch((err) => {
setRequestError(err);
});
}, []);
// Execute request on first mount (better when sharing)
useOnBeforeComponentMount(() => {
performRequest(sqlRequest);
});
const [
exampleRequestsPanelExpanded,
setExampleRequestsPanelExpanded,
] = useState(isPredefinedRequest);
const [sqlEditorPanelExpanded, setSqlEditorPanelExpanded] = useState(
!isPredefinedRequest
);
return (
<div>
<ExpansionPanel
onChange={(e, expanded) => setExampleRequestsPanelExpanded(expanded)}
expanded={exampleRequestsPanelExpanded}
>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">
Éxécuter une des requêtes pré-définies
</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<div>
<ExampleRequests
performRequest={performRequest}
requests={exampleRequests}
/>
</div>
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel
onChange={(e, expanded) => setSqlEditorPanelExpanded(expanded)}
expanded={sqlEditorPanelExpanded}
>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">
Personnaliser la requête (avancée)
</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<div className={classes.fullWidth}>
<SqlEditor
request={sqlRequest}
setRequest={setSqlRequest}
performRequest={performRequest}
/>
</div>
</ExpansionPanelDetails>
</ExpansionPanel>
<Divider className={classes.spacer} />
{requestError !== "" && (
<>
<br />
<Typography variant="caption">{requestError.toString()}</Typography>
<br />
</>
)}
{requestResults.length !== 0 && (
<RequestResults
results={requestResults}
rawDataset={currentDatasetData}
request={sqlRequest}
/>
)}
</div>
);
}
export default RequestInterface;
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import alasql from "alasql";
import Typography from "@material-ui/core/Typography";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
import { makeStyles } from "@material-ui/styles";
import TableFromData from "./Table";
import PlotResult from "./Plot";
// eslint-disable-next-line no-undef
const DataFromBackend = __StatsData;
const cols = Object.keys(DataFromBackend);
const data = [];
// eslint-disable-next-line no-plusplus
for (let i = 0; i < DataFromBackend[cols[0]].length; i++) {
const elem = {};
cols.forEach((col) => {
elem[col] = DataFromBackend[col][i];
});
data.push(elem);
}
const useStyles = makeStyles({});
// eslint-disable-next-line no-shadow
function executeRequest(sqlRequest, data) {
return alasql.promise(sqlRequest, [data]);
}
function SqlRequestResult({ result }) {
return (
<div>
<br />
<TableFromData data={result} />
<PlotResult result={result} />
<br />
<Button
variant="outlined"
color="secondary"
onClick={() => {
alasql(
'SELECT * INTO CSV("export_rex_dri.csv", {headers:true}) FROM ?',
[result]
);
}}
>
Exporter en CSV
</Button>
<br />
<br />
Pour partager votre recherche il vous suffit de copier l'url de la page !
</div>
);
}
SqlRequestResult.propTypes = {
result: PropTypes.array.isRequired,
};
const defaultRequest = `SELECT
date AS x,
nb_connections AS y
FROM ?
ORDER BY x ASC;
`;
// TODO à changer selon le dataset
// TODO si plusieurs requetes par défaut proposées pour un meme dataset : les proposer avec des boutons
/*
SELECT
date AS x,
major AS cat,
sum(nb_contributions) AS y
FROM ?
GROUP BY date, major
ORDER BY date ASC;
*/
/**
SELECT
date AS x,
CASE WHEN
major = 'IM' OR major = 'GM' OR major = 'GSM' THEN 'IM'
ELSE 'AUTRES'
END AS cat,
sum(nb_contributions) AS y
FROM ?
GROUP BY date, major
ORDER BY date ASC;
*/
function getRequestFromUrl() {
const getParamsInUrl = new URL(document.location).searchParams;
let request = defaultRequest;
try {
const requestInfoString = getParamsInUrl.has("request_info")
? getParamsInUrl.get("request_info")
: "";
request = JSON.parse(atob(requestInfoString)).request;
} catch (err) {
// eslint-disable-next-line no-console
console.log(err);
}
return request;
}
/**
*
*/
function setRequestInUrl(request) {
const requestInfo = {
request,
version: 1.0,
};
const requestInfoAsString = btoa(JSON.stringify(requestInfo));
const getParamsInUrl = new URL(document.location).searchParams;
getParamsInUrl.set("request_info", requestInfoAsString);
window.history.replaceState(null, null, `?${getParamsInUrl.toString()}`);
}
// eslint-disable-next-line no-unused-vars
function getDatasetFromUrl() {
const getParamsInUrl = new URL(document.location).searchParams;
let datasetName = "daily_connections";
try {
datasetName = getParamsInUrl.has("dataset")
? getParamsInUrl.get("dataset")
: "daily_connections";
} catch (err) {
// eslint-disable-next-line no-console
console.log(err);
}
return datasetName;
}
// eslint-disable-next-line no-unused-vars
function setDatasetInUrl(datasetName) {
const getParamsInUrl = new URL(document.location).searchParams;
getParamsInUrl.set("dataset", datasetName);
window.history.replaceState(null, null, `?${getParamsInUrl.toString()}`);
}
const requestFromUrl = getRequestFromUrl();
function SqlInterface() {
const classes = useStyles();
const [sqlRequest, setSqlRequest] = useState(requestFromUrl);
useEffect(() => {
setRequestInUrl(sqlRequest);
}, [sqlRequest]);
const [requestError, setRequestError] = useState("");
const [requestResult, setRequestResult] = useState([]);
return (
<div>
<TextField
id="standard-multiline-static"
label="Requête d'exploration"
multiline
fullWidth
margin="normal"
rows={5}
placeholder="Entrez la requête SQL"
value={sqlRequest}
onChange={(event) => setSqlRequest(event.target.value)}
/>
{requestError !== "" && (
<>
<br />
<Typography variant="caption">{requestError.toString()}</Typography>
<br />
</>
)}
<Button
variant="contained"
color="primary"
className={classes.button}
onClick={() => {
setRequestError("");
setRequestResult([]);
executeRequest(sqlRequest, data)
.then((res) => {
setRequestResult(res);
})
.catch((err) => {
setRequestError(err);
});
}}
>
Exécuter
</Button>
{requestResult.length !== 0 && (
<SqlRequestResult result={requestResult} />
)}
</div>
);
}
export default SqlInterface;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment