Skip to content

Commit

Permalink
Adding deadline to shadow assignments.
Browse files Browse the repository at this point in the history
  • Loading branch information
krulis-martin committed Nov 7, 2021
1 parent 1082ba5 commit 8902845
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}) => (
<Box title={<FormattedMessage id="generic.details" defaultMessage="Details" />} noPadding>
<Table responsive size="sm">
<tbody>
Expand All @@ -17,6 +28,12 @@ const ShadowAssignmentDetail = ({ maxPoints, isBonus, isPublic, createdAt, updat
</td>
<th>
<FormattedMessage id="app.shadowAssignment.maxPoints" defaultMessage="Points limit" />:
<Explanation id="pointsExplanation">
<FormattedMessage
id="app.editShadowAssignmentForm.pointsExplanation"
defaultMessage="The maximal amount of points has only informative value for the students. The supervisor may choose to exceed this limit when awarding points."
/>
</Explanation>
</th>
<td>
<FormattedNumber value={maxPoints} />
Expand All @@ -35,6 +52,24 @@ const ShadowAssignmentDetail = ({ maxPoints, isBonus, isPublic, createdAt, updat
</td>
</tr>

<tr>
<td className="text-center text-muted shrink-col px-2">
<DeadlineIcon />
</td>
<th>
<FormattedMessage id="app.assignment.deadline" defaultMessage="Deadline" />:
<Explanation id="deadlineExplanation">
<FormattedMessage
id="app.shadowAssignment.deadlineExplanation"
defaultMessage="The deadline has only informative value for the students. The points are awarded manually, so the supervisor ultimately decides whether a deadline was breached or not."
/>
</Explanation>
</th>
<td>
<DateTime unixts={deadline} isDeadline />
</td>
</tr>

<tr>
<td className="text-center text-muted shrink-col px-2">
<Icon icon={['far', 'copy']} />
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ const ShadowAssignmentsTable = ({
<th>
<FormattedMessage id="generic.created" defaultMessage="Created" />
</th>
<th>
<FormattedMessage id="app.assignments.deadline" defaultMessage="Deadline" />
</th>

<th className="text-center text-nowrap">
{!isAdmin ? (
Expand Down Expand Up @@ -61,7 +64,7 @@ const ShadowAssignmentsTable = ({

{shadowAssignments.some(isLoading) && (
<tr>
<td className="text-center em-padding" colSpan={isAdmin ? 4 : 3}>
<td className="text-center em-padding" colSpan={isAdmin ? 5 : 4}>
<LoadingIcon gapRight />
<FormattedMessage id="app.shadowAssignmentsTable.loading" defaultMessage="Loading shadow assignments..." />
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down Expand Up @@ -50,6 +50,10 @@ const ShadowAssignmentsTableRow = ({
<DateTime unixts={createdAt} />
</td>

<td className="text-nowrap">
<DateTime unixts={deadline} isDeadline />
</td>

<td className="text-center">
{!isAdmin && getUserPoints(points, userId)}
{maxPoints > 0 ? (
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class ShadowAssignmentPointsTable extends Component {
maxLength={6}
validateMin={-10000}
validateMax={10000}
ignoreDirty
label={
<FormattedMessage id="app.editShadowAssignmentPointsForm.points" defaultMessage="Points:" />
}
Expand All @@ -102,13 +103,20 @@ class ShadowAssignmentPointsTable extends Component {
name="note"
component={TextField}
maxLength={1024}
ignoreDirty
label={<FormattedMessage id="app.editShadowAssignmentPointsForm.note" defaultMessage="Note:" />}
/>
</Col>
</Row>
</Container>

{warning && <Callout variant="warning">{warning}</Callout>}
{warning && (
<Row>
<Col xl={12}>
<Callout variant="warning">{warning}</Callout>
</Col>
</Row>
)}
</Container>

<div className="text-center text-nowrap mb-1">
<TheButtonGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -74,17 +75,50 @@ const EditShadowAssignmentForm = ({

<FieldArray name="localizedTexts" component={LocalizedTextsFormField} fieldType="shadowAssignment" />

<NumericTextField
name="maxPoints"
validateMin={0}
validateMax={10000}
maxLength={5}
label={
<FormattedMessage id="app.editShadowAssignmentForm.maxPoints" defaultMessage="Maximal amount of points:" />
}
/>

<Container fluid>
<Row>
<Col sm={6}>
<Field
name="deadline"
component={DatetimeField}
label={
<>
<FormattedMessage id="app.assignment.deadline" defaultMessage="Deadline" />:
<Explanation id="deadlineExplanation">
<FormattedMessage
id="app.editShadowAssignmentForm.deadlineExplanation"
defaultMessage="The deadline has only informative value for the students. It will not affect the assigned points as the points are awarded manually by the supervisor. If you do not wish to set a deadline, leave this field empty."
/>
</Explanation>
</>
}
/>
</Col>

<Col sm={6}>
<NumericTextField
name="maxPoints"
validateMin={0}
validateMax={10000}
maxLength={5}
label={
<>
<FormattedMessage
id="app.editShadowAssignmentForm.maxPoints"
defaultMessage="Maximal amount of points:"
/>
<Explanation id="pointsExplanation">
<FormattedMessage
id="app.editShadowAssignmentForm.pointsExplanation"
defaultMessage="The maximal amount of points has only informative value for the students. The supervisor may choose to exceed this limit when awarding points."
/>
</Explanation>
</>
}
/>
</Col>
</Row>

<Row>
<Col sm={6}>
<Field
Expand Down
3 changes: 3 additions & 0 deletions src/locales/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,9 +497,11 @@
"app.editShadowAssignment.titleName": "Editovat stínovou úlohu — {name}",
"app.editShadowAssignment.titleShort": "Upravit stínovou úlohu",
"app.editShadowAssignment.validation.versionDiffers": "Někdo změnil tuto stínovou úlohu v průběhu její editace. Prosíme obnovte tuto stránku a proveďte své změny znovu.",
"app.editShadowAssignmentForm.deadlineExplanation": "Termín odevzdání má pro studenty pouze informativní charakter a žádným způsobem neovlivňujte přidělené body, neboť jsou přidělovány ručně. Pokud si nepřejete, aby úloha měla nastavený termín, ponechte pole prázdné.",
"app.editShadowAssignmentForm.isBonus": "Stínová úloha je bonusová, její body tedy nejsou počítány do celkového maximálního počtu bodů skupiny",
"app.editShadowAssignmentForm.isPublic": "Viditelné studentům",
"app.editShadowAssignmentForm.maxPoints": "Maximální počet bodů:",
"app.editShadowAssignmentForm.pointsExplanation": "Maximální počet bodů má pro studenty pouze informativní charakter. Vedoucí se může rozhodnout při udělování bodů tento limit překročit.",
"app.editShadowAssignmentForm.sendNotification": "Poslat studentům e-mailem oznámení o nové stínové úloze",
"app.editShadowAssignmentPointsForm.awardedAt": "Ohodnoceno:",
"app.editShadowAssignmentPointsForm.failed": "Nebylo možné uložit body stínové úlohy.",
Expand Down Expand Up @@ -1343,6 +1345,7 @@
"app.scoreConfigInfoWeighted.totals": "Součty",
"app.scoreConfigInfoWeighted.weight": "Váha",
"app.serverManagement.title": "Správa serverových backend služeb",
"app.shadowAssignment.deadlineExplanation": "Termín odevzdání má pro studenty pouze informativní charakter. Body jsou přidělovány ručně, takže o splnění nebo nesplnění řešení v termínu nakonec rozhodne vedoucí.",
"app.shadowAssignment.isBonus": "Bonusová úloha",
"app.shadowAssignment.isPublic": "Viditelná studentům",
"app.shadowAssignment.maxPoints": "Bodový limit",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,9 +497,11 @@
"app.editShadowAssignment.titleName": "Edit Shadow Assignment — {name}",
"app.editShadowAssignment.titleShort": "Edit Shadow Assignment",
"app.editShadowAssignment.validation.versionDiffers": "Somebody has changed the shadow assignment while you have been editing it. Please reload the page and apply your changes once more.",
"app.editShadowAssignmentForm.deadlineExplanation": "The deadline has only informative value for the students. It will not affect the assigned points as the points are awarded manually by the supervisor. If you do not wish to set a deadline, leave this field empty.",
"app.editShadowAssignmentForm.isBonus": "Shadow assignment is bonus one and points from it are not included in students overall score",
"app.editShadowAssignmentForm.isPublic": "Visible to students",
"app.editShadowAssignmentForm.maxPoints": "Maximal amount of points:",
"app.editShadowAssignmentForm.pointsExplanation": "The maximal amount of points has only informative value for the students. The supervisor may choose to exceed this limit when awarding points.",
"app.editShadowAssignmentForm.sendNotification": "Send e-mail notification to students about new shadow assignment",
"app.editShadowAssignmentPointsForm.awardedAt": "Awarded at:",
"app.editShadowAssignmentPointsForm.failed": "Cannot save the shadow assignment points.",
Expand Down Expand Up @@ -1343,6 +1345,7 @@
"app.scoreConfigInfoWeighted.totals": "Totals",
"app.scoreConfigInfoWeighted.weight": "Weight",
"app.serverManagement.title": "Management of Backend Services",
"app.shadowAssignment.deadlineExplanation": "The deadline has only informative value for the students. The points are awarded manually, so the supervisor ultimately decides whether a deadline was breached or not.",
"app.shadowAssignment.isBonus": "Is bonus",
"app.shadowAssignment.isPublic": "Is visible to students",
"app.shadowAssignment.maxPoints": "Points limit",
Expand Down
15 changes: 8 additions & 7 deletions src/pages/EditShadowAssignment/EditShadowAssignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { reset, formValueSelector, SubmissionError } from 'redux-form';
import { defaultMemoize } from 'reselect';
import moment from 'moment';

import Page from '../../components/layout/Page';
import { ShadowAssignmentNavigation } from '../../components/layout/Navigation';
Expand All @@ -25,7 +26,7 @@ import { isReady, getJsData } from '../../redux/helpers/resourceManager';
import { hasPermissions } from '../../helpers/common';
import withLinks from '../../helpers/withLinks';

const localizedTextDefaults = {
const LOCALIZED_TEXT_DEFAULTS = {
name: '',
text: '',
link: '',
Expand All @@ -47,12 +48,13 @@ class EditShadowAssignment extends Component {

static loadAsync = ({ shadowId }, dispatch) => 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 => {
Expand All @@ -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,
});
Expand Down Expand Up @@ -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));
4 changes: 2 additions & 2 deletions src/pages/GroupDetail/GroupDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
/>
)}
</ResourceRenderer>
Expand Down Expand Up @@ -276,7 +276,7 @@ class GroupDetail extends Component {
}>
<ShadowAssignmentsTable
shadowAssignments={shadowAssignments}
isAdmin={isGroupAdmin || isGroupSupervisor}
isAdmin={isGroupAdmin || isGroupSupervisor || isSuperadminRole(effectiveRole)}
userId={userId}
/>
</Box>
Expand Down

0 comments on commit 8902845

Please sign in to comment.