Skip to content

Commit f5cfaad

Browse files
committed
Refactoring pipeline edit page and related forms. Pipeline structure removed from basic edit form (will be placed into separate component).
1 parent 63cc585 commit f5cfaad

File tree

9 files changed

+348
-163
lines changed

9 files changed

+348
-163
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import { reduxForm } from 'redux-form';
4+
import { FormattedMessage } from 'react-intl';
5+
6+
import EditEnvironmentList from '../EditEnvironmentSimpleForm/EditEnvironmentList';
7+
import { SaveIcon } from '../../icons';
8+
import Callout from '../../widgets/Callout';
9+
import FormBox from '../../widgets/FormBox';
10+
import SubmitButton from '../SubmitButton';
11+
12+
class EditPipelineEnvironmentsForm extends Component {
13+
render() {
14+
const { runtimeEnvironments, dirty, submitting, handleSubmit, submitFailed, submitSucceeded, invalid } = this.props;
15+
return (
16+
<FormBox
17+
title={
18+
<FormattedMessage
19+
id="app.editPipelineEnvironmentsForm.title"
20+
defaultMessage="Pipeline Runtime Environments"
21+
/>
22+
}
23+
succeeded={submitSucceeded}
24+
dirty={dirty}
25+
footer={
26+
<div className="text-center">
27+
<SubmitButton
28+
id="editPipelineEnvironments"
29+
invalid={invalid}
30+
submitting={submitting}
31+
dirty={dirty}
32+
hasSucceeded={submitSucceeded}
33+
hasFailed={submitFailed}
34+
handleSubmit={handleSubmit}
35+
defaultIcon={<SaveIcon gapRight />}
36+
messages={{
37+
submit: <FormattedMessage id="generic.save" defaultMessage="Save" />,
38+
submitting: <FormattedMessage id="generic.saving" defaultMessage="Saving..." />,
39+
success: <FormattedMessage id="generic.saved" defaultMessage="Saved" />,
40+
}}
41+
/>
42+
</div>
43+
}>
44+
{submitFailed && (
45+
<Callout variant="danger">
46+
<FormattedMessage id="generic.savingFailed" defaultMessage="Saving failed. Please try again later." />
47+
</Callout>
48+
)}
49+
50+
<EditEnvironmentList runtimeEnvironments={runtimeEnvironments} />
51+
</FormBox>
52+
);
53+
}
54+
}
55+
56+
EditPipelineEnvironmentsForm.propTypes = {
57+
runtimeEnvironments: PropTypes.array.isRequired,
58+
handleSubmit: PropTypes.func.isRequired,
59+
dirty: PropTypes.bool,
60+
submitting: PropTypes.bool,
61+
submitFailed: PropTypes.bool,
62+
submitSucceeded: PropTypes.bool,
63+
invalid: PropTypes.bool,
64+
};
65+
66+
export default reduxForm({
67+
form: 'editPipelineEnvironments',
68+
enableReinitialize: true,
69+
keepDirtyOnReinitialize: false,
70+
})(EditPipelineEnvironmentsForm);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import EditPipelineEnvironmentsForm from './EditPipelineEnvironmentsForm';
2+
export default EditPipelineEnvironmentsForm;
Lines changed: 117 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,46 @@
11
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
3-
import ImmutablePropTypes from 'react-immutable-proptypes';
4-
import { connect } from 'react-redux';
5-
import { reduxForm, Field, touch, formValueSelector } from 'redux-form';
3+
import { reduxForm, Field } from 'redux-form';
64
import { FormattedMessage } from 'react-intl';
75
import { Container, Row, Col } from 'react-bootstrap';
86

9-
import { TextField, MarkdownTextAreaField, PipelineField, PipelineVariablesField } from '../Fields';
10-
7+
import { TextField, MarkdownTextAreaField, CheckboxField } from '../Fields';
8+
import { SaveIcon } from '../../icons';
119
import Callout from '../../widgets/Callout';
1210
import FormBox from '../../widgets/FormBox';
1311
import SubmitButton from '../SubmitButton';
14-
import { validatePipeline } from '../../../redux/modules/pipelines';
15-
import { extractVariables } from '../../../helpers/boxes';
16-
import { fetchSupplementaryFilesForPipeline } from '../../../redux/modules/pipelineFiles';
17-
import { createGetPipelineFiles } from '../../../redux/selectors/pipelineFiles';
1812

1913
class EditPipelineForm extends Component {
20-
componentDidMount = () => this.props.loadAsync();
21-
22-
componentDidUpdate(prevProps) {
23-
if (this.props.pipeline.id !== prevProps.pipeline.id) {
24-
this.props.loadAsync();
25-
}
26-
}
27-
2814
render() {
2915
const {
30-
initialValues: pipeline,
31-
anyTouched,
16+
isSuperadmin = false,
17+
dirty,
3218
submitting,
3319
handleSubmit,
3420
submitFailed,
3521
submitSucceeded,
36-
variables = [],
3722
invalid,
38-
asyncValidating,
39-
supplementaryFiles,
4023
} = this.props;
4124
return (
4225
<FormBox
43-
title={
44-
<FormattedMessage
45-
id="app.editPipelineForm.title"
46-
defaultMessage="Edit pipeline {name}"
47-
values={{ name: pipeline.name }}
48-
/>
49-
}
26+
title={<FormattedMessage id="app.editPipelineForm.title" defaultMessage="Pipeline Metadata" />}
5027
succeeded={submitSucceeded}
51-
dirty={anyTouched}
28+
dirty={dirty}
5229
footer={
5330
<div className="text-center">
5431
<SubmitButton
5532
id="editPipeline"
5633
invalid={invalid}
5734
submitting={submitting}
58-
dirty={anyTouched}
35+
dirty={dirty}
5936
hasSucceeded={submitSucceeded}
6037
hasFailed={submitFailed}
6138
handleSubmit={handleSubmit}
62-
asyncValidating={asyncValidating}
39+
defaultIcon={<SaveIcon gapRight />}
6340
messages={{
64-
submit: <FormattedMessage id="app.editPipelineForm.submit" defaultMessage="Save changes" />,
65-
submitting: (
66-
<FormattedMessage id="app.editPipelineForm.submitting" defaultMessage="Saving changes..." />
67-
),
68-
success: <FormattedMessage id="app.editPipelineForm.success" defaultMessage="Settings were saved." />,
69-
validating: <FormattedMessage id="generic.validating" defaultMessage="Validating..." />,
41+
submit: <FormattedMessage id="generic.save" defaultMessage="Save" />,
42+
submitting: <FormattedMessage id="generic.saving" defaultMessage="Saving..." />,
43+
success: <FormattedMessage id="generic.saved" defaultMessage="Saved" />,
7044
}}
7145
/>
7246
</div>
@@ -93,57 +67,126 @@ class EditPipelineForm extends Component {
9367
label={
9468
<FormattedMessage
9569
id="app.editPipelineForm.description"
96-
defaultMessage="Description for supervisors:"
70+
defaultMessage="Detailed description (for exercise authors):"
9771
/>
9872
}
9973
/>
10074
</Col>
10175
</Row>
10276

103-
<Row>
104-
<Col lg={12}>
105-
<Field
106-
name="pipeline.boxes"
107-
component={PipelineField}
108-
label={<FormattedMessage id="app.editPipelineFields.pipeline" defaultMessage="The pipeline:" />}
109-
/>
110-
</Col>
111-
112-
<Col lg={12}>
113-
<Field
114-
name="pipeline.variables"
115-
component={PipelineVariablesField}
116-
variables={variables}
117-
label={
118-
<FormattedMessage
119-
id="app.editPipelineFields.pipelineVariables"
120-
defaultMessage="Pipeline variables:"
77+
{isSuperadmin && (
78+
<>
79+
<hr />
80+
81+
<Row>
82+
<Col lg={12}>
83+
<Field
84+
name="global"
85+
component={CheckboxField}
86+
onOff
87+
label={
88+
<FormattedMessage
89+
id="app.editPipelineForm.global"
90+
defaultMessage="Global pipeline associated with particular runtime environments"
91+
/>
92+
}
12193
/>
122-
}
123-
supplementaryFiles={supplementaryFiles}
124-
/>
125-
</Col>
126-
</Row>
94+
</Col>
95+
</Row>
96+
97+
<hr className="mt-0" />
98+
99+
<Row>
100+
<Col xl={4} lg={6} md={12}>
101+
<Field
102+
name="parameters.isCompilationPipeline"
103+
component={CheckboxField}
104+
onOff
105+
label={
106+
<FormattedMessage id="app.editPipelineForm.isCompilationPipeline" defaultMessage="Compilation" />
107+
}
108+
/>
109+
</Col>
110+
<Col xl={4} lg={6} md={12}>
111+
<Field
112+
name="parameters.isExecutionPipeline"
113+
component={CheckboxField}
114+
onOff
115+
label={
116+
<FormattedMessage id="app.editPipelineForm.isExecutionPipeline" defaultMessage="Execution" />
117+
}
118+
/>
119+
</Col>
120+
<Col xl={4} lg={6} md={12}>
121+
<Field
122+
name="parameters.judgeOnlyPipeline"
123+
component={CheckboxField}
124+
onOff
125+
label={<FormattedMessage id="app.editPipelineForm.judgeOnlyPipeline" defaultMessage="Judge-Only" />}
126+
/>
127+
</Col>
128+
<Col xl={4} lg={6} md={12}>
129+
<Field
130+
name="parameters.producesStdout"
131+
component={CheckboxField}
132+
onOff
133+
label={
134+
<FormattedMessage id="app.editPipelineForm.producesStdout" defaultMessage="Produces std. out" />
135+
}
136+
/>
137+
</Col>
138+
<Col xl={4} lg={6} md={12}>
139+
<Field
140+
name="parameters.producesFiles"
141+
component={CheckboxField}
142+
onOff
143+
label={
144+
<FormattedMessage
145+
id="app.editPipelineForm.producesFiles"
146+
defaultMessage="Produces output files"
147+
/>
148+
}
149+
/>
150+
</Col>
151+
<Col xl={4} lg={6} md={12}>
152+
<Field
153+
name="parameters.hasEntryPoint"
154+
component={CheckboxField}
155+
onOff
156+
label={
157+
<FormattedMessage id="app.editPipelineForm.hasEntryPoint" defaultMessage="Has entry-point" />
158+
}
159+
/>
160+
</Col>
161+
<Col xl={4} lg={6} md={12}>
162+
<Field
163+
name="parameters.hasExtraFiles"
164+
component={CheckboxField}
165+
onOff
166+
label={
167+
<FormattedMessage id="app.editPipelineForm.hasExtraFiles" defaultMessage="Has extra files" />
168+
}
169+
/>
170+
</Col>
171+
</Row>
172+
</>
173+
)}
127174
</Container>
128175
</FormBox>
129176
);
130177
}
131178
}
132179

133180
EditPipelineForm.propTypes = {
134-
initialValues: PropTypes.object.isRequired,
181+
isSuperadmin: PropTypes.bool,
135182
values: PropTypes.object,
136183
handleSubmit: PropTypes.func.isRequired,
137-
anyTouched: PropTypes.bool,
184+
dirty: PropTypes.bool,
138185
submitting: PropTypes.bool,
139186
submitFailed: PropTypes.bool,
140187
submitSucceeded: PropTypes.bool,
141188
invalid: PropTypes.bool,
142-
variables: PropTypes.array,
143189
asyncValidating: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
144-
supplementaryFiles: ImmutablePropTypes.map,
145-
loadAsync: PropTypes.func.isRequired,
146-
pipeline: PropTypes.object,
147190
};
148191

149192
const validate = ({ name, description }) => {
@@ -170,42 +213,9 @@ const validate = ({ name, description }) => {
170213
return errors;
171214
};
172215

173-
const asyncValidate = (values, dispatch, { initialValues: { id, version } }) =>
174-
new Promise((resolve, reject) =>
175-
dispatch(validatePipeline(id, version))
176-
.then(res => res.value)
177-
.then(({ versionIsUpToDate }) => {
178-
const errors = {};
179-
if (versionIsUpToDate === false) {
180-
errors.name = (
181-
<FormattedMessage
182-
id="app.editPipelineForm.validation.versionDiffers"
183-
defaultMessage="Somebody has changed the pipeline while you have been editing it. Please reload the page and apply your changes once more."
184-
/>
185-
);
186-
dispatch(touch('editPipeline', 'name'));
187-
}
188-
189-
if (Object.keys(errors).length > 0) {
190-
throw errors;
191-
}
192-
})
193-
.then(resolve())
194-
.catch(errors => reject(errors))
195-
);
196-
197-
export default connect(
198-
(state, { pipeline }) => ({
199-
variables: extractVariables(formValueSelector('editPipeline')(state, 'pipeline.boxes')),
200-
supplementaryFiles: createGetPipelineFiles(pipeline.supplementaryFilesIds)(state),
201-
}),
202-
(dispatch, { pipeline }) => ({
203-
loadAsync: () => dispatch(fetchSupplementaryFilesForPipeline(pipeline.id)),
204-
})
205-
)(
206-
reduxForm({
207-
form: 'editPipeline',
208-
validate,
209-
asyncValidate,
210-
})(EditPipelineForm)
211-
);
216+
export default reduxForm({
217+
form: 'editPipeline',
218+
enableReinitialize: true,
219+
keepDirtyOnReinitialize: false,
220+
validate,
221+
})(EditPipelineForm);

src/locales/cs.json

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -480,14 +480,18 @@
480480
"app.editPipeline.disclaimer": "Upozornění",
481481
"app.editPipeline.disclaimerWarning": "Upravení pipeline může rozbít všechny úlohy, které pipeline používají!",
482482
"app.editPipeline.title": "Změnit nastavení a obsah pipeline",
483-
"app.editPipelineFields.pipeline": "Pipeline:",
484-
"app.editPipelineFields.pipelineVariables": "Pipeline proměnné:",
485-
"app.editPipelineForm.description": "Popis pro vedoucího skupiny:",
483+
"app.editPipelineEnvironmentsForm.title": "Běhová prostředí pipeline",
484+
"app.editPipelineForm.description": "Podrobnější popis (pro autory úloh):",
485+
"app.editPipelineForm.global": "Globalní pipeline spojená s konkrétními běhovými prostředími",
486+
"app.editPipelineForm.hasEntryPoint": "Obsahuje vstupní bod",
487+
"app.editPipelineForm.hasExtraFiles": "Obsahuje extra soubory",
488+
"app.editPipelineForm.isCompilationPipeline": "Kompilační",
489+
"app.editPipelineForm.isExecutionPipeline": "Spouštěcí",
490+
"app.editPipelineForm.judgeOnlyPipeline": "Pouze sudí",
486491
"app.editPipelineForm.name": "Jméno pipeline:",
487-
"app.editPipelineForm.submit": "Uložit změny",
488-
"app.editPipelineForm.submitting": "Ukládání...",
489-
"app.editPipelineForm.success": "Změny byly uloženy.",
490-
"app.editPipelineForm.title": "Změnit pipeline {name}",
492+
"app.editPipelineForm.producesFiles": "Produkuje výstupní soubory",
493+
"app.editPipelineForm.producesStdout": "Produkuje std. výstup",
494+
"app.editPipelineForm.title": "Metadata pipeline",
491495
"app.editPipelineForm.validation.description": "Prosíme vyplňte popis této pipeline.",
492496
"app.editPipelineForm.validation.emptyName": "Prosíme vyplňte název této pipeline.",
493497
"app.editPipelineForm.validation.versionDiffers": "Někdo změnil nastavení této pipeline v průběhu její editace. Prosíme obnovte tuto stránku a proveďte své změny znovu.",

0 commit comments

Comments
 (0)