diff --git a/.gitignore b/.gitignore index f01d1cee2..cb2437104 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ npm-debug.log prod/ package-lock.json +/run_server.bat diff --git a/src/components/Exercises/AttachedFilesTable/AttachedFilesTable.js b/src/components/Exercises/AttachedFilesTable/AttachedFilesTable.js index 33571e5e9..9f8a362a1 100644 --- a/src/components/Exercises/AttachedFilesTable/AttachedFilesTable.js +++ b/src/components/Exercises/AttachedFilesTable/AttachedFilesTable.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import Icon from 'react-fontawesome'; import { Table } from 'react-bootstrap'; @@ -28,7 +28,8 @@ const AttachedFilesTable = ({ downloadFile, uploadId, HeaderComponent, - RowComponent + RowComponent, + intl }) =>
@@ -62,7 +63,7 @@ const AttachedFilesTable = ({ {attachments - .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => a.name.localeCompare(b.name, intl.locale)) .map((data, i) => ( +const ExercisesList = ({ exercises = [], createActions, intl, ...rest }) => @@ -44,19 +44,18 @@ const ExercisesList = ({ exercises = [], createActions, ...rest }) => ( .filter(e => e !== null) .sort( (a, b) => - a.name < b.name - ? -1 - : b.name < a.name ? 1 : b.createdAt - a.createdAt + a.name.localeCompare(b.name, intl.locale) || + b.createdAt - a.createdAt ) - .map(exercise => ( + .map(exercise => - ))} + )} - {exercises.length === 0 && ( + {exercises.length === 0 && - - )} + } -
( defaultMessage="There are no exercises in this list." />
-); + ; ExercisesList.propTypes = { exercises: PropTypes.array, - createActions: PropTypes.func + createActions: PropTypes.func, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default ExercisesList; +export default injectIntl(ExercisesList); diff --git a/src/components/Exercises/ExercisesSimpleList/ExercisesSimpleList.js b/src/components/Exercises/ExercisesSimpleList/ExercisesSimpleList.js index 4f4211627..96e568de8 100644 --- a/src/components/Exercises/ExercisesSimpleList/ExercisesSimpleList.js +++ b/src/components/Exercises/ExercisesSimpleList/ExercisesSimpleList.js @@ -1,11 +1,11 @@ import React from 'react'; import { Table } from 'react-bootstrap'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import GroupExercisesListItem from '../ExercisesSimpleListItem'; -const ExercisesSimpleList = ({ exercises, createActions, ...rest }) => ( +const ExercisesSimpleList = ({ exercises, createActions, intl, ...rest }) => @@ -33,22 +33,22 @@ const ExercisesSimpleList = ({ exercises, createActions, ...rest }) => ( {exercises .sort((a, b) => { - var tmp = a.name.localeCompare(b.name); + var tmp = a.name.localeCompare(b.name, intl.locale); if (tmp === 0) { return b.createdAt - a.createdAt; } else { return tmp; } }) - .map(exercise => ( + .map(exercise => - ))} + )} - {exercises.length === 0 && ( + {exercises.length === 0 && - - )} + } -
( defaultMessage="There are no exercises in this list." />
-); + ; ExercisesSimpleList.propTypes = { exercises: PropTypes.array.isRequired, - createActions: PropTypes.func + createActions: PropTypes.func, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default ExercisesSimpleList; +export default injectIntl(ExercisesSimpleList); diff --git a/src/components/Instances/InstancesTable/InstancesTable.js b/src/components/Instances/InstancesTable/InstancesTable.js index 94fc6be30..02ef73151 100644 --- a/src/components/Instances/InstancesTable/InstancesTable.js +++ b/src/components/Instances/InstancesTable/InstancesTable.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import { Table } from 'react-bootstrap'; import { Link } from 'react-router'; import { MaybeSucceededIcon } from '../../icons'; @@ -8,7 +8,7 @@ import UsersNameContainer from '../../../containers/UsersNameContainer'; import withLinks from '../../../hoc/withLinks'; -const InstancesTable = ({ instances, links: { INSTANCE_URI_FACTORY } }) => ( +const InstancesTable = ({ instances, links: { INSTANCE_URI_FACTORY }, intl }) => @@ -34,11 +34,13 @@ const InstancesTable = ({ instances, links: { INSTANCE_URI_FACTORY } }) => ( {instances - .sort((a, b) => (a.name < b.name ? -1 : 1)) - .map(({ id, name, admin, hasValidLicence }) => ( + .sort((a, b) => a.name.localeCompare(b.name, intl.locale)) + .map(({ id, name, admin, hasValidLicence }) => - ))} + )} -
- {name} + + {name} + @@ -47,14 +49,14 @@ const InstancesTable = ({ instances, links: { INSTANCE_URI_FACTORY } }) => (
-); + ; InstancesTable.propTypes = { instances: PropTypes.array.isRequired, - links: PropTypes.object + links: PropTypes.object, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default withLinks(InstancesTable); +export default injectIntl(withLinks(InstancesTable)); diff --git a/src/components/Pipelines/PipelinesList/PipelinesList.js b/src/components/Pipelines/PipelinesList/PipelinesList.js index 3871f3dce..0c1982b7a 100644 --- a/src/components/Pipelines/PipelinesList/PipelinesList.js +++ b/src/components/Pipelines/PipelinesList/PipelinesList.js @@ -1,11 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Table } from 'react-bootstrap'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import PipelinesListItem from '../PipelinesListItem'; -const PipelinesList = ({ pipelines = [], createActions }) => +const PipelinesList = ({ pipelines = [], createActions, intl }) => @@ -36,7 +36,7 @@ const PipelinesList = ({ pipelines = [], createActions }) => {pipelines .filter(a => a !== null) - .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => a.name.localeCompare(b.name, intl.locale)) .map(pipeline => PipelinesList.propTypes = { pipelines: PropTypes.array, - createActions: PropTypes.func + createActions: PropTypes.func, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default PipelinesList; +export default injectIntl(PipelinesList); diff --git a/src/components/Pipelines/PipelinesSimpleList/PipelinesSimpleList.js b/src/components/Pipelines/PipelinesSimpleList/PipelinesSimpleList.js index 868b01e2c..9b13d4160 100644 --- a/src/components/Pipelines/PipelinesSimpleList/PipelinesSimpleList.js +++ b/src/components/Pipelines/PipelinesSimpleList/PipelinesSimpleList.js @@ -1,11 +1,11 @@ import React from 'react'; import { Table } from 'react-bootstrap'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import ExercisePipelinesListItem from '../PipelinesSimpleListItem'; -const PipelinesSimpleList = ({ pipelines, createActions, ...rest }) => +const PipelinesSimpleList = ({ pipelines, createActions, intl, ...rest }) =>
@@ -32,14 +32,11 @@ const PipelinesSimpleList = ({ pipelines, createActions, ...rest }) => {pipelines - .sort((a, b) => { - var tmp = a.name.localeCompare(b.name); - if (tmp === 0) { - return b.createdAt - a.createdAt; - } else { - return tmp; - } - }) + .sort( + (a, b) => + a.name.localeCompare(b.name, intl.locale) || + b.createdAt - a.createdAt + ) .map((pipeline, i) => PipelinesSimpleList.propTypes = { pipelines: PropTypes.array.isRequired, - createActions: PropTypes.func + createActions: PropTypes.func, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default PipelinesSimpleList; +export default injectIntl(PipelinesSimpleList); diff --git a/src/components/Users/UsersList/UsersList.js b/src/components/Users/UsersList/UsersList.js index 6e12d663f..a40a45a95 100644 --- a/src/components/Users/UsersList/UsersList.js +++ b/src/components/Users/UsersList/UsersList.js @@ -1,17 +1,17 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Table } from 'react-bootstrap'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import UsersListItem from '../UsersListItem'; -const UsersList = ({ users = [], createActions, ...rest }) => +const UsersList = ({ users = [], createActions, intl, ...rest }) =>
{users .sort((a, b) => { const aName = a.name.lastName + ' ' + a.name.firstName; const bName = b.name.lastName + ' ' + b.name.firstName; - return aName.localeCompare(bName); + return aName.localeCompare(bName, intl.locale); }) .map(user => UsersList.propTypes = { users: PropTypes.array, - createActions: PropTypes.func + createActions: PropTypes.func, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default UsersList; +export default injectIntl(UsersList); diff --git a/src/components/forms/EditExerciseConfigForm/EditExerciseConfigTest.js b/src/components/forms/EditExerciseConfigForm/EditExerciseConfigTest.js index 405cfee24..a7edc7cb8 100644 --- a/src/components/forms/EditExerciseConfigForm/EditExerciseConfigTest.js +++ b/src/components/forms/EditExerciseConfigForm/EditExerciseConfigTest.js @@ -1,4 +1,5 @@ import React from 'react'; +import { injectIntl } from 'react-intl'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { Field } from 'redux-form'; @@ -12,7 +13,8 @@ const EditExerciseConfigTest = ({ supplementaryFiles, pipelines, runtimeEnvironmentIndex, - fetchVariables + fetchVariables, + intl }) => {tests.map((test, index) => [ @@ -30,7 +32,7 @@ const EditExerciseConfigTest = ({ component={SelectField} options={[{ key: '', name: '...' }].concat( pipelines - .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => a.name.localeCompare(b.name, intl.locale)) .map(data => { const obj = {}; obj['key'] = data.id; @@ -67,7 +69,7 @@ const EditExerciseConfigTest = ({ component={SelectField} options={[{ key: '', name: '...' }].concat( pipelines - .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => a.name.localeCompare(b.name, intl.locale)) .map(data => { const obj = {}; obj['key'] = data.id; @@ -104,7 +106,8 @@ EditExerciseConfigTest.propTypes = { supplementaryFiles: ImmutablePropTypes.map, pipelines: ImmutablePropTypes.map, runtimeEnvironmentIndex: PropTypes.number.isRequired, - fetchVariables: PropTypes.func + fetchVariables: PropTypes.func, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default EditExerciseConfigTest; +export default injectIntl(EditExerciseConfigTest); diff --git a/src/components/forms/EditExerciseConfigForm/EditExerciseConfigVariable.js b/src/components/forms/EditExerciseConfigForm/EditExerciseConfigVariable.js index a28456ef6..1d11c1cca 100644 --- a/src/components/forms/EditExerciseConfigForm/EditExerciseConfigVariable.js +++ b/src/components/forms/EditExerciseConfigForm/EditExerciseConfigVariable.js @@ -1,4 +1,5 @@ import React from 'react'; +import { injectIntl } from 'react-intl'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { Row, Col } from 'react-bootstrap'; @@ -11,7 +12,12 @@ import { } from '../Fields'; import ResourceRenderer from '../../helpers/ResourceRenderer'; -const EditExerciseConfigVariable = ({ prefix, data, supplementaryFiles }) => +const EditExerciseConfigVariable = ({ + prefix, + data, + supplementaryFiles, + intl +}) => @@ -39,7 +45,7 @@ const EditExerciseConfigVariable = ({ prefix, data, supplementaryFiles }) => label={''} options={[{ key: '', name: '...' }].concat( supplementaryFiles - .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => a.name.localeCompare(b.name, intl.locale)) .filter((item, pos, arr) => arr.indexOf(item) === pos) .map(data => ({ key: data.hashName, @@ -65,7 +71,7 @@ const EditExerciseConfigVariable = ({ prefix, data, supplementaryFiles }) => label={''} options={[{ key: '', name: '...' }].concat( supplementaryFiles - .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => a.name.localeCompare(b.name, intl.locale)) .filter((item, pos, arr) => arr.indexOf(item) === pos) .map(data => ({ key: data.hashName, @@ -81,7 +87,8 @@ const EditExerciseConfigVariable = ({ prefix, data, supplementaryFiles }) => EditExerciseConfigVariable.propTypes = { prefix: PropTypes.string.isRequired, data: PropTypes.object.isRequired, - supplementaryFiles: ImmutablePropTypes.map + supplementaryFiles: ImmutablePropTypes.map, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default EditExerciseConfigVariable; +export default injectIntl(EditExerciseConfigVariable); diff --git a/src/components/forms/Fields/PipelineVariablesField.js b/src/components/forms/Fields/PipelineVariablesField.js index b8311efbd..3a2fcc95b 100644 --- a/src/components/forms/Fields/PipelineVariablesField.js +++ b/src/components/forms/Fields/PipelineVariablesField.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Field } from 'redux-form'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import { TextField, SelectField, @@ -18,7 +18,8 @@ const PipelineVariablesField = ({ input, label, variables, - supplementaryFiles + supplementaryFiles, + intl }) =>

@@ -39,7 +40,7 @@ const PipelineVariablesField = ({ component={isArray(type) ? ExpandingSelectField : SelectField} options={[{ key: '', name: '...' }].concat( supplementaryFiles - .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => a.name.localeCompare(b.name, intl.locale)) .filter((item, pos, arr) => arr.indexOf(item) === pos) .map(data => ({ key: data.hashName, @@ -71,7 +72,8 @@ PipelineVariablesField.propTypes = { PropTypes.element ]).isRequired, variables: PropTypes.array, - supplementaryFiles: ImmutablePropTypes.map + supplementaryFiles: ImmutablePropTypes.map, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default PipelineVariablesField; +export default injectIntl(PipelineVariablesField); diff --git a/src/components/forms/ForkPipelineForm/ForkPipelineForm.js b/src/components/forms/ForkPipelineForm/ForkPipelineForm.js index 7d29129b3..23cbfdf0b 100644 --- a/src/components/forms/ForkPipelineForm/ForkPipelineForm.js +++ b/src/components/forms/ForkPipelineForm/ForkPipelineForm.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import { Alert, Form } from 'react-bootstrap'; import { connect } from 'react-redux'; import { push } from 'react-router-redux'; @@ -39,7 +39,8 @@ class ForkPipelineForm extends Component { hasFailed = false, hasSucceeded = false, invalid, - exercises + exercises, + intl } = this.props; switch (forkStatus) { @@ -77,7 +78,9 @@ class ForkPipelineForm extends Component { label={''} options={[{ key: '', name: '_Public_' }].concat( exercises - .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => + a.name.localeCompare(b.name, intl.locale) + ) .filter((item, pos, arr) => arr.indexOf(item) === pos) .map(exercise => ({ key: exercise.id, @@ -137,7 +140,8 @@ ForkPipelineForm.propTypes = { handleSubmit: PropTypes.func.isRequired, push: PropTypes.func.isRequired, links: PropTypes.object, - exercises: ImmutablePropTypes.map + exercises: ImmutablePropTypes.map, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; const mapStateToProps = (state, { pipelineId, forkId }) => { @@ -160,6 +164,6 @@ export default withLinks( reduxForm({ form: 'forkPipeline', validate - })(ForkPipelineForm) + })(injectIntl(ForkPipelineForm)) ) ); diff --git a/src/components/layout/Sidebar/Supervisor.js b/src/components/layout/Sidebar/Supervisor.js index f12d8606f..5410e41cf 100644 --- a/src/components/layout/Sidebar/Supervisor.js +++ b/src/components/layout/Sidebar/Supervisor.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import MenuTitle from '../../widgets/Sidebar/MenuTitle'; import MenuGroup from '../../widgets/Sidebar/MenuGroup'; @@ -15,7 +15,8 @@ const Supervisor = ({ supervisorOf, isCollapsed, notifications, - links: { GROUP_URI_FACTORY, EXERCISES_URI, PIPELINES_URI } + links: { GROUP_URI_FACTORY, EXERCISES_URI, PIPELINES_URI }, + intl }) =>
    } - items={supervisorOf.toList()} + items={supervisorOf + .toList() + .sort((a, b) => + a + .getIn(['data', 'name']) + .localeCompare(b.getIn(['data', 'name']), intl.locale) + )} notifications={{}} icon="wrench" currentPath={currentUrl} @@ -69,7 +76,8 @@ Supervisor.propTypes = { supervisorOf: ImmutablePropTypes.map, isCollapsed: PropTypes.bool, notifications: PropTypes.object, - links: PropTypes.object + links: PropTypes.object, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; -export default withLinks(Supervisor); +export default injectIntl(withLinks(Supervisor)); diff --git a/src/pages/AssignmentStats/AssignmentStats.js b/src/pages/AssignmentStats/AssignmentStats.js index b8d28f198..73ff2ef1b 100644 --- a/src/pages/AssignmentStats/AssignmentStats.js +++ b/src/pages/AssignmentStats/AssignmentStats.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Row, Col } from 'react-bootstrap'; import { connect } from 'react-redux'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import { usersSelector } from '../../redux/selectors/users'; import { groupSelector, studentsOfGroup } from '../../redux/selectors/groups'; import { getAssignment } from '../../redux/selectors/assignments'; @@ -39,7 +39,13 @@ class AssignmentStats extends Component { } render() { - const { assignmentId, assignment, getStudents, getGroup } = this.props; + const { + assignmentId, + assignment, + getStudents, + getGroup, + intl + } = this.props; return ( { const aName = a.name.lastName + ' ' + a.name.firstName; const bName = b.name.lastName + ' ' + b.name.firstName; - return aName.localeCompare(bName); + return aName.localeCompare(bName, intl.locale); }) .map(user => @@ -133,7 +139,8 @@ AssignmentStats.propTypes = { assignment: PropTypes.object, getStudents: PropTypes.func.isRequired, getGroup: PropTypes.func.isRequired, - loadAsync: PropTypes.func.isRequired + loadAsync: PropTypes.func.isRequired, + intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; export default connect( @@ -156,4 +163,4 @@ export default connect( (dispatch, { params: { assignmentId } }) => ({ loadAsync: () => AssignmentStats.loadAsync({ assignmentId }, dispatch) }) -)(AssignmentStats); +)(injectIntl(AssignmentStats));