Commit 8647ed5c authored by Florent Chehab's avatar Florent Chehab
Browse files

Added js linting settings and fixed linting issues

Added editor config
parent 7c509208
# editorconfig.org
root = true
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.py]
indent_size = 4
[*.js]
indent_size = 2
[*.json]
indent_size = 2
\ No newline at end of file
module.exports = {
"env": {
"browser": true,
"es6": true,
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"plugins": [
"react"
],
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"double"
],
"semi": [
"error",
"always"
],
"react/no-unescaped-entities": "warn",
"react/prop-types": "warn",
"react/no-deprecated": "warn"
}
};
This diff is collapsed.
......@@ -4,6 +4,8 @@
"description": "[![build](/../badges/master/build.svg)](https://gitlab.utc.fr/chehabfl/outgoing_rex/pipelines) [![coverage](/../badges/master/coverage.svg)](https://chehabfl.gitlab.utc.fr/outgoing_rex/) [![License](https://img.shields.io/badge/License-BSD%202--Clause-green.svg)](https://opensource.org/licenses/BSD-2-Clause)",
"main": "manage.py",
"scripts": {
"lint": "eslint \"./src/**/*.js\"",
"lint-fix": "eslint \"./src/**/*.js\" --fix",
"dev": "webpack --mode development",
"build": "webpack --mode production",
"test": "echo \"Error: no test specified\" && exit 1",
......@@ -45,6 +47,7 @@
"devDependencies": {
"autoprefixer": "^9.1.5",
"babel-core": "^6.26.3",
"babel-eslint": "^10.0.1",
"babel-loader": "^7.1.5",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-env": "^1.7.0",
......@@ -52,8 +55,9 @@
"babel-preset-react": "^6.24.1",
"babel-preset-stage-1": "^6.24.1",
"css-loader": "^1.0.0",
"eslint": "^5.4.0",
"eslint": "^5.13.0",
"eslint-config-google": "^0.9.1",
"eslint-plugin-react": "^7.12.4",
"file-loader": "^2.0.0",
"js-yaml-loader": "^1.0.1",
"mini-css-extract-plugin": "^0.4.2",
......
export const SAVE_MAIN_MAP_POSITION = 'SAVE_MAIN_MAP_POSITION';
export const SAVE_SELECTED_UNIVERSITIES = 'SAVE_SELECTED_UNIVERSITIES';
export const SAVE_FILTER_CONFIG = 'SAVE_FILTER_CONFIG';
export const SAVE_APP_THEME = 'SAVE_APP_THEME';
export const SAVE_APP_COLOR_PICKER = 'SAVE_APP_COLOR_PICKER';
export const SAVE_UNIVERSITY_BEING_VIEWED = 'SAVE_UNIVERSITY_BEING_VIEWED';
export const SAVE_MAIN_MAP_POSITION = "SAVE_MAIN_MAP_POSITION";
export const SAVE_SELECTED_UNIVERSITIES = "SAVE_SELECTED_UNIVERSITIES";
export const SAVE_FILTER_CONFIG = "SAVE_FILTER_CONFIG";
export const SAVE_APP_THEME = "SAVE_APP_THEME";
export const SAVE_APP_COLOR_PICKER = "SAVE_APP_COLOR_PICKER";
export const SAVE_UNIVERSITY_BEING_VIEWED = "SAVE_UNIVERSITY_BEING_VIEWED";
......@@ -9,7 +9,7 @@ function _isReading(status, type) {
return {
type,
status
}
};
}
function _readFailed(failed, error, type) {
......@@ -17,7 +17,7 @@ function _readFailed(failed, error, type) {
type,
failed,
error
}
};
}
function _readSucceeded(data, type) {
......@@ -82,7 +82,7 @@ export default class CrudActions {
readAllSucceeded,
this.setInvalidatedAll.bind(this),
readAllFailed
)
);
}
......@@ -116,7 +116,7 @@ export default class CrudActions {
readSpecificSucceeded,
this.setInvalidatedSpecific.bind(this),
readSpecificFailed
)
);
}
......@@ -182,7 +182,7 @@ export default class CrudActions {
isCreating,
createSucceeded,
createFailed
)
);
}
/**
......@@ -218,7 +218,7 @@ export default class CrudActions {
}
self._checkNotReadonly();
if (!'id' in data) {
if (!("id" in data)) {
throw Error("When updating an object, an id is expected in the data");
}
......@@ -228,7 +228,7 @@ export default class CrudActions {
isUpdating,
updateSucceeded,
updateFailed
)
);
}
///////////
......@@ -246,7 +246,7 @@ export default class CrudActions {
return {
type: this.types.isInvalidatedAll,
isInvalidated: bool
}
};
}
/**
......@@ -260,6 +260,6 @@ export default class CrudActions {
return {
type: this.types.isInvalidatedSpecific,
isInvalidated: bool
}
};
}
}
\ No newline at end of file
import { combineReducers } from 'redux';
import { combineReducers } from "redux";
import getCrudActionTypes from "./getCrudActionTypes";
import SmartActions from "./SmartActions";
......@@ -10,7 +10,7 @@ function failed(state, action, type) {
return {
failed: action.failed,
error: action.error
}
};
default:
return state;
......@@ -23,7 +23,7 @@ function succeeded(state, action, type) {
return {
data: action.data,
readAt: (new Date()).getTime()
}
};
default:
return state;
......@@ -150,7 +150,7 @@ export default class CrudReducers {
readSucceeded: readSpecificSucceeded,
readFailed: readSpecificFailed,
isInvalidated: isInvalidatedSpecific,
}
};
// Add only appropriate reducers
if (this.readOnly !== true) {
......
import Cookies from 'js-cookie';
import Cookies from "js-cookie";
// TODO uodate parameters name to match new CRUD actions
......@@ -32,11 +32,11 @@ export default class SmartActions {
* @memberof SmartActions
*/
_FetchData(pk, api_end_point, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError, pk_required = false) {
if (pk_required && (typeof pk == 'undefined')) {
if (pk_required && (typeof pk == "undefined")) {
throw "pk shouldn't be empty when requesting a specific element";
}
if (pk != "") {
api_end_point += pk + '/';
api_end_point += pk + "/";
}
if (!this.shouldFetchEndPoint(api_end_point)) {
......@@ -47,8 +47,8 @@ export default class SmartActions {
return (dispatch) => {
dispatch(_IsLoading(true));
let token = Cookies.get('csrftoken');
fetch(api_end_point, { credentials: 'same-origin', headers: { 'X-CSRFToken': token } })
let token = Cookies.get("csrftoken");
fetch(api_end_point, { credentials: "same-origin", headers: { "X-CSRFToken": token } })
.then((response) => {
if (!response.ok) {
this.fetching.delete(api_end_point);
......@@ -88,26 +88,26 @@ export default class SmartActions {
return (dispatch) => {
let method = "POST";
let pk = "";
if ('id' in data) {
if ("id" in data) {
method = "PUT";
pk = data.id + '/';
pk = data.id + "/";
}
let __apiAttr = '';
if ('__apiAttr' in data && data.__apiAttr != '') {
__apiAttr = data.__apiAttr + '/';
let __apiAttr = "";
if ("__apiAttr" in data && data.__apiAttr != "") {
__apiAttr = data.__apiAttr + "/";
}
let errorStatusText = '';
let errorStatusText = "";
dispatch(_ElIsSaving(true));
let token = Cookies.get('csrftoken');
let token = Cookies.get("csrftoken");
fetch(api_end_point + __apiAttr + pk, {
method: method,
credentials: 'same-origin',
credentials: "same-origin",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': token
"Accept": "application/json",
"Content-Type": "application/json",
"X-CSRFToken": token
},
body: JSON.stringify(data)
})
......@@ -123,18 +123,19 @@ export default class SmartActions {
dispatch(_ElIsSaving(false));
})
.catch((e) => {
if (typeof e.json == 'function') {
return e.json()
if (typeof e.json == "function") {
return e.json();
} else {
return new Promise(function (resolve, reject) { resolve(e) });
// eslint-disable-next-line no-unused-vars
return new Promise(function (resolve, reject) { resolve(e); });
}
})
.then((errorContent) => {
if (typeof errorContent != 'undefined') {
if (typeof errorContent != "undefined") {
dispatch(_ElHasError(true, { message: errorStatusText, content: errorContent }));
dispatch(_ElIsSaving(false));
}
})
});
};
}
}
......@@ -14,7 +14,7 @@ const otherAPI = [
name: "serverModerationStatus",
api_end_point: "serverModerationStatus"
}
]
];
/**
* Create api actions and reducers for given the info in each arr obj
......@@ -43,7 +43,7 @@ function addAPIs(arr) {
const reducers = new CrudReducers(apiInfo);
apiReducersTmp[`${apiInfo.name}All`] = reducers.getCombinedAll();
apiReducersTmp[`${apiInfo.name}Specific`] = reducers.getCombinedSpecific();
})
});
}
addAPIs(otherAPI);
......
import { apiActions } from "./buildApiActionsAndReducers";
import CrudActions from "./CrudActions";
/**
* Function to get the the actions corresponding to an API end point.
......@@ -10,7 +9,7 @@ import CrudActions from "./CrudActions";
*/
export default function getActions(name) {
if (!(name in apiActions)) {
console.error("available actions", apiActions);
console.error("available actions", apiActions); // eslint-disable-line no-console
throw Error(`Requested api action is not defined, check the name: ${name}`);
}
return apiActions[name];
......
......@@ -30,5 +30,5 @@ export default function getCrudActionTypes(name) {
// Not directly a CRUD action but needed for in app behavior
isInvalidatedAll: `API_${name}_ALL_INVALIDATED`,
isInvalidatedSpecific: `API_${name}_SPECIFIC_INVALIDATED`,
}
};
}
\ No newline at end of file
// Inspired by https://github.com/mui-org/material-ui/tree/master/docs/src/pages/page-layout-examples/dashboard
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '@material-ui/core/styles/withStyles';
import CssBaseline from '@material-ui/core/CssBaseline';
import Drawer from '@material-ui/core/Drawer';
import List from '@material-ui/core/List';
import Divider from '@material-ui/core/Divider';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import Chip from '@material-ui/core/Chip';
import Avatar from '@material-ui/core/Avatar';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import SchoolIcon from '@material-ui/icons/School';
import { mainListItems, secondaryListItems, thirdListItems } from './template/listItems';
import React from "react";
import PropTypes from "prop-types";
import classNames from "classnames";
import withStyles from "@material-ui/core/styles/withStyles";
import CssBaseline from "@material-ui/core/CssBaseline";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import Divider from "@material-ui/core/Divider";
import IconButton from "@material-ui/core/IconButton";
import MenuIcon from "@material-ui/icons/Menu";
import Chip from "@material-ui/core/Chip";
import Avatar from "@material-ui/core/Avatar";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import SchoolIcon from "@material-ui/icons/School";
import { mainListItems, secondaryListItems, thirdListItems } from "./template/listItems";
import { connect } from "react-redux";
import CustomComponentForAPI from './CustomComponentForAPI'
import CustomComponentForAPI from "./CustomComponentForAPI";
// import route Components here
import {
Route,
Redirect
} from 'react-router-dom';
} from "react-router-dom";
import getActions from "../api/getActions";
import PageMap from './pages/PageMap';
import PageHome from './pages/PageHome';
import PageUniversity from './pages/PageUniversity';
import PageSearch from './pages/PageSearch';
import PageSettings from './pages/PageSettings';
import PageMap from "./pages/PageMap";
import PageHome from "./pages/PageHome";
import PageUniversity from "./pages/PageUniversity";
import PageSearch from "./pages/PageSearch";
import PageSettings from "./pages/PageSettings";
const drawerWidth = 240;
const styles = theme => ({
root: {
display: 'flex',
display: "flex",
},
toolbar: {
paddingRight: 24, // keep right padding when drawer closed
},
toolbarIcon: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
padding: "0 8px",
...theme.mixins.toolbar,
},
chip: {
......@@ -56,36 +56,36 @@ const styles = theme => ({
marginRight: 4,
},
hideIt: {
display: 'none',
display: "none",
},
title: {
flexGrow: 1,
},
drawerPaper: {
position: 'relative',
whiteSpace: 'nowrap',
position: "relative",
whiteSpace: "nowrap",
width: drawerWidth,
transition: theme.transitions.create('width', {
transition: theme.transitions.create("width", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
drawerPaperClose: {
overflowX: 'hidden',
transition: theme.transitions.create('width', {
overflowX: "hidden",
transition: theme.transitions.create("width", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
width: theme.spacing.unit * 7,
[theme.breakpoints.up('sm')]: {
[theme.breakpoints.up("sm")]: {
width: theme.spacing.unit * 9,
},
},
content: {
flexGrow: 1,
padding: theme.spacing.unit * 3,
height: '100vh',
overflow: 'auto',
height: "100vh",
overflow: "auto",
paddingTop: "0px"
},
paddingTop: {
......@@ -191,7 +191,7 @@ const mapStateToProps = (state) => {
return {
countries: state.api.countriesAll,
currencies: state.api.currenciesAll,
}
};
};
const mapDispatchToProps = (dispatch) => {
......
import React, { Component } from 'react';
import Loading from './other/Loading';
import React, { Component } from "react";
import Loading from "./other/Loading";
// Stores the name of the reducers/actions that result in read data
const successActionsWithReads = ["readSucceeded", "createSucceeded", "updateSucceeded"];
......@@ -21,7 +21,7 @@ class CustomComponentForAPI extends Component {
// a little bit of optimization
// Stores the list of props that use the API
this.apiProps = Array();
if (typeof props === 'object' && 'api' in props) {
if (typeof props === "object" && "api" in props) {
const { api } = props;
this.apiProps = Object.keys(api);
}
......@@ -35,7 +35,7 @@ class CustomComponentForAPI extends Component {
this.customComponentDidMount();
this.forceUpdate(); // bug otherwise
}
customComponentDidMount() { };
customComponentDidMount() { }
shouldComponentUpdate(nextProps, nextState) {
// Below is buggy with redux connect
......@@ -53,6 +53,7 @@ class CustomComponentForAPI extends Component {
// // }
return this.customShouldComponentUpdate(nextProps, nextState);
}
// eslint-disable-next-line no-unused-vars
customShouldComponentUpdate(nextProps, nextState) { return true; }
componentDidUpdate(prevProps, prevState, snapshot) {
......@@ -60,7 +61,7 @@ class CustomComponentForAPI extends Component {
this.readPropsIfNeeded();
this.customComponentDidUpdate(prevProps, prevState, snapshot);
}
customComponentDidUpdate() { };
customComponentDidUpdate() { }
// Override of the default render behaviour to wait for data to arrive.
......@@ -89,12 +90,13 @@ class CustomComponentForAPI extends Component {
checkPropsFailed() {
return this.apiProps.some((propName) => {
if (typeof this.props[propName] === "undefined") {
// eslint-disable-next-line no-console
console.error(this.props, propName);
throw Error(`${propName} is not in the class props ! Dev, check what your are doing`);
}
const prop = this.props[propName];
return prop.readFailed.failed; // general handling of all types of API reducers
})
});
}
......@@ -141,7 +143,7 @@ class CustomComponentForAPI extends Component {
readPropsIfNeeded() {
this.getListPropsNeedRead().map((propName) => {
this.performReadFromApi(propName);
})
});
}
/**
......@@ -185,10 +187,10 @@ class CustomComponentForAPI extends Component {
.map(action => prop[action])
.reduce(
(prev, curr) => prev.readAt < curr.readAt ? curr : prev,
{ readAt: 0 })
{ readAt: 0 });
if (!"data" in out) {
throw Error(`No read data from the api could be retreived for: ${propName}`)
if (!("data" in out)) {
throw Error(`No read data from the api could be retreived for: ${propName}`);
} else {
return out;
}
......@@ -213,7 +215,7 @@ class CustomComponentForAPI extends Component {
* @memberof CustomComponentForAPI
*/
getAllReadData() {
let out = Object()
let out = Object();
this.apiProps.forEach((propName) => {
out[propName] = this.getReadData(propName);
});
......@@ -226,8 +228,8 @@ class CustomComponentForAPI extends Component {
const { universities, countries, cities } = this.getAllReadData();
let res = Object.assign({}, campus); //copy for safety
res.university = universities[campus.university];
res.city = cities[campus.city]
res.country = countries[res.city.country]
res.city = cities[campus.city];
res.country = countries[res.city.country];
return res;
}
......@@ -237,13 +239,13 @@ class CustomComponentForAPI extends Component {
const countries = this.getReadData("countries");
const city = cities[univMainCampus.city];
const country = countries[city.country];
return { city, country }
return { city, country };
}
findMainCampus(univId) {