Skip to content

Commit

Permalink
Merge pull request ansible#5491 from marshmalien/inv-host-add
Browse files Browse the repository at this point in the history
Add Inventory Host Add form 

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
  • Loading branch information
softwarefactory-project-zuul[bot] authored Dec 16, 2019
2 parents 00b7d65 + 5d35506 commit c5b4681
Show file tree
Hide file tree
Showing 13 changed files with 349 additions and 150 deletions.
4 changes: 4 additions & 0 deletions awx/ui_next/src/api/models/Inventories.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ class Inventories extends InstanceGroupsMixin(Base) {
});
}

createHost(id, data) {
return this.http.post(`${this.baseUrl}${id}/hosts/`, data);
}

readHosts(id, params) {
return this.http.get(`${this.baseUrl}${id}/hosts/`, { params });
}
Expand Down
20 changes: 2 additions & 18 deletions awx/ui_next/src/screens/Host/HostAdd/HostAdd.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
import React from 'react';
import { withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
Card,
CardHeader,
CardBody,
Tooltip,
} from '@patternfly/react-core';

import { PageSection, Card, CardBody } from '@patternfly/react-core';
import { HostsAPI } from '@api';
import { Config } from '@contexts/Config';
import CardCloseButton from '@components/CardCloseButton';

import HostForm from '../shared/HostForm';
import HostForm from '../shared';

class HostAdd extends React.Component {
constructor(props) {
Expand All @@ -41,16 +31,10 @@ class HostAdd extends React.Component {

render() {
const { error } = this.state;
const { i18n } = this.props;

return (
<PageSection>
<Card>
<CardHeader className="at-u-textRight">
<Tooltip content={i18n._(t`Close`)} position="top">
<CardCloseButton onClick={this.handleCancel} />
</Tooltip>
</CardHeader>
<CardBody>
<Config>
{({ me }) => (
Expand Down
12 changes: 0 additions & 12 deletions awx/ui_next/src/screens/Host/HostAdd/HostAdd.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,6 @@ describe('<HostAdd />', () => {
expect(history.location.pathname).toEqual('/hosts');
});

test('should navigate to hosts list when close (x) is clicked', async () => {
const history = createMemoryHistory({});
let wrapper;
await act(async () => {
wrapper = mountWithContexts(<HostAdd />, {
context: { router: { history } },
});
});
wrapper.find('button[aria-label="Close"]').invoke('onClick')();
expect(history.location.pathname).toEqual('/hosts');
});

test('successful form submission should trigger redirect', async () => {
const history = createMemoryHistory({});
const hostData = {
Expand Down
2 changes: 1 addition & 1 deletion awx/ui_next/src/screens/Host/HostEdit/HostEdit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CardBody } from '@patternfly/react-core';
import { HostsAPI } from '@api';
import { Config } from '@contexts/Config';

import HostForm from '../shared/HostForm';
import HostForm from '../shared';

class HostEdit extends Component {
constructor(props) {
Expand Down
186 changes: 76 additions & 110 deletions awx/ui_next/src/screens/Host/shared/HostForm.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import { func, shape } from 'prop-types';

import { withRouter } from 'react-router-dom';
import { Formik, Field } from 'formik';
Expand All @@ -15,120 +15,86 @@ import { VariablesField } from '@components/CodeMirrorInput';
import { required } from '@util/validators';
import { InventoryLookup } from '@components/Lookup';

class HostForm extends Component {
constructor(props) {
super(props);
function HostForm({ handleSubmit, handleCancel, host, i18n }) {
const [inventory, setInventory] = useState(
host ? host.summary_fields.inventory : ''
);

this.handleSubmit = this.handleSubmit.bind(this);

this.state = {
formIsValid: true,
inventory: props.host.summary_fields.inventory,
};
}

handleSubmit(values) {
const { handleSubmit } = this.props;

handleSubmit(values);
}

render() {
const { host, handleCancel, i18n } = this.props;
const { formIsValid, inventory, error } = this.state;

const initialValues = !host.id
? {
name: host.name,
description: host.description,
inventory: host.inventory || '',
variables: host.variables,
}
: {
name: host.name,
description: host.description,
variables: host.variables,
};

return (
<Formik
initialValues={initialValues}
onSubmit={this.handleSubmit}
render={formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormRow>
<FormField
id="host-name"
name="name"
type="text"
label={i18n._(t`Name`)}
validate={required(null, i18n)}
isRequired
/>
<FormField
id="host-description"
name="description"
type="text"
label={i18n._(t`Description`)}
/>
{!host.id && (
<Field
name="inventory"
validate={required(
i18n._(t`Select a value for this field`),
i18n
)}
render={({ form }) => (
<InventoryLookup
value={inventory}
onBlur={() => form.setFieldTouched('inventory')}
tooltip={i18n._(
t`Select the inventory that this host will belong to.`
)}
isValid={
!form.touched.inventory || !form.errors.inventory
}
helperTextInvalid={form.errors.inventory}
onChange={value => {
form.setFieldValue('inventory', value.id);
this.setState({ inventory: value });
}}
required
touched={form.touched.inventory}
error={form.errors.inventory}
/>
)}
/>
)}
</FormRow>
<FormRow>
<VariablesField
id="host-variables"
name="variables"
label={i18n._(t`Variables`)}
return (
<Formik
initialValues={{
name: host.name,
description: host.description,
inventory: host.inventory || '',
variables: host.variables,
}}
onSubmit={handleSubmit}
render={formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormRow>
<FormField
id="host-name"
name="name"
type="text"
label={i18n._(t`Name`)}
validate={required(null, i18n)}
isRequired
/>
<FormField
id="host-description"
name="description"
type="text"
label={i18n._(t`Description`)}
/>
{!host.id && (
<Field
name="inventory"
validate={required(
i18n._(t`Select a value for this field`),
i18n
)}
render={({ form }) => (
<InventoryLookup
value={inventory}
onBlur={() => form.setFieldTouched('inventory')}
tooltip={i18n._(
t`Select the inventory that this host will belong to.`
)}
isValid={!form.touched.inventory || !form.errors.inventory}
helperTextInvalid={form.errors.inventory}
onChange={value => {
form.setFieldValue('inventory', value.id);
setInventory(value);
}}
required
touched={form.touched.inventory}
error={form.errors.inventory}
/>
)}
/>
</FormRow>
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
submitDisabled={!formIsValid}
)}
</FormRow>
<FormRow>
<VariablesField
id="host-variables"
name="variables"
label={i18n._(t`Variables`)}
/>
{error ? <div>error</div> : null}
</Form>
)}
/>
);
}
</FormRow>
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</Form>
)}
/>
);
}

FormField.propTypes = {
label: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
};

HostForm.propTypes = {
host: PropTypes.shape(),
handleSubmit: PropTypes.func.isRequired,
handleCancel: PropTypes.func.isRequired,
handleSubmit: func.isRequired,
handleCancel: func.isRequired,
host: shape({}),
};

HostForm.defaultProps = {
Expand Down
6 changes: 1 addition & 5 deletions awx/ui_next/src/screens/Host/shared/HostForm.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,7 @@ describe('<HostForm />', () => {
expect(handleSubmit).not.toHaveBeenCalled();
wrapper.find('button[aria-label="Save"]').simulate('click');
await sleep(1);
expect(handleSubmit).toHaveBeenCalledWith({
name: 'Foo',
description: 'Bar',
variables: '---',
});
expect(handleSubmit).toHaveBeenCalled();
});

test('calls "handleCancel" when Cancel button is clicked', () => {
Expand Down
1 change: 1 addition & 0 deletions awx/ui_next/src/screens/Host/shared/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './HostForm';
Original file line number Diff line number Diff line change
@@ -1,8 +1,36 @@
import React from 'react';
import React, { useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import { CardBody } from '@patternfly/react-core';
import InventoryHostForm from '../shared/InventoryHostForm';
import { InventoriesAPI } from '@api';

function InventoryHostAdd() {
return <CardBody>Coming soon :)</CardBody>;
const [formError, setFormError] = useState(null);
const history = useHistory();
const { id } = useParams();

const handleSubmit = async values => {
try {
const { data: response } = await InventoriesAPI.createHost(id, values);
history.push(`/inventories/inventory/${id}/hosts/${response.id}/details`);
} catch (error) {
setFormError(error);
}
};

const handleCancel = () => {
history.push(`/inventories/inventory/${id}/hosts`);
};

return (
<CardBody>
<InventoryHostForm
handleSubmit={handleSubmit}
handleCancel={handleCancel}
/>
{formError ? <div className="formSubmitError">error</div> : ''}
</CardBody>
);
}

export default InventoryHostAdd;
Loading

0 comments on commit c5b4681

Please sign in to comment.