diff --git a/__mocks__/axios.js b/__mocks__/axios.js
index 23f96b475f..aad497303f 100644
--- a/__mocks__/axios.js
+++ b/__mocks__/axios.js
@@ -1,5 +1,13 @@
-const axios = require('axios');
+import * as endpoints from '../src/endpoints';
+const axios = require('axios');
+const mockAPIConfigData = {
+ data: {
+ custom_virtualenvs: ['foo', 'bar'],
+ ansible_version: "2.7.2",
+ version: "2.1.1-40-g2758a3848"
+ }
+};
jest.genMockFromModule('axios');
axios.create = jest.fn(() => axios);
@@ -9,7 +17,16 @@ axios.create.mockReturnValue({
get: axios.get,
post: axios.post
});
-axios.get.mockResolvedValue('get results');
+axios.get.mockImplementation((endpoint) => {
+ if (endpoint === endpoints.API_CONFIG) {
+ return new Promise((resolve, reject) => {
+ resolve(mockAPIConfigData);
+ });
+ }
+ else {
+ return 'get results';
+ }
+});
axios.post.mockResolvedValue('post results');
axios.customClearMocks = () => {
diff --git a/__tests__/components/AnsibleSelect.test.jsx b/__tests__/components/AnsibleSelect.test.jsx
index 47a068ef4f..d2eacf2129 100644
--- a/__tests__/components/AnsibleSelect.test.jsx
+++ b/__tests__/components/AnsibleSelect.test.jsx
@@ -2,16 +2,29 @@ import React from 'react';
import { mount } from 'enzyme';
import AnsibleSelect from '../../src/components/AnsibleSelect';
-const mockData = ['foo', 'bar'];
+const label = "test select"
+const mockData = ["/venv/baz/", "/venv/ansible/"];
describe('', () => {
- test('initially renders succesfully', async() => {
- const wrapper = mount( {}} />);
- wrapper.setState({ isHidden: false });
+ test('initially renders succesfully', async () => {
+ mount(
+ { }}
+ labelName={label}
+ data={mockData}
+ />
+ );
});
test('calls "onSelectChange" on dropdown select change', () => {
const spy = jest.spyOn(AnsibleSelect.prototype, 'onSelectChange');
- const wrapper = mount( {}} />);
- wrapper.setState({ isHidden: false });
+ const wrapper = mount(
+ { }}
+ labelName={label}
+ data={mockData}
+ />
+ );
expect(spy).not.toHaveBeenCalled();
wrapper.find('select').simulate('change');
expect(spy).toHaveBeenCalled();
diff --git a/__tests__/pages/Organizations/views/Organization.add.test.jsx b/__tests__/pages/Organizations/views/Organization.add.test.jsx
index 8c25eb1eef..30990942a4 100644
--- a/__tests__/pages/Organizations/views/Organization.add.test.jsx
+++ b/__tests__/pages/Organizations/views/Organization.add.test.jsx
@@ -1,8 +1,29 @@
import React from 'react';
import { mount } from 'enzyme';
-import OrganizationAdd from '../../../../src/pages/Organizations/views/Organization.add';
import { MemoryRouter } from 'react-router-dom';
+let OrganizationAdd;
+const getAppWithConfigContext = (context = {
+ custom_virtualenvs: ['foo', 'bar']
+}) => {
+
+ // Mock the ConfigContext module being used in our OrganizationAdd component
+ jest.doMock('../../../../src/context', () => {
+ return {
+ ConfigContext: {
+ Consumer: (props) => props.children(context)
+ }
+ }
+ });
+
+ // Return the updated OrganizationAdd module with mocked context
+ return require('../../../../src/pages/Organizations/views/Organization.add').default;
+};
+
+beforeEach(() => {
+ OrganizationAdd = getAppWithConfigContext();
+})
+
describe('', () => {
test('initially renders succesfully', () => {
mount(
diff --git a/package.json b/package.json
index 833f11652c..c2d0e85ac0 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,7 @@
"@patternfly/react-styles": "^2.3.0",
"@patternfly/react-tokens": "^1.9.0",
"axios": "^0.18.0",
+ "prop-types": "^15.6.2",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-router-dom": "^4.3.1"
diff --git a/src/App.jsx b/src/App.jsx
index 3b03de3382..7e65262444 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,6 +1,11 @@
import React, { Fragment } from 'react';
+<<<<<<< HEAD
import { I18nProvider, I18n } from '@lingui/react';
import { t } from '@lingui/macro';
+=======
+import { ConfigContext } from './context';
+
+>>>>>>> Implement React Context API
import {
Redirect,
Switch,
@@ -22,7 +27,7 @@ import {
import { global_breakpoint_md as breakpointMd } from '@patternfly/react-tokens';
import api from './api';
-import { API_LOGOUT } from './endpoints';
+import { API_LOGOUT, API_CONFIG } from './endpoints';
import HelpDropdown from './components/HelpDropdown';
import LogoutButton from './components/LogoutButton';
@@ -68,24 +73,39 @@ const languageWithoutRegionCode = language.toLowerCase().split(/[_-]+/)[0];
class App extends React.Component {
- constructor (props) {
+ constructor(props) {
super(props);
const isNavOpen = typeof window !== 'undefined' && window.innerWidth >= parseInt(breakpointMd.value, 10);
this.state = {
- isNavOpen
+ isNavOpen,
};
}
+ getSessionObject(key) {
+ return JSON.parse(sessionStorage.getItem(key) || '{}');
+ }
+
onNavToggle = () => {
this.setState(({ isNavOpen }) => ({ isNavOpen: !isNavOpen }));
};
onDevLogout = async () => {
await api.get(API_LOGOUT);
+ this.setState({ activeGroup: 'views_group', activeItem: 'views_group_dashboard' });
+ if (sessionStorage.config) {
+ sessionStorage.clear();
+ }
}
- render () {
+ async componentDidMount() {
+ // Grab our config data from the API and store in sessionStorage
+ if (!sessionStorage.config) {
+ const { data } = await api.get(API_CONFIG);
+ sessionStorage.setItem('config', JSON.stringify(data));
+ }
+ }
+ render() {
const { isNavOpen } = this.state;
const { logo, loginInfo, history } = this.props;
@@ -119,17 +139,12 @@ class App extends React.Component {
}}
/>
- api.isAuthenticated()}
- redirectPath="/"
- path="/login"
- component={() => }
- />
+ api.isAuthenticated()} redirectPath="/" path="/login" component={() => } />
}
+ logo={}
toolbar={PageToolbar}
showNavToggle
onNavToggle={this.onNavToggle}
@@ -139,66 +154,133 @@ class App extends React.Component {
- {({ i18n }) => (
-
- )}
-
+
)}
/>
)}
@@ -214,7 +296,9 @@ class App extends React.Component {
!api.isAuthenticated()} redirectPath="/login" path="/projects" component={Projects} />
!api.isAuthenticated()} redirectPath="/login" path="/inventories" component={Inventories} />
!api.isAuthenticated()} redirectPath="/login" path="/inventory_scripts" component={InventoryScripts} />
- !api.isAuthenticated()} redirectPath="/login" path="/organizations" component={Organizations} />
+
+ !api.isAuthenticated()} redirectPath="/login" path="/organizations" component={Organizations} />
+
!api.isAuthenticated()} redirectPath="/login" path="/users" component={Users} />
!api.isAuthenticated()} redirectPath="/login" path="/teams" component={Teams} />
!api.isAuthenticated()} redirectPath="/login" path="/credential_types" component={CredentialTypes} />
diff --git a/src/components/AnsibleSelect/AnsibleSelect.jsx b/src/components/AnsibleSelect/AnsibleSelect.jsx
index d411c1d17a..001e83853b 100644
--- a/src/components/AnsibleSelect/AnsibleSelect.jsx
+++ b/src/components/AnsibleSelect/AnsibleSelect.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+
import {
FormGroup,
Select,
@@ -16,19 +17,19 @@ class AnsibleSelect extends React.Component {
}
render() {
- const { hidden } = this.props;
- if (hidden) {
- return null;
- } else {
+ if (this.props.data.length > 1) {
return (
- );
+ )
+ }
+ else {
+ return null;
}
}
}
diff --git a/src/context.jsx b/src/context.jsx
new file mode 100644
index 0000000000..446f82bd63
--- /dev/null
+++ b/src/context.jsx
@@ -0,0 +1,3 @@
+import React from "react";
+
+export const ConfigContext = React.createContext({});
diff --git a/src/pages/Organizations/views/Organization.add.jsx b/src/pages/Organizations/views/Organization.add.jsx
index 023817fe1d..75e2147a0c 100644
--- a/src/pages/Organizations/views/Organization.add.jsx
+++ b/src/pages/Organizations/views/Organization.add.jsx
@@ -1,4 +1,5 @@
import React, { Fragment } from 'react';
+import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { Trans } from '@lingui/macro';
import {
@@ -17,7 +18,8 @@ import {
CardBody,
} from '@patternfly/react-core';
-import { API_ORGANIZATIONS, API_CONFIG } from '../../../endpoints';
+import { ConfigContext } from '../../../context';
+import { API_ORGANIZATIONS } from '../../../endpoints';
import api from '../../../api';
import AnsibleSelect from '../../../components/AnsibleSelect'
const { light } = PageSectionVariants;
@@ -38,8 +40,6 @@ class OrganizationAdd extends React.Component {
description: '',
instanceGroups: '',
custom_virtualenv: '',
- custom_virtualenvs: [],
- hideAnsibleSelect: true,
error:'',
};
@@ -69,22 +69,10 @@ class OrganizationAdd extends React.Component {
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 (
@@ -128,13 +116,16 @@ class OrganizationAdd extends React.Component {
onChange={this.handleChange}
/>
-
+
+ {({ custom_virtualenvs }) =>
+
+ }
+
@@ -155,4 +146,8 @@ class OrganizationAdd extends React.Component {
}
}
+OrganizationAdd.contextTypes = {
+ custom_virtualenvs: PropTypes.array,
+};
+
export default withRouter(OrganizationAdd);