diff --git a/awx/api/conf.py b/awx/api/conf.py
index 493eed6981..f7da952004 100644
--- a/awx/api/conf.py
+++ b/awx/api/conf.py
@@ -16,6 +16,7 @@ register(
help_text=_('Number of seconds that a user is inactive before they will need to login again.'),
category=_('Authentication'),
category_slug='authentication',
+ unit=_('seconds'),
)
register(
'SESSIONS_PER_USER',
@@ -49,6 +50,7 @@ register(
'in the number of seconds.'),
category=_('Authentication'),
category_slug='authentication',
+ unit=_('seconds'),
)
register(
'ALLOW_OAUTH2_FOR_EXTERNAL_USERS',
diff --git a/awx/api/metadata.py b/awx/api/metadata.py
index 847e353890..0b60f9a1ef 100644
--- a/awx/api/metadata.py
+++ b/awx/api/metadata.py
@@ -39,7 +39,7 @@ class Metadata(metadata.SimpleMetadata):
'min_length', 'max_length',
'min_value', 'max_value',
'category', 'category_slug',
- 'defined_in_file'
+ 'defined_in_file', 'unit',
]
for attr in text_attrs:
diff --git a/awx/conf/registry.py b/awx/conf/registry.py
index 63336fc55e..e8e52fe695 100644
--- a/awx/conf/registry.py
+++ b/awx/conf/registry.py
@@ -129,12 +129,14 @@ class SettingsRegistry(object):
placeholder = field_kwargs.pop('placeholder', empty)
encrypted = bool(field_kwargs.pop('encrypted', False))
defined_in_file = bool(field_kwargs.pop('defined_in_file', False))
+ unit = field_kwargs.pop('unit', None)
if getattr(field_kwargs.get('child', None), 'source', None) is not None:
field_kwargs['child'].source = None
field_instance = field_class(**field_kwargs)
field_instance.category_slug = category_slug
field_instance.category = category
field_instance.depends_on = depends_on
+ field_instance.unit = unit
if placeholder is not empty:
field_instance.placeholder = placeholder
field_instance.defined_in_file = defined_in_file
diff --git a/awx/main/conf.py b/awx/main/conf.py
index 7e6d3485fa..3b41c3a19b 100644
--- a/awx/main/conf.py
+++ b/awx/main/conf.py
@@ -148,7 +148,7 @@ register(
default='https://example.com',
schemes=('http', 'https'),
allow_plain_hostname=True, # Allow hostname only without TLD.
- label=_('Automation Analytics upload URL.'),
+ label=_('Automation Analytics upload URL'),
help_text=_('This setting is used to to configure data collection for the Automation Analytics dashboard'),
category=_('System'),
category_slug='system',
@@ -253,6 +253,7 @@ register(
help_text=_('The number of seconds to sleep between status checks for jobs running on isolated instances.'),
category=_('Jobs'),
category_slug='jobs',
+ unit=_('seconds'),
)
register(
@@ -264,6 +265,7 @@ register(
'This includes the time needed to copy source control files (playbooks) to the isolated instance.'),
category=_('Jobs'),
category_slug='jobs',
+ unit=_('seconds'),
)
register(
@@ -276,6 +278,7 @@ register(
'Value should be substantially greater than expected network latency.'),
category=_('Jobs'),
category_slug='jobs',
+ unit=_('seconds'),
)
register(
@@ -497,6 +500,7 @@ register(
'timeout should be imposed. A timeout set on an individual job template will override this.'),
category=_('Jobs'),
category_slug='jobs',
+ unit=_('seconds'),
)
register(
@@ -509,6 +513,7 @@ register(
'timeout should be imposed. A timeout set on an individual inventory source will override this.'),
category=_('Jobs'),
category_slug='jobs',
+ unit=_('seconds'),
)
register(
@@ -521,6 +526,7 @@ register(
'timeout should be imposed. A timeout set on an individual project will override this.'),
category=_('Jobs'),
category_slug='jobs',
+ unit=_('seconds'),
)
register(
@@ -535,6 +541,7 @@ register(
'Use a value of 0 to indicate that no timeout should be imposed.'),
category=_('Jobs'),
category_slug='jobs',
+ unit=_('seconds'),
)
register(
@@ -542,7 +549,7 @@ register(
field_class=fields.IntegerField,
allow_null=False,
default=200,
- label=_('Maximum number of forks per job.'),
+ label=_('Maximum number of forks per job'),
help_text=_('Saving a Job Template with more than this number of forks will result in an error. '
'When set to 0, no limit is applied.'),
category=_('Jobs'),
@@ -672,6 +679,7 @@ register(
'aggregator protocols.'),
category=_('Logging'),
category_slug='logging',
+ unit=_('seconds'),
)
register(
'LOG_AGGREGATOR_VERIFY_CERT',
@@ -752,7 +760,8 @@ register(
default=14400, # every 4 hours
min_value=1800, # every 30 minutes
category=_('System'),
- category_slug='system'
+ category_slug='system',
+ unit=_('seconds'),
)
diff --git a/awx/sso/conf.py b/awx/sso/conf.py
index 7be4f23de1..5f595517cc 100644
--- a/awx/sso/conf.py
+++ b/awx/sso/conf.py
@@ -515,6 +515,7 @@ register(
help_text=_('TACACS+ session timeout value in seconds, 0 disables timeout.'),
category=_('TACACS+'),
category_slug='tacacsplus',
+ unit=_('seconds'),
)
register(
diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx
index a39b217575..3e83ed8f5e 100644
--- a/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx
+++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx
@@ -4,6 +4,7 @@ import { node, number, oneOfType, shape, string, arrayOf } from 'prop-types';
import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core';
import { DetailName, DetailValue } from '../DetailList';
import MultiButtonToggle from '../MultiButtonToggle';
+import DetailPopover from '../DetailPopover';
import {
yamlToJson,
jsonToYaml,
@@ -27,7 +28,7 @@ function getValueAsMode(value, mode) {
return mode === YAML_MODE ? jsonToYaml(value) : yamlToJson(value);
}
-function VariablesDetail({ value, label, rows, fullHeight }) {
+function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) {
const [mode, setMode] = useState(
isJsonObject(value) || isJsonString(value) ? JSON_MODE : YAML_MODE
);
@@ -46,9 +47,14 @@ function VariablesDetail({ value, label, rows, fullHeight }) {
/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [value]);
+ const labelCy = dataCy ? `${dataCy}-label` : null;
+ const valueCy = dataCy ? `${dataCy}-value` : null;
+
return (
<>
{label}
+ {helpText && (
+
+ )}
@@ -84,6 +93,7 @@ function VariablesDetail({ value, label, rows, fullHeight }) {
(
@@ -15,7 +16,7 @@ const DetailName = styled(({ fullWidth, ...props }) => (
`;
const DetailValue = styled(
- ({ fullWidth, isEncrypted, isUnconfigured, ...props }) => (
+ ({ fullWidth, isEncrypted, isNotConfigured, ...props }) => (
)
)`
@@ -26,7 +27,7 @@ const DetailValue = styled(
grid-column: 2 / -1;
`}
${props =>
- (props.isEncrypted || props.isUnconfigured) &&
+ (props.isEncrypted || props.isNotConfigured) &&
`
color: var(--pf-global--Color--400);
`}
@@ -39,8 +40,9 @@ const Detail = ({
className,
dataCy,
alwaysVisible,
+ helpText,
isEncrypted,
- isUnconfigured,
+ isNotConfigured,
}) => {
if (!value && typeof value !== 'number' && !alwaysVisible) {
return null;
@@ -56,8 +58,12 @@ const Detail = ({
component={TextListItemVariants.dt}
fullWidth={fullWidth}
data-cy={labelCy}
+ id={dataCy}
>
{label}
+ {helpText && (
+
+ )}
{value}
@@ -77,11 +83,13 @@ Detail.propTypes = {
value: node,
fullWidth: bool,
alwaysVisible: bool,
+ helpText: string,
};
Detail.defaultProps = {
value: null,
fullWidth: false,
alwaysVisible: false,
+ helpText: null,
};
export default Detail;
diff --git a/awx/ui_next/src/components/DetailPopover/DetailPopover.jsx b/awx/ui_next/src/components/DetailPopover/DetailPopover.jsx
new file mode 100644
index 0000000000..fa4aec9ee8
--- /dev/null
+++ b/awx/ui_next/src/components/DetailPopover/DetailPopover.jsx
@@ -0,0 +1,51 @@
+import React, { useState } from 'react';
+import { node, string } from 'prop-types';
+import { Button as _Button, Popover } from '@patternfly/react-core';
+import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons';
+import styled from 'styled-components';
+
+const Button = styled(_Button)`
+ --pf-c-button--PaddingTop: 0;
+ --pf-c-button--PaddingBottom: 0;
+`;
+
+function DetailPopover({ header, content, id }) {
+ const [showPopover, setShowPopover] = useState(false);
+ if (!content) {
+ return null;
+ }
+ return (
+ setShowPopover(false)}
+ >
+
+
+ );
+}
+
+DetailPopover.propTypes = {
+ content: node,
+ header: node,
+ id: string,
+};
+DetailPopover.defaultProps = {
+ content: null,
+ header: null,
+ id: 'detail-popover',
+};
+
+export default DetailPopover;
diff --git a/awx/ui_next/src/components/DetailPopover/index.js b/awx/ui_next/src/components/DetailPopover/index.js
new file mode 100644
index 0000000000..02b42518c5
--- /dev/null
+++ b/awx/ui_next/src/components/DetailPopover/index.js
@@ -0,0 +1 @@
+export { default } from './DetailPopover';
diff --git a/awx/ui_next/src/components/ResourceAccessList/__snapshots__/ResourceAccessListItem.test.jsx.snap b/awx/ui_next/src/components/ResourceAccessList/__snapshots__/ResourceAccessListItem.test.jsx.snap
index d9bb8bed4e..818f2cf945 100644
--- a/awx/ui_next/src/components/ResourceAccessList/__snapshots__/ResourceAccessListItem.test.jsx.snap
+++ b/awx/ui_next/src/components/ResourceAccessList/__snapshots__/ResourceAccessListItem.test.jsx.snap
@@ -74,6 +74,7 @@ exports[` initially renders succesfully 1`] = `
@@ -86,6 +87,7 @@ exports[` initially renders succesfully 1`] = `
initially renders succesfully 1`] = `
@@ -150,6 +153,7 @@ exports[` initially renders succesfully 1`] = `
initially renders succesfully 1`] = `
@@ -237,6 +242,7 @@ exports[` initially renders succesfully 1`] = `
initially renders succesfully 1`] = `
@@ -463,9 +470,9 @@ exports[` initially renders succesfully 1`] = `
"$$typeof": Symbol(react.forward_ref),
"attrs": Array [],
"componentStyle": ComponentStyle {
- "componentId": "sc-htpNat",
+ "componentId": "sc-bxivhb",
"isStatic": false,
- "lastClassName": "iYJcPm",
+ "lastClassName": "gQwVdc",
"rules": Array [
"
font-weight: var(--pf-global--FontWeight--bold);
@@ -478,7 +485,7 @@ exports[` initially renders succesfully 1`] = `
"displayName": "Styled(Component)",
"foldedComponentIds": Array [],
"render": [Function],
- "styledComponentId": "sc-htpNat",
+ "styledComponentId": "sc-bxivhb",
"target": [Function],
"toString": [Function],
"warnTooManyClasses": [Function],
@@ -489,18 +496,18 @@ exports[` initially renders succesfully 1`] = `
fullWidth={false}
>
@@ -523,9 +530,9 @@ exports[` initially renders succesfully 1`] = `
"$$typeof": Symbol(react.forward_ref),
"attrs": Array [],
"componentStyle": ComponentStyle {
- "componentId": "sc-bxivhb",
+ "componentId": "sc-ifAKCX",
"isStatic": false,
- "lastClassName": "gxmPlV",
+ "lastClassName": "boHWLt",
"rules": Array [
"
word-break: break-all;
@@ -541,7 +548,7 @@ exports[` initially renders succesfully 1`] = `
"displayName": "Styled(Component)",
"foldedComponentIds": Array [],
"render": [Function],
- "styledComponentId": "sc-bxivhb",
+ "styledComponentId": "sc-ifAKCX",
"target": [Function],
"toString": [Function],
"warnTooManyClasses": [Function],
@@ -552,18 +559,18 @@ exports[` initially renders succesfully 1`] = `
fullWidth={false}
>
@@ -670,6 +677,7 @@ exports[` initially renders succesfully 1`] = `
initially renders succesfully 1`] = `
"$$typeof": Symbol(react.forward_ref),
"attrs": Array [],
"componentStyle": ComponentStyle {
- "componentId": "sc-htpNat",
+ "componentId": "sc-bxivhb",
"isStatic": false,
- "lastClassName": "iYJcPm",
+ "lastClassName": "gQwVdc",
"rules": Array [
"
font-weight: var(--pf-global--FontWeight--bold);
@@ -718,7 +726,7 @@ exports[` initially renders succesfully 1`] = `
"displayName": "Styled(Component)",
"foldedComponentIds": Array [],
"render": [Function],
- "styledComponentId": "sc-htpNat",
+ "styledComponentId": "sc-bxivhb",
"target": [Function],
"toString": [Function],
"warnTooManyClasses": [Function],
@@ -729,18 +737,18 @@ exports[` initially renders succesfully 1`] = `
fullWidth={false}
>
@@ -763,9 +771,9 @@ exports[` initially renders succesfully 1`] = `
"$$typeof": Symbol(react.forward_ref),
"attrs": Array [],
"componentStyle": ComponentStyle {
- "componentId": "sc-bxivhb",
+ "componentId": "sc-ifAKCX",
"isStatic": false,
- "lastClassName": "gxmPlV",
+ "lastClassName": "boHWLt",
"rules": Array [
"
word-break: break-all;
@@ -781,7 +789,7 @@ exports[` initially renders succesfully 1`] = `
"displayName": "Styled(Component)",
"foldedComponentIds": Array [],
"render": [Function],
- "styledComponentId": "sc-bxivhb",
+ "styledComponentId": "sc-ifAKCX",
"target": [Function],
"toString": [Function],
"warnTooManyClasses": [Function],
@@ -792,18 +800,18 @@ exports[` initially renders succesfully 1`] = `
fullWidth={false}
>
diff --git a/awx/ui_next/src/screens/Setting/ActivityStream/ActivityStreamDetail/ActivityStreamDetail.jsx b/awx/ui_next/src/screens/Setting/ActivityStream/ActivityStreamDetail/ActivityStreamDetail.jsx
index 9b51b1caa6..1412421ed5 100644
--- a/awx/ui_next/src/screens/Setting/ActivityStream/ActivityStreamDetail/ActivityStreamDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/ActivityStream/ActivityStreamDetail/ActivityStreamDetail.jsx
@@ -70,8 +70,11 @@ function ActivityStreamDetail({ i18n }) {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/AzureAD/AzureADDetail/AzureADDetail.jsx b/awx/ui_next/src/screens/Setting/AzureAD/AzureADDetail/AzureADDetail.jsx
index f73e4d6c44..cb97d182a1 100644
--- a/awx/ui_next/src/screens/Setting/AzureAD/AzureADDetail/AzureADDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/AzureAD/AzureADDetail/AzureADDetail.jsx
@@ -62,8 +62,11 @@ function AzureADDetail({ i18n }) {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/GitHub/GitHub.jsx b/awx/ui_next/src/screens/Setting/GitHub/GitHub.jsx
index 01ba2f6ada..c134adca9c 100644
--- a/awx/ui_next/src/screens/Setting/GitHub/GitHub.jsx
+++ b/awx/ui_next/src/screens/Setting/GitHub/GitHub.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Link, Redirect, Route, Switch } from 'react-router-dom';
+import { Link, Redirect, Route, Switch, useRouteMatch } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { PageSection, Card } from '@patternfly/react-core';
@@ -9,11 +9,23 @@ import GitHubEdit from './GitHubEdit';
function GitHub({ i18n }) {
const baseURL = '/settings/github';
+ const baseRoute = useRouteMatch({ path: '/settings/github', exact: true });
+ const categoryRoute = useRouteMatch({
+ path: '/settings/github/:category',
+ exact: true,
+ });
+
return (
-
+ {baseRoute && }
+ {categoryRoute && (
+
+ )}
diff --git a/awx/ui_next/src/screens/Setting/GitHub/GitHub.test.jsx b/awx/ui_next/src/screens/Setting/GitHub/GitHub.test.jsx
index e0c2d57e7e..37a1c62a67 100644
--- a/awx/ui_next/src/screens/Setting/GitHub/GitHub.test.jsx
+++ b/awx/ui_next/src/screens/Setting/GitHub/GitHub.test.jsx
@@ -49,7 +49,7 @@ describe('', () => {
test('should show content error when user navigates to erroneous route', async () => {
const history = createMemoryHistory({
- initialEntries: ['/settings/github/foo'],
+ initialEntries: ['/settings/github/foo/bar'],
});
await act(async () => {
wrapper = mountWithContexts(, {
diff --git a/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.jsx b/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.jsx
index 691d4db325..0b70e09d70 100644
--- a/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.jsx
@@ -98,8 +98,11 @@ function GitHubDetail({ i18n }) {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.test.jsx b/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.test.jsx
index 517621aa89..11db4b57f0 100644
--- a/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.test.jsx
@@ -175,9 +175,9 @@ describe('', () => {
'GitHub Organization OAuth2 Callback URL',
'https://towerhost/sso/complete/github-org/'
);
- assertDetail(wrapper, 'GitHub Organization OAuth2 Key', 'Unconfigured');
+ assertDetail(wrapper, 'GitHub Organization OAuth2 Key', 'Not configured');
assertDetail(wrapper, 'GitHub Organization OAuth2 Secret', 'Encrypted');
- assertDetail(wrapper, 'GitHub Organization Name', 'Unconfigured');
+ assertDetail(wrapper, 'GitHub Organization Name', 'Not configured');
assertVariableDetail(
wrapper,
'GitHub Organization OAuth2 Organization Map',
diff --git a/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.jsx b/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.jsx
index 21dae3a215..bbf512249c 100644
--- a/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.jsx
+++ b/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.jsx
@@ -62,8 +62,11 @@ function GoogleOAuth2Detail({ i18n }) {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.test.jsx b/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.test.jsx
index e4545dd943..ab4ce44ce3 100644
--- a/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.test.jsx
@@ -72,7 +72,7 @@ describe('', () => {
assertDetail(wrapper, 'Google OAuth2 Secret', 'Encrypted');
assertVariableDetail(
wrapper,
- 'Google OAuth2 Whitelisted Domains',
+ 'Google OAuth2 Allowed Domains',
'[\n "example.com",\n "example_2.com"\n]'
);
assertVariableDetail(wrapper, 'Google OAuth2 Extra Arguments', '{}');
diff --git a/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.jsx b/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.jsx
index 11f32069ab..5b099a802a 100644
--- a/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.jsx
@@ -29,7 +29,6 @@ function JobsDetail({ i18n }) {
AWX_ISOLATED_KEY_GENERATION,
AWX_ISOLATED_PRIVATE_KEY,
AWX_ISOLATED_PUBLIC_KEY,
- GALAXY_IGNORE_CERTS,
STDOUT_MAX_BYTES_DISPLAY,
EVENT_STDOUT_MAX_BYTES_DISPLAY,
...jobsData
@@ -76,12 +75,15 @@ function JobsDetail({ i18n }) {
{!isLoading && error && }
{!isLoading && jobs && (
- {Array.from(jobs).map(([, detail]) => {
+ {jobs.map(([key, detail]) => {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.test.jsx b/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.test.jsx
index bcb6908249..02ec0b8118 100644
--- a/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.test.jsx
@@ -52,9 +52,9 @@ describe('', () => {
test('should render expected details', () => {
assertDetail(wrapper, 'Enable job isolation', 'On');
assertDetail(wrapper, 'Job execution path', '/tmp');
- assertDetail(wrapper, 'Isolated status check interval', '1');
- assertDetail(wrapper, 'Isolated launch timeout', '600');
- assertDetail(wrapper, 'Isolated connection timeout', '10');
+ assertDetail(wrapper, 'Isolated status check interval', '1 seconds');
+ assertDetail(wrapper, 'Isolated launch timeout', '600 seconds');
+ assertDetail(wrapper, 'Isolated connection timeout', '10 seconds');
assertDetail(wrapper, 'Isolated host key checking', 'Off');
assertDetail(
wrapper,
@@ -67,28 +67,15 @@ describe('', () => {
assertDetail(wrapper, 'Follow symlinks', 'Off');
assertDetail(
wrapper,
- 'Primary Galaxy Server URL',
- 'https://galaxy.server.com'
+ 'Ignore Ansible Galaxy SSL Certificate Verification',
+ 'Off'
);
- assertDetail(wrapper, 'Primary Galaxy Server Username', 'Unconfigured');
- assertDetail(wrapper, 'Primary Galaxy Server Password', 'Unconfigured');
- assertDetail(wrapper, 'Primary Galaxy Server Token', 'Encrypted');
- assertDetail(
- wrapper,
- 'Primary Galaxy Authentication URL',
- 'https://galaxy.auth.com'
- );
- assertDetail(wrapper, 'Allow Access to Public Galaxy', 'On');
assertDetail(wrapper, 'Maximum Scheduled Jobs', '10');
- assertDetail(wrapper, 'Default Job Timeout', 'Unconfigured');
- assertDetail(wrapper, 'Default Inventory Update Timeout', 'Unconfigured');
- assertDetail(wrapper, 'Default Project Update Timeout', 'Unconfigured');
- assertDetail(
- wrapper,
- 'Per-Host Ansible Fact Cache Timeout',
- 'Unconfigured'
- );
- assertDetail(wrapper, 'Maximum number of forks per job.', '200');
+ assertDetail(wrapper, 'Default Job Timeout', '0 seconds');
+ assertDetail(wrapper, 'Default Inventory Update Timeout', '0 seconds');
+ assertDetail(wrapper, 'Default Project Update Timeout', '0 seconds');
+ assertDetail(wrapper, 'Per-Host Ansible Fact Cache Timeout', '0 seconds');
+ assertDetail(wrapper, 'Maximum number of forks per job', '200');
assertVariableDetail(
wrapper,
'Ansible Modules Allowed for Ad Hoc Jobs',
diff --git a/awx/ui_next/src/screens/Setting/LDAP/LDAP.jsx b/awx/ui_next/src/screens/Setting/LDAP/LDAP.jsx
index e675132912..722127079c 100644
--- a/awx/ui_next/src/screens/Setting/LDAP/LDAP.jsx
+++ b/awx/ui_next/src/screens/Setting/LDAP/LDAP.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Link, Redirect, Route, Switch } from 'react-router-dom';
+import { Link, Redirect, Route, Switch, useRouteMatch } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { PageSection, Card } from '@patternfly/react-core';
@@ -9,11 +9,23 @@ import LDAPEdit from './LDAPEdit';
function LDAP({ i18n }) {
const baseURL = '/settings/ldap';
+ const baseRoute = useRouteMatch({ path: '/settings/ldap', exact: true });
+ const categoryRoute = useRouteMatch({
+ path: '/settings/ldap/:category',
+ exact: true,
+ });
+
return (
-
+ {baseRoute && }
+ {categoryRoute && (
+
+ )}
diff --git a/awx/ui_next/src/screens/Setting/LDAP/LDAP.test.jsx b/awx/ui_next/src/screens/Setting/LDAP/LDAP.test.jsx
index 2b3d185257..bcc6c60be0 100644
--- a/awx/ui_next/src/screens/Setting/LDAP/LDAP.test.jsx
+++ b/awx/ui_next/src/screens/Setting/LDAP/LDAP.test.jsx
@@ -49,7 +49,7 @@ describe('', () => {
test('should show content error when user navigates to erroneous route', async () => {
const history = createMemoryHistory({
- initialEntries: ['/settings/ldap/foo'],
+ initialEntries: ['/settings/ldap/foo/bar'],
});
await act(async () => {
wrapper = mountWithContexts(, {
diff --git a/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.jsx b/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.jsx
index bb5196c93f..dd881572e2 100644
--- a/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.jsx
@@ -138,12 +138,15 @@ function LDAPDetail({ i18n }) {
{!isLoading && error && }
{!isLoading && !Object.values(LDAPDetails)?.includes(null) && (
- {Array.from(LDAPDetails[category]).map(([, detail]) => {
+ {LDAPDetails[category].map(([key, detail]) => {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.test.jsx b/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.test.jsx
index 7720dc9b3b..e688882a20 100644
--- a/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.test.jsx
@@ -82,7 +82,7 @@ describe('', () => {
'LDAP Require Group',
'CN=Tower Users,OU=Users,DC=example,DC=com'
);
- assertDetail(wrapper, 'LDAP Deny Group', 'Unconfigured');
+ assertDetail(wrapper, 'LDAP Deny Group', 'Not configured');
assertVariableDetail(wrapper, 'LDAP User Search', '[]');
assertVariableDetail(wrapper, 'LDAP User Attribute Map', '{}');
assertVariableDetail(wrapper, 'LDAP Group Search', '[]');
diff --git a/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.jsx b/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.jsx
index 8e9fabc4bd..11fe55ddfc 100644
--- a/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.jsx
@@ -84,8 +84,11 @@ function LoggingDetail({ i18n }) {
{logging.map(([key, detail]) => (
))}
diff --git a/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.test.jsx b/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.test.jsx
index aa292af616..dc669252d7 100644
--- a/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.test.jsx
@@ -58,7 +58,7 @@ describe('', () => {
assertDetail(wrapper, 'Logging Aggregator Password/Token', 'Encrypted');
assertDetail(wrapper, 'Log System Tracking Facts Individually', 'Off');
assertDetail(wrapper, 'Logging Aggregator Protocol', 'https');
- assertDetail(wrapper, 'TCP Connection Timeout', '5');
+ assertDetail(wrapper, 'TCP Connection Timeout', '5 seconds');
assertDetail(wrapper, 'Logging Aggregator Level Threshold', 'INFO');
assertDetail(
wrapper,
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 8328ba0755..a8fcdf411d 100644
--- a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx
@@ -125,8 +125,11 @@ function MiscSystemDetail({ i18n }) {
{system.map(([key, detail]) => (
))}
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 20c1166306..8437930be2 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
@@ -69,24 +69,28 @@ describe('', () => {
});
test('should render expected details', () => {
- assertDetail(wrapper, 'Access Token Expiration', '1');
+ assertDetail(wrapper, 'Access Token Expiration', '1 seconds');
assertDetail(wrapper, 'All Users Visible to Organization Admins', 'On');
assertDetail(
wrapper,
'Allow External Users to Create OAuth2 Tokens',
'Off'
);
- assertDetail(wrapper, 'Authorization Code Expiration', '2');
- assertDetail(wrapper, 'Automation Analytics Gather Interval', '14400');
+ assertDetail(wrapper, 'Authorization Code Expiration', '2 seconds');
assertDetail(
wrapper,
- 'Automation Analytics upload URL.',
+ 'Automation Analytics Gather Interval',
+ '14400 seconds'
+ );
+ assertDetail(
+ wrapper,
+ 'Automation Analytics upload URL',
'https://example.com'
);
assertDetail(wrapper, 'Base URL of the Tower host', 'https://towerhost');
assertDetail(wrapper, 'Enable HTTP Basic Auth', 'On');
assertDetail(wrapper, 'Gather data for Automation Analytics', 'Off');
- assertDetail(wrapper, 'Idle Time Force Log Out', '30000000000');
+ assertDetail(wrapper, 'Idle Time Force Log Out', '30000000000 seconds');
assertDetail(
wrapper,
'Login redirect override URL',
@@ -104,7 +108,7 @@ describe('', () => {
);
assertDetail(wrapper, 'Red Hat customer password', 'Encrypted');
assertDetail(wrapper, 'Red Hat customer username', 'mock name');
- assertDetail(wrapper, 'Refresh Token Expiration', '3');
+ assertDetail(wrapper, 'Refresh Token Expiration', '3 seconds');
assertVariableDetail(wrapper, 'Remote Host Headers', '[]');
assertVariableDetail(wrapper, 'Custom virtual environment paths', '[]');
});
diff --git a/awx/ui_next/src/screens/Setting/RADIUS/RADIUSDetail/RADIUSDetail.jsx b/awx/ui_next/src/screens/Setting/RADIUS/RADIUSDetail/RADIUSDetail.jsx
index 37a8c74bdf..d1d8a4e6f6 100644
--- a/awx/ui_next/src/screens/Setting/RADIUS/RADIUSDetail/RADIUSDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/RADIUS/RADIUSDetail/RADIUSDetail.jsx
@@ -62,8 +62,11 @@ function RADIUSDetail({ i18n }) {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.jsx b/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.jsx
index b5228ea311..e6694d8591 100644
--- a/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.jsx
@@ -62,8 +62,11 @@ function SAMLDetail({ i18n }) {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.test.jsx b/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.test.jsx
index b5a003c1d2..1afaee4e24 100644
--- a/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.test.jsx
@@ -75,7 +75,11 @@ describe('', () => {
'SAML Service Provider Public Certificate',
'mock_cert'
);
- assertDetail(wrapper, 'SAML Service Provider Private Key', 'Unconfigured');
+ assertDetail(
+ wrapper,
+ 'SAML Service Provider Private Key',
+ 'Not configured'
+ );
assertVariableDetail(
wrapper,
'SAML Service Provider Organization Info',
diff --git a/awx/ui_next/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.jsx b/awx/ui_next/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.jsx
index cd5c59595b..de85665808 100644
--- a/awx/ui_next/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.jsx
@@ -62,8 +62,11 @@ function TACACSDetail({ i18n }) {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.test.jsx b/awx/ui_next/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.test.jsx
index d79bd132fd..66e673b2e0 100644
--- a/awx/ui_next/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.test.jsx
@@ -55,7 +55,7 @@ describe('', () => {
assertDetail(wrapper, 'TACACS+ Server', 'mockhost');
assertDetail(wrapper, 'TACACS+ Port', '49');
assertDetail(wrapper, 'TACACS+ Secret', 'Encrypted');
- assertDetail(wrapper, 'TACACS+ Auth Session Timeout', '5');
+ assertDetail(wrapper, 'TACACS+ Auth Session Timeout', '5 seconds');
assertDetail(wrapper, 'TACACS+ Authentication Protocol', 'ascii');
});
diff --git a/awx/ui_next/src/screens/Setting/UI/UIDetail/UIDetail.jsx b/awx/ui_next/src/screens/Setting/UI/UIDetail/UIDetail.jsx
index 18776447df..2d4e475006 100644
--- a/awx/ui_next/src/screens/Setting/UI/UIDetail/UIDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/UI/UIDetail/UIDetail.jsx
@@ -77,8 +77,11 @@ function UIDetail({ i18n }) {
return (
);
diff --git a/awx/ui_next/src/screens/Setting/shared/SettingDetail.jsx b/awx/ui_next/src/screens/Setting/shared/SettingDetail.jsx
index 6d56aa2ba1..56a4e42d2d 100644
--- a/awx/ui_next/src/screens/Setting/shared/SettingDetail.jsx
+++ b/awx/ui_next/src/screens/Setting/shared/SettingDetail.jsx
@@ -3,84 +3,115 @@ import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Detail } from '../../../components/DetailList';
import { VariablesDetail } from '../../../components/CodeMirrorInput';
+// import DetailPopover from '../../../components/DetailList/DetailPopover';
-export default withI18n()(({ i18n, label, type, value }) => {
- const dataType = value === '$encrypted$' ? 'encrypted' : type;
- let detail = null;
+export default withI18n()(
+ ({ i18n, helpText, id, label, type, unit = '', value }) => {
+ const dataType = value === '$encrypted$' ? 'encrypted' : type;
+ let detail = null;
- switch (dataType) {
- case 'nested object':
- detail = (
-
- );
- break;
- case 'list':
- detail = ;
- break;
- case 'image':
- detail = (
- }
- />
- );
- break;
- case 'encrypted':
- detail = (
-
- );
- break;
- case 'boolean':
- detail = (
-
- );
- break;
- case 'choice':
- detail = (
-
- );
- break;
- case 'integer':
- detail = (
-
- );
- break;
- case 'string':
- detail = (
-
- );
- break;
- default:
- detail = null;
+ switch (dataType) {
+ case 'nested object':
+ detail = (
+
+ );
+ break;
+ case 'list':
+ detail = (
+
+ );
+ break;
+ case 'image':
+ detail = (
+
+ )
+ }
+ />
+ );
+ break;
+ case 'encrypted':
+ detail = (
+
+ );
+ break;
+ case 'boolean':
+ detail = (
+
+ );
+ break;
+ case 'choice':
+ detail = (
+
+ );
+ break;
+ case 'integer':
+ detail = (
+
+ );
+ break;
+ case 'string':
+ detail = (
+
+ );
+ break;
+ default:
+ detail = null;
+ }
+ return detail;
}
- return detail;
-});
+);
diff --git a/awx/ui_next/src/screens/Setting/shared/data.allSettingOptions.json b/awx/ui_next/src/screens/Setting/shared/data.allSettingOptions.json
index 35ca07e6c0..4587e845d8 100644
--- a/awx/ui_next/src/screens/Setting/shared/data.allSettingOptions.json
+++ b/awx/ui_next/src/screens/Setting/shared/data.allSettingOptions.json
@@ -1,4 +1,3 @@
-
{
"name": "Setting Detail",
"actions": {
@@ -94,7 +93,7 @@
},
"AUTOMATION_ANALYTICS_URL": {
"type": "string",
- "label": "Automation Analytics upload URL.",
+ "label": "Automation Analytics upload URL",
"help_text": "This setting is used to to configure data collection for the Automation Analytics dashboard",
"category": "System",
"category_slug": "system",
@@ -196,7 +195,8 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"AWX_ISOLATED_LAUNCH_TIMEOUT": {
"type": "integer",
@@ -205,7 +205,8 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"AWX_ISOLATED_CONNECTION_TIMEOUT": {
"type": "integer",
@@ -214,7 +215,8 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"AWX_ISOLATED_HOST_KEY_CHECKING": {
"type": "boolean",
@@ -331,58 +333,10 @@
"category_slug": "jobs",
"defined_in_file": false
},
- "PRIMARY_GALAXY_URL": {
- "type": "string",
- "label": "Primary Galaxy Server URL",
- "help_text": "For organizations that run their own Galaxy service, this gives the option to specify a host as the primary galaxy server. Requirements will be downloaded from the primary if the specific role or collection is available there. If the content is not avilable in the primary, or if this field is left blank, it will default to galaxy.ansible.com.",
- "category": "Jobs",
- "category_slug": "jobs",
- "defined_in_file": false
- },
- "PRIMARY_GALAXY_USERNAME": {
- "type": "string",
- "label": "Primary Galaxy Server Username",
- "help_text": "(This setting is deprecated and will be removed in a future release) For using a galaxy server at higher precedence than the public Ansible Galaxy. The username to use for basic authentication against the Galaxy instance, this is mutually exclusive with PRIMARY_GALAXY_TOKEN.",
- "category": "Jobs",
- "category_slug": "jobs",
- "defined_in_file": false
- },
- "PRIMARY_GALAXY_PASSWORD": {
- "type": "string",
- "label": "Primary Galaxy Server Password",
- "help_text": "(This setting is deprecated and will be removed in a future release) For using a galaxy server at higher precedence than the public Ansible Galaxy. The password to use for basic authentication against the Galaxy instance, this is mutually exclusive with PRIMARY_GALAXY_TOKEN.",
- "category": "Jobs",
- "category_slug": "jobs",
- "defined_in_file": false
- },
- "PRIMARY_GALAXY_TOKEN": {
- "type": "string",
- "label": "Primary Galaxy Server Token",
- "help_text": "For using a galaxy server at higher precedence than the public Ansible Galaxy. The token to use for connecting with the Galaxy instance, this is mutually exclusive with corresponding username and password settings.",
- "category": "Jobs",
- "category_slug": "jobs",
- "defined_in_file": false
- },
- "PRIMARY_GALAXY_AUTH_URL": {
- "type": "string",
- "label": "Primary Galaxy Authentication URL",
- "help_text": "For using a galaxy server at higher precedence than the public Ansible Galaxy. The token_endpoint of a Keycloak server.",
- "category": "Jobs",
- "category_slug": "jobs",
- "defined_in_file": false
- },
- "PUBLIC_GALAXY_ENABLED": {
- "type": "boolean",
- "label": "Allow Access to Public Galaxy",
- "help_text": "Allow or deny access to the public Ansible Galaxy during project updates.",
- "category": "Jobs",
- "category_slug": "jobs",
- "defined_in_file": false
- },
"GALAXY_IGNORE_CERTS": {
"type": "boolean",
"label": "Ignore Ansible Galaxy SSL Certificate Verification",
- "help_text": "If set to true, certificate validation will not be done wheninstalling content from any Galaxy server.",
+ "help_text": "If set to true, certificate validation will not be done when installing content from any Galaxy server.",
"category": "Jobs",
"category_slug": "jobs",
"defined_in_file": false
@@ -432,7 +386,8 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"DEFAULT_INVENTORY_UPDATE_TIMEOUT": {
"type": "integer",
@@ -441,7 +396,8 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"DEFAULT_PROJECT_UPDATE_TIMEOUT": {
"type": "integer",
@@ -450,7 +406,8 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"ANSIBLE_FACT_CACHE_TIMEOUT": {
"type": "integer",
@@ -459,11 +416,12 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"MAX_FORKS": {
"type": "integer",
- "label": "Maximum number of forks per job.",
+ "label": "Maximum number of forks per job",
"help_text": "Saving a Job Template with more than this number of forks will result in an error. When set to 0, no limit is applied.",
"category": "Jobs",
"category_slug": "jobs",
@@ -598,7 +556,8 @@
"help_text": "Number of seconds for a TCP connection to external log aggregator to timeout. Applies to HTTPS and TCP log aggregator protocols.",
"category": "Logging",
"category_slug": "logging",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"LOG_AGGREGATOR_VERIFY_CERT": {
"type": "boolean",
@@ -677,7 +636,8 @@
"min_value": 1800,
"category": "System",
"category_slug": "system",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"SESSION_COOKIE_AGE": {
"type": "integer",
@@ -687,7 +647,8 @@
"max_value": 30000000000,
"category": "Authentication",
"category_slug": "authentication",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"SESSIONS_PER_USER": {
"type": "integer",
@@ -713,6 +674,7 @@
"category": "Authentication",
"category_slug": "authentication",
"defined_in_file": false,
+ "unit": "seconds",
"child": {
"type": "integer",
"min_value": 1
@@ -2204,7 +2166,8 @@
"min_value": 0,
"category": "TACACS+",
"category_slug": "tacacsplus",
- "defined_in_file": false
+ "defined_in_file": false,
+ "unit": "seconds"
},
"TACACSPLUS_AUTH_PROTOCOL": {
"type": "choice",
@@ -2250,7 +2213,7 @@
},
"SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS": {
"type": "list",
- "label": "Google OAuth2 Whitelisted Domains",
+ "label": "Google OAuth2 Allowed Domains",
"help_text": "Update this setting to restrict the domains who are allowed to login using Google OAuth2.",
"category": "Google OAuth2",
"category_slug": "google-oauth2",
@@ -2542,6 +2505,14 @@
}
}
},
+ "SAML_AUTO_CREATE_OBJECTS": {
+ "type": "boolean",
+ "label": "Automatically Create Organizations and Teams on SAML Login",
+ "help_text": "When enabled (the default), mapped Organizations and Teams will be created automatically on successful SAML login.",
+ "category": "SAML",
+ "category_slug": "saml",
+ "defined_in_file": false
+ },
"SOCIAL_AUTH_SAML_CALLBACK_URL": {
"type": "string",
"label": "SAML Assertion Consumer Service (ACS) URL",
@@ -2844,7 +2815,7 @@
"AUTOMATION_ANALYTICS_URL": {
"type": "string",
"required": false,
- "label": "Automation Analytics upload URL.",
+ "label": "Automation Analytics upload URL",
"help_text": "This setting is used to to configure data collection for the Automation Analytics dashboard",
"category": "System",
"category_slug": "system",
@@ -2975,6 +2946,7 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
+ "unit": "seconds",
"default": 1
},
"AWX_ISOLATED_LAUNCH_TIMEOUT": {
@@ -2985,6 +2957,7 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
+ "unit": "seconds",
"default": 600
},
"AWX_ISOLATED_CONNECTION_TIMEOUT": {
@@ -2995,6 +2968,7 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
+ "unit": "seconds",
"default": 10
},
"AWX_ISOLATED_HOST_KEY_CHECKING": {
@@ -3104,65 +3078,11 @@
"category_slug": "jobs",
"default": false
},
- "PRIMARY_GALAXY_URL": {
- "type": "string",
- "required": false,
- "label": "Primary Galaxy Server URL",
- "help_text": "For organizations that run their own Galaxy service, this gives the option to specify a host as the primary galaxy server. Requirements will be downloaded from the primary if the specific role or collection is available there. If the content is not avilable in the primary, or if this field is left blank, it will default to galaxy.ansible.com.",
- "category": "Jobs",
- "category_slug": "jobs",
- "default": ""
- },
- "PRIMARY_GALAXY_USERNAME": {
- "type": "string",
- "required": false,
- "label": "Primary Galaxy Server Username",
- "help_text": "(This setting is deprecated and will be removed in a future release) For using a galaxy server at higher precedence than the public Ansible Galaxy. The username to use for basic authentication against the Galaxy instance, this is mutually exclusive with PRIMARY_GALAXY_TOKEN.",
- "category": "Jobs",
- "category_slug": "jobs",
- "default": ""
- },
- "PRIMARY_GALAXY_PASSWORD": {
- "type": "string",
- "required": false,
- "label": "Primary Galaxy Server Password",
- "help_text": "(This setting is deprecated and will be removed in a future release) For using a galaxy server at higher precedence than the public Ansible Galaxy. The password to use for basic authentication against the Galaxy instance, this is mutually exclusive with PRIMARY_GALAXY_TOKEN.",
- "category": "Jobs",
- "category_slug": "jobs",
- "default": ""
- },
- "PRIMARY_GALAXY_TOKEN": {
- "type": "string",
- "required": false,
- "label": "Primary Galaxy Server Token",
- "help_text": "For using a galaxy server at higher precedence than the public Ansible Galaxy. The token to use for connecting with the Galaxy instance, this is mutually exclusive with corresponding username and password settings.",
- "category": "Jobs",
- "category_slug": "jobs",
- "default": ""
- },
- "PRIMARY_GALAXY_AUTH_URL": {
- "type": "string",
- "required": false,
- "label": "Primary Galaxy Authentication URL",
- "help_text": "For using a galaxy server at higher precedence than the public Ansible Galaxy. The token_endpoint of a Keycloak server.",
- "category": "Jobs",
- "category_slug": "jobs",
- "default": ""
- },
- "PUBLIC_GALAXY_ENABLED": {
- "type": "boolean",
- "required": false,
- "label": "Allow Access to Public Galaxy",
- "help_text": "Allow or deny access to the public Ansible Galaxy during project updates.",
- "category": "Jobs",
- "category_slug": "jobs",
- "default": true
- },
"GALAXY_IGNORE_CERTS": {
"type": "boolean",
"required": false,
"label": "Ignore Ansible Galaxy SSL Certificate Verification",
- "help_text": "If set to true, certificate validation will not be done wheninstalling content from any Galaxy server.",
+ "help_text": "If set to true, certificate validation will not be done when installing content from any Galaxy server.",
"category": "Jobs",
"category_slug": "jobs",
"default": false
@@ -3219,6 +3139,7 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
+ "unit": "seconds",
"default": 0
},
"DEFAULT_INVENTORY_UPDATE_TIMEOUT": {
@@ -3229,6 +3150,7 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
+ "unit": "seconds",
"default": 0
},
"DEFAULT_PROJECT_UPDATE_TIMEOUT": {
@@ -3239,6 +3161,7 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
+ "unit": "seconds",
"default": 0
},
"ANSIBLE_FACT_CACHE_TIMEOUT": {
@@ -3249,12 +3172,13 @@
"min_value": 0,
"category": "Jobs",
"category_slug": "jobs",
+ "unit": "seconds",
"default": 0
},
"MAX_FORKS": {
"type": "integer",
"required": false,
- "label": "Maximum number of forks per job.",
+ "label": "Maximum number of forks per job",
"help_text": "Saving a Job Template with more than this number of forks will result in an error. When set to 0, no limit is applied.",
"category": "Jobs",
"category_slug": "jobs",
@@ -3407,6 +3331,7 @@
"help_text": "Number of seconds for a TCP connection to external log aggregator to timeout. Applies to HTTPS and TCP log aggregator protocols.",
"category": "Logging",
"category_slug": "logging",
+ "unit": "seconds",
"default": 5
},
"LOG_AGGREGATOR_VERIFY_CERT": {
@@ -3493,6 +3418,7 @@
"min_value": 1800,
"category": "System",
"category_slug": "system",
+ "unit": "seconds",
"default": 14400
},
"SESSION_COOKIE_AGE": {
@@ -3504,6 +3430,7 @@
"max_value": 30000000000,
"category": "Authentication",
"category_slug": "authentication",
+ "unit": "seconds",
"default": 1800
},
"SESSIONS_PER_USER": {
@@ -3532,6 +3459,7 @@
"help_text": "Dictionary for customizing OAuth 2 timeouts, available items are `ACCESS_TOKEN_EXPIRE_SECONDS`, the duration of access tokens in the number of seconds, `AUTHORIZATION_CODE_EXPIRE_SECONDS`, the duration of authorization codes in the number of seconds, and `REFRESH_TOKEN_EXPIRE_SECONDS`, the duration of refresh tokens, after expired access tokens, in the number of seconds.",
"category": "Authentication",
"category_slug": "authentication",
+ "unit": "seconds",
"default": {
"ACCESS_TOKEN_EXPIRE_SECONDS": 31536000000,
"AUTHORIZATION_CODE_EXPIRE_SECONDS": 600,
@@ -5668,6 +5596,7 @@
"min_value": 0,
"category": "TACACS+",
"category_slug": "tacacsplus",
+ "unit": "seconds",
"default": 5
},
"TACACSPLUS_AUTH_PROTOCOL": {
@@ -5712,7 +5641,7 @@
"SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS": {
"type": "list",
"required": false,
- "label": "Google OAuth2 Whitelisted Domains",
+ "label": "Google OAuth2 Allowed Domains",
"help_text": "Update this setting to restrict the domains who are allowed to login using Google OAuth2.",
"category": "Google OAuth2",
"category_slug": "google-oauth2",
@@ -6208,6 +6137,15 @@
}
}
},
+ "SAML_AUTO_CREATE_OBJECTS": {
+ "type": "boolean",
+ "required": false,
+ "label": "Automatically Create Organizations and Teams on SAML Login",
+ "help_text": "When enabled (the default), mapped Organizations and Teams will be created automatically on successful SAML login.",
+ "category": "SAML",
+ "category_slug": "saml",
+ "default": true
+ },
"SOCIAL_AUTH_SAML_SP_ENTITY_ID": {
"type": "string",
"required": false,
diff --git a/awx/ui_next/src/screens/Setting/shared/data.jobSettings.json b/awx/ui_next/src/screens/Setting/shared/data.jobSettings.json
index 25f5126ef6..190a346560 100644
--- a/awx/ui_next/src/screens/Setting/shared/data.jobSettings.json
+++ b/awx/ui_next/src/screens/Setting/shared/data.jobSettings.json
@@ -1,3 +1,4 @@
+
{
"AD_HOC_COMMANDS": [
"command"
@@ -23,12 +24,6 @@
"AWX_ROLES_ENABLED": true,
"AWX_COLLECTIONS_ENABLED": true,
"AWX_SHOW_PLAYBOOK_LINKS": false,
- "PRIMARY_GALAXY_URL": "https://galaxy.server.com",
- "PRIMARY_GALAXY_USERNAME": "",
- "PRIMARY_GALAXY_PASSWORD": "",
- "PRIMARY_GALAXY_TOKEN": "$encrypted$",
- "PRIMARY_GALAXY_AUTH_URL": "https://galaxy.auth.com",
- "PUBLIC_GALAXY_ENABLED": true,
"GALAXY_IGNORE_CERTS": false,
"STDOUT_MAX_BYTES_DISPLAY": 1048576,
"EVENT_STDOUT_MAX_BYTES_DISPLAY": 1024,
diff --git a/awx/ui_next/src/screens/Setting/shared/settingUtils.js b/awx/ui_next/src/screens/Setting/shared/settingUtils.js
index 5e33e0e54f..78d27142aa 100644
--- a/awx/ui_next/src/screens/Setting/shared/settingUtils.js
+++ b/awx/ui_next/src/screens/Setting/shared/settingUtils.js
@@ -3,10 +3,13 @@ export function sortNestedDetails(obj = {}) {
const notNested = Object.entries(obj).filter(
([, value]) => !nestedTypes.includes(value.type)
);
- const nested = Object.entries(obj).filter(([, value]) =>
- nestedTypes.includes(value.type)
+ const nestedList = Object.entries(obj).filter(
+ ([, value]) => value.type === 'list'
);
- return [...notNested, ...nested];
+ const nestedObject = Object.entries(obj).filter(
+ ([, value]) => value.type === 'nested object'
+ );
+ return [...notNested, ...nestedList, ...nestedObject];
}
export function pluck(sourceObject, ...keys) {