Skip to content

Commit

Permalink
Rewriting Expanding fields to be completely compatible with redux-form.
Browse files Browse the repository at this point in the history
Fixing multiple bugs in simple edit form related to expanding fields and to recent change in test identification (using id instead of name).
  • Loading branch information
Martin Krulis committed Dec 11, 2017
1 parent 6c31c98 commit f4067df
Show file tree
Hide file tree
Showing 14 changed files with 357 additions and 473 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import { reduxForm, getFormValues } from 'redux-form';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { Alert } from 'react-bootstrap';
import FormBox from '../../widgets/FormBox';

import EditExerciseSimpleConfigTest from './EditExerciseSimpleConfigTest';
import FormBox from '../../widgets/FormBox';
import Button from '../../widgets/FlatButton';
import { RefreshIcon } from '../../icons';
import SubmitButton from '../SubmitButton';
import ResourceRenderer from '../../helpers/ResourceRenderer';
import { createGetSupplementaryFiles } from '../../../redux/selectors/supplementaryFiles';

import Button from '../../widgets/FlatButton';
import { RefreshIcon } from '../../icons';
import EditExerciseSimpleConfigTest from './EditExerciseSimpleConfigTest';
import { createGetSupplementaryFiles } from '../../../redux/selectors/supplementaryFiles';
import { encodeTestId } from '../../../redux/modules/simpleLimits';

const EditExerciseSimpleConfigForm = ({
reset,
Expand Down Expand Up @@ -104,14 +105,16 @@ const EditExerciseSimpleConfigForm = ({
<ResourceRenderer resource={supplementaryFiles.toArray()}>
{(...files) =>
<div>
{exerciseTests.map((test, i) =>
{exerciseTests.map((test, idx) =>
<EditExerciseSimpleConfigTest
key={i}
key={idx}
formValues={formValues}
supplementaryFiles={files}
testName={test.name}
test={`config.${i}`}
i={i}
test={'config.' + encodeTestId(test.id)}
testKey={encodeTestId(test.id)}
testIndex={idx}
smartFill={() => undefined}
/>
)}
</div>}
Expand All @@ -134,83 +137,6 @@ EditExerciseSimpleConfigForm.propTypes = {
exerciseTests: PropTypes.array
};

const validate = ({ config }) => {
const errors = {};

const configErrors = {};
for (let i = 0; i < config.length; ++i) {
const test = config[i];
const testErrors = {};

if (!test.expectedOutput || test.expectedOutput === '') {
testErrors['expectedOutput'] = (
<FormattedMessage
id="app.editExerciseSimpleConfigForm.validation.expectedOutput"
defaultMessage="Please fill the expected output file."
/>
);
}

if (test.useOutFile && (!test.outputFile || test.outputFile === '')) {
testErrors['outputFile'] = (
<FormattedMessage
id="app.editExerciseSimpleConfigForm.validation.outputFile"
defaultMessage="Please fill the name of the output file or use standard input instead."
/>
);
}

if (!test.judgeBinary || test.judgeBinary === '') {
testErrors['judgeBinary'] = (
<FormattedMessage
id="app.editExerciseSimpleConfigForm.validation.judgeBinary"
defaultMessage="Please select the judge type for this test."
/>
);
}

if (
test.useCustomJudge &&
(!test.customJudgeBinary || test.customJudgeBinary === '')
) {
testErrors['customJudgeBinary'] = (
<FormattedMessage
id="app.editExerciseSimpleConfigForm.validation.customJudge"
defaultMessage="Please select the custom judge binary for this test or use one of the standard judges instead."
/>
);
}

const inputErrorMessage = (
<FormattedMessage
id="app.editExerciseSimpleConfigForm.validation.inputFilesNotPaired"
defaultMessage="Input files are not properly paired with their names. Please make sure each file has a name."
/>
);
const inFilesArr =
test.inputFiles && Array.isArray(test.inputFiles) ? test.inputFiles : [];
for (const inputFilePair of inFilesArr) {
if (
(!inputFilePair.first || inputFilePair.first === '') &&
inputFilePair.second !== ''
) {
testErrors['inputFiles'] = inputErrorMessage;
}
if (
(!inputFilePair.second || inputFilePair.second === '') &&
inputFilePair.first !== ''
) {
testErrors['inputFiles'] = inputErrorMessage;
}
}

configErrors[i] = testErrors;
}
errors['config'] = configErrors;

return errors;
};

export default connect((state, { exercise }) => {
const getSupplementaryFilesForExercise = createGetSupplementaryFiles(
exercise.supplementaryFilesIds
Expand All @@ -223,13 +149,12 @@ export default connect((state, { exercise }) => {
reduxForm({
form: 'editExerciseSimpleConfig',
enableReinitialize: true,
keepDirtyOnReinitialize: true,
keepDirtyOnReinitialize: false,
immutableProps: [
'formValues',
'supplementaryFiles',
'exerciseTests',
'handleSubmit'
],
validate
]
})(EditExerciseSimpleConfigForm)
);
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Field } from 'redux-form';
import { Field, FieldArray } from 'redux-form';
import { Row, Col } from 'react-bootstrap';
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
import Icon from 'react-fontawesome';

import Button from '../../widgets/FlatButton';
import {
SelectField,
TextField,
ExpandingTextField,
ExpandingInputFilesField,
CheckboxField
} from '../Fields';
import Confirm from '../../forms/Confirm';

import './EditExerciseSimpleConfigForm.css';

Expand Down Expand Up @@ -53,23 +56,47 @@ const messages = defineMessages({
}
});

const validateExpectedOutput = value =>
!value || value.trim() === ''
? <FormattedMessage
id="app.editExerciseSimpleConfigForm.validation.expectedOutput"
defaultMessage="Please, fill in the expected output file."
/>
: undefined;

const validateOutputFile = value =>
!value || value.trim() === ''
? <FormattedMessage
id="app.editExerciseSimpleConfigForm.validation.outputFile"
defaultMessage="Please, fill in the name of the output file."
/>
: undefined;

const validateCustomJudge = value =>
!value || value.trim() === ''
? <FormattedMessage
id="app.editExerciseSimpleConfigForm.validation.customJudge"
defaultMessage="Please, select the custom judge binary for this test or use one of the standard judges instead."
/>
: undefined;

const EditExerciseSimpleConfigTest = ({
supplementaryFiles,
formValues,
testName,
test,
i,
testKey,
testIndex,
smartFill,
intl
}) => {
const supplementaryFilesOptions = [{ key: '', name: '...' }].concat(
supplementaryFiles
.sort((a, b) => a.name.localeCompare(b.name, intl.locale))
.filter((item, pos, arr) => arr.indexOf(item) === pos)
.map(data => ({
key: data.name,
name: data.name
}))
);
const supplementaryFilesOptions = supplementaryFiles
.sort((a, b) => a.name.localeCompare(b.name, intl.locale))
.filter((item, pos, arr) => arr.indexOf(item) === pos)
.map(data => ({
key: data.name,
name: data.name
}));
return (
<div className="configRow">
<Row>
Expand All @@ -87,7 +114,7 @@ const EditExerciseSimpleConfigTest = ({
defaultMessage="Input"
/>
</h4>
<Field
<FieldArray
name={`${test}.inputFiles`}
component={ExpandingInputFilesField}
options={supplementaryFilesOptions}
Expand All @@ -100,14 +127,15 @@ const EditExerciseSimpleConfigTest = ({
rightLabel={
<FormattedMessage
id="app.editExerciseSimpleConfigTests.inputFilesRename"
defaultMessage="Renamed file name:"
defaultMessage="Rename as:"
/>
}
/>
<Field
name={`${test}.inputStdin`}
component={SelectField}
options={supplementaryFilesOptions}
addEmptyOption={true}
label={
<FormattedMessage
id="app.editExerciseSimpleConfigTests.inputStdin"
Expand All @@ -123,7 +151,7 @@ const EditExerciseSimpleConfigTest = ({
defaultMessage="Execution"
/>
</h4>
<Field
<FieldArray
name={`${test}.runArgs`}
component={ExpandingTextField}
label={
Expand Down Expand Up @@ -154,12 +182,13 @@ const EditExerciseSimpleConfigTest = ({
/>
{formValues &&
formValues.config &&
formValues.config[i] &&
(formValues.config[i].useOutFile === true ||
formValues.config[i].useOutFile === 'true') &&
formValues.config[testKey] &&
(formValues.config[testKey].useOutFile === true ||
formValues.config[testKey].useOutFile === 'true') &&
<Field
name={`${test}.outputFile`}
component={TextField}
validate={validateOutputFile}
label={
<FormattedMessage
id="app.editExerciseSimpleConfigTests.outputFile"
Expand All @@ -171,6 +200,8 @@ const EditExerciseSimpleConfigTest = ({
name={`${test}.expectedOutput`}
component={SelectField}
options={supplementaryFilesOptions}
addEmptyOption={true}
validate={validateExpectedOutput}
label={
<FormattedMessage
id="app.editExerciseSimpleConfigTests.expectedOutput"
Expand Down Expand Up @@ -199,17 +230,19 @@ const EditExerciseSimpleConfigTest = ({
/>
{formValues &&
formValues.config &&
formValues.config[i] &&
(formValues.config[i].useCustomJudge === true ||
formValues.config[i].useCustomJudge === 'true')
formValues.config[testKey] &&
(formValues.config[testKey].useCustomJudge === true ||
formValues.config[testKey].useCustomJudge === 'true')
? <Field
name={`${test}.customJudgeBinary`}
component={SelectField}
options={supplementaryFilesOptions}
addEmptyOption={true}
validate={validateCustomJudge}
label={
<FormattedMessage
id="app.editExerciseSimpleConfigTests.customJudgeBinary"
defaultMessage="Custom judge binary:"
defaultMessage="Custom judge executable:"
/>
}
/>
Expand Down Expand Up @@ -256,26 +289,47 @@ const EditExerciseSimpleConfigTest = ({
]}
label={
<FormattedMessage
id="app.editExerciseSimpleConfigTests.judgeBinary"
defaultMessage="Judge binary:"
id="app.editExerciseSimpleConfigTests.judgeType"
defaultMessage="Judge:"
/>
}
/>}
{formValues &&
formValues.config &&
formValues.config[i] &&
(formValues.config[i].useCustomJudge === true ||
formValues.config[i].useCustomJudge === 'true') &&
<Field
formValues.config[testKey] &&
(formValues.config[testKey].useCustomJudge === true ||
formValues.config[testKey].useCustomJudge === 'true') &&
<FieldArray
name={`${test}.judgeArgs`}
component={TextField}
component={ExpandingTextField}
label={
<FormattedMessage
id="app.editExerciseSimpleConfigTests.judgeArgs"
defaultMessage="Judge arguments:"
/>
}
/>}
{testIndex === 0 &&
<div style={{ textAlign: 'right', padding: '1em' }}>
<Confirm
id={'smartFill'}
onConfirmed={smartFill}
question={
<FormattedMessage
id="app.editExerciseConfigForm.smartFill.yesNoQuestion"
defaultMessage="Do you really wish to overwrite configuration of all subsequent tests using the first test as a template? Files will be paired to individual test configurations by a heuristics based on matching name substrings."
/>
}
>
<Button bsStyle={'primary'} className="btn-flat">
<Icon name="arrows" />{' '}
<FormattedMessage
id="app.editExerciseConfigForm.smartFill"
defaultMessage="Smart Fill"
/>
</Button>
</Confirm>
</div>}
</Col>
</Row>
</div>
Expand All @@ -285,10 +339,12 @@ const EditExerciseSimpleConfigTest = ({
EditExerciseSimpleConfigTest.propTypes = {
testName: PropTypes.string.isRequired,
test: PropTypes.string.isRequired,
i: PropTypes.number.isRequired,
testKey: PropTypes.string.isRequired,
testIndex: PropTypes.number.isRequired,
supplementaryFiles: PropTypes.array.isRequired,
exerciseTests: PropTypes.array,
formValues: PropTypes.object,
smartFill: PropTypes.func.isRequired,
intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ const validate = ({ limits }) => {
export default reduxForm({
form: 'editSimpleLimits',
enableReinitialize: true,
keepDirtyOnReinitialize: true,
keepDirtyOnReinitialize: false,
immutableProps: [
'environments',
'tests',
Expand Down
2 changes: 1 addition & 1 deletion src/components/forms/EditTestsForm/EditTests.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.testRow {
margin-bottom: 0;
margin-top: -20px;
margin-top: 0;
}
Loading

0 comments on commit f4067df

Please sign in to comment.