}}
/>
}
successful={hasSucceeded}
@@ -233,8 +232,7 @@ EditAssignmentForm.propTypes = {
PropTypes.string
]),
localizedTexts: PropTypes.array
- }),
- intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired
+ })
};
const isNonNegativeInteger = n =>
@@ -441,10 +439,8 @@ const asyncValidate = (values, dispatch, { assignment: { id, version } }) =>
.catch(errors => reject(errors))
);
-export default injectIntl(
- reduxForm({
- form: 'editAssignment',
- validate,
- asyncValidate
- })(EditAssignmentForm)
-);
+export default reduxForm({
+ form: 'editAssignment',
+ validate,
+ asyncValidate
+})(EditAssignmentForm);
diff --git a/src/components/forms/EditExerciseForm/EditExerciseForm.js b/src/components/forms/EditExerciseForm/EditExerciseForm.js
index c7a6c9856..0a8afbf6e 100644
--- a/src/components/forms/EditExerciseForm/EditExerciseForm.js
+++ b/src/components/forms/EditExerciseForm/EditExerciseForm.js
@@ -18,9 +18,9 @@ import FormBox from '../../widgets/FormBox';
import SubmitButton from '../SubmitButton';
import Button from '../../widgets/FlatButton';
import LocalizedTextsFormField from '../LocalizedTextsFormField';
+import LocalizedExerciseName from '../../helpers/LocalizedExerciseName';
import { validateExercise } from '../../../redux/modules/exercises';
import withLinks from '../../../hoc/withLinks';
-import { getLocalizedName } from '../../../helpers/getLocalizedData';
if (canUseDOM) {
require('codemirror/mode/yaml/yaml');
@@ -59,7 +59,7 @@ const EditExerciseForm = ({
}}
/>
}
succeeded={hasSucceeded}
diff --git a/src/components/helpers/LocalizedExerciseName/LocalizedExerciseName.js b/src/components/helpers/LocalizedExerciseName/LocalizedExerciseName.js
new file mode 100644
index 000000000..c46ece4f5
--- /dev/null
+++ b/src/components/helpers/LocalizedExerciseName/LocalizedExerciseName.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { injectIntl } from 'react-intl';
+import { OverlayTrigger, Tooltip } from 'react-bootstrap';
+import Icon from 'react-fontawesome';
+
+import {
+ getLocalizedName,
+ getOtherLocalizedNames
+} from '../../../helpers/getLocalizedData';
+
+const LocalizedExerciseName = ({ entity, intl: { locale } }) => {
+ const otherNames = getOtherLocalizedNames(entity, locale);
+ return (
+
+ {getLocalizedName(entity, locale)}
+ {otherNames.length > 0 &&
+
+ n.name).join(', ')}>
+ {otherNames.map(name =>
+
+ {name.name} [{name.locale}]
+
+ )}
+
+ }
+ >
+
+
+ }
+
+ );
+};
+
+LocalizedExerciseName.propTypes = {
+ entity: PropTypes.object,
+ intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired
+};
+
+export default injectIntl(LocalizedExerciseName);
diff --git a/src/components/helpers/LocalizedExerciseName/index.js b/src/components/helpers/LocalizedExerciseName/index.js
new file mode 100644
index 000000000..d9cd439e2
--- /dev/null
+++ b/src/components/helpers/LocalizedExerciseName/index.js
@@ -0,0 +1 @@
+export default from './LocalizedExerciseName';
diff --git a/src/helpers/getLocalizedData.js b/src/helpers/getLocalizedData.js
index e692486b7..1de68cd7b 100644
--- a/src/helpers/getLocalizedData.js
+++ b/src/helpers/getLocalizedData.js
@@ -7,3 +7,10 @@ const getLocalizedX = field => (entity, locale) => {
export const getLocalizedName = getLocalizedX('name');
export const getLocalizedDescription = getLocalizedX('description');
+
+export const getOtherLocalizedNames = (entity, locale) => {
+ const name = getLocalizedName(entity, locale);
+ return entity.localizedTexts
+ .filter(text => text.name && text.name !== name)
+ .map(({ name, locale }) => ({ name, locale }));
+};
diff --git a/src/pages/Assignment/Assignment.js b/src/pages/Assignment/Assignment.js
index f1a763b35..d588ca906 100644
--- a/src/pages/Assignment/Assignment.js
+++ b/src/pages/Assignment/Assignment.js
@@ -2,8 +2,9 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
-import { FormattedMessage, injectIntl } from 'react-intl';
+import { FormattedMessage } from 'react-intl';
import { Col, Row, Alert } from 'react-bootstrap';
+
import Button from '../../components/widgets/FlatButton';
import { LinkContainer } from 'react-router-bootstrap';
@@ -34,6 +35,7 @@ import { runtimeEnvironmentSelector } from '../../redux/selectors/runtimeEnviron
import Page from '../../components/layout/Page';
import ResourceRenderer from '../../components/helpers/ResourceRenderer';
+import LocalizedExerciseName from '../../components/helpers/LocalizedExerciseName';
import UsersNameContainer from '../../containers/UsersNameContainer';
import { ResubmitAllSolutionsContainer } from '../../containers/ResubmitSolutionContainer';
import HierarchyLineContainer from '../../containers/HierarchyLineContainer';
@@ -45,7 +47,6 @@ import SubmitSolutionContainer from '../../containers/SubmitSolutionContainer';
import SubmissionsTableContainer from '../../containers/SubmissionsTableContainer';
import withLinks from '../../hoc/withLinks';
-import { getLocalizedName } from '../../helpers/getLocalizedData';
class Assignment extends Component {
static loadAsync = ({ assignmentId }, dispatch) =>
@@ -82,17 +83,13 @@ class Assignment extends Component {
canSubmit,
runtimeEnvironments,
exerciseSync,
- intl: { locale },
links: { ASSIGNMENT_EDIT_URI_FACTORY, SUPERVISOR_STATS_URI_FACTORY }
} = this.props;
return (
-
- {getLocalizedName(assignment, locale)}
- }
+ title={assignment => }
description={
{
- const assignmentSelector = getAssignment(assignmentId);
- const environments = runtimeEnvironmentsSelector(assignmentId)(
- state
- ).toJS();
- const loggedInUserId = loggedInUserIdSelector(state);
- userId = userId || loggedInUserId;
- return {
- assignment: assignmentSelector(state),
- submitting: isSubmitting(state),
- runtimeEnvironments: environments.map(i =>
- runtimeEnvironmentSelector(i)(state)
- ),
- userId,
- loggedInUserId,
- isSuperAdmin: isSuperAdmin(loggedInUserId)(state),
- isStudentOf: groupId => isStudentOf(loggedInUserId, groupId)(state),
- isSupervisorOf: groupId =>
- isSupervisorOf(loggedInUserId, groupId)(state),
- canSubmit: canSubmitSolution(assignmentId)(state)
- };
- },
- (dispatch, { params: { assignmentId } }) => ({
- init: userId => () => dispatch(init(userId, assignmentId)),
- loadAsync: () => Assignment.loadAsync({ assignmentId }, dispatch),
- exerciseSync: () => dispatch(syncWithExercise(assignmentId))
- })
- )(Assignment)
- )
+export default withLinks(
+ connect(
+ (state, { params: { assignmentId, userId } }) => {
+ const assignmentSelector = getAssignment(assignmentId);
+ const environments = runtimeEnvironmentsSelector(assignmentId)(
+ state
+ ).toJS();
+ const loggedInUserId = loggedInUserIdSelector(state);
+ userId = userId || loggedInUserId;
+ return {
+ assignment: assignmentSelector(state),
+ submitting: isSubmitting(state),
+ runtimeEnvironments: environments.map(i =>
+ runtimeEnvironmentSelector(i)(state)
+ ),
+ userId,
+ loggedInUserId,
+ isSuperAdmin: isSuperAdmin(loggedInUserId)(state),
+ isStudentOf: groupId => isStudentOf(loggedInUserId, groupId)(state),
+ isSupervisorOf: groupId =>
+ isSupervisorOf(loggedInUserId, groupId)(state),
+ canSubmit: canSubmitSolution(assignmentId)(state)
+ };
+ },
+ (dispatch, { params: { assignmentId } }) => ({
+ init: userId => () => dispatch(init(userId, assignmentId)),
+ loadAsync: () => Assignment.loadAsync({ assignmentId }, dispatch),
+ exerciseSync: () => dispatch(syncWithExercise(assignmentId))
+ })
+ )(Assignment)
);
diff --git a/src/pages/EditExercise/EditExercise.js b/src/pages/EditExercise/EditExercise.js
index 8f3515e6c..16381e4fc 100644
--- a/src/pages/EditExercise/EditExercise.js
+++ b/src/pages/EditExercise/EditExercise.js
@@ -12,6 +12,7 @@ import Box from '../../components/widgets/Box';
import EditExerciseForm from '../../components/forms/EditExerciseForm';
import AdditionalExerciseFilesTableContainer from '../../containers/AdditionalExerciseFilesTableContainer';
import DeleteExerciseButtonContainer from '../../containers/DeleteExerciseButtonContainer';
+import LocalizedExerciseName from '../../components/helpers/LocalizedExerciseName';
import {
fetchExerciseIfNeeded,
@@ -50,7 +51,7 @@ class EditExercise extends Component {
return (
getLocalizedName(exercise, locale)}
+ title={exercise => }
description={
getLocalizedName(exercise, locale)}
+ title={exercise => }
description={
getLocalizedName(exercise, locale)}
+ title={exercise => }
resource={exercise}
description={
@@ -49,14 +49,13 @@ class Submission extends Component {
assignment,
submission,
params: { assignmentId },
- isSupervisorOrMore,
- intl: { locale }
+ isSupervisorOrMore
} = this.props;
return (
getLocalizedName(assignment, locale)}
+ title={assignment => }
description={
({
- submission: getSubmission(submissionId)(state),
- assignment: getAssignment(assignmentId)(state),
- isSupervisorOrMore: groupId =>
- isSupervisorOf(loggedInUserIdSelector(state), groupId)(state) ||
- isAdminOf(loggedInUserIdSelector(state), groupId)(state) ||
- isSuperAdmin(loggedInUserIdSelector(state))(state)
- }),
- (dispatch, { params }) => ({
- loadAsync: () => Submission.loadAsync(params, dispatch)
- })
- )(Submission)
-);
+export default connect(
+ (state, { params: { submissionId, assignmentId } }) => ({
+ submission: getSubmission(submissionId)(state),
+ assignment: getAssignment(assignmentId)(state),
+ isSupervisorOrMore: groupId =>
+ isSupervisorOf(loggedInUserIdSelector(state), groupId)(state) ||
+ isAdminOf(loggedInUserIdSelector(state), groupId)(state) ||
+ isSuperAdmin(loggedInUserIdSelector(state))(state)
+ }),
+ (dispatch, { params }) => ({
+ loadAsync: () => Submission.loadAsync(params, dispatch)
+ })
+)(Submission);