diff --git a/awx/ui_next/src/components/Lookup/ExecutionEnvironmentLookup.jsx b/awx/ui_next/src/components/Lookup/ExecutionEnvironmentLookup.jsx
index ecab4f3b44fb..86f659c4309a 100644
--- a/awx/ui_next/src/components/Lookup/ExecutionEnvironmentLookup.jsx
+++ b/awx/ui_next/src/components/Lookup/ExecutionEnvironmentLookup.jsx
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect } from 'react';
import { string, func, bool } from 'prop-types';
-import { withRouter, useLocation } from 'react-router-dom';
+import { useLocation } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { FormGroup, Tooltip } from '@patternfly/react-core';
@@ -164,4 +164,4 @@ ExecutionEnvironmentLookup.defaultProps = {
value: null,
};
-export default withI18n()(withRouter(ExecutionEnvironmentLookup));
+export default withI18n()(ExecutionEnvironmentLookup);
diff --git a/awx/ui_next/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.jsx b/awx/ui_next/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.jsx
index 0db70f2dbf72..67ea90f4eacf 100644
--- a/awx/ui_next/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.jsx
+++ b/awx/ui_next/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.jsx
@@ -1,14 +1,14 @@
import React, { useCallback, useEffect } from 'react';
-import { useHistory, useParams } from 'react-router-dom';
+import { useHistory } from 'react-router-dom';
import { Card } from '@patternfly/react-core';
import { InventorySourcesAPI } from '../../../api';
import useRequest from '../../../util/useRequest';
import { CardBody } from '../../../components/Card';
import InventorySourceForm from '../shared/InventorySourceForm';
-function InventorySourceAdd() {
+function InventorySourceAdd({ inventory }) {
const history = useHistory();
- const { id } = useParams();
+ const { id, organization } = inventory;
const { error, request, result } = useRequest(
useCallback(async values => {
@@ -31,6 +31,7 @@ function InventorySourceAdd() {
source_path,
source_project,
source_script,
+ execution_environment,
...remainingForm
} = form;
@@ -46,6 +47,7 @@ function InventorySourceAdd() {
credential: credential?.id || null,
inventory: id,
source_script: source_script?.id || null,
+ execution_environment: execution_environment?.id || null,
...sourcePath,
...sourceProject,
...remainingForm,
@@ -63,6 +65,7 @@ function InventorySourceAdd() {
onCancel={handleCancel}
onSubmit={handleSubmit}
submitError={error}
+ organizationId={organization}
/>
diff --git a/awx/ui_next/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.test.jsx b/awx/ui_next/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.test.jsx
index afc4d69d0e98..ff5702193513 100644
--- a/awx/ui_next/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.test.jsx
+++ b/awx/ui_next/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.test.jsx
@@ -35,6 +35,12 @@ describe('', () => {
verbosity: 1,
};
+ const mockInventory = {
+ id: 111,
+ name: 'Foo',
+ organization: 2,
+ };
+
InventorySourcesAPI.readOptions.mockResolvedValue({
data: {
actions: {
@@ -67,14 +73,17 @@ describe('', () => {
wrapper.unmount();
});
- test('new form displays primary form fields', async () => {
+ test.only('new form displays primary form fields', async () => {
const config = {
custom_virtualenvs: ['venv/foo', 'venv/bar'],
};
await act(async () => {
- wrapper = mountWithContexts(, {
- context: { config },
- });
+ wrapper = mountWithContexts(
+ ,
+ {
+ context: { config },
+ }
+ );
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(wrapper.find('FormGroup[label="Name"]')).toHaveLength(1);
@@ -88,9 +97,12 @@ describe('', () => {
test('should navigate to inventory sources list when cancel is clicked', async () => {
const history = createMemoryHistory({});
await act(async () => {
- wrapper = mountWithContexts(, {
- context: { router: { history } },
- });
+ wrapper = mountWithContexts(
+ ,
+ {
+ context: { router: { history } },
+ }
+ );
});
await act(async () => {
wrapper.find('InventorySourceForm').invoke('onCancel')();
@@ -103,7 +115,9 @@ describe('', () => {
test('should post to the api when submit is clicked', async () => {
InventorySourcesAPI.create.mockResolvedValueOnce({ data: {} });
await act(async () => {
- wrapper = mountWithContexts();
+ wrapper = mountWithContexts(
+
+ );
});
await act(async () => {
wrapper.find('InventorySourceForm').invoke('onSubmit')(invSourceData);
@@ -114,6 +128,7 @@ describe('', () => {
credential: 222,
source_project: 999,
source_script: null,
+ execution_environment: null,
});
});
@@ -123,9 +138,12 @@ describe('', () => {
data: { id: 123, inventory: 111 },
});
await act(async () => {
- wrapper = mountWithContexts(, {
- context: { router: { history } },
- });
+ wrapper = mountWithContexts(
+ ,
+ {
+ context: { router: { history } },
+ }
+ );
});
await act(async () => {
wrapper.find('InventorySourceForm').invoke('onSubmit')(invSourceData);
@@ -143,7 +161,9 @@ describe('', () => {
};
InventorySourcesAPI.create.mockImplementation(() => Promise.reject(error));
await act(async () => {
- wrapper = mountWithContexts();
+ wrapper = mountWithContexts(
+
+ );
});
expect(wrapper.find('FormSubmitError').length).toBe(0);
await act(async () => {
diff --git a/awx/ui_next/src/screens/Inventory/InventorySourceDetail/InventorySourceDetail.jsx b/awx/ui_next/src/screens/Inventory/InventorySourceDetail/InventorySourceDetail.jsx
index f3fcdebfca5b..4383998994a2 100644
--- a/awx/ui_next/src/screens/Inventory/InventorySourceDetail/InventorySourceDetail.jsx
+++ b/awx/ui_next/src/screens/Inventory/InventorySourceDetail/InventorySourceDetail.jsx
@@ -50,6 +50,7 @@ function InventorySourceDetail({ inventorySource, i18n }) {
organization,
source_project,
user_capabilities,
+ execution_environment,
},
} = inventorySource;
const [deletionError, setDeletionError] = useState(false);
@@ -214,6 +215,18 @@ function InventorySourceDetail({ inventorySource, i18n }) {
}
/>
)}
+ {execution_environment?.name && (
+
+ {execution_environment.name}
+
+ }
+ />
+ )}
{source === 'scm' ? (
diff --git a/awx/ui_next/src/screens/Inventory/InventorySourceEdit/InventorySourceEdit.test.jsx b/awx/ui_next/src/screens/Inventory/InventorySourceEdit/InventorySourceEdit.test.jsx
index 87ec0288c183..cc8ad163b2ea 100644
--- a/awx/ui_next/src/screens/Inventory/InventorySourceEdit/InventorySourceEdit.test.jsx
+++ b/awx/ui_next/src/screens/Inventory/InventorySourceEdit/InventorySourceEdit.test.jsx
@@ -18,7 +18,7 @@ jest.mock('react-router-dom', () => ({
}),
}));
-describe('', () => {
+describe('', () => {
let wrapper;
let history;
const mockInvSrc = {
@@ -37,6 +37,11 @@ describe('', () => {
update_on_project_update: false,
verbosity: 1,
};
+ const mockInventory = {
+ id: 1,
+ name: 'Foo',
+ organization: 1,
+ };
InventorySourcesAPI.readOptions.mockResolvedValue({
data: {
actions: {
@@ -89,9 +94,12 @@ describe('', () => {
beforeAll(async () => {
history = createMemoryHistory();
await act(async () => {
- wrapper = mountWithContexts(, {
- context: { router: { history } },
- });
+ wrapper = mountWithContexts(
+ ,
+ {
+ context: { router: { history } },
+ }
+ );
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
});
@@ -133,7 +141,9 @@ describe('', () => {
};
InventorySourcesAPI.replace.mockImplementation(() => Promise.reject(error));
await act(async () => {
- wrapper = mountWithContexts();
+ wrapper = mountWithContexts(
+
+ );
});
expect(wrapper.find('FormSubmitError').length).toBe(0);
await act(async () => {
diff --git a/awx/ui_next/src/screens/Inventory/InventorySources/InventorySources.jsx b/awx/ui_next/src/screens/Inventory/InventorySources/InventorySources.jsx
index 2e8f1a378505..e55125187df3 100644
--- a/awx/ui_next/src/screens/Inventory/InventorySources/InventorySources.jsx
+++ b/awx/ui_next/src/screens/Inventory/InventorySources/InventorySources.jsx
@@ -9,7 +9,7 @@ function InventorySources({ inventory, setBreadcrumb }) {
return (
-
+
diff --git a/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.jsx b/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.jsx
index 3bc824fca826..05bbd4e370be 100644
--- a/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.jsx
+++ b/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.jsx
@@ -31,6 +31,7 @@ import {
VMwareSubForm,
VirtualizationSubForm,
} from './InventorySourceSubForms';
+import { ExecutionEnvironmentLookup } from '../../../components/Lookup';
const buildSourceChoiceOptions = options => {
const sourceChoices = options.actions.GET.source.choices.map(
@@ -39,7 +40,12 @@ const buildSourceChoiceOptions = options => {
return sourceChoices.filter(({ key }) => key !== 'file');
};
-const InventorySourceFormFields = ({ source, sourceOptions, i18n }) => {
+const InventorySourceFormFields = ({
+ source,
+ sourceOptions,
+ organizationId,
+ i18n,
+}) => {
const {
values,
initialValues,
@@ -51,6 +57,13 @@ const InventorySourceFormFields = ({ source, sourceOptions, i18n }) => {
name: 'source',
validate: required(i18n._(t`Set a value for this field`), i18n),
});
+ const [
+ executionEnvironmentField,
+ executionEnvironmentMeta,
+ executionEnvironmentHelpers,
+ ] = useField({
+ name: 'execution_environment',
+ });
const { custom_virtualenvs } = useContext(ConfigContext);
const [venvField] = useField('custom_virtualenv');
const defaultVenv = {
@@ -111,6 +124,17 @@ const InventorySourceFormFields = ({ source, sourceOptions, i18n }) => {
name="description"
type="text"
/>
+ executionEnvironmentHelpers.setTouched()}
+ value={executionEnvironmentField.value}
+ onChange={value => executionEnvironmentHelpers.setValue(value)}
+ globallyAvailable
+ organizationId={organizationId}
+ />
{
const initialValues = {
credential: source?.summary_fields?.credential || null,
@@ -264,6 +289,8 @@ const InventorySourceForm = ({
enabled_var: source?.enabled_var || '',
enabled_value: source?.enabled_value || '',
host_filter: source?.host_filter || '',
+ execution_environment:
+ source?.summary_fields?.execution_environment || null,
};
const {
@@ -306,6 +333,7 @@ const InventorySourceForm = ({
i18n={i18n}
source={source}
sourceOptions={sourceOptions}
+ organizationId={organizationId}
/>
{submitError && }
', () => {
expect(
wrapper.find('FormGroup[label="Ansible Environment"]')
).toHaveLength(1);
+ expect(wrapper.find('ExecutionEnvironmentLookup')).toHaveLength(1);
});
test('should display subform when source dropdown has a value', async () => {