mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
Add a new key "unit" to api setting fields
* Add detail popover * Fix broken redirects * Add additional id and data-cy attributes to Detail components * Remove galaxy fields from job settings
This commit is contained in:
parent
a69a40a429
commit
558dfb685e
@ -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',
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -515,6 +515,7 @@ register(
|
||||
help_text=_('TACACS+ session timeout value in seconds, 0 disables timeout.'),
|
||||
category=_('TACACS+'),
|
||||
category_slug='tacacsplus',
|
||||
unit=_('seconds'),
|
||||
)
|
||||
|
||||
register(
|
||||
|
||||
@ -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 (
|
||||
<>
|
||||
<DetailName
|
||||
data-cy={labelCy}
|
||||
id={dataCy}
|
||||
component={TextListItemVariants.dt}
|
||||
fullWidth
|
||||
css="grid-column: 1 / -1"
|
||||
@ -62,6 +68,9 @@ function VariablesDetail({ value, label, rows, fullHeight }) {
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
{helpText && (
|
||||
<DetailPopover header={label} content={helpText} id={dataCy} />
|
||||
)}
|
||||
</div>
|
||||
</SplitItem>
|
||||
<SplitItem>
|
||||
@ -84,6 +93,7 @@ function VariablesDetail({ value, label, rows, fullHeight }) {
|
||||
</Split>
|
||||
</DetailName>
|
||||
<DetailValue
|
||||
data-cy={valueCy}
|
||||
component={TextListItemVariants.dd}
|
||||
fullWidth
|
||||
css="grid-column: 1 / -1; margin-top: -20px"
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import { node, bool } from 'prop-types';
|
||||
import { node, bool, string } from 'prop-types';
|
||||
import { TextListItem, TextListItemVariants } from '@patternfly/react-core';
|
||||
import styled from 'styled-components';
|
||||
import DetailPopover from '../DetailPopover';
|
||||
|
||||
const DetailName = styled(({ fullWidth, ...props }) => (
|
||||
<TextListItem {...props} />
|
||||
@ -15,7 +16,7 @@ const DetailName = styled(({ fullWidth, ...props }) => (
|
||||
`;
|
||||
|
||||
const DetailValue = styled(
|
||||
({ fullWidth, isEncrypted, isUnconfigured, ...props }) => (
|
||||
({ fullWidth, isEncrypted, isNotConfigured, ...props }) => (
|
||||
<TextListItem {...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 && (
|
||||
<DetailPopover header={label} content={helpText} id={dataCy} />
|
||||
)}
|
||||
</DetailName>
|
||||
<DetailValue
|
||||
className={className}
|
||||
@ -65,7 +71,7 @@ const Detail = ({
|
||||
fullWidth={fullWidth}
|
||||
data-cy={valueCy}
|
||||
isEncrypted={isEncrypted}
|
||||
isUnconfigured={isUnconfigured}
|
||||
isNotConfigured={isNotConfigured}
|
||||
>
|
||||
{value}
|
||||
</DetailValue>
|
||||
@ -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;
|
||||
|
||||
51
awx/ui_next/src/components/DetailPopover/DetailPopover.jsx
Normal file
51
awx/ui_next/src/components/DetailPopover/DetailPopover.jsx
Normal file
@ -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 (
|
||||
<Popover
|
||||
bodyContent={content}
|
||||
headerContent={header}
|
||||
hideOnOutsideClick
|
||||
id={id}
|
||||
isVisible={showPopover}
|
||||
shouldClose={() => setShowPopover(false)}
|
||||
>
|
||||
<Button
|
||||
onClick={() => setShowPopover(!showPopover)}
|
||||
variant="plain"
|
||||
aria-haspopup="true"
|
||||
aria-expanded={showPopover}
|
||||
>
|
||||
<OutlinedQuestionCircleIcon
|
||||
onClick={() => setShowPopover(!showPopover)}
|
||||
/>
|
||||
</Button>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
DetailPopover.propTypes = {
|
||||
content: node,
|
||||
header: node,
|
||||
id: string,
|
||||
};
|
||||
DetailPopover.defaultProps = {
|
||||
content: null,
|
||||
header: null,
|
||||
id: 'detail-popover',
|
||||
};
|
||||
|
||||
export default DetailPopover;
|
||||
1
awx/ui_next/src/components/DetailPopover/index.js
Normal file
1
awx/ui_next/src/components/DetailPopover/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './DetailPopover';
|
||||
@ -74,6 +74,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
alwaysVisible={false}
|
||||
fullWidth={false}
|
||||
helpText={null}
|
||||
label="Name"
|
||||
value="jane brown"
|
||||
/>
|
||||
@ -86,6 +87,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
alwaysVisible={false}
|
||||
fullWidth={false}
|
||||
helpText={null}
|
||||
label="Team Roles"
|
||||
value={
|
||||
<WithI18n
|
||||
@ -138,6 +140,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
alwaysVisible={false}
|
||||
fullWidth={false}
|
||||
helpText={null}
|
||||
label="Name"
|
||||
value="jane brown"
|
||||
/>
|
||||
@ -150,6 +153,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
alwaysVisible={false}
|
||||
fullWidth={false}
|
||||
helpText={null}
|
||||
label="Team Roles"
|
||||
value={
|
||||
<WithI18n
|
||||
@ -225,6 +229,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
alwaysVisible={false}
|
||||
fullWidth={false}
|
||||
helpText={null}
|
||||
label="Name"
|
||||
value="jane brown"
|
||||
/>
|
||||
@ -237,6 +242,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
alwaysVisible={false}
|
||||
fullWidth={false}
|
||||
helpText={null}
|
||||
label="Team Roles"
|
||||
value={
|
||||
<WithI18n
|
||||
@ -447,6 +453,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
alwaysVisible={false}
|
||||
fullWidth={false}
|
||||
helpText={null}
|
||||
label="Name"
|
||||
value="jane brown"
|
||||
>
|
||||
@ -463,9 +470,9 @@ exports[`<ResourceAccessListItem /> 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[`<ResourceAccessListItem /> 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[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
fullWidth={false}
|
||||
>
|
||||
<Component
|
||||
className="sc-htpNat iYJcPm"
|
||||
className="sc-bxivhb gQwVdc"
|
||||
component="dt"
|
||||
data-cy={null}
|
||||
fullWidth={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="sc-htpNat iYJcPm"
|
||||
className="sc-bxivhb gQwVdc"
|
||||
component="dt"
|
||||
data-cy={null}
|
||||
>
|
||||
<dt
|
||||
className="sc-htpNat iYJcPm"
|
||||
className="sc-bxivhb gQwVdc"
|
||||
data-cy={null}
|
||||
data-pf-content={true}
|
||||
>
|
||||
@ -523,9 +530,9 @@ exports[`<ResourceAccessListItem /> 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[`<ResourceAccessListItem /> 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[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
fullWidth={false}
|
||||
>
|
||||
<Component
|
||||
className="sc-bxivhb gxmPlV"
|
||||
className="sc-ifAKCX boHWLt"
|
||||
component="dd"
|
||||
data-cy={null}
|
||||
fullWidth={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="sc-bxivhb gxmPlV"
|
||||
className="sc-ifAKCX boHWLt"
|
||||
component="dd"
|
||||
data-cy={null}
|
||||
>
|
||||
<dd
|
||||
className="sc-bxivhb gxmPlV"
|
||||
className="sc-ifAKCX boHWLt"
|
||||
data-cy={null}
|
||||
data-pf-content={true}
|
||||
>
|
||||
@ -670,6 +677,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
alwaysVisible={false}
|
||||
fullWidth={false}
|
||||
helpText={null}
|
||||
label="Team Roles"
|
||||
value={
|
||||
<WithI18n
|
||||
@ -703,9 +711,9 @@ exports[`<ResourceAccessListItem /> 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[`<ResourceAccessListItem /> 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[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
fullWidth={false}
|
||||
>
|
||||
<Component
|
||||
className="sc-htpNat iYJcPm"
|
||||
className="sc-bxivhb gQwVdc"
|
||||
component="dt"
|
||||
data-cy={null}
|
||||
fullWidth={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="sc-htpNat iYJcPm"
|
||||
className="sc-bxivhb gQwVdc"
|
||||
component="dt"
|
||||
data-cy={null}
|
||||
>
|
||||
<dt
|
||||
className="sc-htpNat iYJcPm"
|
||||
className="sc-bxivhb gQwVdc"
|
||||
data-cy={null}
|
||||
data-pf-content={true}
|
||||
>
|
||||
@ -763,9 +771,9 @@ exports[`<ResourceAccessListItem /> 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[`<ResourceAccessListItem /> 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[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
fullWidth={false}
|
||||
>
|
||||
<Component
|
||||
className="sc-bxivhb gxmPlV"
|
||||
className="sc-ifAKCX boHWLt"
|
||||
component="dd"
|
||||
data-cy={null}
|
||||
fullWidth={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="sc-bxivhb gxmPlV"
|
||||
className="sc-ifAKCX boHWLt"
|
||||
component="dd"
|
||||
data-cy={null}
|
||||
>
|
||||
<dd
|
||||
className="sc-bxivhb gxmPlV"
|
||||
className="sc-ifAKCX boHWLt"
|
||||
data-cy={null}
|
||||
data-pf-content={true}
|
||||
>
|
||||
|
||||
@ -70,8 +70,11 @@ function ActivityStreamDetail({ i18n }) {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={record?.help_text}
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={activityStream?.[key]}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -62,8 +62,11 @@ function AzureADDetail({ i18n }) {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={record?.help_text}
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={azure?.[key]}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -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 (
|
||||
<PageSection>
|
||||
<Card>
|
||||
<Switch>
|
||||
<Redirect from={baseURL} to={`${baseURL}/default/details`} exact />
|
||||
{baseRoute && <Redirect to={`${baseURL}/default/details`} exact />}
|
||||
{categoryRoute && (
|
||||
<Redirect
|
||||
to={`${baseURL}/${categoryRoute.params.category}/details`}
|
||||
exact
|
||||
/>
|
||||
)}
|
||||
<Route path={`${baseURL}/:category/details`}>
|
||||
<GitHubDetail />
|
||||
</Route>
|
||||
|
||||
@ -49,7 +49,7 @@ describe('<GitHub />', () => {
|
||||
|
||||
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(<GitHub />, {
|
||||
|
||||
@ -98,8 +98,11 @@ function GitHubDetail({ i18n }) {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={record?.help_text}
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={gitHubDetails[category][key]}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -175,9 +175,9 @@ describe('<GitHubDetail />', () => {
|
||||
'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',
|
||||
|
||||
@ -62,8 +62,11 @@ function GoogleOAuth2Detail({ i18n }) {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={record?.help_text}
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={googleOAuth2?.[key]}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -72,7 +72,7 @@ describe('<GoogleOAuth2Detail />', () => {
|
||||
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', '{}');
|
||||
|
||||
@ -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 && <ContentError error={error} />}
|
||||
{!isLoading && jobs && (
|
||||
<DetailList>
|
||||
{Array.from(jobs).map(([, detail]) => {
|
||||
{jobs.map(([key, detail]) => {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={detail?.label}
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={detail?.help_text}
|
||||
label={detail?.label}
|
||||
type={detail?.type}
|
||||
unit={detail?.unit}
|
||||
value={detail?.value}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -52,9 +52,9 @@ describe('<JobsDetail />', () => {
|
||||
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('<JobsDetail />', () => {
|
||||
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',
|
||||
|
||||
@ -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 (
|
||||
<PageSection>
|
||||
<Card>
|
||||
<Switch>
|
||||
<Redirect from={baseURL} to={`${baseURL}/default/details`} exact />
|
||||
{baseRoute && <Redirect to={`${baseURL}/default/details`} exact />}
|
||||
{categoryRoute && (
|
||||
<Redirect
|
||||
to={`${baseURL}/${categoryRoute.params.category}/details`}
|
||||
exact
|
||||
/>
|
||||
)}
|
||||
<Route path={`${baseURL}/:category/details`}>
|
||||
<LDAPDetail />
|
||||
</Route>
|
||||
|
||||
@ -49,7 +49,7 @@ describe('<LDAP />', () => {
|
||||
|
||||
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(<LDAP />, {
|
||||
|
||||
@ -138,12 +138,15 @@ function LDAPDetail({ i18n }) {
|
||||
{!isLoading && error && <ContentError error={error} />}
|
||||
{!isLoading && !Object.values(LDAPDetails)?.includes(null) && (
|
||||
<DetailList>
|
||||
{Array.from(LDAPDetails[category]).map(([, detail]) => {
|
||||
{LDAPDetails[category].map(([key, detail]) => {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={detail?.label}
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={detail?.help_text}
|
||||
label={detail?.label}
|
||||
type={detail?.type}
|
||||
unit={detail?.unit}
|
||||
value={detail?.value}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -82,7 +82,7 @@ describe('<LDAPDetail />', () => {
|
||||
'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', '[]');
|
||||
|
||||
@ -84,8 +84,11 @@ function LoggingDetail({ i18n }) {
|
||||
{logging.map(([key, detail]) => (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={detail?.help_text}
|
||||
label={detail?.label}
|
||||
type={detail?.type}
|
||||
unit={detail?.unit}
|
||||
value={detail?.value}
|
||||
/>
|
||||
))}
|
||||
|
||||
@ -58,7 +58,7 @@ describe('<LoggingDetail />', () => {
|
||||
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,
|
||||
|
||||
@ -125,8 +125,11 @@ function MiscSystemDetail({ i18n }) {
|
||||
{system.map(([key, detail]) => (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={detail?.help_text}
|
||||
label={detail?.label}
|
||||
type={detail?.type}
|
||||
unit={detail?.unit}
|
||||
value={detail?.value}
|
||||
/>
|
||||
))}
|
||||
|
||||
@ -69,24 +69,28 @@ describe('<MiscSystemDetail />', () => {
|
||||
});
|
||||
|
||||
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('<MiscSystemDetail />', () => {
|
||||
);
|
||||
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', '[]');
|
||||
});
|
||||
|
||||
@ -62,8 +62,11 @@ function RADIUSDetail({ i18n }) {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={record?.help_text}
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={radius?.[key]}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -62,8 +62,11 @@ function SAMLDetail({ i18n }) {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={record?.help_text}
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={saml?.[key]}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -75,7 +75,11 @@ describe('<SAMLDetail />', () => {
|
||||
'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',
|
||||
|
||||
@ -62,8 +62,11 @@ function TACACSDetail({ i18n }) {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={record?.help_text}
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={tacacs?.[key]}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -55,7 +55,7 @@ describe('<TACACSDetail />', () => {
|
||||
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');
|
||||
});
|
||||
|
||||
|
||||
@ -77,8 +77,11 @@ function UIDetail({ i18n }) {
|
||||
return (
|
||||
<SettingDetail
|
||||
key={key}
|
||||
id={key}
|
||||
helpText={record?.help_text}
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={ui?.[key]}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -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 = (
|
||||
<VariablesDetail
|
||||
label={label}
|
||||
rows={4}
|
||||
value={JSON.stringify(value || {}, undefined, 2)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'list':
|
||||
detail = <VariablesDetail rows={4} label={label} value={value} />;
|
||||
break;
|
||||
case 'image':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
label={label}
|
||||
value={<img src={value} alt={label} height="40" width="40" />}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'encrypted':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
isEncrypted
|
||||
label={label}
|
||||
value={i18n._(t`Encrypted`)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'boolean':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
label={label}
|
||||
value={value ? i18n._(t`On`) : i18n._(t`Off`)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'choice':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
label={label}
|
||||
value={!value ? i18n._(t`Unconfigured`) : value}
|
||||
isUnconfigured={!value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'integer':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
label={label}
|
||||
value={!value ? i18n._(t`Unconfigured`) : value}
|
||||
isUnconfigured={!value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'string':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
label={label}
|
||||
value={!value ? i18n._(t`Unconfigured`) : value}
|
||||
isUnconfigured={!value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
detail = null;
|
||||
switch (dataType) {
|
||||
case 'nested object':
|
||||
detail = (
|
||||
<VariablesDetail
|
||||
dataCy={id}
|
||||
label={label}
|
||||
helpText={helpText}
|
||||
rows={4}
|
||||
value={JSON.stringify(value || {}, undefined, 2)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'list':
|
||||
detail = (
|
||||
<VariablesDetail
|
||||
dataCy={id}
|
||||
helpText={helpText}
|
||||
rows={4}
|
||||
label={label}
|
||||
value={value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'image':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
dataCy={id}
|
||||
helpText={helpText}
|
||||
isNotConfigured={!value}
|
||||
label={label}
|
||||
value={
|
||||
!value ? (
|
||||
i18n._(t`Not configured`)
|
||||
) : (
|
||||
<img src={value} alt={label} height="40" width="40" />
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'encrypted':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
dataCy={id}
|
||||
helpText={helpText}
|
||||
isEncrypted
|
||||
label={label}
|
||||
value={i18n._(t`Encrypted`)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'boolean':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
dataCy={id}
|
||||
helpText={helpText}
|
||||
label={label}
|
||||
value={value ? i18n._(t`On`) : i18n._(t`Off`)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'choice':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
dataCy={id}
|
||||
helpText={helpText}
|
||||
isNotConfigured={!value}
|
||||
label={label}
|
||||
value={!value ? i18n._(t`Not configured`) : value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'integer':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
dataCy={id}
|
||||
helpText={helpText}
|
||||
label={label}
|
||||
value={unit ? `${value} ${unit}` : `${value}`}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'string':
|
||||
detail = (
|
||||
<Detail
|
||||
alwaysVisible
|
||||
dataCy={id}
|
||||
helpText={helpText}
|
||||
isNotConfigured={!value}
|
||||
label={label}
|
||||
value={!value ? i18n._(t`Not configured`) : value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
detail = null;
|
||||
}
|
||||
return detail;
|
||||
}
|
||||
return detail;
|
||||
});
|
||||
);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user