Skip to content

Commit

Permalink
Refactoring pipeline edit page and related forms. Pipeline structure …
Browse files Browse the repository at this point in the history
…removed from basic edit form (will be placed into separate component).
  • Loading branch information
krulis-martin committed Nov 25, 2021
1 parent 63cc585 commit f5cfaad
Show file tree
Hide file tree
Showing 9 changed files with 348 additions and 163 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { reduxForm } from 'redux-form';
import { FormattedMessage } from 'react-intl';

import EditEnvironmentList from '../EditEnvironmentSimpleForm/EditEnvironmentList';
import { SaveIcon } from '../../icons';
import Callout from '../../widgets/Callout';
import FormBox from '../../widgets/FormBox';
import SubmitButton from '../SubmitButton';

class EditPipelineEnvironmentsForm extends Component {
render() {
const { runtimeEnvironments, dirty, submitting, handleSubmit, submitFailed, submitSucceeded, invalid } = this.props;
return (
<FormBox
title={
<FormattedMessage
id="app.editPipelineEnvironmentsForm.title"
defaultMessage="Pipeline Runtime Environments"
/>
}
succeeded={submitSucceeded}
dirty={dirty}
footer={
<div className="text-center">
<SubmitButton
id="editPipelineEnvironments"
invalid={invalid}
submitting={submitting}
dirty={dirty}
hasSucceeded={submitSucceeded}
hasFailed={submitFailed}
handleSubmit={handleSubmit}
defaultIcon={<SaveIcon gapRight />}
messages={{
submit: <FormattedMessage id="generic.save" defaultMessage="Save" />,
submitting: <FormattedMessage id="generic.saving" defaultMessage="Saving..." />,
success: <FormattedMessage id="generic.saved" defaultMessage="Saved" />,
}}
/>
</div>
}>
{submitFailed && (
<Callout variant="danger">
<FormattedMessage id="generic.savingFailed" defaultMessage="Saving failed. Please try again later." />
</Callout>
)}

<EditEnvironmentList runtimeEnvironments={runtimeEnvironments} />
</FormBox>
);
}
}

EditPipelineEnvironmentsForm.propTypes = {
runtimeEnvironments: PropTypes.array.isRequired,
handleSubmit: PropTypes.func.isRequired,
dirty: PropTypes.bool,
submitting: PropTypes.bool,
submitFailed: PropTypes.bool,
submitSucceeded: PropTypes.bool,
invalid: PropTypes.bool,
};

export default reduxForm({
form: 'editPipelineEnvironments',
enableReinitialize: true,
keepDirtyOnReinitialize: false,
})(EditPipelineEnvironmentsForm);
2 changes: 2 additions & 0 deletions src/components/forms/EditPipelineEnvironmentsForm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import EditPipelineEnvironmentsForm from './EditPipelineEnvironmentsForm';
export default EditPipelineEnvironmentsForm;
224 changes: 117 additions & 107 deletions src/components/forms/EditPipelineForm/EditPipelineForm.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,46 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { reduxForm, Field, touch, formValueSelector } from 'redux-form';
import { reduxForm, Field } from 'redux-form';
import { FormattedMessage } from 'react-intl';
import { Container, Row, Col } from 'react-bootstrap';

import { TextField, MarkdownTextAreaField, PipelineField, PipelineVariablesField } from '../Fields';

import { TextField, MarkdownTextAreaField, CheckboxField } from '../Fields';
import { SaveIcon } from '../../icons';
import Callout from '../../widgets/Callout';
import FormBox from '../../widgets/FormBox';
import SubmitButton from '../SubmitButton';
import { validatePipeline } from '../../../redux/modules/pipelines';
import { extractVariables } from '../../../helpers/boxes';
import { fetchSupplementaryFilesForPipeline } from '../../../redux/modules/pipelineFiles';
import { createGetPipelineFiles } from '../../../redux/selectors/pipelineFiles';

class EditPipelineForm extends Component {
componentDidMount = () => this.props.loadAsync();

componentDidUpdate(prevProps) {
if (this.props.pipeline.id !== prevProps.pipeline.id) {
this.props.loadAsync();
}
}

render() {
const {
initialValues: pipeline,
anyTouched,
isSuperadmin = false,
dirty,
submitting,
handleSubmit,
submitFailed,
submitSucceeded,
variables = [],
invalid,
asyncValidating,
supplementaryFiles,
} = this.props;
return (
<FormBox
title={
<FormattedMessage
id="app.editPipelineForm.title"
defaultMessage="Edit pipeline {name}"
values={{ name: pipeline.name }}
/>
}
title={<FormattedMessage id="app.editPipelineForm.title" defaultMessage="Pipeline Metadata" />}
succeeded={submitSucceeded}
dirty={anyTouched}
dirty={dirty}
footer={
<div className="text-center">
<SubmitButton
id="editPipeline"
invalid={invalid}
submitting={submitting}
dirty={anyTouched}
dirty={dirty}
hasSucceeded={submitSucceeded}
hasFailed={submitFailed}
handleSubmit={handleSubmit}
asyncValidating={asyncValidating}
defaultIcon={<SaveIcon gapRight />}
messages={{
submit: <FormattedMessage id="app.editPipelineForm.submit" defaultMessage="Save changes" />,
submitting: (
<FormattedMessage id="app.editPipelineForm.submitting" defaultMessage="Saving changes..." />
),
success: <FormattedMessage id="app.editPipelineForm.success" defaultMessage="Settings were saved." />,
validating: <FormattedMessage id="generic.validating" defaultMessage="Validating..." />,
submit: <FormattedMessage id="generic.save" defaultMessage="Save" />,
submitting: <FormattedMessage id="generic.saving" defaultMessage="Saving..." />,
success: <FormattedMessage id="generic.saved" defaultMessage="Saved" />,
}}
/>
</div>
Expand All @@ -93,57 +67,126 @@ class EditPipelineForm extends Component {
label={
<FormattedMessage
id="app.editPipelineForm.description"
defaultMessage="Description for supervisors:"
defaultMessage="Detailed description (for exercise authors):"
/>
}
/>
</Col>
</Row>

<Row>
<Col lg={12}>
<Field
name="pipeline.boxes"
component={PipelineField}
label={<FormattedMessage id="app.editPipelineFields.pipeline" defaultMessage="The pipeline:" />}
/>
</Col>

<Col lg={12}>
<Field
name="pipeline.variables"
component={PipelineVariablesField}
variables={variables}
label={
<FormattedMessage
id="app.editPipelineFields.pipelineVariables"
defaultMessage="Pipeline variables:"
{isSuperadmin && (
<>
<hr />

<Row>
<Col lg={12}>
<Field
name="global"
component={CheckboxField}
onOff
label={
<FormattedMessage
id="app.editPipelineForm.global"
defaultMessage="Global pipeline associated with particular runtime environments"
/>
}
/>
}
supplementaryFiles={supplementaryFiles}
/>
</Col>
</Row>
</Col>
</Row>

<hr className="mt-0" />

<Row>
<Col xl={4} lg={6} md={12}>
<Field
name="parameters.isCompilationPipeline"
component={CheckboxField}
onOff
label={
<FormattedMessage id="app.editPipelineForm.isCompilationPipeline" defaultMessage="Compilation" />
}
/>
</Col>
<Col xl={4} lg={6} md={12}>
<Field
name="parameters.isExecutionPipeline"
component={CheckboxField}
onOff
label={
<FormattedMessage id="app.editPipelineForm.isExecutionPipeline" defaultMessage="Execution" />
}
/>
</Col>
<Col xl={4} lg={6} md={12}>
<Field
name="parameters.judgeOnlyPipeline"
component={CheckboxField}
onOff
label={<FormattedMessage id="app.editPipelineForm.judgeOnlyPipeline" defaultMessage="Judge-Only" />}
/>
</Col>
<Col xl={4} lg={6} md={12}>
<Field
name="parameters.producesStdout"
component={CheckboxField}
onOff
label={
<FormattedMessage id="app.editPipelineForm.producesStdout" defaultMessage="Produces std. out" />
}
/>
</Col>
<Col xl={4} lg={6} md={12}>
<Field
name="parameters.producesFiles"
component={CheckboxField}
onOff
label={
<FormattedMessage
id="app.editPipelineForm.producesFiles"
defaultMessage="Produces output files"
/>
}
/>
</Col>
<Col xl={4} lg={6} md={12}>
<Field
name="parameters.hasEntryPoint"
component={CheckboxField}
onOff
label={
<FormattedMessage id="app.editPipelineForm.hasEntryPoint" defaultMessage="Has entry-point" />
}
/>
</Col>
<Col xl={4} lg={6} md={12}>
<Field
name="parameters.hasExtraFiles"
component={CheckboxField}
onOff
label={
<FormattedMessage id="app.editPipelineForm.hasExtraFiles" defaultMessage="Has extra files" />
}
/>
</Col>
</Row>
</>
)}
</Container>
</FormBox>
);
}
}

EditPipelineForm.propTypes = {
initialValues: PropTypes.object.isRequired,
isSuperadmin: PropTypes.bool,
values: PropTypes.object,
handleSubmit: PropTypes.func.isRequired,
anyTouched: PropTypes.bool,
dirty: PropTypes.bool,
submitting: PropTypes.bool,
submitFailed: PropTypes.bool,
submitSucceeded: PropTypes.bool,
invalid: PropTypes.bool,
variables: PropTypes.array,
asyncValidating: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
supplementaryFiles: ImmutablePropTypes.map,
loadAsync: PropTypes.func.isRequired,
pipeline: PropTypes.object,
};

const validate = ({ name, description }) => {
Expand All @@ -170,42 +213,9 @@ const validate = ({ name, description }) => {
return errors;
};

const asyncValidate = (values, dispatch, { initialValues: { id, version } }) =>
new Promise((resolve, reject) =>
dispatch(validatePipeline(id, version))
.then(res => res.value)
.then(({ versionIsUpToDate }) => {
const errors = {};
if (versionIsUpToDate === false) {
errors.name = (
<FormattedMessage
id="app.editPipelineForm.validation.versionDiffers"
defaultMessage="Somebody has changed the pipeline while you have been editing it. Please reload the page and apply your changes once more."
/>
);
dispatch(touch('editPipeline', 'name'));
}

if (Object.keys(errors).length > 0) {
throw errors;
}
})
.then(resolve())
.catch(errors => reject(errors))
);

export default connect(
(state, { pipeline }) => ({
variables: extractVariables(formValueSelector('editPipeline')(state, 'pipeline.boxes')),
supplementaryFiles: createGetPipelineFiles(pipeline.supplementaryFilesIds)(state),
}),
(dispatch, { pipeline }) => ({
loadAsync: () => dispatch(fetchSupplementaryFilesForPipeline(pipeline.id)),
})
)(
reduxForm({
form: 'editPipeline',
validate,
asyncValidate,
})(EditPipelineForm)
);
export default reduxForm({
form: 'editPipeline',
enableReinitialize: true,
keepDirtyOnReinitialize: false,
validate,
})(EditPipelineForm);
18 changes: 11 additions & 7 deletions src/locales/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -480,14 +480,18 @@
"app.editPipeline.disclaimer": "Upozornění",
"app.editPipeline.disclaimerWarning": "Upravení pipeline může rozbít všechny úlohy, které pipeline používají!",
"app.editPipeline.title": "Změnit nastavení a obsah pipeline",
"app.editPipelineFields.pipeline": "Pipeline:",
"app.editPipelineFields.pipelineVariables": "Pipeline proměnné:",
"app.editPipelineForm.description": "Popis pro vedoucího skupiny:",
"app.editPipelineEnvironmentsForm.title": "Běhová prostředí pipeline",
"app.editPipelineForm.description": "Podrobnější popis (pro autory úloh):",
"app.editPipelineForm.global": "Globalní pipeline spojená s konkrétními běhovými prostředími",
"app.editPipelineForm.hasEntryPoint": "Obsahuje vstupní bod",
"app.editPipelineForm.hasExtraFiles": "Obsahuje extra soubory",
"app.editPipelineForm.isCompilationPipeline": "Kompilační",
"app.editPipelineForm.isExecutionPipeline": "Spouštěcí",
"app.editPipelineForm.judgeOnlyPipeline": "Pouze sudí",
"app.editPipelineForm.name": "Jméno pipeline:",
"app.editPipelineForm.submit": "Uložit změny",
"app.editPipelineForm.submitting": "Ukládání...",
"app.editPipelineForm.success": "Změny byly uloženy.",
"app.editPipelineForm.title": "Změnit pipeline {name}",
"app.editPipelineForm.producesFiles": "Produkuje výstupní soubory",
"app.editPipelineForm.producesStdout": "Produkuje std. výstup",
"app.editPipelineForm.title": "Metadata pipeline",
"app.editPipelineForm.validation.description": "Prosíme vyplňte popis této pipeline.",
"app.editPipelineForm.validation.emptyName": "Prosíme vyplňte název této pipeline.",
"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.",
Expand Down
Loading

0 comments on commit f5cfaad

Please sign in to comment.