From d2cf2c275b5a44f3ae02f3d6f7b4326b519def8d Mon Sep 17 00:00:00 2001 From: Marliana Lara Date: Fri, 22 Feb 2019 14:53:17 -0500 Subject: [PATCH] Add Organization Edit view --- src/components/Lookup/Lookup.jsx | 4 +- .../screens/Organization/Organization.jsx | 20 +- .../screens/Organization/OrganizationEdit.jsx | 304 +++++++++++++++++- 3 files changed, 304 insertions(+), 24 deletions(-) diff --git a/src/components/Lookup/Lookup.jsx b/src/components/Lookup/Lookup.jsx index 8568498f8e..bc57dbb1c4 100644 --- a/src/components/Lookup/Lookup.jsx +++ b/src/components/Lookup/Lookup.jsx @@ -30,9 +30,10 @@ const paginationStyling = { class Lookup extends React.Component { constructor (props) { super(props); + this.state = { isModalOpen: false, - lookupSelectedItems: [], + lookupSelectedItems: props.value || [], results: [], count: 0, page: 1, @@ -43,7 +44,6 @@ class Lookup extends React.Component { }; this.onSetPage = this.onSetPage.bind(this); this.handleModalToggle = this.handleModalToggle.bind(this); - this.wrapTags = this.wrapTags.bind(this); this.toggleSelected = this.toggleSelected.bind(this); this.saveModal = this.saveModal.bind(this); this.getData = this.getData.bind(this); diff --git a/src/pages/Organizations/screens/Organization/Organization.jsx b/src/pages/Organizations/screens/Organization/Organization.jsx index 2b63bf0877..248b93c6d3 100644 --- a/src/pages/Organizations/screens/Organization/Organization.jsx +++ b/src/pages/Organizations/screens/Organization/Organization.jsx @@ -119,14 +119,18 @@ class Organization extends Component { to="/organizations/:id/details" exact /> - ( - - )} - /> + {organization && ( + ( + + )} + /> + )} {organization && ( ( - -

edit view

- - save/cancel and go back to view - -
-); +import { ConfigContext } from '../../../../context'; +import Lookup from '../../../../components/Lookup'; +import FormActionGroup from '../../../../components/FormActionGroup'; +import AnsibleSelect from '../../../../components/AnsibleSelect'; -export default OrganizationEdit; +class OrganizationEdit extends Component { + constructor (props) { + super(props); + + this.getInstanceGroups = this.getInstanceGroups.bind(this); + this.getRelatedInstanceGroups = this.getRelatedInstanceGroups.bind(this); + this.checkValidity = this.checkValidity.bind(this); + this.onFieldChange = this.onFieldChange.bind(this); + this.onLookupSave = this.onLookupSave.bind(this); + this.onSubmit = this.onSubmit.bind(this); + this.postInstanceGroups = this.postInstanceGroups.bind(this); + this.onCancel = this.onCancel.bind(this); + this.onSuccess = this.onSuccess.bind(this); + + this.state = { + form: { + name: { + value: '', + isValid: true, + validation: { + required: true + }, + helperTextInvalid: i18nMark('This field must not be blank') + }, + description: { + value: '' + }, + instanceGroups: { + value: null, + initialValue: null + }, + custom_virtualenv: { + value: '', + defaultValue: '/venv/ansible/' + } + }, + error: '', + formIsValid: true + }; + } + + async componentDidMount () { + const { organization } = this.props; + const { form: formData } = this.state; + + formData.name.value = organization.name; + formData.description.value = organization.description; + formData.custom_virtualenv.value = organization.custom_virtualenv; + + try { + formData.instanceGroups.value = await this.getRelatedInstanceGroups(); + formData.instanceGroups.initialValue = [...formData.instanceGroups.value]; + } catch (err) { + this.setState({ error: err }); + } + + this.setState({ form: formData }); + } + + onFieldChange (val, evt) { + const targetName = evt.target.name; + const value = val; + + const { form: updatedForm } = this.state; + const updatedFormEl = { ...updatedForm[targetName] }; + + updatedFormEl.value = value; + updatedForm[targetName] = updatedFormEl; + + let formIsValid = true; + if (updatedFormEl.validation) { + updatedFormEl.isValid = this.checkValidity(updatedFormEl.value, updatedFormEl.validation); + formIsValid = updatedFormEl.isValid && formIsValid; + } + + this.setState({ form: updatedForm, formIsValid }); + } + + onLookupSave (val, targetName) { + const { form: updatedForm } = this.state; + updatedForm[targetName].value = val; + + this.setState({ form: updatedForm }); + } + + async onSubmit () { + const { api, organization } = this.props; + const { form: { name, description, custom_virtualenv } } = this.state; + const formData = { name, description, custom_virtualenv }; + + const updatedData = {}; + Object.keys(formData) + .forEach(formId => { + updatedData[formId] = formData[formId].value; + }); + + try { + await api.updateOrganizationDetails(organization.id, updatedData); + await this.postInstanceGroups(); + } catch (err) { + this.setState({ error: err }); + } finally { + this.onSuccess(); + } + } + + onCancel () { + const { organization: { id }, history } = this.props; + history.push(`/organizations/${id}`); + } + + onSuccess () { + const { organization: { id }, history } = this.props; + history.push(`/organizations/${id}`); + } + + async getInstanceGroups (params) { + const { api } = this.props; + const data = await api.getInstanceGroups(params); + return data; + } + + async getRelatedInstanceGroups () { + const { + api, + organization: { id } + } = this.props; + const { data } = await api.getOrganizationInstanceGroups(id); + const { results } = data; + return results; + } + + checkValidity = (value, validation) => { + let isValid = true; + if (validation.required) { + isValid = value.trim() !== '' && isValid; + } + return isValid; + } + + async postInstanceGroups () { + const { api, organization } = this.props; + const { form: { instanceGroups } } = this.state; + const url = organization.related.instance_groups; + + const initialInstanceGroups = instanceGroups.initialValue.map(ig => ig.id); + const updatedInstanceGroups = instanceGroups.value.map(ig => ig.id); + + const groupsToAssociate = [...updatedInstanceGroups] + .filter(x => !initialInstanceGroups.includes(x)); + const groupsToDisassociate = [...initialInstanceGroups] + .filter(x => !updatedInstanceGroups.includes(x)); + + try { + await Promise.all(groupsToAssociate.map(async id => { + await api.associateInstanceGroup(url, id); + })); + await Promise.all(groupsToDisassociate.map(async id => { + await api.disassociateInstanceGroup(url, id); + })); + } catch (err) { + this.setState({ error: err }); + } + } + + render () { + const { + form: { + name, + description, + instanceGroups, + custom_virtualenv + }, + formIsValid, + error + } = this.state; + + const instanceGroupsLookupColumns = [ + { name: i18nMark('Name'), key: 'name', isSortable: true }, + { name: i18nMark('Modified'), key: 'modified', isSortable: false, isNumeric: true }, + { name: i18nMark('Created'), key: 'created', isSortable: false, isNumeric: true } + ]; + + return ( + +
+ + {({ i18n }) => ( + + + + + + + + + { instanceGroups.value + && ( + + ) + } + + + {({ custom_virtualenvs }) => ( + custom_virtualenvs && custom_virtualenvs.length > 1 && ( + + + + ) + )} + + + )} + + + { error ?
error
: '' } + +
+ ); + } +} + +OrganizationEdit.contextTypes = { + custom_virtualenvs: PropTypes.arrayOf(PropTypes.string) +}; + +export default withRouter(OrganizationEdit);