Merge "Add advanced configuration of container images"
This commit is contained in:
commit
efd135b199
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* Copyright 2018 Red Hat Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import { reduxForm, Field, SubmissionError } from 'redux-form';
|
||||
import { Form, Wizard } from 'patternfly-react';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
import { OverlayLoader } from '../ui/Loader';
|
||||
import ModalFormErrorList from '../ui/forms/ModalFormErrorList';
|
||||
import AceEditorInput from '../ui/reduxForm/AceEditorInput';
|
||||
import { updateParameters } from '../../actions/ParametersActions';
|
||||
|
||||
const messages = defineMessages({
|
||||
updatingConfiguration: {
|
||||
id: 'ContainerImagePrepareParameterForm.updatingConfiguration',
|
||||
defaultMessage: 'Updating configuration...'
|
||||
},
|
||||
yamlSyntaxError: {
|
||||
id: 'ContainerImagePrepareParameterForm.yamlSyntaxError',
|
||||
defaultMessage: 'Invalid Yaml Syntax:'
|
||||
}
|
||||
});
|
||||
|
||||
const ContainerImagePrepareParameterForm = ({
|
||||
currentPlanName,
|
||||
error,
|
||||
handleSubmit,
|
||||
intl: { formatMessage },
|
||||
parameter,
|
||||
submitting
|
||||
}) => (
|
||||
<Form onSubmit={handleSubmit} horizontal>
|
||||
<OverlayLoader
|
||||
loaded={!submitting}
|
||||
content={formatMessage(messages.updatingConfiguration)}
|
||||
>
|
||||
<ModalFormErrorList errors={error ? [error] : []} />
|
||||
<Wizard.Main style={{ padding: 0 }}>
|
||||
<Wizard.Contents stepIndex={1} activeStepIndex={1}>
|
||||
<Field
|
||||
width="100%"
|
||||
height="680px"
|
||||
name={parameter.name}
|
||||
component={AceEditorInput}
|
||||
description={parameter.description}
|
||||
/>
|
||||
</Wizard.Contents>
|
||||
</Wizard.Main>
|
||||
</OverlayLoader>
|
||||
</Form>
|
||||
);
|
||||
ContainerImagePrepareParameterForm.propTypes = {
|
||||
currentPlanName: PropTypes.string.isRequired,
|
||||
error: PropTypes.object,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
parameter: ImmutablePropTypes.record.isRequired,
|
||||
submitting: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
const form = reduxForm({
|
||||
form: 'parametersForm',
|
||||
onSubmit: (
|
||||
{ ContainerImagePrepare },
|
||||
dispatch,
|
||||
{ currentPlanName, intl: { formatMessage } }
|
||||
) => {
|
||||
try {
|
||||
ContainerImagePrepare = yaml.safeLoad(ContainerImagePrepare, {
|
||||
json: true
|
||||
});
|
||||
dispatch(updateParameters(currentPlanName, { ContainerImagePrepare }));
|
||||
} catch (e) {
|
||||
return Promise.reject(
|
||||
new SubmissionError({
|
||||
_error: {
|
||||
title: formatMessage(messages.yamlSyntaxError),
|
||||
message: e.message
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
validate: ({ ContainerImagePrepare }) => {
|
||||
try {
|
||||
yaml.safeLoad(ContainerImagePrepare, { json: true });
|
||||
return {};
|
||||
} catch (e) {
|
||||
return { ContainerImagePrepare: e.message };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default injectIntl(form(ContainerImagePrepareParameterForm));
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* Copyright 2018 Red Hat Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Icon, Button } from 'patternfly-react';
|
||||
import { submit, isSubmitting, isPristine, isInvalid } from 'redux-form';
|
||||
|
||||
import { CloseModalButton } from '../ui/Modals';
|
||||
|
||||
const messages = defineMessages({
|
||||
back: {
|
||||
id: 'ContainerImagePrepareParameterFormActions.back',
|
||||
defaultMessage: 'Back'
|
||||
},
|
||||
save: {
|
||||
id: 'ContainerImagePrepareParameterFormActions.save',
|
||||
defaultMessage: 'Save Changes'
|
||||
},
|
||||
close: {
|
||||
id: 'ContainerImagePrepareParameterFormActions.close',
|
||||
defaultMessage: 'Close'
|
||||
}
|
||||
});
|
||||
|
||||
const ContainerImagePrepareParameterFormActions = ({
|
||||
goBack,
|
||||
isSubmitting,
|
||||
isInvalid,
|
||||
isPristine,
|
||||
submitForm
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Button bsStyle="default" onClick={goBack} disabled={isSubmitting}>
|
||||
<Icon type="fa" name="angle-left" />
|
||||
<FormattedMessage {...messages.back} />
|
||||
</Button>
|
||||
<Button
|
||||
bsStyle="primary"
|
||||
onClick={submitForm}
|
||||
disabled={isSubmitting || isPristine || isInvalid}
|
||||
>
|
||||
<FormattedMessage {...messages.save} />
|
||||
</Button>
|
||||
<CloseModalButton>
|
||||
<FormattedMessage {...messages.close} />
|
||||
</CloseModalButton>
|
||||
</Fragment>
|
||||
);
|
||||
ContainerImagePrepareParameterFormActions.propTypes = {
|
||||
goBack: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
isInvalid: PropTypes.bool.isRequired,
|
||||
isPristine: PropTypes.bool.isRequired,
|
||||
isSubmitting: PropTypes.bool.isRequired,
|
||||
submitForm: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
isSubmitting: isSubmitting('parametersForm')(state),
|
||||
isPristine: isPristine('parametersForm')(state),
|
||||
isInvalid: isInvalid('parametersForm')(state)
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
submitForm: () => dispatch(submit('parametersForm'))
|
||||
});
|
||||
|
||||
export default injectIntl(
|
||||
connect(mapStateToProps, mapDispatchToProps)(
|
||||
ContainerImagePrepareParameterFormActions
|
||||
)
|
||||
);
|
|
@ -21,11 +21,20 @@ import PropTypes from 'prop-types';
|
|||
import { Icon, Button } from 'patternfly-react';
|
||||
import { submit, isSubmitting, isPristine, isInvalid } from 'redux-form';
|
||||
|
||||
import { CloseModalButton } from '../ui/Modals';
|
||||
import { startContainerImagesPrepare } from '../../actions/ContainerImagesActions';
|
||||
|
||||
const messages = defineMessages({
|
||||
cancel: {
|
||||
id: 'ContainerImagesWizard.cancel',
|
||||
defaultMessage: 'Cancel'
|
||||
},
|
||||
save: {
|
||||
id: 'ContainerImagesPrepareFormActions.save',
|
||||
defaultMessage: 'Save Changes'
|
||||
},
|
||||
next: {
|
||||
id: 'ContainerImagesWizard.next',
|
||||
id: 'ContainerImagesPrepareFormActions.next',
|
||||
defaultMessage: 'Next'
|
||||
},
|
||||
reset: {
|
||||
|
@ -35,38 +44,44 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
const ContainerImagesPrepareFormActions = ({
|
||||
goForward,
|
||||
isSubmitting,
|
||||
isInvalid,
|
||||
isPristine,
|
||||
resetToDefaults,
|
||||
submitImagesPrepareForm
|
||||
submitForm
|
||||
}) => (
|
||||
<Fragment>
|
||||
<CloseModalButton>
|
||||
<FormattedMessage {...messages.cancel} />
|
||||
</CloseModalButton>
|
||||
<Button onClick={resetToDefaults} disabled={isSubmitting}>
|
||||
<FormattedMessage {...messages.reset} />
|
||||
</Button>
|
||||
<Button
|
||||
bsStyle="primary"
|
||||
onClick={submitImagesPrepareForm}
|
||||
onClick={submitForm}
|
||||
disabled={isSubmitting || isPristine || isInvalid}
|
||||
>
|
||||
<FormattedMessage {...messages.save} />
|
||||
</Button>
|
||||
<Button bsStyle="default" onClick={goForward} disabled={isSubmitting}>
|
||||
<FormattedMessage {...messages.next} />
|
||||
<Icon type="fa" name="angle-right" />
|
||||
</Button>
|
||||
</Fragment>
|
||||
);
|
||||
ContainerImagesPrepareFormActions.propTypes = {
|
||||
goForward: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
isFetchingParameters: PropTypes.bool.isRequired,
|
||||
isInvalid: PropTypes.bool.isRequired,
|
||||
isPristine: PropTypes.bool.isRequired,
|
||||
isSubmitting: PropTypes.bool.isRequired,
|
||||
resetToDefaults: PropTypes.func.isRequired,
|
||||
submitImagesPrepareForm: PropTypes.func.isRequired
|
||||
submitForm: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
isFetchingParameters: state.parameters.isFetching,
|
||||
isSubmitting: isSubmitting('containerImagesPrepareForm')(state),
|
||||
isPristine: isPristine('containerImagesPrepareForm')(state),
|
||||
isInvalid: isInvalid('containerImagesPrepareForm')(state)
|
||||
|
@ -74,7 +89,7 @@ const mapStateToProps = state => ({
|
|||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
resetToDefaults: () => dispatch(startContainerImagesPrepare({})),
|
||||
submitImagesPrepareForm: () => dispatch(submit('containerImagesPrepareForm'))
|
||||
submitForm: () => dispatch(submit('containerImagesPrepareForm'))
|
||||
});
|
||||
|
||||
export default injectIntl(
|
||||
|
|
|
@ -14,43 +14,30 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Wizard, Modal, Icon, Button } from 'patternfly-react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { Wizard, Modal } from 'patternfly-react';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
import { checkRunningDeployment } from '../utils/checkRunningDeploymentHOC';
|
||||
import { getCurrentPlanName } from '../../selectors/plans';
|
||||
import { Loader } from '../ui/Loader';
|
||||
import { fetchParameters } from '../../actions/ParametersActions';
|
||||
import { startContainerImagesPrepare } from '../../actions/ContainerImagesActions';
|
||||
import {
|
||||
RoutedWizard,
|
||||
CloseModalXButton,
|
||||
CloseModalButton
|
||||
} from '../ui/Modals';
|
||||
import { RoutedWizard, CloseModalXButton } from '../ui/Modals';
|
||||
import ContainerImagesPrepareForm from './ContainerImagesPrepareForm';
|
||||
import { getContainerImagePrepareParameterSeed } from '../../selectors/parameters';
|
||||
import {
|
||||
getContainerImagePrepareParameterSeed,
|
||||
getContainerImagePrepareParameter
|
||||
} from '../../selectors/parameters';
|
||||
import ContainerImagesPrepareFormActions from './ContainerImagesPrepareFormActions';
|
||||
import ContainerImagePrepareParameterForm from './ContainerImagePrepareParameterForm';
|
||||
import ContainerImagePrepareParameterFormActions from './ContainerImagePrepareParameterFormActions';
|
||||
|
||||
const messages = defineMessages({
|
||||
close: {
|
||||
id: 'ContainerImagesWizard.close',
|
||||
defaultMessage: 'Close'
|
||||
},
|
||||
cancel: {
|
||||
id: 'ContainerImagesWizard.cancel',
|
||||
defaultMessage: 'Cancel'
|
||||
},
|
||||
back: {
|
||||
id: 'ContainerImagesWizard.back',
|
||||
defaultMessage: 'Back'
|
||||
},
|
||||
save: {
|
||||
id: 'ContainerImagesWizard.save',
|
||||
defaultMessage: 'Save Changes'
|
||||
},
|
||||
title: {
|
||||
id: 'ContainerImagesWizard.title',
|
||||
defaultMessage: 'Prepare Container Images'
|
||||
|
@ -93,6 +80,7 @@ class ContainerImagesWizard extends Component {
|
|||
intl: { formatMessage },
|
||||
isFetchingParameters,
|
||||
containerImagePrepareParameterSeed,
|
||||
containerImagePrepareParameter,
|
||||
resetToDefaults
|
||||
} = this.props;
|
||||
|
||||
|
@ -152,31 +140,28 @@ class ContainerImagesWizard extends Component {
|
|||
resetToDefaults={resetToDefaults}
|
||||
/>
|
||||
) : (
|
||||
<p>parameter form here</p>
|
||||
<ContainerImagePrepareParameterForm
|
||||
parameter={containerImagePrepareParameter}
|
||||
currentPlanName={currentPlanName}
|
||||
initialValues={{
|
||||
[containerImagePrepareParameter.name]: yaml.safeDump(
|
||||
containerImagePrepareParameter.default
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Loader>
|
||||
</Wizard.Body>
|
||||
<Wizard.Footer>
|
||||
<CloseModalButton>
|
||||
<FormattedMessage {...messages.cancel} />
|
||||
</CloseModalButton>
|
||||
{activeStepIndex === 0 && <ContainerImagesPrepareFormActions />}
|
||||
{activeStepIndex === 0 && (
|
||||
<ContainerImagesPrepareFormActions
|
||||
goForward={() => this.setActiveStepIndex(1)}
|
||||
/>
|
||||
)}
|
||||
{activeStepIndex === 1 && (
|
||||
<Fragment>
|
||||
<Button
|
||||
bsStyle="default"
|
||||
onClick={() => this.setActiveStepIndex(0)}
|
||||
>
|
||||
<Icon type="fa" name="angle-left" />
|
||||
<FormattedMessage {...messages.back} />
|
||||
</Button>
|
||||
<Button bsStyle="primary" onClick={this.onNextButtonClick}>
|
||||
<FormattedMessage {...messages.save} />
|
||||
</Button>
|
||||
<CloseModalButton>
|
||||
<FormattedMessage {...messages.close} />
|
||||
</CloseModalButton>
|
||||
</Fragment>
|
||||
<ContainerImagePrepareParameterFormActions
|
||||
goBack={() => this.setActiveStepIndex(0)}
|
||||
/>
|
||||
)}
|
||||
</Wizard.Footer>
|
||||
</RoutedWizard>
|
||||
|
@ -184,6 +169,7 @@ class ContainerImagesWizard extends Component {
|
|||
}
|
||||
}
|
||||
ContainerImagesWizard.propTypes = {
|
||||
containerImagePrepareParameter: ImmutablePropTypes.record.isRequired,
|
||||
containerImagePrepareParameterSeed: PropTypes.object.isRequired,
|
||||
currentPlanName: PropTypes.string.isRequired,
|
||||
fetchParameters: PropTypes.func.isRequired,
|
||||
|
@ -196,6 +182,7 @@ const mapStateToProps = state => ({
|
|||
containerImagePrepareParameterSeed: getContainerImagePrepareParameterSeed(
|
||||
state
|
||||
),
|
||||
containerImagePrepareParameter: getContainerImagePrepareParameter(state),
|
||||
currentPlanName: getCurrentPlanName(state),
|
||||
isFetchingParameters: state.parameters.isFetching
|
||||
});
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Copyright 2018 Red Hat Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import AceEditor from 'react-ace';
|
||||
import 'brace/theme/textmate';
|
||||
import 'brace/mode/yaml';
|
||||
|
||||
import AceEditorInputToolbar from './AceEditorInputToolbar';
|
||||
|
||||
const aceOnBlur = onBlur => (_event, editor) => {
|
||||
const value = editor && editor.getValue();
|
||||
onBlur(value);
|
||||
};
|
||||
|
||||
const AceEditorInput = ({ input, meta, description, ...rest }) => (
|
||||
<Fragment>
|
||||
<AceEditor {...input} onBlur={aceOnBlur(input.onBlur)} {...rest} />
|
||||
<AceEditorInputToolbar {...meta} description={description} />
|
||||
</Fragment>
|
||||
);
|
||||
AceEditorInput.propTypes = {
|
||||
description: PropTypes.string.isRequired,
|
||||
input: PropTypes.object.isRequired,
|
||||
meta: PropTypes.object.isRequired,
|
||||
mode: PropTypes.string.isRequired,
|
||||
theme: PropTypes.string.isRequired
|
||||
};
|
||||
AceEditorInput.defaultProps = {
|
||||
theme: 'textmate',
|
||||
mode: 'yaml',
|
||||
tabSize: 2,
|
||||
enableBasicAutocompletion: false,
|
||||
editorProps: { $blockScrolling: true }
|
||||
};
|
||||
|
||||
export default AceEditorInput;
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* Copyright 2018 Red Hat Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Icon } from 'patternfly-react';
|
||||
|
||||
const AceEditorInputToolbar = ({
|
||||
valid,
|
||||
invalid,
|
||||
warning,
|
||||
error,
|
||||
description
|
||||
}) => (
|
||||
<div className="ace-editor-toolbar">
|
||||
{invalid && (
|
||||
<Fragment>
|
||||
<Icon type="pf" name="error-circle-o" /> {error}
|
||||
</Fragment>
|
||||
)}
|
||||
{warning && (
|
||||
<Fragment>
|
||||
<Icon type="pf" name="warning-triangle-o" /> {warning}
|
||||
</Fragment>
|
||||
)}
|
||||
{valid &&
|
||||
!warning &&
|
||||
description && (
|
||||
<Fragment>
|
||||
<Icon type="pf" name="info" /> {description}
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
AceEditorInputToolbar.propTypes = {
|
||||
description: PropTypes.string,
|
||||
error: PropTypes.string,
|
||||
invalid: PropTypes.bool.isRequired,
|
||||
valid: PropTypes.bool.isRequired,
|
||||
warning: PropTypes.string
|
||||
};
|
||||
|
||||
export default AceEditorInputToolbar;
|
|
@ -163,6 +163,7 @@
|
|||
@import "ui/Sidebar";
|
||||
@import "ui/Toolbar";
|
||||
@import "ui/Tooltips";
|
||||
@import "ui/AceEditorToolbar";
|
||||
@import "components/Breadcrumbs";
|
||||
@import "components/MainContent";
|
||||
@import "components/EnvironmentConfiguration";
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
|
||||
&.card-loader {
|
||||
box-sizing: content-box;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Copyright 2018 Red Hat Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
.ace-editor-toolbar {
|
||||
background: #f0f0f0;
|
||||
color: #333;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding: 3px 5px;
|
||||
min-height: 24px;
|
||||
}
|
Loading…
Reference in New Issue