From 890284570ea550eb7eb6386807722b6c493e44ea Mon Sep 17 00:00:00 2001 From: Martin Krulis Date: Thu, 4 Nov 2021 00:17:28 +0100 Subject: [PATCH] Adding deadline to shadow assignments. --- .../ShadowAssignmentDetail.js | 40 ++++++++++++- .../ShadowAssignmentsTable.js | 5 +- .../ShadowAssignmentsTableRow.js | 7 ++- .../ShadowAssignmentPointsTable.js | 12 +++- .../EditShadowAssignmentForm.js | 56 +++++++++++++++---- src/locales/cs.json | 3 + src/locales/en.json | 3 + .../EditShadowAssignment.js | 15 ++--- src/pages/GroupDetail/GroupDetail.js | 4 +- 9 files changed, 119 insertions(+), 26 deletions(-) diff --git a/src/components/Assignments/ShadowAssignment/ShadowAssignmentDetail/ShadowAssignmentDetail.js b/src/components/Assignments/ShadowAssignment/ShadowAssignmentDetail/ShadowAssignmentDetail.js index 1affc2aeb..0c69130a0 100644 --- a/src/components/Assignments/ShadowAssignment/ShadowAssignmentDetail/ShadowAssignmentDetail.js +++ b/src/components/Assignments/ShadowAssignment/ShadowAssignmentDetail/ShadowAssignmentDetail.js @@ -2,12 +2,23 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Table } from 'react-bootstrap'; import { FormattedMessage, FormattedNumber } from 'react-intl'; -import Icon, { BonusIcon, VisibleIcon, SuccessOrFailureIcon } from '../../../icons'; + +import Icon, { BonusIcon, VisibleIcon, SuccessOrFailureIcon, DeadlineIcon } from '../../../icons'; import Box from '../../../widgets/Box'; +import Explanation from '../../../widgets/Explanation'; import DateTime from '../../../widgets/DateTime'; import Version from '../../../widgets/Version/Version'; -const ShadowAssignmentDetail = ({ maxPoints, isBonus, isPublic, createdAt, updatedAt, version, permissionHints }) => ( +const ShadowAssignmentDetail = ({ + maxPoints, + isBonus, + isPublic, + createdAt, + deadline, + updatedAt, + version, + permissionHints, +}) => ( } noPadding> @@ -17,6 +28,12 @@ const ShadowAssignmentDetail = ({ maxPoints, isBonus, isPublic, createdAt, updat + + + + + + + - diff --git a/src/components/Assignments/ShadowAssignment/ShadowAssignmentsTable/ShadowAssignmentsTableRow.js b/src/components/Assignments/ShadowAssignment/ShadowAssignmentsTable/ShadowAssignmentsTableRow.js index 9067abf95..6bf31957b 100644 --- a/src/components/Assignments/ShadowAssignment/ShadowAssignmentsTable/ShadowAssignmentsTableRow.js +++ b/src/components/Assignments/ShadowAssignment/ShadowAssignmentsTable/ShadowAssignmentsTableRow.js @@ -21,7 +21,7 @@ const getUserPointsNote = defaultMemoize((points, userId) => ); const ShadowAssignmentsTableRow = ({ - item: { id, localizedTexts, createdAt, isBonus, isPublic, maxPoints, points, permissionHints }, + item: { id, localizedTexts, createdAt, deadline, isBonus, isPublic, maxPoints, points, permissionHints }, userId, isAdmin, links: { SHADOW_ASSIGNMENT_DETAIL_URI_FACTORY, SHADOW_ASSIGNMENT_EDIT_URI_FACTORY }, @@ -50,6 +50,10 @@ const ShadowAssignmentsTableRow = ({ + + + {warning} + + + )} +
diff --git a/src/components/forms/EditShadowAssignmentForm/EditShadowAssignmentForm.js b/src/components/forms/EditShadowAssignmentForm/EditShadowAssignmentForm.js index 74efcff54..4611f39ad 100644 --- a/src/components/forms/EditShadowAssignmentForm/EditShadowAssignmentForm.js +++ b/src/components/forms/EditShadowAssignmentForm/EditShadowAssignmentForm.js @@ -7,9 +7,10 @@ import { Container, Row, Col } from 'react-bootstrap'; import Callout from '../../widgets/Callout'; import FormBox from '../../widgets/FormBox'; import { SaveIcon } from '../../icons'; -import { CheckboxField, NumericTextField } from '../Fields'; +import { CheckboxField, NumericTextField, DatetimeField } from '../Fields'; import LocalizedTextsFormField from '../LocalizedTextsFormField'; import SubmitButton from '../SubmitButton'; +import Explanation from '../../widgets/Explanation'; import { LocalizedExerciseName } from '../../helpers/LocalizedNames'; import { validateLocalizedTextsFormData } from '../../../helpers/localizedData'; import { safeGet } from '../../../helpers/common'; @@ -74,17 +75,50 @@ const EditShadowAssignmentForm = ({ - - } - /> - + +
+ + : + + + + + } + /> + + + + + + + + + + } + /> + + + dispatch(fetchShadowAssignment(shadowId)); - getInitialValues = defaultMemoize(({ localizedTexts, isPublic, isBonus, maxPoints }) => ({ + getInitialValues = defaultMemoize(({ localizedTexts, isPublic, isBonus, maxPoints, deadline }) => ({ sendNotification: true, isPublic, isBonus, maxPoints, - localizedTexts: getLocalizedTextsInitialValues(localizedTexts, localizedTextDefaults), + deadline: deadline ? moment.unix(deadline) : null, + localizedTexts: getLocalizedTextsInitialValues(localizedTexts, LOCALIZED_TEXT_DEFAULTS), })); editShadowAssignmentSubmitHandler = formData => { @@ -76,9 +78,10 @@ class EditShadowAssignment extends Component { }) .then(() => { // prepare the data and submit them - const { localizedTexts, ...data } = formData; + const { localizedTexts, deadline, ...data } = formData; return editShadowAssignment({ ...data, + deadline: deadline ? moment(deadline).unix() : null, localizedTexts: transformLocalizedTextsFormData(formData.localizedTexts), version, }); @@ -197,9 +200,7 @@ export default connect( ) => ({ reset: () => dispatch(reset('editShadowAssignment')), loadAsync: () => EditShadowAssignment.loadAsync({ shadowId }, dispatch), - editShadowAssignment: data => { - return dispatch(editShadowAssignment(shadowId, data)); - }, + editShadowAssignment: data => dispatch(editShadowAssignment(shadowId, data)), validateShadowAssignment: version => dispatch(validateShadowAssignment(shadowId, version)), }) )(withLinks(EditShadowAssignment)); diff --git a/src/pages/GroupDetail/GroupDetail.js b/src/pages/GroupDetail/GroupDetail.js index 9f5157cea..68ea7b734 100644 --- a/src/pages/GroupDetail/GroupDetail.js +++ b/src/pages/GroupDetail/GroupDetail.js @@ -240,7 +240,7 @@ class GroupDetail extends Component { statuses={statuses} stats={groupStats.find(item => item.userId === userId)} userId={isGroupAdmin || isGroupSupervisor ? null : userId} - isAdmin={isGroupAdmin || isGroupSupervisor} + isAdmin={isGroupAdmin || isGroupSupervisor || isSuperadminRole(effectiveRole)} /> )} @@ -276,7 +276,7 @@ class GroupDetail extends Component { }>
: + + + @@ -35,6 +52,24 @@ const ShadowAssignmentDetail = ({ maxPoints, isBonus, isPublic, createdAt, updat
+ + + : + + + + + +
@@ -82,6 +117,7 @@ ShadowAssignmentDetail.propTypes = { isBonus: PropTypes.bool, isPublic: PropTypes.bool, createdAt: PropTypes.number.isRequired, + deadline: PropTypes.number, updatedAt: PropTypes.number.isRequired, version: PropTypes.number.isRequired, permissionHints: PropTypes.object, diff --git a/src/components/Assignments/ShadowAssignment/ShadowAssignmentsTable/ShadowAssignmentsTable.js b/src/components/Assignments/ShadowAssignment/ShadowAssignmentsTable/ShadowAssignmentsTable.js index bc2c87ca0..ce485c055 100644 --- a/src/components/Assignments/ShadowAssignment/ShadowAssignmentsTable/ShadowAssignmentsTable.js +++ b/src/components/Assignments/ShadowAssignment/ShadowAssignmentsTable/ShadowAssignmentsTable.js @@ -28,6 +28,9 @@ const ShadowAssignmentsTable = ({ + + {!isAdmin ? ( @@ -61,7 +64,7 @@ const ShadowAssignmentsTable = ({ {shadowAssignments.some(isLoading) && (
+ + + {!isAdmin && getUserPoints(points, userId)} {maxPoints > 0 ? ( @@ -86,6 +90,7 @@ ShadowAssignmentsTableRow.propTypes = { id: PropTypes.string, localizedTexts: PropTypes.array, createdAt: PropTypes.number, + deadline: PropTypes.number, isBonus: PropTypes.bool, isPublic: PropTypes.bool, maxPoints: PropTypes.number, diff --git a/src/components/Assignments/ShadowAssignmentPointsTable/ShadowAssignmentPointsTable.js b/src/components/Assignments/ShadowAssignmentPointsTable/ShadowAssignmentPointsTable.js index a03d4371c..27e5c6705 100644 --- a/src/components/Assignments/ShadowAssignmentPointsTable/ShadowAssignmentPointsTable.js +++ b/src/components/Assignments/ShadowAssignmentPointsTable/ShadowAssignmentPointsTable.js @@ -91,6 +91,7 @@ class ShadowAssignmentPointsTable extends Component { maxLength={6} validateMin={-10000} validateMax={10000} + ignoreDirty label={ } @@ -102,13 +103,20 @@ class ShadowAssignmentPointsTable extends Component { name="note" component={TextField} maxLength={1024} + ignoreDirty label={} /> - - {warning && {warning}} + {warning && ( + +