From af94db31d09ffb6ef91fe907298335a430bcf987 Mon Sep 17 00:00:00 2001 From: Aparna Karve Date: Wed, 14 Mar 2018 16:01:41 -0700 Subject: [PATCH 1/8] Custom component for bootstrap-select --- .../App/common/forms/BootstrapSelect.js | 75 +++++++++++++++++++ package.json | 2 + 2 files changed, 77 insertions(+) create mode 100644 app/javascript/react/screens/App/common/forms/BootstrapSelect.js diff --git a/app/javascript/react/screens/App/common/forms/BootstrapSelect.js b/app/javascript/react/screens/App/common/forms/BootstrapSelect.js new file mode 100644 index 0000000000..0237820419 --- /dev/null +++ b/app/javascript/react/screens/App/common/forms/BootstrapSelect.js @@ -0,0 +1,75 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Form, Grid } from 'patternfly-react'; +import { focus } from 'redux-form'; + +const $ = require('jquery'); +require('bootstrap-select'); + +export class BootstrapSelect extends React.Component { + componentDidMount() { + const { input, form_name, meta: { visited, dispatch } } = this.props; + $(`#${input.name}`).selectpicker(); + + $(`.${input.name}_select`).on('click', '.dropdown-toggle', e => { + if (!visited) dispatch(focus(form_name, input.name)); + }); + } + + render = () => { + const { + input, + label, + required, + data_live_search, + options, + option_key, + option_value, + meta: { visited, error, active } + } = this.props; + + const formGroupProps = { key: { label }, ...this.props }; + + if (visited && !active && error) formGroupProps.validationState = 'error'; + + return ( + + + {label} + {required && ' *'} + + + + {visited && + !active && + error && {error}} + + + ); + }; +} + +BootstrapSelect.propTypes = { + label: PropTypes.string, + input: PropTypes.object, + required: PropTypes.bool, + data_live_search: PropTypes.string, + type: PropTypes.string, + options: PropTypes.array, + option_key: PropTypes.string, + option_value: PropTypes.string, + meta: PropTypes.object, + form_name: PropTypes.string +}; diff --git a/package.json b/package.json index db003ffbf3..be2a1d47ed 100644 --- a/package.json +++ b/package.json @@ -55,10 +55,12 @@ }, "dependencies": { "axios": "^0.17.1", + "bootstrap-select": "^1.12.4", "classnames": "^2.2.5", "csv": "^2.0.0", "cx": "^18.1.11", "intl": "~1.2.5", + "jquery": "^3.3.1", "moment": "^2.20.1", "numeral": "^2.0.6", "patternfly": "^3.35.1", From e146ff88e8b8a5f172e5c4861bb6e0e36ab09c44 Mon Sep 17 00:00:00 2001 From: Aparna Karve Date: Wed, 14 Mar 2018 16:02:42 -0700 Subject: [PATCH 2/8] Use BootstrapSelect in Plan Wizard Step1 --- .../PlanWizardGeneralStep/PlanWizardGeneralStep.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/javascript/react/screens/App/Overview/screens/PlanWizard/components/PlanWizardGeneralStep/PlanWizardGeneralStep.js b/app/javascript/react/screens/App/Overview/screens/PlanWizard/components/PlanWizardGeneralStep/PlanWizardGeneralStep.js index bc9dca5f4a..9c2484172d 100644 --- a/app/javascript/react/screens/App/Overview/screens/PlanWizard/components/PlanWizardGeneralStep/PlanWizardGeneralStep.js +++ b/app/javascript/react/screens/App/Overview/screens/PlanWizard/components/PlanWizardGeneralStep/PlanWizardGeneralStep.js @@ -4,6 +4,7 @@ import { required } from 'redux-form-validators'; import { Form } from 'patternfly-react'; import PropTypes from 'prop-types'; import { FormField } from '../../../../../common/forms/FormField'; +import { BootstrapSelect } from '../../../../../common/forms/BootstrapSelect'; const PlanWizardGeneralStep = ({ transformationMappings }) => (
@@ -11,12 +12,13 @@ const PlanWizardGeneralStep = ({ transformationMappings }) => ( name="infrastructure_mapping" label={__('Infrastructure Mapping')} required - component={FormField} + data_live_search="true" + component={BootstrapSelect} validate={[required({ msg: __('Required') })]} options={transformationMappings} - optionKey="id" - optionValue="name" - type="select" + option_key="id" + option_value="name" + form_name="planWizardGeneralStep" /> Date: Fri, 16 Mar 2018 16:42:07 -0700 Subject: [PATCH 3/8] Custom dropdown applied to Datastores --- .../MappingWizardDatastoresStep.js | 48 +++++++++++--- .../App/common/forms/BootstrapSelect.js | 62 +++++++++++++++---- 2 files changed, 92 insertions(+), 18 deletions(-) diff --git a/app/javascript/react/screens/App/Overview/screens/MappingWizard/components/MappingWizardDatastoresStep/MappingWizardDatastoresStep.js b/app/javascript/react/screens/App/Overview/screens/MappingWizard/components/MappingWizardDatastoresStep/MappingWizardDatastoresStep.js index 45a7c9743c..666f21bd4c 100644 --- a/app/javascript/react/screens/App/Overview/screens/MappingWizard/components/MappingWizardDatastoresStep/MappingWizardDatastoresStep.js +++ b/app/javascript/react/screens/App/Overview/screens/MappingWizard/components/MappingWizardDatastoresStep/MappingWizardDatastoresStep.js @@ -2,9 +2,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Field, reduxForm } from 'redux-form'; import { length } from 'redux-form-validators'; -import { noop, bindMethods } from 'patternfly-react'; +import { noop, bindMethods, Form } from 'patternfly-react'; import SourceClusterSelect from '../SourceClusterSelect/SourceClusterSelect'; import DatastoresStepForm from './components/DatastoresStepForm/DatastoresStepForm'; +import { BootstrapSelect } from '../../../../../common/forms/BootstrapSelect'; class MappingWizardDatastoresStep extends React.Component { constructor(props) { @@ -109,16 +110,49 @@ class MappingWizardDatastoresStep extends React.Component { const { selectedCluster, selectedClusterMapping } = this.state; + const sourceClustersWithAssociatedTargetClusters = clusterMappings.reduce( + (mappings, targetClusterWithSourceClusters) => { + const { + nodes: sourceClusters, + ...targetCluster + } = targetClusterWithSourceClusters; + const sourceToTargetMappings = sourceClusters.map(sourceCluster => ({ + sourceCluster, + targetCluster, + sourceClusterMappedToTargetCluster: { + name: `${sourceCluster.name} (${targetCluster.name})`, + id: sourceCluster.id + } + })); + return mappings.concat(sourceToTargetMappings); + }, + [] + ); + + const clusterOptions = sourceClustersWithAssociatedTargetClusters.map( + ({ sourceClusterMappedToTargetCluster }) => + sourceClusterMappedToTargetCluster + ); + // first we render the dropdown selection for each source cluster in clusterMappings, // then we call `selectSourceCluster` and go get that cluster's datastores on selection return (
- `} + render_within_form="true" + form_name={form} /> { if (!visited) dispatch(focus(form_name, input.name)); }); + if (onSelect) + $(`#${input.name}`).on('changed.bs.select', e => { + onSelect(e.target.value); + }); } - render = () => { + renderFormGroup = (labelWidth, controlWidth) => { const { input, label, @@ -25,27 +46,29 @@ export class BootstrapSelect extends React.Component { options, option_key, option_value, + choose_text, meta: { visited, error, active } } = this.props; - const formGroupProps = { key: { label }, ...this.props }; if (visited && !active && error) formGroupProps.validationState = 'error'; return ( - - + + {label} {required && ' *'} - +