Commit 58094660 authored by Florent Chehab's avatar Florent Chehab

fixes(=>v0.9.1)

* increase UWSGI buffer size
* Fixed feedback invalidation on edit
* cleaner scholarships presentation
* Fixed missing arg in cron
* Fixed typos
* lighter empty feedbacks
* cleaner notifications

Closes #141 #140
parent 1e5f9d9f
Pipeline #42831 passed with stages
in 6 minutes and 26 seconds
...@@ -40,7 +40,7 @@ def update_utc_ent(num): ...@@ -40,7 +40,7 @@ def update_utc_ent(num):
@timer(60 * 60, target="spooler") # run it every hour @timer(60 * 60, target="spooler") # run it every hour
@harakiri(60) @harakiri(60)
def update_extra_denormalization(): def update_extra_denormalization(num):
update_denormalized_univ_major_minor() update_denormalized_univ_major_minor()
update_denormalized_univ_field() update_denormalized_univ_field()
......
...@@ -28,7 +28,7 @@ class NotifierImportantInformation extends CustomComponentForAPI { ...@@ -28,7 +28,7 @@ class NotifierImportantInformation extends CustomComponentForAPI {
el => el =>
<Notifier key={el.id} <Notifier key={el.id}
message={el.message} message={el.message}
options={{variant: el.variant, autoHideDuration: 5000}}/>)} options={{variant: el.variant, autoHideDuration: null}}/>)}
</> </>
); );
} }
......
...@@ -33,10 +33,10 @@ class TextField extends Field { ...@@ -33,10 +33,10 @@ class TextField extends Field {
messages.push("Ce champ est requis mais il est vide."); messages.push("Ce champ est requis mais il est vide.");
} }
if (this.props.maxLength && value !== null && value.length > this.props.maxLength) { if (this.props.maxLength && value !== null && value.length > this.props.maxLength) {
messages.push("L'URL est trop long."); messages.push("L'URL est trop longue.");
} }
if (this.props.isUrl && value != "" && !isUrl(value)) { if (this.props.isUrl && value != "" && !isUrl(value)) {
messages.push("L'URL entrer n'est pas reconnu."); messages.push("L'URL entrée n'est pas reconnue.");
} }
if (this.props.isUrl && value != "" && this.props.urlExtensions.length > 0) { if (this.props.isUrl && value != "" && this.props.urlExtensions.length > 0) {
if (!stringHasExtension(value, this.props.urlExtensions)) { if (!stringHasExtension(value, this.props.urlExtensions)) {
......
...@@ -50,13 +50,13 @@ class UsefulLinksField extends Field { ...@@ -50,13 +50,13 @@ class UsefulLinksField extends Field {
if (hasEmpty) { messages.push("Les deux champs url et description doivent être saisis."); } if (hasEmpty) { messages.push("Les deux champs url et description doivent être saisis."); }
const hasInvalidUrl = usefulLinks.some(el => !isUrl(el.url)); const hasInvalidUrl = usefulLinks.some(el => !isUrl(el.url));
if (hasInvalidUrl) { messages.push("Un url n'est pas reconnu dans le formulaire."); } if (hasInvalidUrl) { messages.push("Une URL n'est pas reconnu dans le formulaire."); }
const hasTooLongUrlOrDesc = usefulLinks.some(el => const hasTooLongUrlOrDesc = usefulLinks.some(el =>
(el.url && el.url.length > this.props.urlMaxLength) (el.url && el.url.length > this.props.urlMaxLength)
|| (el.description && el.description.length > this.props.descriptionMaxLength) || (el.description && el.description.length > this.props.descriptionMaxLength)
); );
if (hasTooLongUrlOrDesc) { messages.push("Un url ou une description est trop longue."); } if (hasTooLongUrlOrDesc) { messages.push("Une URL ou une description est trop longue."); }
return new CustomError(messages); return new CustomError(messages);
} }
......
...@@ -15,7 +15,7 @@ function renderCore(rawModelData, classes, outsideData) { ...@@ -15,7 +15,7 @@ function renderCore(rawModelData, classes, outsideData) {
<> <>
{ {
comment.length === 0 ? comment.length === 0 ?
<Typography><em>Aucune information n'est disponible... contribuez ! 😉</em></Typography> <Typography variant={"caption"}><em>Aucune information n'est disponible... contribuez ! 😉</em></Typography>
: :
<TruncatedMarkdown source={comment}/> <TruncatedMarkdown source={comment}/>
} }
......
...@@ -94,11 +94,11 @@ export function CourseFeedbackCore(props) { ...@@ -94,11 +94,11 @@ export function CourseFeedbackCore(props) {
languageName ? languageName ?
<Typography>Cours enseigné en {LanguagesHelper.getLanguageName(languageCode)}.</Typography> <Typography>Cours enseigné en {LanguagesHelper.getLanguageName(languageCode)}.</Typography>
: :
<Typography>La langue dans lequel ce cours est enseigné n'est pas connue.</Typography> <></>
} }
{ {
untouched ? untouched ?
<Typography><em>Aucun avis saisi.</em></Typography> <></>
: :
<> <>
<GridLine> <GridLine>
......
...@@ -96,7 +96,11 @@ const mapDispatchToProps = (dispatch) => { ...@@ -96,7 +96,11 @@ const mapDispatchToProps = (dispatch) => {
api: { api: {
courseFeedbacks: (params) => dispatch(getActions("courseFeedbacks").readAll(params)) courseFeedbacks: (params) => dispatch(getActions("courseFeedbacks").readAll(params))
}, },
invalidateData: () => dispatch(getActions("courseFeedbacks").invalidateAll()) invalidateData: () => {
dispatch(getActions("courseFeedbacks").invalidateAll());
// also invalidate all to make sure all the site pages are consistent
dispatch(getActions("exchangeFeedbacks").invalidateAll());
}
}; };
}; };
......
...@@ -43,6 +43,8 @@ class EditModuleGeneralFeedback extends CustomComponentForAPI { ...@@ -43,6 +43,8 @@ class EditModuleGeneralFeedback extends CustomComponentForAPI {
editor={GeneralFeedbackEditor} editor={GeneralFeedbackEditor}
renderCore={renderCore} renderCore={renderCore}
coreClasses={classes} coreClasses={classes}
// small hack to invalidate data
moduleInGroupInfos={{isInGroup: true, invalidateGroup: () => this.props.invalidateData()}}
/> />
); );
} }
...@@ -64,7 +66,11 @@ const mapDispatchToProps = (dispatch) => { ...@@ -64,7 +66,11 @@ const mapDispatchToProps = (dispatch) => {
api: { api: {
exchangeFeedback: (params) => dispatch(getActions("exchangeFeedbacks").readOne(params)) exchangeFeedback: (params) => dispatch(getActions("exchangeFeedbacks").readOne(params))
}, },
invalidateData: () => dispatch(getActions("exchangeFeedbacks").invalidateOne()) invalidateData: () => {
dispatch(getActions("exchangeFeedbacks").invalidateOne());
// also invalidate all to make sure all the site pages are consistent
dispatch(getActions("exchangeFeedbacks").invalidateAll());
}
}; };
}; };
......
import React, {Component} from "react"; import React from "react";
import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles";
import compose from "recompose/compose";
import Grid from "@material-ui/core/Grid"; import Grid from "@material-ui/core/Grid";
...@@ -11,45 +8,26 @@ import CountryScholarships from "../modules/CountryScholarships"; ...@@ -11,45 +8,26 @@ import CountryScholarships from "../modules/CountryScholarships";
/** /**
* Tab on the university page containing information related to scholarship * Tab on the university page containing information related to scholarship
*
* @class ScholarshipsTab
* @extends {Component}
*/ */
class ScholarshipsTab extends Component { function ScholarshipsTab() {
render() { return (
const { classes } = this.props; <>
return ( <Grid container spacing={3}>
<div className={classes.root}>
<Grid container spacing={2} >
<Grid item xs={12}>
<UniversityScholarships/>
</Grid>
<Grid item xs={12}>
<CountryScholarships/>
</Grid>
<Grid item md={6} xs={12}>
<UniversityScholarships/>
</Grid>
<Grid item md={6} xs={12}>
<CountryScholarships/>
</Grid> </Grid>
</div> </Grid>
);
} </>
);
} }
ScholarshipsTab.propTypes = { ScholarshipsTab.propTypes = {};
classes: PropTypes.object.isRequired,
}; export default ScholarshipsTab;
const styles = {
root: {
display: "flex",
width: "90%",
marginLeft: "auto",
marginRight: "auto"
},
};
export default compose(
withStyles(styles),
)(ScholarshipsTab);
...@@ -17,7 +17,7 @@ const deleteMessage = ` ...@@ -17,7 +17,7 @@ const deleteMessage = `
# Attention # Attention
* Cette action entrainera la suppression de toute vos données sous licence « REX-DRI Private » * Cette action entrainera la suppression de toute vos données sous licence « REX-DRI Private »
(login UTC, adresses mails, pseudos, listes privée, réglages personnels, etc.), (login UTC, adresses mails, pseudos, listes privées, réglages personnels, etc.),
* Afin de satisfaire les exigences de la licence « REX-DRI BY », votre nom et prénom seront conservés, * Afin de satisfaire les exigences de la licence « REX-DRI BY », votre nom et prénom seront conservés,
* Pour toute demande supplémentaire, merci de contacter le SIMDE. * Pour toute demande supplémentaire, merci de contacter le SIMDE.
* La suppression de votre compte sera effective **sous 48h**. * La suppression de votre compte sera effective **sous 48h**.
...@@ -26,7 +26,7 @@ const deleteMessage = ` ...@@ -26,7 +26,7 @@ const deleteMessage = `
# Rappel # Rappel
* Cette action sera de toute manière automatiquement réalisée passer 5 ans d'inactivité de votre compte. * Cette action sera de toute manière automatiquement réalisée après 5 ans d'inactivité de votre compte.
*Si vous souhaitez définitivement supprimer votre compte, cliquez sur le bouton ci-dessous.* *Si vous souhaitez définitivement supprimer votre compte, cliquez sur le bouton ci-dessous.*
`; `;
......
...@@ -164,7 +164,7 @@ class UserInfo extends CustomComponentForAPI { ...@@ -164,7 +164,7 @@ class UserInfo extends CustomComponentForAPI {
</> </>
: :
<Typography variant="caption"> <Typography variant="caption">
Aucune addresse email secondaire n'est disponible. Aucune adresse email secondaire n'est disponible.
</Typography> </Typography>
} }
......
...@@ -4,39 +4,86 @@ import {Provider} from "react-redux"; ...@@ -4,39 +4,86 @@ import {Provider} from "react-redux";
import {BrowserRouter as Router} from "react-router-dom"; import {BrowserRouter as Router} from "react-router-dom";
import {SnackbarProvider} from "notistack"; // provider to easily handle notifications across the app import {SnackbarProvider} from "notistack"; // provider to easily handle notifications across the app
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import green from "@material-ui/core/colors/green";
import amber from "@material-ui/core/colors/amber";
import store from "../redux/store"; import store from "../redux/store";
import App from "../components/app/App"; import App from "../components/app/App";
import ThemeProvider from "../components/common/theme/ThemeProvider"; import ThemeProvider from "../components/common/theme/ThemeProvider";
import CssBaseline from "@material-ui/core/CssBaseline"; import CssBaseline from "@material-ui/core/CssBaseline";
import {makeStyles} from "@material-ui/styles";
/**
* Get the correct style for a color of notistack (not enough contrast some times with default settings)
* @param color
* @param theme
*/
function getStyle(color, theme) {
return {
backgroundColor: color,
color: theme.palette.getContrastText(color),
};
}
const useStylesNotiStack = makeStyles(theme => ({
base: {
...theme.typography.body2
},
variantSuccess: {
...getStyle(green[600], theme),
},
variantError: {
...getStyle(theme.palette.error.dark, theme),
},
variantInfo: {
...getStyle("#2979ff", theme),
},
variantWarning: {
...getStyle(amber[700], theme),
},
}));
function SubEntry() {
// to ba able to use the theme from here
const classesNotistack = useStylesNotiStack();
return (
<SnackbarProvider
maxSnack={3}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
action={[
<Button key={0} color="inherit" size="small">
{"Fermer"}
</Button>
]}
classes={{...classesNotistack}}
>
<>
<CssBaseline/>
<App/>
</>
</SnackbarProvider>
);
}
function MainReactEntry() {
return (
<Provider store={store}>
{/* <React.StrictMode> */}
<ThemeProvider>
<Router>
<SubEntry/>
</Router>
</ThemeProvider>
{/* </React.StrictMode> */}
</Provider>
);
}
const MainReactEntry = () => (
<Provider store={store}>
{/* <React.StrictMode> */}
<ThemeProvider>
<Router>
<SnackbarProvider
maxSnack={3}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
action={[
<Button key={0} color="secondary" size="small">
{"Fermer"}
</Button>
]}
>
<>
<CssBaseline/>
<App/>
</>
</SnackbarProvider>
</Router>
</ThemeProvider>
{/* </React.StrictMode> */}
</Provider>
);
const wrapper = document.getElementById("app"); const wrapper = document.getElementById("app");
......
...@@ -28,6 +28,9 @@ max-worker-lifetime = 600 # reload workers at least every 10 minutes ...@@ -28,6 +28,9 @@ max-worker-lifetime = 600 # reload workers at least every 10 minutes
# daemonize = /var/log/uwsgi/rex-dri.log # background the process & log TODO not working # daemonize = /var/log/uwsgi/rex-dri.log # background the process & log TODO not working
pidfile = /tmp/project-master.pid # create a pidfile pidfile = /tmp/project-master.pid # create a pidfile
# Some users had too many cookies
buffer-size = 6144
# Cron setup # Cron setup
spooler = /usr/src/spooler spooler = /usr/src/spooler
; load the task.py module ; load the task.py module
......
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