mirror of
https://github.com/ansible/awx.git
synced 2026-05-17 06:17:36 -02:30
Inventory File field and playbook field are both now type ahead.
This commit is contained in:
@@ -161,7 +161,7 @@ const InventorySourceFormFields = ({ source, sourceOptions, i18n }) => {
|
|||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
{sourceField.value !== '' && (
|
{!['', 'custom'].includes(sourceField.value) && (
|
||||||
<SubFormLayout>
|
<SubFormLayout>
|
||||||
<Title size="md" headingLevel="h4">
|
<Title size="md" headingLevel="h4">
|
||||||
{i18n._(t`Source details`)}
|
{i18n._(t`Source details`)}
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ describe('<InventorySourceForm />', () => {
|
|||||||
id: 2,
|
id: 2,
|
||||||
name: 'mock proj',
|
name: 'mock proj',
|
||||||
});
|
});
|
||||||
wrapper.find('AnsibleSelect#source_path').prop('onChange')(null, 'foo');
|
wrapper.find('Select#source_path').prop('onToggle')();
|
||||||
|
wrapper.find('Select#source_path').prop('onSelect')(null, 'foo');
|
||||||
wrapper.find('AnsibleSelect#verbosity').prop('onChange')(null, '2');
|
wrapper.find('AnsibleSelect#verbosity').prop('onChange')(null, '2');
|
||||||
wrapper.find('button[aria-label="Save"]').simulate('click');
|
wrapper.find('button[aria-label="Save"]').simulate('click');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import React, { useCallback, useEffect } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { useField, useFormikContext } from 'formik';
|
import { useField, useFormikContext } from 'formik';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { FormGroup } from '@patternfly/react-core';
|
import {
|
||||||
|
FormGroup,
|
||||||
|
SelectVariant,
|
||||||
|
Select,
|
||||||
|
SelectOption,
|
||||||
|
} from '@patternfly/react-core';
|
||||||
import { ProjectsAPI } from '../../../../api';
|
import { ProjectsAPI } from '../../../../api';
|
||||||
import useRequest from '../../../../util/useRequest';
|
import useRequest from '../../../../util/useRequest';
|
||||||
import { required } from '../../../../util/validators';
|
import { required } from '../../../../util/validators';
|
||||||
|
|
||||||
import AnsibleSelect from '../../../../components/AnsibleSelect';
|
|
||||||
import CredentialLookup from '../../../../components/Lookup/CredentialLookup';
|
import CredentialLookup from '../../../../components/Lookup/CredentialLookup';
|
||||||
import ProjectLookup from '../../../../components/Lookup/ProjectLookup';
|
import ProjectLookup from '../../../../components/Lookup/ProjectLookup';
|
||||||
import Popover from '../../../../components/Popover';
|
import Popover from '../../../../components/Popover';
|
||||||
@@ -21,6 +25,7 @@ import {
|
|||||||
} from './SharedFields';
|
} from './SharedFields';
|
||||||
|
|
||||||
const SCMSubForm = ({ autoPopulateProject, i18n }) => {
|
const SCMSubForm = ({ autoPopulateProject, i18n }) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const { setFieldValue, setFieldTouched } = useFormikContext();
|
const { setFieldValue, setFieldTouched } = useFormikContext();
|
||||||
const [credentialField] = useField('credential');
|
const [credentialField] = useField('credential');
|
||||||
const [projectField, projectMeta, projectHelpers] = useField({
|
const [projectField, projectMeta, projectHelpers] = useField({
|
||||||
@@ -106,26 +111,25 @@ const SCMSubForm = ({ autoPopulateProject, i18n }) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<AnsibleSelect
|
<Select
|
||||||
{...sourcePathField}
|
variant={SelectVariant.typeahead}
|
||||||
|
onToggle={setIsOpen}
|
||||||
|
isOpen={isOpen}
|
||||||
|
selections={sourcePathField.value}
|
||||||
id="source_path"
|
id="source_path"
|
||||||
isValid={
|
isValid={
|
||||||
(!sourcePathMeta.error || !sourcePathMeta.touched) &&
|
(!sourcePathMeta.error || !sourcePathMeta.touched) &&
|
||||||
!sourcePathError?.message
|
!sourcePathError?.message
|
||||||
}
|
}
|
||||||
data={[
|
onSelect={(event, value) => {
|
||||||
{
|
|
||||||
value: '',
|
|
||||||
key: '',
|
|
||||||
label: i18n._(t`Choose an inventory file`),
|
|
||||||
isDisabled: true,
|
|
||||||
},
|
|
||||||
...sourcePath.map(value => ({ value, label: value, key: value })),
|
|
||||||
]}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
sourcePathHelpers.setValue(value);
|
sourcePathHelpers.setValue(value);
|
||||||
}}
|
}}
|
||||||
/>
|
isCreateable={false}
|
||||||
|
>
|
||||||
|
{sourcePath.map(path => (
|
||||||
|
<SelectOption key={path} value={path} />
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<VerbosityField />
|
<VerbosityField />
|
||||||
<HostFilterField />
|
<HostFilterField />
|
||||||
|
|||||||
@@ -89,16 +89,16 @@ describe('<SCMSubForm />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('changing source project should reset source path dropdown', async () => {
|
test('changing source project should reset source path dropdown', async () => {
|
||||||
expect(wrapper.find('AnsibleSelect#source_path').prop('value')).toEqual('');
|
expect(wrapper.find('Select#source_path').prop('selections')).toEqual('');
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await wrapper.find('AnsibleSelect#source_path').prop('onChange')(
|
await wrapper.find('Select#source_path').prop('onToggle')();
|
||||||
null,
|
|
||||||
'bar'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('AnsibleSelect#source_path').prop('value')).toEqual(
|
await act(async () => {
|
||||||
|
await wrapper.find('Select#source_path').prop('onSelect')(null, 'bar');
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(wrapper.find('Select#source_path').prop('selections')).toEqual(
|
||||||
'bar'
|
'bar'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -109,6 +109,6 @@ describe('<SCMSubForm />', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('AnsibleSelect#source_path').prop('value')).toEqual('');
|
expect(wrapper.find('Select#source_path').prop('selections')).toEqual('');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -145,12 +145,9 @@ describe('<JobTemplateAdd />', () => {
|
|||||||
summary_fields: { organization: { id: 1, name: 'Org Foo' } },
|
summary_fields: { organization: { id: 1, name: 'Org Foo' } },
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
wrapper
|
wrapper.find('Select#template-playbook').prop('onToggle')();
|
||||||
.find('PlaybookSelect')
|
wrapper.update();
|
||||||
.prop('field')
|
wrapper.find('Select#template-playbook').prop('onSelect')(null, 'Baz');
|
||||||
.onChange({
|
|
||||||
target: { value: 'Baz', name: 'playbook' },
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -207,12 +204,9 @@ describe('<JobTemplateAdd />', () => {
|
|||||||
summary_fields: { organization: { id: 1, name: 'Org Foo' } },
|
summary_fields: { organization: { id: 1, name: 'Org Foo' } },
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
wrapper
|
wrapper.find('Select#template-playbook').prop('onToggle')();
|
||||||
.find('PlaybookSelect')
|
wrapper.update();
|
||||||
.prop('field')
|
wrapper.find('Select#template-playbook').prop('onSelect')(null, 'Bar');
|
||||||
.onChange({
|
|
||||||
target: { value: 'Bar', name: 'playbook' },
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
act(() => {
|
act(() => {
|
||||||
|
|||||||
@@ -307,9 +307,10 @@ function JobTemplateForm({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<PlaybookSelect
|
<PlaybookSelect
|
||||||
|
onChange={playbookHelpers.setValue}
|
||||||
projectId={projectField.value?.id}
|
projectId={projectField.value?.id}
|
||||||
isValid={!playbookMeta.touched || !playbookMeta.error}
|
isValid={!playbookMeta.touched || !playbookMeta.error}
|
||||||
field={playbookField}
|
selected={playbookField.value}
|
||||||
onBlur={() => playbookHelpers.setTouched()}
|
onBlur={() => playbookHelpers.setTouched()}
|
||||||
onError={setContentError}
|
onError={setContentError}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -200,9 +200,12 @@ describe('<JobTemplateForm />', () => {
|
|||||||
'devel'
|
'devel'
|
||||||
);
|
);
|
||||||
wrapper.find('TextInputBase#template-limit').prop('onChange')(1234567890);
|
wrapper.find('TextInputBase#template-limit').prop('onChange')(1234567890);
|
||||||
wrapper.find('AnsibleSelect[name="playbook"]').simulate('change', {
|
wrapper.find('Select#template-playbook').prop('onToggle')();
|
||||||
target: { value: 'new baz type', name: 'playbook' },
|
wrapper.update();
|
||||||
});
|
wrapper.find('Select#template-playbook').prop('onSelect')(
|
||||||
|
null,
|
||||||
|
'new baz type'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -237,9 +240,9 @@ describe('<JobTemplateForm />', () => {
|
|||||||
expect(wrapper.find('input#template-limit').prop('value')).toEqual(
|
expect(wrapper.find('input#template-limit').prop('value')).toEqual(
|
||||||
1234567890
|
1234567890
|
||||||
);
|
);
|
||||||
expect(
|
expect(wrapper.find('Select#template-playbook').prop('selections')).toEqual(
|
||||||
wrapper.find('AnsibleSelect[name="playbook"]').prop('value')
|
'new baz type'
|
||||||
).toEqual('new baz type');
|
);
|
||||||
expect(wrapper.find('MultiCredentialsLookup').prop('value')).toEqual([
|
expect(wrapper.find('MultiCredentialsLookup').prop('value')).toEqual([
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
|
|||||||
@@ -2,12 +2,21 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||||||
import { number, string, oneOfType } from 'prop-types';
|
import { number, string, oneOfType } from 'prop-types';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import AnsibleSelect from '../../../components/AnsibleSelect';
|
import { SelectVariant, Select, SelectOption } from '@patternfly/react-core';
|
||||||
import { ProjectsAPI } from '../../../api';
|
import { ProjectsAPI } from '../../../api';
|
||||||
import useRequest from '../../../util/useRequest';
|
import useRequest from '../../../util/useRequest';
|
||||||
|
|
||||||
function PlaybookSelect({ projectId, isValid, field, onBlur, onError, i18n }) {
|
function PlaybookSelect({
|
||||||
|
projectId,
|
||||||
|
isValid,
|
||||||
|
selected,
|
||||||
|
onBlur,
|
||||||
|
onError,
|
||||||
|
onChange,
|
||||||
|
i18n,
|
||||||
|
}) {
|
||||||
const [isDisabled, setIsDisabled] = useState(false);
|
const [isDisabled, setIsDisabled] = useState(false);
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const {
|
const {
|
||||||
result: options,
|
result: options,
|
||||||
request: fetchOptions,
|
request: fetchOptions,
|
||||||
@@ -20,21 +29,8 @@ function PlaybookSelect({ projectId, isValid, field, onBlur, onError, i18n }) {
|
|||||||
}
|
}
|
||||||
const { data } = await ProjectsAPI.readPlaybooks(projectId);
|
const { data } = await ProjectsAPI.readPlaybooks(projectId);
|
||||||
|
|
||||||
const opts = (data || []).map(playbook => ({
|
return data;
|
||||||
value: playbook,
|
}, [projectId]),
|
||||||
key: playbook,
|
|
||||||
label: playbook,
|
|
||||||
isDisabled: false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
opts.unshift({
|
|
||||||
value: '',
|
|
||||||
key: '',
|
|
||||||
label: i18n._(t`Choose a playbook`),
|
|
||||||
isDisabled: false,
|
|
||||||
});
|
|
||||||
return opts;
|
|
||||||
}, [projectId, i18n]),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -52,23 +48,26 @@ function PlaybookSelect({ projectId, isValid, field, onBlur, onError, i18n }) {
|
|||||||
}
|
}
|
||||||
}, [error, onError]);
|
}, [error, onError]);
|
||||||
|
|
||||||
const isDisabledData = [
|
|
||||||
{
|
|
||||||
value: field.value || '',
|
|
||||||
label: field.value || '',
|
|
||||||
key: 1,
|
|
||||||
isDisabled: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return (
|
return (
|
||||||
<AnsibleSelect
|
<Select
|
||||||
|
isOpen={isOpen}
|
||||||
|
variant={SelectVariant.typeahead}
|
||||||
|
selections={selected}
|
||||||
|
onToggle={setIsOpen}
|
||||||
|
placeholderText={i18n._(t`Select a playbook`)}
|
||||||
|
isCreateable={false}
|
||||||
|
onSelect={(event, value) => {
|
||||||
|
onChange(value);
|
||||||
|
}}
|
||||||
id="template-playbook"
|
id="template-playbook"
|
||||||
data={isDisabled ? isDisabledData : options}
|
|
||||||
isValid={isValid}
|
isValid={isValid}
|
||||||
{...field}
|
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
isDisabled={isLoading || isDisabled}
|
isDisabled={isLoading || isDisabled}
|
||||||
/>
|
>
|
||||||
|
{options.map(opt => (
|
||||||
|
<SelectOption key={opt} value={opt} />
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
PlaybookSelect.propTypes = {
|
PlaybookSelect.propTypes = {
|
||||||
|
|||||||
Reference in New Issue
Block a user