diff --git a/src/components/Exercises/ExercisesListItem/ExercisesListItem.js b/src/components/Exercises/ExercisesListItem/ExercisesListItem.js
index b675d24a2..1734600db 100644
--- a/src/components/Exercises/ExercisesListItem/ExercisesListItem.js
+++ b/src/components/Exercises/ExercisesListItem/ExercisesListItem.js
@@ -9,7 +9,7 @@ import { Link } from 'react-router';
import withLinks from '../../../hoc/withLinks';
import { LocalizedExerciseName } from '../../helpers/LocalizedNames';
-import { MaybeLockedExerciseIcon } from '../../icons';
+import { ExercisePrefixIcons } from '../../icons';
const ExercisesListItem = ({
id,
@@ -20,6 +20,8 @@ const ExercisesListItem = ({
localizedTexts,
createdAt,
isLocked,
+ isBroken,
+ validationError,
createActions,
locale,
links: { EXERCISE_URI_FACTORY }
@@ -29,7 +31,12 @@ const ExercisesListItem = ({
-
+
@@ -74,6 +81,8 @@ ExercisesListItem.propTypes = {
difficulty: PropTypes.string.isRequired,
createdAt: PropTypes.number.isRequired,
isLocked: PropTypes.bool.isRequired,
+ isBroken: PropTypes.bool.isRequired,
+ validationError: PropTypes.string,
localizedTexts: PropTypes.array.isRequired,
createActions: PropTypes.func,
locale: PropTypes.string.isRequired,
diff --git a/src/components/Exercises/ExercisesName/ExercisesName.js b/src/components/Exercises/ExercisesName/ExercisesName.js
index 19b00a590..8a740cbdb 100644
--- a/src/components/Exercises/ExercisesName/ExercisesName.js
+++ b/src/components/Exercises/ExercisesName/ExercisesName.js
@@ -5,18 +5,25 @@ import { Link } from 'react-router';
import withLinks from '../../../hoc/withLinks';
import { LocalizedExerciseName } from '../../helpers/LocalizedNames';
-import { MaybeLockedExerciseIcon } from '../../icons';
+import { ExercisePrefixIcons } from '../../icons';
const ExercisesName = ({
id,
name,
localizedTexts,
isLocked,
+ isBroken,
+ validationError,
noLink,
links: { EXERCISE_URI_FACTORY }
}) =>
-
+
{noLink
?
@@ -31,6 +38,8 @@ ExercisesName.propTypes = {
name: PropTypes.string.isRequired,
localizedTexts: PropTypes.array.isRequired,
isLocked: PropTypes.bool.isRequired,
+ isBroken: PropTypes.bool.isRequired,
+ validationError: PropTypes.string,
noLink: PropTypes.bool,
links: PropTypes.object
};
diff --git a/src/components/Exercises/ExercisesSimpleListItem/ExercisesSimpleListItem.js b/src/components/Exercises/ExercisesSimpleListItem/ExercisesSimpleListItem.js
index 294c6a32f..1a14fa2cf 100644
--- a/src/components/Exercises/ExercisesSimpleListItem/ExercisesSimpleListItem.js
+++ b/src/components/Exercises/ExercisesSimpleListItem/ExercisesSimpleListItem.js
@@ -6,7 +6,7 @@ import { Link } from 'react-router';
import withLinks from '../../../hoc/withLinks';
import { LocalizedExerciseName } from '../../helpers/LocalizedNames';
-import { MaybeLockedExerciseIcon } from '../../icons';
+import { ExercisePrefixIcons } from '../../icons';
const ExercisesSimpleListItem = ({
id,
@@ -14,6 +14,8 @@ const ExercisesSimpleListItem = ({
difficulty,
authorId,
isLocked,
+ isBroken,
+ validationError,
localizedTexts,
createActions,
locale,
@@ -21,7 +23,12 @@ const ExercisesSimpleListItem = ({
}) =>
-
+
@@ -36,7 +43,7 @@ const ExercisesSimpleListItem = ({
|
{createActions &&
- {createActions(id, isLocked)}
+ {createActions(id, isLocked, isBroken)}
| }
;
@@ -46,6 +53,8 @@ ExercisesSimpleListItem.propTypes = {
name: PropTypes.string.isRequired,
difficulty: PropTypes.string.isRequired,
isLocked: PropTypes.bool.isRequired,
+ isBroken: PropTypes.bool.isRequired,
+ validationError: PropTypes.string,
localizedTexts: PropTypes.array.isRequired,
createActions: PropTypes.func,
locale: PropTypes.string.isRequired,
diff --git a/src/components/Groups/SupervisorsView/SupervisorsView.js b/src/components/Groups/SupervisorsView/SupervisorsView.js
index 7e492a435..b99fabc77 100644
--- a/src/components/Groups/SupervisorsView/SupervisorsView.js
+++ b/src/components/Groups/SupervisorsView/SupervisorsView.js
@@ -140,10 +140,11 @@ const SupervisorsView = ({
{(...exercises) =>
+ createActions={(exerciseId, isLocked, isBroken) =>
assignExercise(exerciseId)}
/>
diff --git a/src/components/buttons/AssignExerciseButton/AssignExerciseButton.js b/src/components/buttons/AssignExerciseButton/AssignExerciseButton.js
index 91c73b280..25c5cb36a 100644
--- a/src/components/buttons/AssignExerciseButton/AssignExerciseButton.js
+++ b/src/components/buttons/AssignExerciseButton/AssignExerciseButton.js
@@ -1,19 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
+import Icon from 'react-fontawesome';
import Button from '../../widgets/FlatButton';
import { SendIcon, InfoIcon } from '../../../components/icons';
-const AssignExerciseButton = ({ isLocked, assignExercise, ...props }) => {
- if (isLocked) {
+const AssignExerciseButton = ({
+ isLocked,
+ isBroken,
+ assignExercise,
+ ...props
+}) => {
+ if (isLocked || isBroken) {
return (
);
} else {
@@ -32,6 +43,7 @@ const AssignExerciseButton = ({ isLocked, assignExercise, ...props }) => {
AssignExerciseButton.propTypes = {
isLocked: PropTypes.bool.isRequired,
+ isBroken: PropTypes.bool.isRequired,
assignExercise: PropTypes.func.isRequired
};
diff --git a/src/components/icons/ExercisePrefixIcons.js b/src/components/icons/ExercisePrefixIcons.js
new file mode 100644
index 000000000..a1904b1dd
--- /dev/null
+++ b/src/components/icons/ExercisePrefixIcons.js
@@ -0,0 +1,51 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { FormattedMessage } from 'react-intl';
+import Icon from 'react-fontawesome';
+import { OverlayTrigger, Tooltip } from 'react-bootstrap';
+
+const ExercisePrefixIcons = ({ id, isLocked, isBroken, ...props }) =>
+
+ {isLocked &&
+
+
+
+
+ }
+ >
+
+
+
+ }
+ {isBroken &&
+
+
+
+
+ }
+ >
+
+
+
+ }
+ ;
+
+ExercisePrefixIcons.propTypes = {
+ id: PropTypes.any.isRequired,
+ isLocked: PropTypes.bool.isRequired,
+ isBroken: PropTypes.bool.isRequired
+};
+
+export default ExercisePrefixIcons;
diff --git a/src/components/icons/MaybeLockedExerciseIcon.js b/src/components/icons/MaybeLockedExerciseIcon.js
deleted file mode 100644
index 48b666bd7..000000000
--- a/src/components/icons/MaybeLockedExerciseIcon.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { FormattedMessage } from 'react-intl';
-import Icon from 'react-fontawesome';
-import { OverlayTrigger, Tooltip } from 'react-bootstrap';
-
-const MaybeLockedExerciseIcon = ({ id, isLocked, ...props }) =>
- isLocked && (
-
-
-
-
- }
- >
-
-
- {' '}
-
- );
-
-MaybeLockedExerciseIcon.propTypes = {
- id: PropTypes.any.isRequired,
- isLocked: PropTypes.bool.isRequired
-};
-
-export default MaybeLockedExerciseIcon;
diff --git a/src/components/icons/index.js b/src/components/icons/index.js
index d8b1e699a..8ad560be5 100644
--- a/src/components/icons/index.js
+++ b/src/components/icons/index.js
@@ -20,6 +20,6 @@ export { default as SettingsIcon } from './SettingsIcon';
export {
default as MaybeBonusAssignmentIcon
} from './MaybeBonusAssignmentIcon';
-export { default as MaybeLockedExerciseIcon } from './MaybeLockedExerciseIcon';
+export { default as ExercisePrefixIcons } from './ExercisePrefixIcons';
export { default as CopyIcon } from './CopyIcon';
export { default as LocalIcon } from './LocalIcon';
diff --git a/src/locales/cs.json b/src/locales/cs.json
index d91ca9912..7b83ba6f2 100644
--- a/src/locales/cs.json
+++ b/src/locales/cs.json
@@ -5,6 +5,7 @@
"app.EditSimpleLimitsForm.validation.NaN": "Given value is not a number.",
"app.EditSimpleLimitsForm.validation.tooHigh": "Given value exceeds the recommended maximum ({max}).",
"app.EditSimpleLimitsForm.validation.tooLow": "Given value is below the recommended minimum ({min}).",
+ "app.ExercisePrefixIcons.isLocked": "Exercise is locked by author and cannot be assigned",
"app.acceptSolution.accepted": "Zrušit jako finální",
"app.acceptSolution.notAccepted": "Akceptovat jako finální",
"app.addLicence.addLicenceTitle": "Přidat novou licenci",
@@ -32,6 +33,7 @@
"app.adminAssignmentsTable.noAssignments": "Nejsou dostupné žádné úlohy.",
"app.adminAssignmentsTableRow.edit": "Upravit",
"app.adminAssignmentsTableRow.loading": "Načítají se zadané úlohy ...",
+ "app.assignExerciseButton.isBroken": "Broken",
"app.assignExerciseButton.isLocked": "Locked",
"app.assignemntStatusIcon.evaluationFailed": "Žádné řesení nebylo správně vyhodnoceno.",
"app.assignemntStatusIcon.failed": "Žádné správné řešení nebylo zatím odevzdáno.",
@@ -486,6 +488,7 @@
"app.exercise.forked": "Duplikováno z:",
"app.exercise.groups": "Groups:",
"app.exercise.groupsBox": "Skupiny",
+ "app.exercise.isBroken": "Exercise configuration is incorrect and needs fixing",
"app.exercise.isLocked": "Is locked:",
"app.exercise.isPublic": "Is public:",
"app.exercise.noReferenceSolutions": "Nyní zde nejsou žádná referenční řešení pro tuto úlohu.",
diff --git a/src/locales/en.json b/src/locales/en.json
index 64e8e3082..ecad5041e 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -5,6 +5,7 @@
"app.EditSimpleLimitsForm.validation.NaN": "Given value is not a number.",
"app.EditSimpleLimitsForm.validation.tooHigh": "Given value exceeds the recommended maximum ({max}).",
"app.EditSimpleLimitsForm.validation.tooLow": "Given value is below the recommended minimum ({min}).",
+ "app.ExercisePrefixIcons.isLocked": "Exercise is locked by author and cannot be assigned",
"app.acceptSolution.accepted": "Revoke as Final",
"app.acceptSolution.notAccepted": "Accept as Final",
"app.addLicence.addLicenceTitle": "Add new licence",
@@ -32,6 +33,7 @@
"app.adminAssignmentsTable.noAssignments": "There are no assignments.",
"app.adminAssignmentsTableRow.edit": "Edit",
"app.adminAssignmentsTableRow.loading": "Loading assignments ...",
+ "app.assignExerciseButton.isBroken": "Broken",
"app.assignExerciseButton.isLocked": "Locked",
"app.assignemntStatusIcon.evaluationFailed": "No solution was evaluated correctly by ReCodEx.",
"app.assignemntStatusIcon.failed": "No correct solution was submitted yet.",
@@ -486,6 +488,7 @@
"app.exercise.forked": "Forked from:",
"app.exercise.groups": "Groups:",
"app.exercise.groupsBox": "Groups",
+ "app.exercise.isBroken": "Exercise configuration is incorrect and needs fixing",
"app.exercise.isLocked": "Is locked:",
"app.exercise.isPublic": "Is public:",
"app.exercise.noReferenceSolutions": "There are no reference solutions for this exercise yet.",
diff --git a/src/pages/EditExercise/EditExercise.js b/src/pages/EditExercise/EditExercise.js
index 912c73caa..90a198d39 100644
--- a/src/pages/EditExercise/EditExercise.js
+++ b/src/pages/EditExercise/EditExercise.js
@@ -6,6 +6,7 @@ import { Row, Col } from 'react-bootstrap';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { reset, getFormValues } from 'redux-form';
+import Icon from 'react-fontawesome';
import Page from '../../components/layout/Page';
import Box from '../../components/widgets/Box';
@@ -88,6 +89,21 @@ class EditExercise extends Component {
>
{exercise =>
+ {exercise.isBroken &&
+
+
+
+
+
+
+
+ {exercise.validationError}
+
+
+ }
+ {exercise.isBroken &&
+
+
+
+
+
+
+
+ {exercise.validationError}
+
+
+ }
{exercise =>
+ {exercise.isBroken &&
+
+
+
+
+
+
+
+ {exercise.validationError}
+
+
+ }
{canEditExercise(exercise.id) &&
@@ -239,33 +255,36 @@ class Exercise extends Component {
{exercise.localizedTexts.length > 0 &&
}
-
-
-
- }
- noPadding
- >
-
+
+
+ }
+ noPadding
>
- {() =>
-
- this.assignExercise(groupId)}
- />}
- />}
-
-
+
+ {() =>
+
+
+ this.assignExercise(groupId)}
+ />}
+ />}
+
+ }
-
- {(...pipelines) =>
+
+ {pipelines =>
@@ -419,8 +441,6 @@ class Exercise extends Component {
}
-
-
|