diff --git a/.eslintrc b/.eslintrc
index 2459981..572e228 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,48 +1,49 @@
{
- "comment": "off = 0, warn = 1, error = 2",
+ "comment": "off = 0, warn = 1, error = 2",
- "parser": "babel-eslint",
- "env": {
- "browser": true
- },
- "extends": "airbnb",
- "rules": {
- "max-len": [1, 100, 2, {ignoreComments: true}],
- "quote-props": [1, "consistent-as-needed"],
- "no-cond-assign": [2, "except-parens"],
- "radix": 0,
- "space-infix-ops": 0,
- "no-unused-vars": [1, {"vars": "local", "args": "none"}],
- "default-case": 0,
- "no-else-return": 0,
- "no-param-reassign": 0,
- "quotes": 0,
- "comma-dangle": [1, "only-multiline"],
- "vars-on-top": 0,
- "prefer-const": 1,
- "eqeqeq": 1,
- "import/imports-first": 1,
- "consistent-return": 0,
- "import/no-mutable-exports": 0,
- "no-class-assign": 0,
- "jsx-a11y/label-has-for": 0,
- "jsx-a11y/href-no-hash": 1,
- "camelcase": 0,
- "no-fallthrough": 0,
- "no-restricted-syntax": 1,
- "guard-for-in": 1,
- "array-callback-return": 1,
- "class-methods-use-this": 1,
- "jsx-a11y/no-static-element-interactions": 1,
- "react/forbid-prop-types": 1,
- "arrow-parens": 1,
- "no-bitwise": 1,
- "no-plusplus": 1,
- "no-extend-native": 1,
- "no-use-before-define": 1,
- "no-unused-expressions": 1,
- "no-continue": 1,
- "no-prototype-builtins": 1,
- "dot-notation": 1,
- }
+ "parser": "babel-eslint",
+ "env": {
+ "browser": true
+ },
+ "extends": "airbnb",
+ "rules": {
+ "max-len": [1, 100, 2, {ignoreComments: true}],
+ "quote-props": [1, "consistent-as-needed"],
+ "no-cond-assign": [2, "except-parens"],
+ "radix": 0,
+ "space-infix-ops": 0,
+ "no-unused-vars": [1, {"vars": "local", "args": "none"}],
+ "default-case": 0,
+ "no-else-return": 0,
+ "no-param-reassign": 0,
+ "quotes": 0,
+ "comma-dangle": [1, "only-multiline"],
+ "vars-on-top": 0,
+ "prefer-const": 1,
+ "eqeqeq": 1,
+ "import/imports-first": 1,
+ "consistent-return": 0,
+ "import/no-mutable-exports": 0,
+ "no-class-assign": 0,
+ "jsx-a11y/label-has-for": 0,
+ "jsx-a11y/href-no-hash": 1,
+ "camelcase": 0,
+ "no-fallthrough": 0,
+ "no-restricted-syntax": 1,
+ "guard-for-in": 1,
+ "array-callback-return": 1,
+ "class-methods-use-this": 1,
+ "jsx-a11y/no-static-element-interactions": 1,
+ "react/forbid-prop-types": 1,
+ "arrow-parens": 1,
+ "no-bitwise": 1,
+ "no-plusplus": 1,
+ "no-extend-native": 1,
+ "no-use-before-define": 1,
+ "no-unused-expressions": 1,
+ "no-continue": 1,
+ "no-prototype-builtins": 1,
+ "dot-notation": 1,
+ "react/no-array-index-key": 1
+ }
}
diff --git a/.travis/travis_script.sh b/.travis/travis_script.sh
index a490d57..05442b1 100755
--- a/.travis/travis_script.sh
+++ b/.travis/travis_script.sh
@@ -3,10 +3,17 @@
set -ex
+section "ESLint"
+
+make lint-install
+make lint
+
+section_end "ESLint"
+
+
section "Tests"
make log &
make ${TEST_TARGET}
section_end "Tests"
-
diff --git a/baselayer b/baselayer
index bc2991f..4b64f33 160000
--- a/baselayer
+++ b/baselayer
@@ -1 +1 @@
-Subproject commit bc2991f441a2caf61a057bae51065d7f8a137732
+Subproject commit 4b64f339d9d450119991d8f00c546b1e3dbb32ee
diff --git a/package.json b/package.json
index b5ce18e..331ba17 100644
--- a/package.json
+++ b/package.json
@@ -39,12 +39,12 @@
"babel-preset-stage-2": "^6.22.0",
"css-loader": "^0.26.1",
"cwise": "^1.0.9",
- "eslint": "^3.16.1",
- "eslint-config-airbnb": "^14.1.0",
+ "eslint": "^4.19.1",
+ "eslint-config-airbnb": "^16.1.0",
"eslint-loader": "^1.6.3",
- "eslint-plugin-import": "^2.2.0",
- "eslint-plugin-jsx-a11y": "^4.0.0",
- "eslint-plugin-react": "^6.10.0",
+ "eslint-plugin-import": "^2.11.0",
+ "eslint-plugin-jsx-a11y": "^6.0.3",
+ "eslint-plugin-react": "^7.7.0",
"exports-loader": "^0.6.3",
"glslify": "^6.0.1",
"imports-loader": "^0.7.0",
diff --git a/static/js/CesiumMessageHandler.js b/static/js/CesiumMessageHandler.js
index f0fbef7..44f35b8 100644
--- a/static/js/CesiumMessageHandler.js
+++ b/static/js/CesiumMessageHandler.js
@@ -1,37 +1,36 @@
-import * as Action from './actions';
import { SHOW_NOTIFICATION, showNotification } from 'baselayer/components/Notifications';
import MessageHandler from 'baselayer/MessageHandler';
+import * as Action from './actions';
-let CesiumMessageHandler = dispatch => {
- return new MessageHandler(dispatch, message => {
- switch (message.action) {
- case Action.FETCH_PROJECTS:
- dispatch(Action.fetchProjects());
- break;
- case Action.FETCH_FEATURES:
- dispatch(Action.fetchFeatures());
- break;
- case Action.FETCH_DATASETS:
- dispatch(Action.fetchDatasets());
- break;
- case Action.FETCH_FEATURESETS:
- dispatch(Action.fetchFeaturesets());
- break;
- case Action.FETCH_MODELS:
- dispatch(Action.fetchModels());
- break;
- case Action.FETCH_PREDICTIONS:
- dispatch(Action.fetchPredictions());
- break;
- case Action.FEATURIZE_PROGRESS:
- let time_update = message.payload;
- dispatch(Action.featurizeUpdateProgress(time_update));
- break;
- default:
- console.log('Unknown message received through flow:',
- message);
+const CesiumMessageHandler = dispatch => new MessageHandler(dispatch, (message) => {
+ switch (message.action) {
+ case Action.FETCH_PROJECTS:
+ dispatch(Action.fetchProjects());
+ break;
+ case Action.FETCH_FEATURES:
+ dispatch(Action.fetchFeatures());
+ break;
+ case Action.FETCH_DATASETS:
+ dispatch(Action.fetchDatasets());
+ break;
+ case Action.FETCH_FEATURESETS:
+ dispatch(Action.fetchFeaturesets());
+ break;
+ case Action.FETCH_MODELS:
+ dispatch(Action.fetchModels());
+ break;
+ case Action.FETCH_PREDICTIONS:
+ dispatch(Action.fetchPredictions());
+ break;
+ case Action.FEATURIZE_PROGRESS: {
+ const time_update = message.payload;
+ dispatch(Action.featurizeUpdateProgress(time_update));
+ break;
}
- });
-}
+ default:
+ console.log('Unknown message received through flow:',
+ message);
+ }
+});
export default CesiumMessageHandler;
diff --git a/static/js/actions.js b/static/js/actions.js
index 34b7f04..a1af2d8 100644
--- a/static/js/actions.js
+++ b/static/js/actions.js
@@ -3,6 +3,10 @@
import { reset as resetForm } from 'redux-form';
+import { showNotification } from 'baselayer/components/Notifications';
+import promiseAction from './action_tools';
+
+
export const HYDRATE = 'cesium/HYDRATE';
export const FETCH_PROJECTS = 'cesium/FETCH_PROJECTS';
@@ -51,15 +55,12 @@ export const RECEIVE_USER_PROFILE = 'cesium/FETCH_USER_PROFILE';
export const FEATURIZE_PROGRESS = 'cesium/FEATURIZE_PROGRESS';
-import { showNotification, reduceNotifications } from 'baselayer/components/Notifications';
-import promiseAction from './action_tools';
-import { objectType } from './utils';
// Refactor this into a utility function
String.prototype.format = function (...args) {
let i = 0;
return this.replace(/{}/g, () => (
- typeof args[i] != 'undefined' ? args[i++] : ''
+ typeof args[i] !== 'undefined' ? args[i++] : ''
));
};
@@ -85,18 +86,18 @@ export function fetchProjects() {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(receiveProjects(json.data));
} else {
dispatch(
showNotification(
'Error downloading projects ({})'.format(json.message)
- ));
+ )
+ );
}
return json;
- }
- ).catch(ex => console.log('fetchProjects exception:', ex))
- );
+ }).catch(ex => console.log('fetchProjects exception:', ex))
+ );
}
@@ -107,18 +108,20 @@ export function addProject(form) {
dispatch,
ADD_PROJECT,
- fetch('/project',
- {
- credentials: 'same-origin',
- method: 'POST',
- body: JSON.stringify(form),
- headers: new Headers({
- 'Content-Type': 'application/json'
- })
- })
+ fetch(
+ '/project',
+ {
+ credentials: 'same-origin',
+ method: 'POST',
+ body: JSON.stringify(form),
+ headers: new Headers({
+ 'Content-Type': 'application/json'
+ })
+ }
+ )
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(resetForm('newProject'));
dispatch(showNotification('Added new project'));
dispatch(selectProject(json.data.id));
@@ -127,7 +130,7 @@ export function addProject(form) {
}
return json;
})
- );
+ );
}
@@ -138,18 +141,20 @@ export function updateProject(form) {
dispatch,
UPDATE_PROJECT,
- fetch('/project/{}'.format(form.projectId),
- {
- credentials: 'same-origin',
- method: 'PUT',
- body: JSON.stringify(form),
- headers: new Headers({
- 'Content-Type': 'application/json'
- })
- })
+ fetch(
+ '/project/{}'.format(form.projectId),
+ {
+ credentials: 'same-origin',
+ method: 'PUT',
+ body: JSON.stringify(form),
+ headers: new Headers({
+ 'Content-Type': 'application/json'
+ })
+ }
+ )
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(resetForm('newProject'));
dispatch(showNotification('Successfully updated project'));
} else {
@@ -157,7 +162,7 @@ export function updateProject(form) {
}
return json;
})
- );
+ );
}
@@ -173,35 +178,35 @@ export function deleteProject(id) {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(showNotification('Project deleted'));
dispatch(selectProject());
} else {
dispatch(
showNotification(
'Error deleting project ({})'.format(json.message)
- ));
+ )
+ );
}
})
- );
+ );
}
export function uploadDataset(form) {
-
- function fileReaderPromise(form, fileName, binary = false){
- return new Promise(resolve => {
- var filereader = new FileReader();
+ function fileReaderPromise(formFields, fileName, binary = false) {
+ return new Promise((resolve) => {
+ const filereader = new FileReader();
if (binary) {
- filereader.readAsDataURL(form[fileName][0]);
+ filereader.readAsDataURL(formFields[fileName][0]);
} else {
- filereader.readAsText(form[fileName][0]);
+ filereader.readAsText(formFields[fileName][0]);
}
- filereader.onloadend = () => resolve({ body: filereader.result,
- name: form[fileName][0].name });
+ filereader.onloadend = () => resolve(
+ { body: filereader.result, name: formFields[fileName][0].name }
+ );
});
}
-
return dispatch =>
promiseAction(
dispatch,
@@ -209,31 +214,31 @@ export function uploadDataset(form) {
Promise.all([fileReaderPromise(form, 'headerFile'),
fileReaderPromise(form, 'tarFile', true)])
- .then(([headerData, tarData]) => {
- form['headerFile'] = headerData;
- form['tarFile'] = tarData;
-
- return fetch('/dataset', {
- credentials: 'same-origin',
- method: 'POST',
- body: JSON.stringify(form),
- headers: new Headers({
- 'Content-Type': 'application/json'
- })
- })
- })
- .then(response => response.json())
- .then((json) => {
- if (json.status == 'success') {
- dispatch(showNotification('Successfully uploaded new dataset'));
- dispatch(hideExpander('newDatasetExpander'));
- dispatch(resetForm('newDataset'));
- } else {
- return Promise.reject({ _error: json.message });
- }
- return json;
- })
- );
+ .then(([headerData, tarData]) => {
+ form.headerFile = headerData;
+ form.tarFile = tarData;
+
+ return fetch('/dataset', {
+ credentials: 'same-origin',
+ method: 'POST',
+ body: JSON.stringify(form),
+ headers: new Headers({
+ 'Content-Type': 'application/json'
+ })
+ });
+ })
+ .then(response => response.json())
+ .then((json) => {
+ if (json.status === 'success') {
+ dispatch(showNotification('Successfully uploaded new dataset'));
+ dispatch(hideExpander('newDatasetExpander'));
+ dispatch(resetForm('newDataset'));
+ } else {
+ return Promise.reject({ _error: json.message });
+ }
+ return json;
+ })
+ );
}
// Download datasets
@@ -247,10 +252,9 @@ export function fetchDatasets() {
credentials: 'same-origin'
})
.then(response => response.json())
- .then((json) => (
+ .then(json => (
dispatch(receiveDatasets(json.data))
- )
- ).catch(ex => console.log('fetchDatasets', ex))
+ )).catch(ex => console.log('fetchDatasets', ex))
);
}
@@ -275,17 +279,17 @@ export function fetchFeaturesets() {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
return dispatch(receiveFeaturesets(json.data));
} else {
return dispatch(
showNotification(
'Error downloading feature sets ({})'.format(json.message)
- ));
+ )
+ );
}
- }
- ).catch(ex => console.log('fetchFeaturesets', ex))
- );
+ }).catch(ex => console.log('fetchFeaturesets', ex))
+ );
}
// Receive list of featuresets
@@ -320,7 +324,7 @@ export function createModel(form) {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(resetForm('newModel'));
dispatch(hideExpander('newModelExpander'));
dispatch(showNotification('Model training begun.'));
@@ -329,7 +333,7 @@ export function createModel(form) {
}
return json;
})
- );
+ );
}
@@ -384,17 +388,17 @@ export function fetchFeatures() {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(receiveFeatures(json.data));
} else {
dispatch(
showNotification(
'Error downloading features ({})'.format(json.message)
- ));
+ )
+ );
}
return json;
- }
- ).catch(ex => console.log('fetchFeatures exception:', ex))
+ }).catch(ex => console.log('fetchFeatures exception:', ex))
);
}
@@ -420,10 +424,8 @@ export function computeFeatures(form) {
headers: new Headers({
'Content-Type': 'application/json'
})
- }
- ).then(response => response.json()
- ).then((json) => {
- if (json.status == 'success') {
+ }).then(response => response.json()).then((json) => {
+ if (json.status === 'success') {
dispatch(resetForm('featurize'));
dispatch(showNotification('Feature computation begun.'));
dispatch(hideExpander('featsetFormExpander'));
@@ -448,16 +450,17 @@ export function deleteDataset(id) {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(showNotification('Dataset deleted'));
} else {
dispatch(
showNotification(
'Error deleting dataset ({})'.format(json.message)
- ));
+ )
+ );
}
})
- );
+ );
}
@@ -473,16 +476,17 @@ export function deleteFeatureset(id) {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(showNotification('Feature set deleted'));
} else {
dispatch(
showNotification(
'Error deleting feature set ({})'.format(json.message)
- ));
+ )
+ );
}
})
- );
+ );
}
@@ -497,18 +501,18 @@ export function fetchSklearnModels() {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(receiveSklearnModels(json.data));
} else {
dispatch(
showNotification(
'Error downloading sklearn models ({})'.format(json.message)
- ));
+ )
+ );
}
return json;
- }
- ).catch(ex => console.log('fetchSklearnModels exception:', ex))
- );
+ }).catch(ex => console.log('fetchSklearnModels exception:', ex))
+ );
}
function receiveSklearnModels(sklearn_models) {
@@ -531,16 +535,16 @@ export function fetchModels() {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
return dispatch(receiveModels(json.data));
} else {
return dispatch(
showNotification(
'Error downloading models ({})'.format(json.message)
- ));
+ )
+ );
}
- }
- ).catch(ex => console.log('fetchModels', ex))
+ }).catch(ex => console.log('fetchModels', ex))
);
}
@@ -565,16 +569,17 @@ export function deleteModel(id) {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(showNotification('Model deleted'));
} else {
dispatch(
showNotification(
'Error deleting model ({})'.format(json.message)
- ));
+ )
+ );
}
})
- );
+ );
}
@@ -591,10 +596,8 @@ export function doPrediction(form) {
headers: new Headers({
'Content-Type': 'application/json'
})
- }
- ).then(response => response.json()
- ).then((json) => {
- if (json.status == 'success') {
+ }).then(response => response.json()).then((json) => {
+ if (json.status === 'success') {
dispatch(resetForm('predict'));
dispatch(showNotification('Model predictions begun.'));
dispatch(hideExpander('predictFormExpander'));
@@ -619,13 +622,14 @@ export function deletePrediction(id) {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(showNotification('Prediction deleted'));
} else {
dispatch(
showNotification(
'Error deleting prediction ({})'.format(json.message)
- ));
+ )
+ );
}
})
);
@@ -644,13 +648,12 @@ export function fetchPredictions() {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
return dispatch(receivePredictions(json.data));
} else {
return dispatch(showNotification(json.message));
}
- }
- ).catch(ex => console.log('fetchPredictions', ex))
+ }).catch(ex => console.log('fetchPredictions', ex))
);
}
@@ -697,18 +700,18 @@ export function fetchUserProfile() {
})
.then(response => response.json())
.then((json) => {
- if (json.status == 'success') {
+ if (json.status === 'success') {
dispatch(receiveUserProfile(json.data));
} else {
dispatch(
showNotification(
'Error downloading user profile ({})'.format(json.message)
- ));
+ )
+ );
}
return json;
- }
- ).catch(ex => console.log('fetchUserProfile exception:', ex))
- );
+ }).catch(ex => console.log('fetchUserProfile exception:', ex))
+ );
}
function receiveUserProfile(userProfile) {
@@ -719,7 +722,6 @@ function receiveUserProfile(userProfile) {
}
-
export function hydrate() {
return (dispatch) => {
dispatch(fetchProjects())
diff --git a/static/js/components/Datasets.jsx b/static/js/components/Datasets.jsx
index 52fc781..0e4dee4 100644
--- a/static/js/components/Datasets.jsx
+++ b/static/js/components/Datasets.jsx
@@ -1,7 +1,9 @@
import React from 'react';
+import PropTypes from 'prop-types';
import { connect } from "react-redux";
import { reduxForm } from 'redux-form';
+import { showNotification } from 'baselayer/components/Notifications';
import { FormComponent, Form, TextInput, FileInput, SubmitButton } from './Form';
import * as Validate from '../validate';
import Expand from './Expand';
@@ -10,7 +12,6 @@ import * as Action from '../actions';
import { reformatDatetime } from '../utils';
import CesiumTooltip from './Tooltip';
import FoldableRow from './FoldableRow';
-import { showNotification } from 'baselayer/components/Notifications';
const DatasetsTab = props => (
@@ -25,12 +26,15 @@ const DatasetsTab = props => (
);
DatasetsTab.propTypes = {
- selectedProject: React.PropTypes.object
+ selectedProject: PropTypes.object
+};
+DatasetsTab.defaultProps = {
+ selectedProject: {}
};
let DatasetForm = (props) => {
const { fields: { datasetName, headerFile, tarFile },
- error, handleSubmit, submitting } = props;
+ error, handleSubmit, submitting } = props;
const description = {
fontStyle: 'italic',
@@ -49,7 +53,7 @@ let DatasetForm = (props) => {
/>
- Format: comma-separated with columns "filename" (of a time series from the uploaded archive), "label" (class label or numerical value), and any metafeatures (numerical).
+ {'Format: comma-separated with columns "filename" (of a time series from the uploaded archive), "label" (class label or numerical value), and any metafeatures (numerical).'}
{
data-for="tarfileTooltip"
/>
- Format: zipfile or tarfile containing time series files, each of which is comma-separated with columns "time", "value", "error" (optional).
+ {'Format: zipfile or tarfile containing time series files, each of which is comma-separated with columns "time", "value", "error" (optional).'}
@@ -67,7 +71,7 @@ let DatasetForm = (props) => {
, "ts1.dat,class_A",
, "..."]}
+ text={["filename,label",
, "ts1.dat,class_A",
, "..."]}
/>
{
);
};
DatasetForm.propTypes = {
- fields: React.PropTypes.object.isRequired,
- error: React.PropTypes.string,
- handleSubmit: React.PropTypes.func.isRequired,
- submitting: React.PropTypes.bool.isRequired
+ fields: PropTypes.object.isRequired,
+ error: PropTypes.string,
+ handleSubmit: PropTypes.func.isRequired,
+ submitting: PropTypes.bool.isRequired
+};
+DatasetForm.defaultProps = {
+ error: ""
};
const dsMapStateToProps = (state, ownProps) => (
@@ -100,7 +107,7 @@ const dsMapStateToProps = (state, ownProps) => (
const dsMapDispatchToProps = (dispatch, ownProps) => (
{
- onSubmit: form => {
+ onSubmit: (form) => {
dispatch(showNotification('Dataset upload has begun.'));
return dispatch(Action.uploadDataset(form));
}
@@ -119,7 +126,7 @@ DatasetForm = reduxForm({
}, dsMapStateToProps, dsMapDispatchToProps)(DatasetForm);
-let DatasetInfo = props => (
+const DatasetInfo = props => (
@@ -140,7 +147,7 @@ let DatasetInfo = props => (
);
DatasetInfo.propTypes = {
- dataset: React.PropTypes.object.isRequired
+ dataset: PropTypes.object.isRequired
};
export let DatasetTable = props => (
@@ -177,7 +184,7 @@ export let DatasetTable = props => (
);
DatasetTable.propTypes = {
- datasets: React.PropTypes.arrayOf(React.PropTypes.object)
+ datasets: PropTypes.arrayOf(PropTypes.object).isRequired
};
diff --git a/static/js/components/Delete.jsx b/static/js/components/Delete.jsx
index 7740cdd..23af35c 100644
--- a/static/js/components/Delete.jsx
+++ b/static/js/components/Delete.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
const Delete = (props) => {
const style = {
@@ -19,11 +20,14 @@ const Delete = (props) => {
);
};
Delete.propTypes = {
- ID: React.PropTypes.oneOfType([
- React.PropTypes.number,
- React.PropTypes.string]).isRequired,
- delete: React.PropTypes.func.isRequired,
- typeName: React.PropTypes.string
+ ID: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string]).isRequired,
+ delete: PropTypes.func.isRequired,
+ typeName: PropTypes.string
+};
+Delete.defaultProps = {
+ typeName: ""
};
export default Delete;
diff --git a/static/js/components/Dot.jsx b/static/js/components/Dot.jsx
index f857df1..76e34dd 100644
--- a/static/js/components/Dot.jsx
+++ b/static/js/components/Dot.jsx
@@ -1,15 +1,15 @@
import React from 'react';
+import PropTypes from 'prop-types';
import colorScheme from './colorscheme';
const cs = colorScheme;
const Dot = (props) => {
- let value = props.value;
+ let { value, height } = { ...props };
if (value === undefined) {
value = 'ยทยทยท';
}
- let height = props.height;
if (height === undefined) {
height = '1em';
}
@@ -37,9 +37,15 @@ const Dot = (props) => {
);
};
Dot.propTypes = {
- value: React.PropTypes.string.isRequired,
- style: React.PropTypes.object,
- height: React.PropTypes.string
+ /* eslint-disable react/no-unused-prop-types */
+ value: PropTypes.string.isRequired,
+ style: PropTypes.object,
+ height: PropTypes.string
+ /* eslint-enable react/no-unused-prop-types */
+};
+Dot.defaultProps = {
+ style: {},
+ height: ""
};
export default Dot;
diff --git a/static/js/components/Expand.jsx b/static/js/components/Expand.jsx
index 58c1c40..4d84bd0 100644
--- a/static/js/components/Expand.jsx
+++ b/static/js/components/Expand.jsx
@@ -1,4 +1,5 @@
-import React, { Component, PropTypes } from 'react';
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { toggleExpander } from '../actions';
import Dot from './Dot';
@@ -61,13 +62,18 @@ let Expand = (props) => {
Expand.propTypes = {
expandBoxStyle: PropTypes.object,
style: PropTypes.object,
- label: PropTypes.string,
- toggle: PropTypes.func,
+ label: PropTypes.string.isRequired,
+ toggle: PropTypes.func.isRequired,
opened: PropTypes.bool,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.oneOfType([
PropTypes.node, PropTypes.element])),
- PropTypes.node, PropTypes.element])
+ PropTypes.node, PropTypes.element]).isRequired
+};
+Expand.defaultProps = {
+ expandBoxStyle: {},
+ style: {},
+ opened: false
};
const mapStateToProps = (state, ownProps) => (
diff --git a/static/js/components/Features.jsx b/static/js/components/Features.jsx
index 9bab7dd..4e61ce3 100644
--- a/static/js/components/Features.jsx
+++ b/static/js/components/Features.jsx
@@ -1,10 +1,11 @@
import React from 'react';
+import PropTypes from 'prop-types';
import { connect } from "react-redux";
import { reduxForm } from 'redux-form';
import ReactTabs from 'react-tabs';
import { FormComponent, Form, TextInput, TextareaInput, SubmitButton,
- CheckBoxInput, SelectInput } from './Form';
+ CheckBoxInput, SelectInput } from './Form';
import * as Validate from '../validate';
import Expand from './Expand';
import * as Action from '../actions';
@@ -13,16 +14,13 @@ import FoldableRow from './FoldableRow';
import { reformatDatetime, contains } from '../utils';
import Delete from './Delete';
-const Tab = ReactTabs.Tab;
-const Tabs = ReactTabs.Tabs;
-const TabList = ReactTabs.TabList;
-const TabPanel = ReactTabs.TabPanel;
+const { Tab, Tabs, TabList, TabPanel } = { ...ReactTabs };
let FeaturizeForm = (props) => {
const { fields, fields: { datasetID, featuresetName, customFeatsCode },
- handleSubmit, submitting, resetForm, error, featuresList,
- featureDescriptions } = props;
+ handleSubmit, submitting, resetForm, error, featuresList,
+ featureDescriptions } = props;
const datasets = props.datasets.map(ds => (
{ id: ds.id,
label: ds.name }
@@ -61,20 +59,22 @@ let FeaturizeForm = (props) => {
{
- Object.keys(props.featuresByCategory).map(ctgy => (
- {ctgy}
+ Object.keys(props.featuresByCategory).map((ctgy, idx) => (
+ {ctgy}
))
}
Custom Features
{
- Object.keys(props.featuresByCategory).map(ctgy => (
-
+ Object.keys(props.featuresByCategory).map((ctgy, idx) => (
+
{
props.dispatch(Action.groupToggleCheckedFeatures(
- props.featuresByCategory[ctgy])); }}
+ props.featuresByCategory[ctgy]
+));
+}}
>
Check/Uncheck All
@@ -83,8 +83,8 @@ let FeaturizeForm = (props) => {
{
props.featuresByCategory[ctgy].filter(feat => (
contains(featuresList, feat)
- )).map((feature, idx) => (
-
+ )).map((feature, idx2) => (
+
{
@@ -116,17 +117,24 @@ let FeaturizeForm = (props) => {
);
};
FeaturizeForm.propTypes = {
- fields: React.PropTypes.object.isRequired,
- datasets: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
- error: React.PropTypes.string,
- handleSubmit: React.PropTypes.func.isRequired,
- submitting: React.PropTypes.bool.isRequired,
- resetForm: React.PropTypes.func.isRequired,
- selectedProject: React.PropTypes.object,
- featuresByCategory: React.PropTypes.object,
- tagList: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
- featuresList: React.PropTypes.array,
- featureDescriptions: React.PropTypes.object
+ fields: PropTypes.object.isRequired,
+ datasets: PropTypes.arrayOf(PropTypes.object).isRequired,
+ error: PropTypes.string,
+ handleSubmit: PropTypes.func.isRequired,
+ submitting: PropTypes.bool.isRequired,
+ resetForm: PropTypes.func.isRequired,
+ selectedProject: PropTypes.object,
+ featuresByCategory: PropTypes.object,
+ tagList: PropTypes.arrayOf(PropTypes.string).isRequired,
+ featuresList: PropTypes.array,
+ featureDescriptions: PropTypes.object
+};
+FeaturizeForm.defaultProps = {
+ error: "",
+ selectedProject: {},
+ featuresByCategory: {},
+ featuresList: [],
+ featureDescriptions: {}
};
@@ -147,10 +155,11 @@ const mapStateToProps = (state, ownProps) => {
featureDescriptions: state.features.descriptions,
datasets: filteredDatasets,
fields: featuresList.concat(
- ['datasetID', 'featuresetName', 'customFeatsCode']),
+ ['datasetID', 'featuresetName', 'customFeatsCode']
+ ),
initialValues: { ...initialValues,
- datasetID: zerothDataset ? zerothDataset.id.toString() : "",
- customFeatsCode: "" }
+ datasetID: zerothDataset ? zerothDataset.id.toString() : "",
+ customFeatsCode: "" }
};
};
@@ -188,9 +197,12 @@ let FeaturesTab = (props) => {
);
};
FeaturesTab.propTypes = {
- featurePlotURL: React.PropTypes.string.isRequired,
- computeFeatures: React.PropTypes.func.isRequired,
- selectedProject: React.PropTypes.object
+ featurePlotURL: PropTypes.string.isRequired,
+ computeFeatures: PropTypes.func.isRequired,
+ selectedProject: PropTypes.object
+};
+FeaturesTab.defaultProps = {
+ selectedProject: {}
};
const ftMapDispatchToProps = dispatch => (
@@ -224,7 +236,8 @@ export let FeatureTable = props => (
|
);
- let elapsed = "", percent = "";
+ let elapsed = "";
+ let percent = "";
if (featureset.progress) {
({ elapsed, percent } = { ...featureset.progress });
}
@@ -248,15 +261,19 @@ export let FeatureTable = props => (
{foldedContent}
- ); })
+ );
+})
}
);
FeatureTable.propTypes = {
- featuresets: React.PropTypes.arrayOf(React.PropTypes.object),
- featurePlotURL: React.PropTypes.string
+ featuresets: PropTypes.arrayOf(PropTypes.object).isRequired,
+ featurePlotURL: PropTypes.string
+};
+FeatureTable.defaultProps = {
+ featurePlotURL: null
};
diff --git a/static/js/components/FoldableRow.jsx b/static/js/components/FoldableRow.jsx
index ab71121..f081d26 100644
--- a/static/js/components/FoldableRow.jsx
+++ b/static/js/components/FoldableRow.jsx
@@ -53,7 +53,8 @@ class FoldableRow extends Component {
e, {
style: this.state.folded ? {} : openStyleContent,
key: idx
- })
+ }
+ )
));
return (
@@ -70,5 +71,8 @@ FoldableRow.propTypes = {
PropTypes.node, PropTypes.element])),
PropTypes.node, PropTypes.element])
};
+FoldableRow.defaultProps = {
+ children: []
+};
export default FoldableRow;
diff --git a/static/js/components/Form.jsx b/static/js/components/Form.jsx
index 56e3e27..69a5271 100644
--- a/static/js/components/Form.jsx
+++ b/static/js/components/Form.jsx
@@ -1,4 +1,6 @@
-import React, { PropTypes } from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
+
export const FormComponent = (props) => {
};
@@ -28,6 +30,10 @@ Error.propTypes = {
error: PropTypes.string,
touched: PropTypes.bool
};
+Error.defaultProps = {
+ error: "",
+ touched: false
+};
export const Form = (props) => {
const style = {
@@ -57,7 +63,10 @@ Form.propTypes = {
PropTypes.element,
PropTypes.arrayOf(PropTypes.element),
PropTypes.arrayOf(PropTypes.node)
- ])
+ ]).isRequired
+};
+Form.defaultProps = {
+ error: ""
};
export const TextInput = (props) => {
@@ -87,8 +96,8 @@ export const TextInput = (props) => {
};
TextInput.propTypes = {
- label: PropTypes.string,
- value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
};
export const TextareaInput = (props) => {
@@ -116,8 +125,8 @@ export const TextareaInput = (props) => {
);
};
TextareaInput.propTypes = {
- label: PropTypes.string,
- value: PropTypes.string
+ label: PropTypes.string.isRequired,
+ value: PropTypes.string.isRequired
};
export const CheckBoxInput = (props) => {
@@ -138,9 +147,12 @@ export const CheckBoxInput = (props) => {
);
};
CheckBoxInput.propTypes = {
- label: PropTypes.string,
+ label: PropTypes.string.isRequired,
divStyle: PropTypes.object
};
+CheckBoxInput.defaultProps = {
+ divStyle: {}
+};
export const SelectInput = (props) => {
const selectInputStyle = {
@@ -186,6 +198,10 @@ SelectInput.propTypes = {
}))
/* eslint-enable react/no-unused-prop-types */
};
+SelectInput.defaultProps = {
+ label: "",
+ options: []
+};
export const SubmitButton = (props) => {
@@ -209,7 +225,10 @@ SubmitButton.propTypes = {
label: PropTypes.string,
disabled: PropTypes.bool
};
-
+SubmitButton.defaultProps = {
+ label: "",
+ disabled: false
+};
export const FileInput = (props) => {
const fileInputStyle = {
@@ -233,9 +252,9 @@ export const FileInput = (props) => {
);
};
FileInput.propTypes = {
- label: PropTypes.string,
+ label: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
- ])
+ ]).isRequired
};
diff --git a/static/js/components/Main.jsx b/static/js/components/Main.jsx
index 54a1d4f..383b443 100644
--- a/static/js/components/Main.jsx
+++ b/static/js/components/Main.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import { connect, Provider } from 'react-redux';
import ReactDOM from 'react-dom';
import ReactTabs from 'react-tabs';
@@ -6,25 +7,22 @@ import ReactTabs from 'react-tabs';
import 'bootstrap-css';
import 'bootstrap';
+import { Notifications } from 'baselayer/components/Notifications';
+import WebSocket from 'baselayer/components/WebSocket';
import configureStore from '../configureStore';
import * as Action from '../actions';
-import WebSocket from 'baselayer/components/WebSocket';
import CesiumMessageHandler from '../CesiumMessageHandler';
import { ProjectSelector, AddProject, ProjectTab } from './Projects';
import DatasetsTab from './Datasets';
import FeaturesTab from './Features';
import ModelsTab from './Models';
import PredictTab from './Predictions';
-import { Notifications } from 'baselayer/components/Notifications';
import colorScheme from './colorscheme';
import Progress from './Progress';
import CesiumTooltip from './Tooltip';
import UserProfile from './UserProfile';
-const Tab = ReactTabs.Tab;
-const Tabs = ReactTabs.Tabs;
-const TabList = ReactTabs.TabList;
-const TabPanel = ReactTabs.TabPanel;
+const { Tab, Tabs, TabList, TabPanel } = { ...ReactTabs };
const cs = colorScheme;
const store = configureStore();
@@ -222,7 +220,7 @@ class MainContent extends React.Component {
/>
-
+
@@ -299,7 +297,7 @@ class MainContent extends React.Component {
>
@@ -315,7 +313,7 @@ class MainContent extends React.Component {
@@ -372,25 +370,30 @@ class MainContent extends React.Component {
}
}
MainContent.propTypes = {
- selectedProject: React.PropTypes.object.isRequired,
- root: React.PropTypes.string.isRequired,
- logoSpinAngle: React.PropTypes.number.isRequired,
- spinLogo: React.PropTypes.func
+ selectedProject: PropTypes.object,
+ root: PropTypes.string.isRequired,
+ logoSpinAngle: PropTypes.number.isRequired,
+ spinLogo: PropTypes.func.isRequired,
+ username: PropTypes.string
+};
+MainContent.defaultProps = {
+ username: "",
+ selectedProject: {}
};
const mapStateToProps = function (state) {
// This can be improved by using
// http://redux-form.com/6.0.0-alpha.13/docs/api/FormValueSelector.md/
- const projectSelector = state.form.projectSelector;
+ const { projectSelector } = { ...state.form };
const selectedProjectId = projectSelector ? projectSelector.project.value : "";
let selectedProject = state.projects.projectList.filter(
p => (p.id == selectedProjectId)
);
- const firstProject = state.projects.projectList[0] || { id: '', label: '', description: '' };
+ const [firstProject] = state.projects.projectList || { id: '', label: '', description: '' };
if (selectedProject.length > 0) {
- selectedProject = selectedProject[0];
+ [selectedProject] = selectedProject;
} else {
selectedProject = firstProject;
}
@@ -420,7 +423,7 @@ MainContent = connect(mapStateToProps, mapDispatchToProps)(MainContent);
ReactDOM.render(
-
+
,
document.getElementById('content')
);
diff --git a/static/js/components/Models.jsx b/static/js/components/Models.jsx
index 1422cb8..e76e47e 100644
--- a/static/js/components/Models.jsx
+++ b/static/js/components/Models.jsx
@@ -1,4 +1,5 @@
-import React, { PropTypes } from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';
@@ -23,13 +24,16 @@ const ModelsTab = props => (
);
ModelsTab.propTypes = {
- selectedProject: React.PropTypes.object
+ selectedProject: PropTypes.object
+};
+ModelsTab.defaultProps = {
+ selectedProject: null
};
let NewModelForm = (props) => {
const { fields,
- fields: { modelName, featureset, modelType },
- error, handleSubmit } = props;
+ fields: { modelName, featureset, modelType },
+ error, handleSubmit } = props;
const skModels = props.models;
const selectModels = [];
@@ -45,13 +49,13 @@ let NewModelForm = (props) => {
}
const featuresets = props.featuresets
- .filter(fs => !Validate.isEmpty(fs.finished))
- .map(fs => (
- {
- id: fs.id,
- label: fs.name
- }
- ));
+ .filter(fs => !Validate.isEmpty(fs.finished))
+ .map(fs => (
+ {
+ id: fs.id,
+ label: fs.name
+ }
+ ));
const chosenModel = props.models[modelType.value];
@@ -62,12 +66,14 @@ let NewModelForm = (props) => {
@@ -79,11 +85,16 @@ let NewModelForm = (props) => {
);
};
NewModelForm.propTypes = {
- fields: React.PropTypes.object.isRequired,
- error: React.PropTypes.string,
- handleSubmit: React.PropTypes.func.isRequired,
- featuresets: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
- models: React.PropTypes.object.isRequired
+ fields: PropTypes.object.isRequired,
+ error: PropTypes.string,
+ handleSubmit: PropTypes.func.isRequired,
+ featuresets: PropTypes.arrayOf(PropTypes.object).isRequired,
+ models: PropTypes.object.isRequired,
+ selectedProject: PropTypes.object
+};
+NewModelForm.defaultProps = {
+ error: null,
+ selectedProject: null
};
const mapStateToProps = function (state, ownProps) {
@@ -142,12 +153,12 @@ export const Model = (props) => {
const style = {
};
- const model = props.model;
+ const { model } = { ...props };
return (
{model.name}
- {model.params.map((param, idx) => {
+ {model.params.map((param, idx) => {
const pProps = props[param.name];
if (param.type === 'bool') {
return ;
@@ -158,12 +169,9 @@ export const Model = (props) => {
);
};
-Model.propTypes = {
- model: React.PropTypes.object.isRequired
-};
-let ModelInfo = props => (
+const ModelInfo = props => (
@@ -181,8 +189,8 @@ let ModelInfo = props => (
{
- Object.keys(props.model.params).map(param => (
-
+ Object.keys(props.model.params).map((param, idx) => (
+
{param} |
{JSON.stringify(props.model.params[param])} |
@@ -199,7 +207,7 @@ let ModelInfo = props => (
);
ModelInfo.propTypes = {
- model: React.PropTypes.object.isRequired
+ model: PropTypes.object.isRequired
};
export let ModelTable = props => (
@@ -242,11 +250,15 @@ export let ModelTable = props => (
ModelTable.propTypes = {
models: PropTypes.arrayOf(PropTypes.object)
};
+ModelTable.defaultProps = {
+ models: null
+};
const mtMapStateToProps = (state, ownProps) => (
{
models: state.models.filter(
- model => (model.project_id === ownProps.selectedProject.id))
+ model => (model.project_id === ownProps.selectedProject.id)
+ )
}
);
diff --git a/static/js/components/Plot.jsx b/static/js/components/Plot.jsx
index f1bf02e..3d2335e 100644
--- a/static/js/components/Plot.jsx
+++ b/static/js/components/Plot.jsx
@@ -1,23 +1,28 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { showNotification } from 'baselayer/components/Notifications';
+/* eslint-disable */
import "../../../node_modules/bokehjs/build/js/bokeh.js";
import "../../../node_modules/bokehjs/build/css/bokeh.css";
+/* eslint-enable */
+
function bokeh_render_plot(node, docs_json, render_items) {
// Create bokeh div element
- var bokeh_div = document.createElement("div");
- var inner_div = document.createElement("div");
- bokeh_div.setAttribute("class", "bk-root" );
+ const bokeh_div = document.createElement("div");
+ const inner_div = document.createElement("div");
+ bokeh_div.setAttribute("class", "bk-root");
inner_div.setAttribute("class", "bk-plotdiv");
inner_div.setAttribute("id", render_items[0].elementid);
bokeh_div.appendChild(inner_div);
node.appendChild(bokeh_div);
// Generate plot
- Bokeh.safely(function() {
+ /* eslint-disable */
+ Bokeh.safely(() => {
Bokeh.embed.embed_items(docs_json, render_items);
});
+ /* eslint-enable */
}
class Plot extends Component {
@@ -50,15 +55,15 @@ class Plot extends Component {
if (!plotData) {
return Please wait while we load your plotting data...;
}
- var docs_json = JSON.parse(plotData.docs_json);
- var render_items = JSON.parse(plotData.render_items);
+ const docs_json = JSON.parse(plotData.docs_json);
+ const render_items = JSON.parse(plotData.render_items);
return (
plotData &&
{
- node && bokeh_render_plot(node, docs_json, render_items)
+ node && bokeh_render_plot(node, docs_json, render_items);
}
}
/>
diff --git a/static/js/components/Predictions.jsx b/static/js/components/Predictions.jsx
index c574259..dd1245d 100644
--- a/static/js/components/Predictions.jsx
+++ b/static/js/components/Predictions.jsx
@@ -1,9 +1,10 @@
-import React, { PropTypes } from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';
import { FormComponent, SelectInput, SubmitButton,
- Form } from './Form';
+ Form } from './Form';
import * as Validate from '../validate';
@@ -16,7 +17,7 @@ import Delete from './Delete';
let PredictForm = (props) => {
const { fields: { modelID, datasetID }, handleSubmit, submitting, resetForm,
- error } = props;
+ error } = props;
const datasets = props.datasets.map(ds => (
{ id: ds.id,
@@ -24,11 +25,11 @@ let PredictForm = (props) => {
));
const models = props.models
- .filter(model => !Validate.isEmpty(model.finished))
- .map(model => (
- { id: model.id,
- label: model.name }
- ));
+ .filter(model => !Validate.isEmpty(model.finished))
+ .map(model => (
+ { id: model.id,
+ label: model.name }
+ ));
return (
@@ -55,14 +56,17 @@ let PredictForm = (props) => {
);
};
PredictForm.propTypes = {
- fields: React.PropTypes.object.isRequired,
- error: React.PropTypes.string,
- handleSubmit: React.PropTypes.func.isRequired,
- resetForm: React.PropTypes.func.isRequired,
- submitting: React.PropTypes.bool.isRequired,
- datasets: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
- models: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
- selectedProject: React.PropTypes.object.isRequired
+ fields: PropTypes.object.isRequired,
+ error: PropTypes.string,
+ handleSubmit: PropTypes.func.isRequired,
+ resetForm: PropTypes.func.isRequired,
+ submitting: PropTypes.bool.isRequired,
+ datasets: PropTypes.arrayOf(PropTypes.object).isRequired,
+ models: PropTypes.arrayOf(PropTypes.object).isRequired,
+ selectedProject: PropTypes.object.isRequired
+};
+PredictForm.defaultProps = {
+ error: null
};
@@ -80,7 +84,7 @@ const mapStateToProps = (state, ownProps) => {
models: filteredModels,
fields: ['modelID', 'datasetID'],
initialValues: { modelID: zerothModel ? zerothModel.id : '',
- datasetID: zerothDataset ? zerothDataset.id : '' }
+ datasetID: zerothDataset ? zerothDataset.id : '' }
};
};
@@ -139,7 +143,8 @@ let PredictionsTable = props => (
{foldedContent}
- ); })
+ );
+})
}
@@ -147,25 +152,26 @@ let PredictionsTable = props => (
PredictionsTable.propTypes = {
predictions: PropTypes.arrayOf(PropTypes.object)
};
+PredictionsTable.defaultProps = {
+ predictions: null
+};
const PredictionResults = (props) => {
- const modelType = props.prediction.model_type;
- const results = props.prediction.results;
+ const { model_type, results, isProbabilistic } = { ...props.prediction };
const firstResult = results ? results[Object.keys(results)[0]] : null;
const classes = (firstResult && firstResult.prediction) ?
- Object.keys(firstResult.prediction) : null;
+ Object.keys(firstResult.prediction) : null;
- let modelHasClass = contains(['RidgeClassifierCV'], modelType);
- const modelHasProba = props.prediction.isProbabilistic;
+ let modelHasClass = contains(['RidgeClassifierCV'], model_type);
const modelHasTarget = contains(['RandomForestRegressor',
- 'LinearRegressor',
- 'BayesianARDRegressor',
- 'BayesianRidgeRegressor'],
- modelType);
- if (modelType === 'LinearSGDClassifier') {
- modelHasClass = !modelHasProba;
+ 'LinearRegressor',
+ 'BayesianARDRegressor',
+ 'BayesianRidgeRegressor'],
+ model_type);
+ if (model_type === 'LinearSGDClassifier') {
+ modelHasClass = !isProbabilistic;
}
const hasTrueTargetLabel = p => (p && p.label);
@@ -177,7 +183,7 @@ const PredictionResults = (props) => {
Time Series |
{hasTrueTargetLabel(firstResult) && True Class/Target | }
- {modelHasProba &&
+ {isProbabilistic &&
classes.map((classLabel, idx) => ([
Predicted Class | ,
Probability |
@@ -190,7 +196,7 @@ const PredictionResults = (props) => {
- {results && Object.keys(results).map((fname, idx) => {
+ {results && Object.keys(results).map((fname, idx) => {
const result = results[fname];
const classesSorted = classes.sort((a, b) => (result.prediction[b] - result.prediction[a]));
@@ -203,7 +209,7 @@ const PredictionResults = (props) => {
[hasTrueTargetLabel(result) &&
{result.label} | ,
- modelHasProba &&
+ isProbabilistic &&
classesSorted.map((classLabel, idx2) => ([
{classLabel} | ,
{result.prediction[classLabel]} |
@@ -215,7 +221,8 @@ const PredictionResults = (props) => {
]}
- ); })}
+ );
+})}
);
@@ -236,12 +243,12 @@ const ptMapStateToProps = (state, ownProps) => {
PredictionsTable = connect(ptMapStateToProps)(PredictionsTable);
const dpMapDispatchToProps = dispatch => (
- { delete: id => dispatch(Action.deletePrediction(id)) }
+ { delete: id => dispatch(Action.deletePrediction(id)) }
);
const DeletePrediction = connect(null, dpMapDispatchToProps)(Delete);
-const DownloadPredCSV = (props) => (
+const DownloadPredCSV = props => (
(
diff --git a/static/js/components/Projects.jsx b/static/js/components/Projects.jsx
index b1f4988..8398a0d 100644
--- a/static/js/components/Projects.jsx
+++ b/static/js/components/Projects.jsx
@@ -13,7 +13,7 @@ const cs = colorScheme;
const ProjectForm = (props) => {
const { fields: { projectName, projectDescription },
- error, resetForm, submitting, handleSubmit } = props;
+ error, resetForm, submitting, handleSubmit } = props;
return (
);
};
ProjectForm.propTypes = {
- fields: React.PropTypes.object.isRequired,
- label: React.PropTypes.string.isRequired,
- error: React.PropTypes.string,
- handleSubmit: React.PropTypes.func.isRequired,
- submitting: React.PropTypes.bool.isRequired,
- resetForm: React.PropTypes.func.isRequired
+ fields: PropTypes.object.isRequired,
+ label: PropTypes.string.isRequired,
+ error: PropTypes.string,
+ handleSubmit: PropTypes.func.isRequired,
+ submitting: PropTypes.bool.isRequired,
+ resetForm: PropTypes.func.isRequired
+};
+ProjectForm.defaultProps = {
+ error: null
};
const validate = Validate.createValidator({
@@ -123,7 +127,8 @@ let AddProject = (props) => {
@@ -136,6 +141,10 @@ AddProject.propTypes = {
addProject: PropTypes.func.isRequired,
style: PropTypes.object
};
+AddProject.defaultProps = {
+ label: "",
+ style: {}
+};
let mapDispatchToProps = dispatch => (
{
@@ -176,11 +185,15 @@ let ProjectSelector = (props) => {
);
};
ProjectSelector.propTypes = {
- fields: PropTypes.object,
+ fields: PropTypes.object.isRequired,
projects: PropTypes.arrayOf(PropTypes.object).isRequired,
style: PropTypes.object,
label: PropTypes.string
};
+ProjectSelector.defaultProps = {
+ style: {},
+ label: ""
+};
const psMapStateToProps = (state) => {
const projectZero = state.projects.projectList[0];
@@ -221,5 +234,5 @@ export const CurrentProject = (props) => {
};
CurrentProject.propTypes = {
- selectedProject: PropTypes.object
+ selectedProject: PropTypes.object.isRequired
};
diff --git a/static/js/components/Tooltip.jsx b/static/js/components/Tooltip.jsx
index 01480e0..bbf0a61 100644
--- a/static/js/components/Tooltip.jsx
+++ b/static/js/components/Tooltip.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import ReactTooltip from 'react-tooltip';
const CesiumTooltip = props => (
@@ -9,13 +10,13 @@ const CesiumTooltip = props => (
);
CesiumTooltip.propTypes = {
- id: React.PropTypes.string.isRequired,
- text: React.PropTypes.oneOfType([
- React.PropTypes.string,
- React.PropTypes.array
+ id: PropTypes.string.isRequired,
+ text: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.array
]).isRequired,
- place: React.PropTypes.string,
- delay: React.PropTypes.number
+ place: PropTypes.string,
+ delay: PropTypes.number
};
CesiumTooltip.defaultProps = {
place: 'top',
diff --git a/static/js/components/UserProfile.jsx b/static/js/components/UserProfile.jsx
index 3a5f5c0..36d67c6 100644
--- a/static/js/components/UserProfile.jsx
+++ b/static/js/components/UserProfile.jsx
@@ -1,10 +1,12 @@
import React from 'react';
import { connect } from 'react-redux';
-let UserProfile = (props) => {
- return (
- {props.profile.username}
- );
+let UserProfile = props => (
+ {props.profile.username}
+);
+UserProfile.propTypes = {
+ style: React.PropTypes.object.isRequired,
+ profile: React.PropTypes.object.isRequired
};
const mapStateToProps = state => (
diff --git a/static/js/reducers.js b/static/js/reducers.js
index 0e022f8..052e043 100644
--- a/static/js/reducers.js
+++ b/static/js/reducers.js
@@ -1,8 +1,8 @@
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
-import * as Action from './actions';
import { reducer as notifications } from 'baselayer/components/Notifications';
+import * as Action from './actions';
import { contains, joinObjectValues } from './utils';
@@ -40,20 +40,21 @@ function featuresets(state=[], action) {
switch (action.type) {
case Action.RECEIVE_FEATURESETS:
return action.payload;
- case Action.FEATURIZE_PROGRESS:
- const newState = [ ...state ];
+ case Action.FEATURIZE_PROGRESS: {
+ const newState = [...state];
const { percent, elapsed } = { ...action.payload };
- const featureIdx = newState.findIndex((element) => (
- element.id == action.payload.fsetID
+ const featureIdx = newState.findIndex(element => (
+ element.id === action.payload.fsetID
));
- if (featureIdx != -1) {
+ if (featureIdx !== -1) {
const feature = newState[featureIdx];
feature.progress = { percent, elapsed };
}
return newState;
+ }
default:
return state;
}
@@ -68,13 +69,13 @@ function features(state={}, action) {
const allFeatsList = joinObjectValues(action.payload.features_by_category);
return { ...action.payload,
- allFeatsList,
- tagList,
- checkedTags: tagList.slice(0),
- featsWithCheckedTags: allFeatsList.slice(0) };
+ allFeatsList,
+ tagList,
+ checkedTags: tagList.slice(0),
+ featsWithCheckedTags: allFeatsList.slice(0) };
}
case Action.CLICK_FEATURE_TAG_CHECKBOX: {
- let checkedTags = state.checkedTags.slice(0);
+ const checkedTags = state.checkedTags.slice(0);
if (checkedTags.indexOf(action.payload.tag) > -1) {
checkedTags.splice(checkedTags.indexOf(action.payload.tag), 1);
@@ -85,8 +86,8 @@ function features(state={}, action) {
const featsWithCheckedTags = state.allFeatsList.filter(feature => (
state.tags[feature].some(tag => contains(checkedTags, tag))));
return { ...state,
- featsWithCheckedTags,
- checkedTags };
+ featsWithCheckedTags,
+ checkedTags };
}
default:
return state;
@@ -124,10 +125,12 @@ const myFormReducer = theirFormReducer => (
}
case Action.GROUP_TOGGLE_FEATURES: {
const field_names = Object.keys(state.featurize).filter(
- field_name => contains(action.payload.ctgy_list, field_name));
+ field_name => contains(action.payload.ctgy_list, field_name)
+ );
const featurizeFormState = Object.assign({}, state.featurize);
const allAreChecked = (field_names.filter(
- el => !featurizeFormState[el].value).length === 0);
+ el => !featurizeFormState[el].value
+ ).length === 0);
for (const idx in field_names) {
featurizeFormState[field_names[idx]].value = !allAreChecked;
}
diff --git a/static/js/validate.js b/static/js/validate.js
index c283672..87f3969 100644
--- a/static/js/validate.js
+++ b/static/js/validate.js
@@ -7,8 +7,6 @@ export function email(value) {
// Let's not start a debate on email regex. This is just for an example app!
if (!isEmpty(value) && !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)) {
return 'Invalid email address';
- } else {
- return;
}
}