diff --git a/releasenotes/notes/parameters-form-performance-improvements-3f42a1cfe622a79d.yaml b/releasenotes/notes/parameters-form-performance-improvements-3f42a1cfe622a79d.yaml new file mode 100644 index 00000000..d9c34319 --- /dev/null +++ b/releasenotes/notes/parameters-form-performance-improvements-3f42a1cfe622a79d.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Improved perfomance in 'Deployment configuration' -> 'Parameters' section, + a general error is shown when sub-section contains validation error +fixes: + - Fixes `bug 1745408 `__ + Parameters form does not load for environments with large amount of parameters diff --git a/src/__tests__/actions/ParametersActions.tests.js b/src/__tests__/actions/ParametersActions.tests.js index 38783c31..c1054952 100644 --- a/src/__tests__/actions/ParametersActions.tests.js +++ b/src/__tests__/actions/ParametersActions.tests.js @@ -115,20 +115,13 @@ describe('ParametersActions', () => { } ); expect(store.getActions()).toEqual([ - ReduxFormActions.startSubmit('nodesAssignment'), - ParametersActions.updateParametersPending(), - ReduxFormActions.stopSubmit('nodesAssignment', { + ReduxFormActions.startSubmit('parametersForm'), + ReduxFormActions.stopSubmit('parametersForm', { _error: { title: 'Parameters could not be updated', message: error.message } - }), - ParametersActions.updateParametersFailed([ - { - title: 'Parameters could not be updated', - message: error.message - } - ]) + }) ]); }); }); diff --git a/src/js/actions/ParametersActions.js b/src/js/actions/ParametersActions.js index 8fca0a44..0280d3c2 100644 --- a/src/js/actions/ParametersActions.js +++ b/src/js/actions/ParametersActions.js @@ -28,6 +28,10 @@ const messages = defineMessages({ id: 'ParametersActions.parametersUpdatedNotficationTitle', defaultMessage: 'Parameters updated' }, + updateParametersFailed: { + id: 'ParametersActions.updateParametersFailed', + defaultMessage: 'Parameters could not be updated' + }, parametersUpdatedNotficationMessage: { id: 'ParametersActions.parametersUpdatedNotficationMessage', defaultMessage: 'The Deployment parameters have been successfully updated.' @@ -108,7 +112,45 @@ export default { }; }, - updateParameters(planName, data, inputFieldNames, redirect) { + updateRoleParameters(planName, data, inputFieldNames, redirect) { + return (dispatch, getState, { getIntl }) => { + const { formatMessage } = getIntl(getState()); + dispatch(this.updateParametersPending()); + return dispatch( + MistralApiService.runAction(MistralConstants.PARAMETERS_UPDATE, { + container: planName, + parameters: data + }) + ) + .then(response => { + dispatch(this.updateParametersSuccess(data)); + dispatch( + NotificationActions.notify({ + title: formatMessage(messages.parametersUpdatedNotficationTitle), + message: formatMessage( + messages.parametersUpdatedNotficationMessage + ), + type: 'success' + }) + ); + if (redirect) { + redirect(); + } + }) + .catch(error => { + dispatch( + this.updateParametersFailed([ + { + title: formatMessage(messages.updateParametersFailed), + message: error.message + } + ]) + ); + }); + }; + }, + + updateNodesAssignment(planName, data) { return (dispatch, getState, { getIntl }) => { const { formatMessage } = getIntl(getState()); dispatch(startSubmit('nodesAssignment')); @@ -131,22 +173,19 @@ export default { type: 'success' }) ); - if (redirect) { - redirect(); - } }) .catch(error => { dispatch( handleErrors( error, - 'Deployment parameters could not be updated', + formatMessage(messages.updateParametersFailed), false ) ); dispatch( stopSubmit('nodesAssignment', { _error: { - title: 'Parameters could not be updated', + title: formatMessage(messages.updateParametersFailed), message: error.message } }) @@ -154,12 +193,42 @@ export default { dispatch( this.updateParametersFailed([ { - title: 'Parameters could not be updated', + title: formatMessage(messages.updateParametersFailed), message: error.message } ]) ); }); }; + }, + + updateParameters(planName, data, redirect) { + return (dispatch, getState, { getIntl }) => { + const { formatMessage } = getIntl(getState()); + dispatch(startSubmit('parametersForm')); + return dispatch( + MistralApiService.runAction(MistralConstants.PARAMETERS_UPDATE, { + container: planName, + parameters: data + }) + ) + .then(response => { + dispatch(this.updateParametersSuccess(data)); + dispatch(stopSubmit('parametersForm')); + if (redirect) { + redirect(); + } + }) + .catch(error => { + dispatch( + stopSubmit('parametersForm', { + _error: { + title: formatMessage(messages.updateParametersFailed), + message: error.message + } + }) + ); + }); + }; } }; diff --git a/src/js/components/deployment_plan/DeploymentConfiguration.js b/src/js/components/deployment_plan/DeploymentConfiguration.js index 37e5ee79..7fa3c736 100644 --- a/src/js/components/deployment_plan/DeploymentConfiguration.js +++ b/src/js/components/deployment_plan/DeploymentConfiguration.js @@ -41,59 +41,50 @@ const messages = defineMessages({ } }); -class DeploymentConfiguration extends React.Component { - constructor() { - super(); - this.state = { show: true }; - } - render() { - const { location, match } = this.props; - return ( - ( + + + + + + + + +
    + - - - - - - + + + + + +
-
    - - - - - - -
- - - - - - -
- ); - } -} + + + + + +
+); DeploymentConfiguration.propTypes = { location: PropTypes.object.isRequired, match: PropTypes.object.isRequired diff --git a/src/js/components/parameters/EnvironmentParameters.js b/src/js/components/parameters/EnvironmentParameters.js index 60ef4d73..1de8d621 100644 --- a/src/js/components/parameters/EnvironmentParameters.js +++ b/src/js/components/parameters/EnvironmentParameters.js @@ -25,7 +25,7 @@ import { getEnvironmentParameters } from '../../selectors/parameters'; import { getEnvironment } from '../../selectors/environmentConfiguration'; import InlineNotification from '../ui/InlineNotification'; import { Loader } from '../ui/Loader'; -import ParameterInputList from './ParameterInputList'; +import ParameterInputList from './NewParameterInputList'; class EnvironmentParameters extends React.Component { componentDidMount() { @@ -41,7 +41,7 @@ class EnvironmentParameters extends React.Component { {environmentError ? (
@@ -70,7 +70,6 @@ function mapStateToProps(state, ownProps) { currentPlanName: getCurrentPlanName(state), environmentError: getEnvironment(state, ownProps.environment).error, parameters: getEnvironmentParameters(state, ownProps.environment), - parametersLoaded: state.parameters.loaded, isFetchingEnvironment: getEnvironment(state, ownProps.environment) .isFetching }; diff --git a/src/js/components/parameters/NewParameterInput.js b/src/js/components/parameters/NewParameterInput.js new file mode 100644 index 00000000..a234a204 --- /dev/null +++ b/src/js/components/parameters/NewParameterInput.js @@ -0,0 +1,121 @@ +/** + * 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 { Field } from 'redux-form'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { isObjectLike } from 'lodash'; + +import HorizontalInput from '../ui/reduxForm/HorizontalInput'; +import HorizontalTextarea from '../ui/reduxForm/HorizontalTextarea'; +import HorizontalCheckBox from '../ui/reduxForm/HorizontalCheckBox'; +import HorizontalStaticText from '../ui/forms/HorizontalStaticText'; + +// TODO(jtomasek): rename this when original Formsy based ParameterInputList and +// ParameterInput are not used +class NewParameterInput extends React.Component { + render() { + const { name, label, description, defaultValue, value, type } = this.props; + const commonProps = { + component: HorizontalInput, + name, + id: name, + label, + description, + labelColumns: 4, + inputColumns: 8 + }; + if (value) { + return ( + + ); + } else if (type.toLowerCase() === 'commadelimitedlist') { + return ( + value.split(',')} + component={HorizontalTextarea} + /> + ); + } else if (type.toLowerCase() === 'json' || isObjectLike(defaultValue)) { + return ; + } else if ( + type.toLowerCase() === 'string' && + /^.*(Key|Cert|Certificate)$/.test(name) + ) { + return ; + } else if (type.toLowerCase() === 'number') { + return ( + + isNaN(parseInt(value)) ? undefined : parseInt(value) + } + /> + ); + } else if (type.toLowerCase() === 'boolean') { + return ( + + ); + } else { + return ( + + ); + } + } +} +NewParameterInput.propTypes = { + defaultValue: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.array, + PropTypes.bool, + PropTypes.number, + PropTypes.string + ]), + description: PropTypes.string.isRequired, + intl: PropTypes.object, + label: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + value: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.array, + PropTypes.bool, + PropTypes.number, + PropTypes.string + ]) +}; +NewParameterInput.defaultProps = { + defaultValue: '' +}; + +export default NewParameterInput; diff --git a/src/js/components/parameters/NewParameterInputList.js b/src/js/components/parameters/NewParameterInputList.js new file mode 100644 index 00000000..8ecd8725 --- /dev/null +++ b/src/js/components/parameters/NewParameterInputList.js @@ -0,0 +1,75 @@ +/** + * 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 { defineMessages, injectIntl } from 'react-intl'; +import PropTypes from 'prop-types'; +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; + +import InlineNotification from '../ui/InlineNotification'; +import ParameterInput from './NewParameterInput'; + +const messages = defineMessages({ + noParameters: { + id: 'ParameterInputList.noParameters', + defaultMessage: + 'There are currently no parameters to configure in this section.' + } +}); + +// TODO(jtomasek): rename this when original Formsy based ParameterInputList and +// ParameterInput are not used +class NewParameterInputList extends React.Component { + render() { + const emptyParametersMessage = + this.props.emptyParametersMessage || + this.props.intl.formatMessage(messages.noParameters); + + const parameters = this.props.parameters.map(parameter => { + return ( + + ); + }); + + if (parameters.isEmpty()) { + return ( +
+ + {emptyParametersMessage} + +
+ ); + } else { + return
{parameters}
; + } + } +} +NewParameterInputList.propTypes = { + emptyParametersMessage: PropTypes.string, + intl: PropTypes.object, + mistralParameters: ImmutablePropTypes.map, + parameters: ImmutablePropTypes.list.isRequired +}; + +export default injectIntl(NewParameterInputList); diff --git a/src/js/components/parameters/Parameters.js b/src/js/components/parameters/Parameters.js index bd7e2ea0..4d8a574e 100644 --- a/src/js/components/parameters/Parameters.js +++ b/src/js/components/parameters/Parameters.js @@ -15,53 +15,28 @@ */ import { connect } from 'react-redux'; -import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; -import Formsy from 'formsy-react'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { isObjectLike, mapValues } from 'lodash'; -import { fromJS, is } from 'immutable'; +import { pickBy, isEqual, mapValues } from 'lodash'; import PropTypes from 'prop-types'; import React from 'react'; -import { CloseModalButton } from '../ui/Modals'; import EnvironmentConfigurationActions from '../../actions/EnvironmentConfigurationActions'; import EnvironmentParameters from './EnvironmentParameters'; import { getCurrentPlanName } from '../../selectors/plans'; import { getRootParameters } from '../../selectors/parameters'; import { getEnabledEnvironments } from '../../selectors/environmentConfiguration'; import { Loader } from '../ui/Loader'; -import ModalFormErrorList from '../ui/forms/ModalFormErrorList'; import ParametersActions from '../../actions/ParametersActions'; -import ParameterInputList from './ParameterInputList'; -import Tab from '../ui/Tab'; +import ParametersForm from './ParametersForm'; +import ParameterInputList from './NewParameterInputList'; +import ParametersSidebar from './ParametersSidebar'; import TabPane from '../ui/TabPane'; -const messages = defineMessages({ - saveChanges: { - id: 'Parameters.saveChanges', - defaultMessage: 'Save Changes' - }, - saveAndClose: { - id: 'Parameters.saveAndClose', - defaultMessage: 'Save And Close' - }, - cancel: { - id: 'Parameters.cancel', - defaultMessage: 'Cancel' - }, - general: { - id: 'Parameters.general', - defaultMessage: 'General' - } -}); - class Parameters extends React.Component { constructor() { super(); this.state = { - canSubmit: false, - closeOnSubmit: false, - selectedTab: 'general' + activeTab: 'general' }; } @@ -70,116 +45,23 @@ class Parameters extends React.Component { currentPlanName, fetchEnvironmentConfiguration, fetchParameters, + history, isFetchingParameters } = this.props; - fetchEnvironmentConfiguration(currentPlanName); + fetchEnvironmentConfiguration(currentPlanName, () => + history.push(`/plans/${currentPlanName}`) + ); !isFetchingParameters && fetchParameters(currentPlanName); } - componentDidUpdate() { - this.invalidateForm(this.props.formFieldErrors.toJS()); - } - - enableButton() { - this.setState({ canSubmit: true }); - } - - disableButton() { - this.setState({ canSubmit: false }); - } - - /** - * Filter out non updated parameters, so only parameters which have been actually changed - * get sent to updateparameters - */ - _filterFormData(formData) { - return fromJS(formData) - .filterNot((value, key) => { - return is(fromJS(this.props.allParameters.get(key).default), value); - }) - .toJS(); - } - - /** - * Json parameter values are sent as string, this function parses them and checks if they're object - * or array. Also, parameters with undefined value are set to null - */ - _jsonParseFormData(formData) { - return mapValues(formData, value => { - try { - const parsedValue = JSON.parse(value); - if (isObjectLike(parsedValue)) { - return parsedValue; - } - return value; - } catch (e) { - return value === undefined ? null : value; - } - }); - } - - invalidateForm(formFieldErrors) { - this.refs.parameterConfigurationForm.updateInputsWithError(formFieldErrors); - } - - handleSubmit(formData, resetForm, invalidateForm) { - this.disableButton(); - - this.props.updateParameters( - this.props.currentPlanName, - this._filterFormData(this._jsonParseFormData(formData)), - Object.keys(this.refs.parameterConfigurationForm.inputs) - ); - - if (this.state.closeOnSubmit) { - this.setState({ - closeOnSubmit: false - }); - - this.props.history.push(`/plans/${this.props.currentPlanName}`); - } - } - - onSubmitAndClose() { - this.setState( - { - closeOnSubmit: true - }, - this.refs.parameterConfigurationForm.submit - ); - } - - selectTab(tabName) { - this.setState({ - selectedTab: tabName - }); - } - - renderTabs() { - return this.props.enabledEnvironments.toList().map(environment => { - return ( - - - {environment.title} - - - ); - }); - } + isTabActive = tabName => tabName === this.state.activeTab; renderTabPanes() { - if (this.state.selectedTab === 'general') { + if (this.state.activeTab === 'general') { return ( @@ -188,7 +70,7 @@ class Parameters extends React.Component { return this.props.enabledEnvironments.toList().map(environment => { return ( @@ -199,75 +81,99 @@ class Parameters extends React.Component { } } + /** + * Filter out non updated parameters, so only parameters which have been actually changed + * get sent to updateparameters + */ + _filterFormData(values, initialValues) { + return pickBy(values, (value, key) => !isEqual(value, initialValues[key])); + } + + /** + * Json parameter values are sent as string, this function parses them and checks if they're object + * or array. Also, parameters with undefined value are set to null + */ + _parseJsonTypeValues(values, parameters) { + return mapValues(values, (value, key) => { + if (parameters.get(key).type.toLowerCase() === 'json') { + try { + return JSON.parse(value); + } catch (e) { + return value === undefined ? null : value; + } + } + return value === undefined ? null : value; + }); + } + + handleSubmit = ({ saveAndClose, ...values }, dispatch, { initialValues }) => { + const { + currentPlanName, + history, + parameters, + updateParameters + } = this.props; + const updatedValues = this._parseJsonTypeValues( + this._filterFormData(values, initialValues), + parameters + ); + updateParameters( + currentPlanName, + updatedValues, + saveAndClose && history.push.bind(this, `/plans/${currentPlanName}`) + ); + }; + + _convertJsonTypeParameterValueToString(value) { + // Heat defaults empty values to empty string also some JSON type parameters + // accept empty string as valid value + return ['', undefined].includes(value) ? '' : JSON.stringify(value); + } + + getFormInitialValues() { + return this.props.parameters + .map(p => { + const value = p.value === undefined ? p.default : p.value; + if (p.type.toLowerCase() === 'json') { + return this._convertJsonTypeParameterValueToString(value); + } else { + return value; + } + }) + .toJS(); + } + render() { + const { enabledEnvironments, parameters, parametersLoaded } = this.props; return ( - -
-
-
-
    - - - - - -
  • - {this.renderTabs()} -
-
-
- - + +
+
+ this.setState({ activeTab: tabName })} + enabledEnvironments={enabledEnvironments.toList()} + isTabActive={this.isTabActive} + /> +
{this.renderTabPanes()}
- +
-
- -
- - - - - -
- + + ); } } Parameters.propTypes = { - allParameters: ImmutablePropTypes.map.isRequired, currentPlanName: PropTypes.string, enabledEnvironments: ImmutablePropTypes.map.isRequired, fetchEnvironmentConfiguration: PropTypes.func.isRequired, @@ -280,12 +186,13 @@ Parameters.propTypes = { mistralParameters: ImmutablePropTypes.map.isRequired, parameters: ImmutablePropTypes.map.isRequired, parametersLoaded: PropTypes.bool, + rootParameters: ImmutablePropTypes.map.isRequired, updateParameters: PropTypes.func }; function mapStateToProps(state, ownProps) { return { - allParameters: state.parameters.parameters, + parameters: state.parameters.parameters, enabledEnvironments: getEnabledEnvironments(state), form: state.parameters.form, formErrors: state.parameters.form.get('formErrors'), @@ -293,7 +200,7 @@ function mapStateToProps(state, ownProps) { currentPlanName: getCurrentPlanName(state), isFetchingParameters: state.parameters.isFetching, mistralParameters: state.parameters.mistralParameters, - parameters: getRootParameters(state), + rootParameters: getRootParameters(state), parametersLoaded: state.parameters.loaded }; } @@ -315,19 +222,12 @@ function mapDispatchToProps(dispatch, ownProps) { ) ); }, - updateParameters: (currentPlanName, data, inputFields, redirect) => { + updateParameters: (currentPlanName, data, redirect) => { dispatch( - ParametersActions.updateParameters( - currentPlanName, - data, - inputFields, - redirect - ) + ParametersActions.updateParameters(currentPlanName, data, redirect) ); } }; } -export default injectIntl( - connect(mapStateToProps, mapDispatchToProps)(Parameters) -); +export default connect(mapStateToProps, mapDispatchToProps)(Parameters); diff --git a/src/js/components/parameters/ParametersForm.js b/src/js/components/parameters/ParametersForm.js new file mode 100644 index 00000000..60376d54 --- /dev/null +++ b/src/js/components/parameters/ParametersForm.js @@ -0,0 +1,166 @@ +/** + * 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 { Button, Form, ModalFooter } from 'react-bootstrap'; +import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { isEqual, pickBy } from 'lodash'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { reduxForm } from 'redux-form'; + +import { CloseModalButton } from '../ui/Modals'; +import ModalFormErrorList from '../ui/forms/ModalFormErrorList'; +import { OverlayLoader } from '../ui/Loader'; + +const messages = defineMessages({ + cancel: { + id: 'ParametersForm.cancel', + defaultMessage: 'Cancel' + }, + saveChanges: { + id: 'ParametersForm.saveChanges', + defaultMessage: 'Save Changes' + }, + saveAndClose: { + id: 'ParametersForm.saveAndClose', + defaultMessage: 'Save And Close' + }, + updatingParameters: { + id: 'ParametersForm.updatingParameters', + defaultMessage: 'Updating parameters' + }, + enterValidJson: { + id: 'ParametersForm.enterValidJson', + defaultMessage: 'Please enter a valid JSON.' + }, + invalidParameters: { + id: 'ParametersForm.invalidParameters', + defaultMessage: 'Some parameter values are invalid:', + description: 'Form error notification title' + }, + invalidParametersList: { + id: 'ParametersForm.invalidParametersList', + defaultMessage: '{parameters}', + description: 'A list of invalid parameters in form error message' + } +}); + +const ParametersForm = ({ + dispatch, + error, + children, + onSubmit, + handleSubmit, + intl: { formatMessage }, + invalid, + pristine, + submitting, + initialValues +}) => ( +
+ + + {children} + + + + + + + + +
+); +ParametersForm.propTypes = { + children: PropTypes.node, + dispatch: PropTypes.func.isRequired, + error: PropTypes.object, + handleSubmit: PropTypes.func.isRequired, + initialValues: PropTypes.object.isRequired, + intl: PropTypes.object.isRequired, + invalid: PropTypes.bool.isRequired, + onSubmit: PropTypes.func.isRequired, + parameters: ImmutablePropTypes.map.isRequired, + pristine: PropTypes.bool.isRequired, + submitting: PropTypes.bool.isRequired +}; + +const isJSON = value => { + try { + // empty string is considered valid JSON type parameter value + return value === '' ? true : !!JSON.parse(value); + } catch (e) { + return false; + } +}; + +const validate = ( + values, + { initialValues, parameters, intl: { formatMessage } } +) => { + const errors = {}; + + // Validate only parameters which were updated by User + const updatedValues = pickBy( + values, + (value, key) => !isEqual(value, initialValues[key]) + ); + + Object.keys(updatedValues).map(key => { + if (parameters.getIn([key, 'type']).toLowerCase() === 'json') { + if (!isJSON(values[key])) { + errors[key] = formatMessage(messages.enterValidJson); + } + } + }); + + // Add global error message + if (Object.keys(errors).length > 0) { + errors['_error'] = { + title: formatMessage(messages.invalidParameters), + message: formatMessage(messages.invalidParametersList, { + parameters: Object.keys(errors).join(', ') + }) + }; + } + return errors; +}; + +const form = reduxForm({ + form: 'parametersForm', + validate +}); + +export default injectIntl(form(ParametersForm)); diff --git a/src/js/components/parameters/ParametersSidebar.js b/src/js/components/parameters/ParametersSidebar.js new file mode 100644 index 00000000..89876de9 --- /dev/null +++ b/src/js/components/parameters/ParametersSidebar.js @@ -0,0 +1,74 @@ +/** + * 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 { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import PropTypes from 'prop-types'; +import React from 'react'; + +import Tab from '../ui/Tab'; + +const messages = defineMessages({ + general: { + id: 'Parameters.general', + defaultMessage: 'General' + } +}); + +const ParametersSidebar = ({ + activateTab, + enabledEnvironments, + intl: { formatMessage }, + isTabActive +}) => ( +
+ +
+); +ParametersSidebar.propTypes = { + activateTab: PropTypes.func.isRequired, + enabledEnvironments: ImmutablePropTypes.list.isRequired, + intl: PropTypes.object.isRequired, + isTabActive: PropTypes.func.isRequired +}; +export default injectIntl(ParametersSidebar); diff --git a/src/js/components/roles/NodesAssignment.js b/src/js/components/roles/NodesAssignment.js index ce34300d..85e749b2 100644 --- a/src/js/components/roles/NodesAssignment.js +++ b/src/js/components/roles/NodesAssignment.js @@ -100,15 +100,8 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => { return { - updateParameters: (currentPlanName, data, inputFields, redirectPath) => { - dispatch( - ParametersActions.updateParameters( - currentPlanName, - data, - inputFields, - redirectPath - ) - ); + updateParameters: (currentPlanName, data) => { + dispatch(ParametersActions.updateNodesAssignment(currentPlanName, data)); } }; }; diff --git a/src/js/components/roles/RoleDetail.js b/src/js/components/roles/RoleDetail.js index ffc0930e..f6e05511 100644 --- a/src/js/components/roles/RoleDetail.js +++ b/src/js/components/roles/RoleDetail.js @@ -294,7 +294,7 @@ function mapDispatchToProps(dispatch) { }, updateParameters: (currentPlanName, data, inputFields, redirectPath) => { dispatch( - ParametersActions.updateParameters( + ParametersActions.updateRoleParameters( currentPlanName, data, inputFields, diff --git a/src/js/components/ui/reduxForm/HorizontalCheckBox.js b/src/js/components/ui/reduxForm/HorizontalCheckBox.js index 0280fc63..686c3f9e 100644 --- a/src/js/components/ui/reduxForm/HorizontalCheckBox.js +++ b/src/js/components/ui/reduxForm/HorizontalCheckBox.js @@ -17,7 +17,7 @@ import cx from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; -import { Checkbox, Col, FormGroup } from 'react-bootstrap'; +import { Checkbox, Col, ControlLabel, FormGroup } from 'react-bootstrap'; import { getValidationState, InputDescription, InputMessage } from './utils'; @@ -35,10 +35,15 @@ const HorizontalCheckBox = ({ }) => { return ( - - - {label} - + + {label} + + + diff --git a/src/js/components/ui/reduxForm/HorizontalTextarea.js b/src/js/components/ui/reduxForm/HorizontalTextarea.js index 4f44d01d..65a93733 100644 --- a/src/js/components/ui/reduxForm/HorizontalTextarea.js +++ b/src/js/components/ui/reduxForm/HorizontalTextarea.js @@ -31,24 +31,22 @@ const HorizontalTextarea = ({ meta, required, ...rest -}) => { - return ( - - - {label} - - - - - - - - ); -}; +}) => ( + + + {label} + + + + + + + +); HorizontalTextarea.propTypes = { description: PropTypes.node, id: PropTypes.string.isRequired,