diff --git a/__tests__/components/AnsibleSelect.test.jsx b/__tests__/components/AnsibleSelect.test.jsx
new file mode 100644
index 0000000000..47a068ef4f
--- /dev/null
+++ b/__tests__/components/AnsibleSelect.test.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import { mount } from 'enzyme';
+import AnsibleSelect from '../../src/components/AnsibleSelect';
+
+const mockData = ['foo', 'bar'];
+describe('', () => {
+ test('initially renders succesfully', async() => {
+ const wrapper = mount( {}} />);
+ wrapper.setState({ isHidden: false });
+ });
+ test('calls "onSelectChange" on dropdown select change', () => {
+ const spy = jest.spyOn(AnsibleSelect.prototype, 'onSelectChange');
+ const wrapper = mount( {}} />);
+ wrapper.setState({ isHidden: false });
+ expect(spy).not.toHaveBeenCalled();
+ wrapper.find('select').simulate('change');
+ expect(spy).toHaveBeenCalled();
+ });
+});
\ No newline at end of file
diff --git a/__tests__/pages/Organizations/views/Organization.add.test.jsx b/__tests__/pages/Organizations/views/Organization.add.test.jsx
index c8822cfc38..8c25eb1eef 100644
--- a/__tests__/pages/Organizations/views/Organization.add.test.jsx
+++ b/__tests__/pages/Organizations/views/Organization.add.test.jsx
@@ -1,14 +1,60 @@
import React from 'react';
import { mount } from 'enzyme';
import OrganizationAdd from '../../../../src/pages/Organizations/views/Organization.add';
+import { MemoryRouter } from 'react-router-dom';
describe('', () => {
test('initially renders succesfully', () => {
mount(
-
+
+
+
);
});
+ test('calls "handleChange" when input values change', () => {
+ const spy = jest.spyOn(OrganizationAdd.WrappedComponent.prototype, 'handleChange');
+ const wrapper = mount(
+
+
+
+ );
+ expect(spy).not.toHaveBeenCalled();
+ wrapper.find('input#add-org-form-name').simulate('change', { target: { value: 'foo' } });
+ wrapper.find('input#add-org-form-description').simulate('change', { target: { value: 'bar' } });
+ expect(spy).toHaveBeenCalledTimes(2);
+ });
+ test('calls "onSubmit" when Save button is clicked', () => {
+ const spy = jest.spyOn(OrganizationAdd.WrappedComponent.prototype, 'onSubmit');
+ const wrapper = mount(
+
+
+
+ );
+ expect(spy).not.toHaveBeenCalled();
+ wrapper.find('button.at-C-SubmitButton').prop('onClick')();
+ expect(spy).toBeCalled();
+ });
+ test('calls "onCancel" when Cancel button is clicked', () => {
+ const spy = jest.spyOn(OrganizationAdd.WrappedComponent.prototype, 'onCancel');
+ const wrapper = mount(
+
+
+
+ );
+ expect(spy).not.toHaveBeenCalled();
+ wrapper.find('button.at-C-CancelButton').prop('onClick')();
+ expect(spy).toBeCalled();
+ });
});
diff --git a/src/api.js b/src/api.js
index 0976d9f9bc..62649fa0e5 100644
--- a/src/api.js
+++ b/src/api.js
@@ -45,6 +45,8 @@ class APIClient {
}
get = (endpoint, params = {}) => this.http.get(endpoint, { params });
+
+ post = (endpoint, data) => this.http.post(endpoint, data);
}
export default new APIClient();
diff --git a/src/app.scss b/src/app.scss
index 5f79cc5505..2d3943a597 100644
--- a/src/app.scss
+++ b/src/app.scss
@@ -118,3 +118,13 @@
--pf-c-about-modal-box--MaxHeight: 40rem;
--pf-c-about-modal-box--MaxWidth: 63rem;
}
+
+
+//
+// layout styles
+//
+.at-align-right {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+}
\ No newline at end of file
diff --git a/src/components/AnsibleSelect/AnsibleSelect.jsx b/src/components/AnsibleSelect/AnsibleSelect.jsx
new file mode 100644
index 0000000000..d411c1d17a
--- /dev/null
+++ b/src/components/AnsibleSelect/AnsibleSelect.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import {
+ FormGroup,
+ Select,
+ SelectOption,
+} from '@patternfly/react-core';
+
+class AnsibleSelect extends React.Component {
+ constructor(props) {
+ super(props);
+ this.onSelectChange = this.onSelectChange.bind(this);
+ }
+
+ onSelectChange(val, _) {
+ this.props.selectChange(val);
+ }
+
+ render() {
+ const { hidden } = this.props;
+ if (hidden) {
+ return null;
+ } else {
+ return (
+
+
+
+ );
+ }
+ }
+}
+
+export default AnsibleSelect;
diff --git a/src/components/AnsibleSelect/index.js b/src/components/AnsibleSelect/index.js
new file mode 100644
index 0000000000..219abcfefd
--- /dev/null
+++ b/src/components/AnsibleSelect/index.js
@@ -0,0 +1,3 @@
+import AnsibleSelect from './AnsibleSelect';
+
+export default AnsibleSelect;
diff --git a/src/pages/Organizations/views/Organization.add.jsx b/src/pages/Organizations/views/Organization.add.jsx
index a1218d3465..023817fe1d 100644
--- a/src/pages/Organizations/views/Organization.add.jsx
+++ b/src/pages/Organizations/views/Organization.add.jsx
@@ -1,24 +1,158 @@
import React, { Fragment } from 'react';
+import { withRouter } from 'react-router-dom';
import { Trans } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
Title,
+ Form,
+ FormGroup,
+ TextInput,
+ ActionGroup,
+ Toolbar,
+ ToolbarGroup,
+ Button,
+ Gallery,
+ Card,
+ CardBody,
} from '@patternfly/react-core';
-const { light, medium } = PageSectionVariants;
+import { API_ORGANIZATIONS, API_CONFIG } from '../../../endpoints';
+import api from '../../../api';
+import AnsibleSelect from '../../../components/AnsibleSelect'
+const { light } = PageSectionVariants;
-const OrganizationView = () => (
-
-
-
- Organization Add
-
-
-
- This is the add view
-
-
-);
+class OrganizationAdd extends React.Component {
+ constructor(props) {
+ super(props);
-export default OrganizationView;
+ this.handleChange = this.handleChange.bind(this);
+ this.onSelectChange = this.onSelectChange.bind(this);
+ this.onSubmit = this.onSubmit.bind(this);
+ this.resetForm = this.resetForm.bind(this);
+ this.onCancel = this.onCancel.bind(this);
+ }
+
+ state = {
+ name: '',
+ description: '',
+ instanceGroups: '',
+ custom_virtualenv: '',
+ custom_virtualenvs: [],
+ hideAnsibleSelect: true,
+ error:'',
+ };
+
+ onSelectChange(value, _) {
+ this.setState({ custom_virtualenv: value });
+ };
+
+ resetForm() {
+ this.setState({
+ ...this.state,
+ name: '',
+ description: ''
+ })
+ }
+
+ handleChange(_, evt) {
+ this.setState({ [evt.target.name]: evt.target.value });
+ }
+
+ async onSubmit() {
+ const data = Object.assign({}, { ...this.state });
+ await api.post(API_ORGANIZATIONS, data);
+ this.resetForm();
+ }
+
+ onCancel() {
+ this.props.history.push('/organizations');
+ }
+
+ async componentDidMount() {
+ try {
+ const { data } = await api.get(API_CONFIG);
+ this.setState({ custom_virtualenvs: [...data.custom_virtualenvs] });
+ if (this.state.custom_virtualenvs.length > 1) {
+ // Show dropdown if we have more than one ansible environment
+ this.setState({ hideAnsibleSelect: !this.state.hideAnsibleSelect });
+ }
+ } catch (error) {
+ this.setState({ error })
+ }
+
+ }
+ render() {
+ const { name } = this.state;
+ const enabled = name.length > 0; // TODO: add better form validation
+ return (
+
+
+
+ Organization Add
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default withRouter(OrganizationAdd);