diff --git a/awx/main/conf.py b/awx/main/conf.py
index dbeaec9040ef..5cfd2977f77c 100644
--- a/awx/main/conf.py
+++ b/awx/main/conf.py
@@ -186,7 +186,7 @@
default=None,
queryset=ExecutionEnvironment.objects.all(),
label=_('Global default execution environment'),
- help_text=_('.'),
+ help_text=_('The Execution Environment to be used when one has not been configured for a job template.'),
category=_('System'),
category_slug='system',
)
diff --git a/awx/ui_next/src/components/Lookup/ExecutionEnvironmentLookup.jsx b/awx/ui_next/src/components/Lookup/ExecutionEnvironmentLookup.jsx
index 4647d5809e25..b3134cb5279f 100644
--- a/awx/ui_next/src/components/Lookup/ExecutionEnvironmentLookup.jsx
+++ b/awx/ui_next/src/components/Lookup/ExecutionEnvironmentLookup.jsx
@@ -25,6 +25,7 @@ function ExecutionEnvironmentLookup({
globallyAvailable,
i18n,
isDefaultEnvironment,
+ isGlobalDefaultEnvironment,
isDisabled,
onBlur,
onChange,
@@ -154,17 +155,26 @@ function ExecutionEnvironmentLookup({
>
);
+ const renderLabel = (
+ globalDefaultEnvironment,
+ defaultExecutionEnvironment
+ ) => {
+ if (globalDefaultEnvironment) {
+ return i18n._(t`Global Default Execution Environment`);
+ }
+ if (defaultExecutionEnvironment) {
+ return i18n._(t`Default Execution Environment`);
+ }
+ return i18n._(t`Execution Environment`);
+ };
+
return (
}
>
- {isDisabled ? (
+ {tooltip ? (
{renderLookup()}
) : (
renderLookup()
@@ -180,6 +190,7 @@ ExecutionEnvironmentLookup.propTypes = {
popoverContent: string,
onChange: func.isRequired,
isDefaultEnvironment: bool,
+ isGlobalDefaultEnvironment: bool,
projectId: oneOfType([number, string]),
organizationId: oneOfType([number, string]),
};
@@ -187,6 +198,7 @@ ExecutionEnvironmentLookup.propTypes = {
ExecutionEnvironmentLookup.defaultProps = {
popoverContent: '',
isDefaultEnvironment: false,
+ isGlobalDefaultEnvironment: false,
value: null,
projectId: null,
organizationId: null,
diff --git a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx
index 02f37b2d966d..54eac90e9fe1 100644
--- a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx
@@ -9,7 +9,7 @@ import ContentError from '../../../../components/ContentError';
import ContentLoading from '../../../../components/ContentLoading';
import { DetailList } from '../../../../components/DetailList';
import RoutedTabs from '../../../../components/RoutedTabs';
-import { SettingsAPI } from '../../../../api';
+import { SettingsAPI, ExecutionEnvironmentsAPI } from '../../../../api';
import useRequest from '../../../../util/useRequest';
import { useConfig } from '../../../../contexts/Config';
import { useSettings } from '../../../../contexts/Settings';
@@ -23,7 +23,15 @@ function MiscSystemDetail({ i18n }) {
const { isLoading, error, request, result: system } = useRequest(
useCallback(async () => {
const { data } = await SettingsAPI.readCategory('all');
-
+ let DEFAULT_EXECUTION_ENVIRONMENT = '';
+ if (data.DEFAULT_EXECUTION_ENVIRONMENT) {
+ const {
+ data: { name },
+ } = await ExecutionEnvironmentsAPI.readDetail(
+ data.DEFAULT_EXECUTION_ENVIRONMENT
+ );
+ DEFAULT_EXECUTION_ENVIRONMENT = name;
+ }
const {
OAUTH2_PROVIDER: {
ACCESS_TOKEN_EXPIRE_SECONDS,
@@ -49,19 +57,17 @@ function MiscSystemDetail({ i18n }) {
'SESSION_COOKIE_AGE',
'TOWER_URL_BASE'
);
-
const systemData = {
...pluckedSystemData,
ACCESS_TOKEN_EXPIRE_SECONDS,
REFRESH_TOKEN_EXPIRE_SECONDS,
AUTHORIZATION_CODE_EXPIRE_SECONDS,
+ DEFAULT_EXECUTION_ENVIRONMENT,
};
-
const {
OAUTH2_PROVIDER: OAUTH2_PROVIDER_OPTIONS,
...options
} = allOptions;
-
const systemOptions = {
...options,
ACCESS_TOKEN_EXPIRE_SECONDS: {
@@ -80,7 +86,6 @@ function MiscSystemDetail({ i18n }) {
label: i18n._(t`Authorization Code Expiration`),
},
};
-
const mergedData = {};
Object.keys(systemData).forEach(key => {
mergedData[key] = systemOptions[key];
diff --git a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.test.jsx b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.test.jsx
index aa8b2e334d20..6fbebb6ab8dc 100644
--- a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.test.jsx
@@ -5,7 +5,7 @@ import {
waitForElement,
} from '../../../../../testUtils/enzymeHelpers';
import { SettingsProvider } from '../../../../contexts/Settings';
-import { SettingsAPI } from '../../../../api';
+import { SettingsAPI, ExecutionEnvironmentsAPI } from '../../../../api';
import {
assertDetail,
assertVariableDetail,
@@ -14,13 +14,14 @@ import mockAllOptions from '../../shared/data.allSettingOptions.json';
import MiscSystemDetail from './MiscSystemDetail';
jest.mock('../../../../api/models/Settings');
+jest.mock('../../../../api/models/ExecutionEnvironments');
+
SettingsAPI.readCategory.mockResolvedValue({
data: {
ALLOW_OAUTH2_FOR_EXTERNAL_USERS: false,
AUTH_BASIC_ENABLED: true,
AUTOMATION_ANALYTICS_GATHER_INTERVAL: 14400,
AUTOMATION_ANALYTICS_URL: 'https://example.com',
- CUSTOM_VENV_PATHS: [],
INSIGHTS_TRACKING_STATE: false,
LOGIN_REDIRECT_OVERRIDE: 'https://redirect.com',
MANAGE_ORGANIZATION_AUTH: true,
@@ -36,6 +37,16 @@ SettingsAPI.readCategory.mockResolvedValue({
SESSIONS_PER_USER: -1,
SESSION_COOKIE_AGE: 30000000000,
TOWER_URL_BASE: 'https://towerhost',
+ DEFAULT_EXECUTION_ENVIRONMENT: 1,
+ },
+});
+
+ExecutionEnvironmentsAPI.readDetail.mockResolvedValue({
+ data: {
+ id: 1,
+ name: 'Foo',
+ image: 'quay.io/ansible/awx-ee',
+ pull: 'missing',
},
});
@@ -110,6 +121,33 @@ describe('', () => {
assertDetail(wrapper, 'Red Hat customer username', 'mock name');
assertDetail(wrapper, 'Refresh Token Expiration', '3 seconds');
assertVariableDetail(wrapper, 'Remote Host Headers', '[]');
+ assertDetail(wrapper, 'Global default execution environment', 'Foo');
+ });
+
+ test('should render execution environment as not configured', async () => {
+ ExecutionEnvironmentsAPI.readDetail.mockResolvedValue({
+ data: {},
+ });
+ let newWrapper;
+ await act(async () => {
+ newWrapper = mountWithContexts(
+
+
+
+ );
+ });
+ await waitForElement(newWrapper, 'ContentLoading', el => el.length === 0);
+
+ assertDetail(
+ newWrapper,
+ 'Global default execution environment',
+ 'Not configured'
+ );
});
test('should hide edit button from non-superusers', async () => {
diff --git a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemEdit/MiscSystemEdit.jsx b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemEdit/MiscSystemEdit.jsx
index bb19b52f215c..5411326eb0e7 100644
--- a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemEdit/MiscSystemEdit.jsx
+++ b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemEdit/MiscSystemEdit.jsx
@@ -9,6 +9,7 @@ import ContentError from '../../../../components/ContentError';
import ContentLoading from '../../../../components/ContentLoading';
import { FormSubmitError } from '../../../../components/FormField';
import { FormColumnLayout } from '../../../../components/FormLayout';
+import { ExecutionEnvironmentLookup } from '../../../../components/Lookup';
import { useSettings } from '../../../../contexts/Settings';
import {
BooleanField,
@@ -20,7 +21,7 @@ import {
} from '../../shared';
import useModal from '../../../../util/useModal';
import useRequest from '../../../../util/useRequest';
-import { SettingsAPI } from '../../../../api';
+import { SettingsAPI, ExecutionEnvironmentsAPI } from '../../../../api';
import { pluck, formatJson } from '../../shared/settingUtils';
function MiscSystemEdit({ i18n }) {
@@ -44,7 +45,6 @@ function MiscSystemEdit({ i18n }) {
'AUTH_BASIC_ENABLED',
'AUTOMATION_ANALYTICS_GATHER_INTERVAL',
'AUTOMATION_ANALYTICS_URL',
- 'CUSTOM_VENV_PATHS',
'INSIGHTS_TRACKING_STATE',
'LOGIN_REDIRECT_OVERRIDE',
'MANAGE_ORGANIZATION_AUTH',
@@ -55,7 +55,8 @@ function MiscSystemEdit({ i18n }) {
'REMOTE_HOST_HEADERS',
'SESSIONS_PER_USER',
'SESSION_COOKIE_AGE',
- 'TOWER_URL_BASE'
+ 'TOWER_URL_BASE',
+ 'DEFAULT_EXECUTION_ENVIRONMENT'
);
const systemData = {
@@ -128,6 +129,7 @@ function MiscSystemEdit({ i18n }) {
AUTHORIZATION_CODE_EXPIRE_SECONDS,
...formData
} = form;
+
await submitForm({
...formData,
REMOTE_HOST_HEADERS: formatJson(formData.REMOTE_HOST_HEADERS),
@@ -136,6 +138,8 @@ function MiscSystemEdit({ i18n }) {
REFRESH_TOKEN_EXPIRE_SECONDS,
AUTHORIZATION_CODE_EXPIRE_SECONDS,
},
+ DEFAULT_EXECUTION_ENVIRONMENT:
+ formData.DEFAULT_EXECUTION_ENVIRONMENT?.id || null,
});
};
@@ -178,16 +182,73 @@ function MiscSystemEdit({ i18n }) {
return acc;
}, {});
+ const executionEnvironmentId =
+ system?.DEFAULT_EXECUTION_ENVIRONMENT?.value || null;
+
+ const {
+ isLoading: isLoadingExecutionEnvironment,
+ error: errorExecutionEnvironment,
+ request: fetchExecutionEnvironment,
+ result: executionEnvironment,
+ } = useRequest(
+ useCallback(async () => {
+ if (!executionEnvironmentId) {
+ return '';
+ }
+ const { data } = await ExecutionEnvironmentsAPI.readDetail(
+ executionEnvironmentId
+ );
+ return data;
+ }, [executionEnvironmentId])
+ );
+
+ useEffect(() => {
+ fetchExecutionEnvironment();
+ }, [fetchExecutionEnvironment]);
+
return (
- {isLoading && }
- {!isLoading && error && }
- {!isLoading && system && (
-
+ {(isLoading || isLoadingExecutionEnvironment) && }
+ {!(isLoading || isLoadingExecutionEnvironment) && error && (
+
+ )}
+ {!(isLoading || isLoadingExecutionEnvironment) && system && (
+
{formik => {
return (