mirror of
https://github.com/ansible/awx.git
synced 2026-03-21 19:07:39 -02:30
refactor out OrganizationForm; share between add & edit
This commit is contained in:
182
src/pages/Organizations/components/OrganizationForm.jsx
Normal file
182
src/pages/Organizations/components/OrganizationForm.jsx
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
import { Formik, Field } from 'formik';
|
||||||
|
import { I18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormGroup,
|
||||||
|
} from '@patternfly/react-core';
|
||||||
|
|
||||||
|
import { ConfigContext } from '../../../context';
|
||||||
|
import FormField from '../../../components/FormField';
|
||||||
|
import FormActionGroup from '../../../components/FormActionGroup';
|
||||||
|
import AnsibleSelect from '../../../components/AnsibleSelect';
|
||||||
|
import InstanceGroupsLookup from './InstanceGroupsLookup';
|
||||||
|
import { required } from '../../../util/validators';
|
||||||
|
|
||||||
|
class OrganizationForm extends Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.getRelatedInstanceGroups = this.getRelatedInstanceGroups.bind(this);
|
||||||
|
this.handleInstanceGroupsChange = this.handleInstanceGroupsChange.bind(this);
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
instanceGroups: [],
|
||||||
|
formIsValid: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount () {
|
||||||
|
let instanceGroups = [];
|
||||||
|
|
||||||
|
if (!this.isEditingNewOrganization()) {
|
||||||
|
try {
|
||||||
|
instanceGroups = await this.getRelatedInstanceGroups();
|
||||||
|
} catch (err) {
|
||||||
|
this.setState({ error: err });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
instanceGroups,
|
||||||
|
initialInstanceGroups: [...instanceGroups],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRelatedInstanceGroups () {
|
||||||
|
const {
|
||||||
|
api,
|
||||||
|
organization: { id }
|
||||||
|
} = this.props;
|
||||||
|
const { data } = await api.getOrganizationInstanceGroups(id);
|
||||||
|
return data.results;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEditingNewOrganization () {
|
||||||
|
const { organization } = this.props;
|
||||||
|
return !organization.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInstanceGroupsChange (instanceGroups) {
|
||||||
|
this.setState({ instanceGroups });
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleSubmit (values) {
|
||||||
|
const { handleSubmit } = this.props;
|
||||||
|
const { instanceGroups, initialInstanceGroups } = this.state;
|
||||||
|
|
||||||
|
const initialIds = initialInstanceGroups.map(ig => ig.id);
|
||||||
|
const updatedIds = instanceGroups.map(ig => ig.id);
|
||||||
|
const groupsToAssociate = [...updatedIds]
|
||||||
|
.filter(x => !initialIds.includes(x));
|
||||||
|
const groupsToDisassociate = [...initialIds]
|
||||||
|
.filter(x => !updatedIds.includes(x));
|
||||||
|
|
||||||
|
handleSubmit(values, groupsToAssociate, groupsToDisassociate);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { api, organization, handleCancel } = this.props;
|
||||||
|
const { instanceGroups, formIsValid, error } = this.state;
|
||||||
|
const defaultVenv = '/venv/ansible/';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<I18n>
|
||||||
|
{({ i18n }) => (
|
||||||
|
<Formik
|
||||||
|
initialValues={{
|
||||||
|
name: organization.name,
|
||||||
|
description: organization.description,
|
||||||
|
custom_virtualenv: organization.custom_virtualenv || '',
|
||||||
|
}}
|
||||||
|
onSubmit={this.handleSubmit}
|
||||||
|
render={formik => (
|
||||||
|
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'grid',
|
||||||
|
gridGap: '20px',
|
||||||
|
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
id="edit-org-form-name"
|
||||||
|
name="name"
|
||||||
|
type="text"
|
||||||
|
label={i18n._(t`Name`)}
|
||||||
|
validate={required()}
|
||||||
|
isRequired
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
id="edit-org-form-description"
|
||||||
|
name="description"
|
||||||
|
type="text"
|
||||||
|
label={i18n._(t`Description`)}
|
||||||
|
/>
|
||||||
|
<ConfigContext.Consumer>
|
||||||
|
{({ custom_virtualenvs }) => (
|
||||||
|
custom_virtualenvs && custom_virtualenvs.length > 1 && (
|
||||||
|
<Field
|
||||||
|
name="custom_virtualenv"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormGroup
|
||||||
|
fieldId="edit-org-custom-virtualenv"
|
||||||
|
label={i18n._(t`Ansible Environment`)}
|
||||||
|
>
|
||||||
|
<AnsibleSelect
|
||||||
|
data={custom_virtualenvs}
|
||||||
|
defaultSelected={defaultVenv}
|
||||||
|
label={i18n._(t`Ansible Environment`)}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</ConfigContext.Consumer>
|
||||||
|
</div>
|
||||||
|
<InstanceGroupsLookup
|
||||||
|
api={api}
|
||||||
|
value={instanceGroups}
|
||||||
|
onChange={this.handleInstanceGroupsChange}
|
||||||
|
/>
|
||||||
|
<FormActionGroup
|
||||||
|
onCancel={handleCancel}
|
||||||
|
onSubmit={formik.handleSubmit}
|
||||||
|
submitDisabled={!formIsValid}
|
||||||
|
/>
|
||||||
|
{error ? <div>error</div> : null}
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</I18n>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OrganizationForm.propTypes = {
|
||||||
|
api: PropTypes.shape().isRequired,
|
||||||
|
organization: PropTypes.shape(),
|
||||||
|
handleSubmit: PropTypes.func.isRequired,
|
||||||
|
handleCancel: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
OrganizationForm.defaultProps = {
|
||||||
|
organization: {
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
custom_virtualenv: '',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
OrganizationForm.contextTypes = {
|
||||||
|
custom_virtualenvs: PropTypes.arrayOf(PropTypes.string)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withRouter(OrganizationForm);
|
||||||
@@ -1,82 +1,30 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
import { Formik, Field } from 'formik';
|
import { CardBody } from '@patternfly/react-core';
|
||||||
import { I18n, i18nMark } from '@lingui/react';
|
|
||||||
import { t } from '@lingui/macro';
|
|
||||||
import {
|
|
||||||
CardBody,
|
|
||||||
Form,
|
|
||||||
FormGroup,
|
|
||||||
} from '@patternfly/react-core';
|
|
||||||
|
|
||||||
import { ConfigContext } from '../../../../context';
|
import OrganizationForm from '../../components/OrganizationForm';
|
||||||
import FormField from '../../../../components/FormField';
|
|
||||||
import FormActionGroup from '../../../../components/FormActionGroup';
|
|
||||||
import AnsibleSelect from '../../../../components/AnsibleSelect';
|
|
||||||
import InstanceGroupsLookup from '../../components/InstanceGroupsLookup';
|
|
||||||
|
|
||||||
function required (message) {
|
|
||||||
return value => {
|
|
||||||
if (!value.trim()) {
|
|
||||||
return message || i18nMark('This field must not be blank');
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrganizationEdit extends Component {
|
class OrganizationEdit extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.getRelatedInstanceGroups = this.getRelatedInstanceGroups.bind(this);
|
// this.getRelatedInstanceGroups = this.getRelatedInstanceGroups.bind(this);
|
||||||
this.handleInstanceGroupsChange = this.handleInstanceGroupsChange.bind(this);
|
|
||||||
this.handleSubmit = this.handleSubmit.bind(this);
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
this.postInstanceGroups = this.postInstanceGroups.bind(this);
|
this.postInstanceGroups = this.postInstanceGroups.bind(this);
|
||||||
this.handleCancel = this.handleCancel.bind(this);
|
this.handleCancel = this.handleCancel.bind(this);
|
||||||
this.handleSuccess = this.handleSuccess.bind(this);
|
this.handleSuccess = this.handleSuccess.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
initialInstanceGroups: [],
|
|
||||||
instanceGroups: [],
|
|
||||||
error: '',
|
error: '',
|
||||||
formIsValid: true,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount () {
|
async handleSubmit (values, groupsToAssociate, groupsToDisassociate) {
|
||||||
let instanceGroups;
|
|
||||||
try {
|
|
||||||
instanceGroups = await this.getRelatedInstanceGroups();
|
|
||||||
} catch (err) {
|
|
||||||
this.setState({ error: err });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
instanceGroups,
|
|
||||||
initialInstanceGroups: instanceGroups,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getRelatedInstanceGroups () {
|
|
||||||
const {
|
|
||||||
api,
|
|
||||||
organization: { id }
|
|
||||||
} = this.props;
|
|
||||||
const { data } = await api.getOrganizationInstanceGroups(id);
|
|
||||||
return data.results;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleInstanceGroupsChange (instanceGroups) {
|
|
||||||
this.setState({ instanceGroups });
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleSubmit (values) {
|
|
||||||
const { api, organization } = this.props;
|
const { api, organization } = this.props;
|
||||||
const { instanceGroups } = this.state;
|
|
||||||
try {
|
try {
|
||||||
await api.updateOrganizationDetails(organization.id, values);
|
await api.updateOrganizationDetails(organization.id, values);
|
||||||
await this.postInstanceGroups(instanceGroups);
|
await this.postInstanceGroups(groupsToAssociate, groupsToDisassociate);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.setState({ error: err });
|
this.setState({ error: err });
|
||||||
} finally {
|
} finally {
|
||||||
@@ -94,19 +42,10 @@ class OrganizationEdit extends Component {
|
|||||||
history.push(`/organizations/${id}`);
|
history.push(`/organizations/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async postInstanceGroups (instanceGroups) {
|
async postInstanceGroups (groupsToAssociate, groupsToDisassociate) {
|
||||||
const { api, organization } = this.props;
|
const { api, organization } = this.props;
|
||||||
const { initialInstanceGroups } = this.state;
|
|
||||||
const url = organization.related.instance_groups;
|
const url = organization.related.instance_groups;
|
||||||
|
|
||||||
const initialIds = initialInstanceGroups.map(ig => ig.id);
|
|
||||||
const updatedIds = instanceGroups.map(ig => ig.id);
|
|
||||||
|
|
||||||
const groupsToAssociate = [...updatedIds]
|
|
||||||
.filter(x => !initialIds.includes(x));
|
|
||||||
const groupsToDisassociate = [...initialIds]
|
|
||||||
.filter(x => !updatedIds.includes(x));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Promise.all(groupsToAssociate.map(async id => {
|
await Promise.all(groupsToAssociate.map(async id => {
|
||||||
await api.associateInstanceGroup(url, id);
|
await api.associateInstanceGroup(url, id);
|
||||||
@@ -121,91 +60,27 @@ class OrganizationEdit extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { api, organization } = this.props;
|
const { api, organization } = this.props;
|
||||||
const {
|
const { error } = this.state;
|
||||||
instanceGroups,
|
|
||||||
formIsValid,
|
|
||||||
error,
|
|
||||||
} = this.state;
|
|
||||||
const defaultVenv = '/venv/ansible/';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<I18n>
|
<OrganizationForm
|
||||||
{({ i18n }) => (
|
api={api}
|
||||||
<Formik
|
organization={organization}
|
||||||
initialValues={{
|
handleSubmit={this.handleSubmit}
|
||||||
name: organization.name,
|
handleCancel={this.handleCancel}
|
||||||
description: organization.description,
|
/>
|
||||||
custom_virtualenv: organization.custom_virtualenv || '',
|
{error ? <div>error</div> : null}
|
||||||
}}
|
|
||||||
onSubmit={this.handleSubmit}
|
|
||||||
render={formik => (
|
|
||||||
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'grid',
|
|
||||||
gridGap: '20px',
|
|
||||||
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormField
|
|
||||||
id="edit-org-form-name"
|
|
||||||
name="name"
|
|
||||||
type="text"
|
|
||||||
label={i18n._(t`Name`)}
|
|
||||||
validate={required()}
|
|
||||||
isRequired
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
id="edit-org-form-description"
|
|
||||||
name="description"
|
|
||||||
type="text"
|
|
||||||
label={i18n._(t`Description`)}
|
|
||||||
/>
|
|
||||||
<ConfigContext.Consumer>
|
|
||||||
{({ custom_virtualenvs }) => (
|
|
||||||
custom_virtualenvs && custom_virtualenvs.length > 1 && (
|
|
||||||
<Field
|
|
||||||
name="custom_virtualenv"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormGroup
|
|
||||||
fieldId="edit-org-custom-virtualenv"
|
|
||||||
label={i18n._(t`Ansible Environment`)}
|
|
||||||
>
|
|
||||||
<AnsibleSelect
|
|
||||||
data={custom_virtualenvs}
|
|
||||||
defaultSelected={defaultVenv}
|
|
||||||
label={i18n._(t`Ansible Environment`)}
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</ConfigContext.Consumer>
|
|
||||||
</div>
|
|
||||||
<InstanceGroupsLookup
|
|
||||||
api={api}
|
|
||||||
value={instanceGroups}
|
|
||||||
onChange={this.handleInstanceGroupsChange}
|
|
||||||
/>
|
|
||||||
<FormActionGroup
|
|
||||||
onCancel={this.handleCancel}
|
|
||||||
onSubmit={formik.handleSubmit}
|
|
||||||
submitDisabled={!formIsValid}
|
|
||||||
/>
|
|
||||||
{ error ? <div>error</div> : '' }
|
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</I18n>
|
|
||||||
</CardBody>
|
</CardBody>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OrganizationEdit.propTypes = {
|
||||||
|
api: PropTypes.shape().isRequired,
|
||||||
|
organization: PropTypes.shape().isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
OrganizationEdit.contextTypes = {
|
OrganizationEdit.contextTypes = {
|
||||||
custom_virtualenvs: PropTypes.arrayOf(PropTypes.string)
|
custom_virtualenvs: PropTypes.arrayOf(PropTypes.string)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,26 +1,19 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
import { I18n } from '@lingui/react';
|
import { I18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import {
|
import {
|
||||||
PageSection,
|
PageSection,
|
||||||
Form,
|
|
||||||
FormGroup,
|
|
||||||
TextInput,
|
|
||||||
Gallery,
|
|
||||||
Card,
|
Card,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardBody,
|
CardBody,
|
||||||
Button,
|
Button,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@patternfly/react-core';
|
} from '@patternfly/react-core';
|
||||||
import { QuestionCircleIcon, TimesIcon } from '@patternfly/react-icons';
|
import { TimesIcon } from '@patternfly/react-icons';
|
||||||
|
|
||||||
import { ConfigContext } from '../../../context';
|
import OrganizationForm from '../components/OrganizationForm';
|
||||||
import AnsibleSelect from '../../../components/AnsibleSelect';
|
|
||||||
import FormActionGroup from '../../../components/FormActionGroup';
|
|
||||||
import InstanceGroupsLookup from '../components/InstanceGroupsLookup';
|
|
||||||
|
|
||||||
class OrganizationAdd extends React.Component {
|
class OrganizationAdd extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -33,12 +26,7 @@ class OrganizationAdd extends React.Component {
|
|||||||
this.handleSuccess = this.handleSuccess.bind(this);
|
this.handleSuccess = this.handleSuccess.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
custom_virtualenv: '',
|
|
||||||
instanceGroups: [],
|
|
||||||
error: '',
|
error: '',
|
||||||
defaultEnv: '/venv/ansible/',
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,23 +38,15 @@ class OrganizationAdd extends React.Component {
|
|||||||
this.setState({ [targetName]: val });
|
this.setState({ [targetName]: val });
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleSubmit () {
|
async handleSubmit (values, groupsToAssociate) {
|
||||||
const { api } = this.props;
|
const { api } = this.props;
|
||||||
const { name, description, custom_virtualenv, instanceGroups } = this.state;
|
|
||||||
const data = {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
custom_virtualenv
|
|
||||||
};
|
|
||||||
try {
|
try {
|
||||||
const { data: response } = await api.createOrganization(data);
|
const { data: response } = await api.createOrganization(values);
|
||||||
const instanceGroupsUrl = response.related.instance_groups;
|
const instanceGroupsUrl = response.related.instance_groups;
|
||||||
try {
|
try {
|
||||||
if (instanceGroups.length > 0) {
|
await Promise.all(groupsToAssociate.map(async id => {
|
||||||
instanceGroups.forEach(async (select) => {
|
await api.associateInstanceGroup(instanceGroupsUrl, id);
|
||||||
await api.associateInstanceGroup(instanceGroupsUrl, select.id);
|
}));
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.setState({ error: err });
|
this.setState({ error: err });
|
||||||
} finally {
|
} finally {
|
||||||
@@ -89,15 +69,7 @@ class OrganizationAdd extends React.Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { api } = this.props;
|
const { api } = this.props;
|
||||||
const {
|
const { error } = this.state;
|
||||||
name,
|
|
||||||
description,
|
|
||||||
custom_virtualenv,
|
|
||||||
defaultEnv,
|
|
||||||
instanceGroups,
|
|
||||||
error
|
|
||||||
} = this.state;
|
|
||||||
const enabled = name.length > 0; // TODO: add better form validation
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageSection>
|
<PageSection>
|
||||||
@@ -119,72 +91,12 @@ class OrganizationAdd extends React.Component {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<Form autoComplete="off">
|
<OrganizationForm
|
||||||
<Gallery gutter="md">
|
api={api}
|
||||||
<FormGroup
|
handleSubmit={this.handleSubmit}
|
||||||
label={i18n._(t`Name`)}
|
handleCancel={this.handleCancel}
|
||||||
isRequired
|
/>
|
||||||
fieldId="add-org-form-name"
|
{error ? <div>error</div> : ''}
|
||||||
>
|
|
||||||
<TextInput
|
|
||||||
isRequired
|
|
||||||
id="add-org-form-name"
|
|
||||||
name="name"
|
|
||||||
value={name}
|
|
||||||
onChange={this.handleFieldChange}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup label={i18n._(t`Description`)} fieldId="add-org-form-description">
|
|
||||||
<TextInput
|
|
||||||
id="add-org-form-description"
|
|
||||||
name="description"
|
|
||||||
value={description}
|
|
||||||
onChange={this.handleFieldChange}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<InstanceGroupsLookup
|
|
||||||
api={api}
|
|
||||||
value={instanceGroups}
|
|
||||||
onChange={this.handleInstanceGroupsChange}
|
|
||||||
/>
|
|
||||||
<ConfigContext.Consumer>
|
|
||||||
{({ custom_virtualenvs }) => (
|
|
||||||
custom_virtualenvs && custom_virtualenvs.length > 1 && (
|
|
||||||
<FormGroup
|
|
||||||
label={(
|
|
||||||
<Fragment>
|
|
||||||
{i18n._(t`Ansible Environment`)}
|
|
||||||
{' '}
|
|
||||||
<Tooltip
|
|
||||||
position="right"
|
|
||||||
content={i18n._(t`Select the custom Python virtual environment for this organization to run on.`)}
|
|
||||||
>
|
|
||||||
<QuestionCircleIcon />
|
|
||||||
</Tooltip>
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
fieldId="add-org-custom-virtualenv"
|
|
||||||
>
|
|
||||||
<AnsibleSelect
|
|
||||||
label={i18n._(t`Ansible Environment`)}
|
|
||||||
name="custom_virtualenv"
|
|
||||||
value={custom_virtualenv}
|
|
||||||
onChange={this.handleFieldChange}
|
|
||||||
data={custom_virtualenvs}
|
|
||||||
defaultSelected={defaultEnv}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</ConfigContext.Consumer>
|
|
||||||
</Gallery>
|
|
||||||
<FormActionGroup
|
|
||||||
onSubmit={this.handleSubmit}
|
|
||||||
submitDisabled={!enabled}
|
|
||||||
onCancel={this.handleCancel}
|
|
||||||
/>
|
|
||||||
{error ? <div>error</div> : ''}
|
|
||||||
</Form>
|
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
@@ -194,6 +106,10 @@ class OrganizationAdd extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OrganizationAdd.propTypes = {
|
||||||
|
api: PropTypes.shape().isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
OrganizationAdd.contextTypes = {
|
OrganizationAdd.contextTypes = {
|
||||||
custom_virtualenvs: PropTypes.arrayOf(PropTypes.string)
|
custom_virtualenvs: PropTypes.arrayOf(PropTypes.string)
|
||||||
};
|
};
|
||||||
|
|||||||
19
src/util/validators.js
Normal file
19
src/util/validators.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { i18nMark } from '@lingui/react';
|
||||||
|
|
||||||
|
export function required (message) {
|
||||||
|
return value => {
|
||||||
|
if (!value.trim()) {
|
||||||
|
return message || i18nMark('This field must not be blank');
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function maxLength (max) {
|
||||||
|
return value => {
|
||||||
|
if (value.trim() > max) {
|
||||||
|
return i18nMark(`This field must not exceed ${max} characters`);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user