diff --git a/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.jsx b/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.jsx index 2b1cff9115..3bc824fca8 100644 --- a/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.jsx +++ b/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.jsx @@ -161,7 +161,7 @@ const InventorySourceFormFields = ({ source, sourceOptions, i18n }) => { /> )} - {sourceField.value !== '' && ( + {!['', 'custom'].includes(sourceField.value) && ( {i18n._(t`Source details`)} diff --git a/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.test.jsx b/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.test.jsx index abc07f0e93..7ba2ee8925 100644 --- a/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.test.jsx +++ b/awx/ui_next/src/screens/Inventory/shared/InventorySourceForm.test.jsx @@ -93,7 +93,8 @@ describe('<InventorySourceForm />', () => { id: 2, 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('button[aria-label="Save"]').simulate('click'); }); diff --git a/awx/ui_next/src/screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.jsx b/awx/ui_next/src/screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.jsx index efc15fe001..fdc1ea0cb4 100644 --- a/awx/ui_next/src/screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.jsx +++ b/awx/ui_next/src/screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.jsx @@ -1,13 +1,17 @@ -import React, { useCallback, useEffect } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { useField, useFormikContext } from 'formik'; import { withI18n } from '@lingui/react'; 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 useRequest from '../../../../util/useRequest'; import { required } from '../../../../util/validators'; -import AnsibleSelect from '../../../../components/AnsibleSelect'; import CredentialLookup from '../../../../components/Lookup/CredentialLookup'; import ProjectLookup from '../../../../components/Lookup/ProjectLookup'; import Popover from '../../../../components/Popover'; @@ -21,6 +25,7 @@ import { } from './SharedFields'; const SCMSubForm = ({ autoPopulateProject, i18n }) => { + const [isOpen, setIsOpen] = useState(false); const { setFieldValue, setFieldTouched } = useFormikContext(); const [credentialField] = useField('credential'); const [projectField, projectMeta, projectHelpers] = useField({ @@ -106,26 +111,25 @@ const SCMSubForm = ({ autoPopulateProject, i18n }) => { /> } > - <AnsibleSelect - {...sourcePathField} + <Select + variant={SelectVariant.typeahead} + onToggle={setIsOpen} + isOpen={isOpen} + selections={sourcePathField.value} id="source_path" isValid={ (!sourcePathMeta.error || !sourcePathMeta.touched) && !sourcePathError?.message } - data={[ - { - value: '', - key: '', - label: i18n._(t`Choose an inventory file`), - isDisabled: true, - }, - ...sourcePath.map(value => ({ value, label: value, key: value })), - ]} - onChange={(event, value) => { + onSelect={(event, value) => { sourcePathHelpers.setValue(value); }} - /> + isCreateable={false} + > + {sourcePath.map(path => ( + <SelectOption key={path} value={path} /> + ))} + </Select> </FormGroup> <VerbosityField /> <HostFilterField /> diff --git a/awx/ui_next/src/screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.test.jsx b/awx/ui_next/src/screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.test.jsx index fdd4fdb317..a394f76b52 100644 --- a/awx/ui_next/src/screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.test.jsx +++ b/awx/ui_next/src/screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.test.jsx @@ -89,16 +89,16 @@ describe('<SCMSubForm />', () => { }); 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 wrapper.find('AnsibleSelect#source_path').prop('onChange')( - null, - 'bar' - ); + await wrapper.find('Select#source_path').prop('onToggle')(); }); 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' ); @@ -109,6 +109,6 @@ describe('<SCMSubForm />', () => { }); }); wrapper.update(); - expect(wrapper.find('AnsibleSelect#source_path').prop('value')).toEqual(''); + expect(wrapper.find('Select#source_path').prop('selections')).toEqual(''); }); }); diff --git a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx index 43897e3803..7b8675cc65 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx @@ -145,12 +145,9 @@ describe('<JobTemplateAdd />', () => { summary_fields: { organization: { id: 1, name: 'Org Foo' } }, }); wrapper.update(); - wrapper - .find('PlaybookSelect') - .prop('field') - .onChange({ - target: { value: 'Baz', name: 'playbook' }, - }); + wrapper.find('Select#template-playbook').prop('onToggle')(); + wrapper.update(); + wrapper.find('Select#template-playbook').prop('onSelect')(null, 'Baz'); }); wrapper.update(); act(() => { @@ -207,12 +204,9 @@ describe('<JobTemplateAdd />', () => { summary_fields: { organization: { id: 1, name: 'Org Foo' } }, }); wrapper.update(); - wrapper - .find('PlaybookSelect') - .prop('field') - .onChange({ - target: { value: 'Bar', name: 'playbook' }, - }); + wrapper.find('Select#template-playbook').prop('onToggle')(); + wrapper.update(); + wrapper.find('Select#template-playbook').prop('onSelect')(null, 'Bar'); }); wrapper.update(); act(() => { diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx index e3bd18ec19..f504224507 100644 --- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx +++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx @@ -307,9 +307,10 @@ function JobTemplateForm({ } > <PlaybookSelect + onChange={playbookHelpers.setValue} projectId={projectField.value?.id} isValid={!playbookMeta.touched || !playbookMeta.error} - field={playbookField} + selected={playbookField.value} onBlur={() => playbookHelpers.setTouched()} onError={setContentError} /> diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx index 55b485c438..3eaa244e92 100644 --- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx +++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx @@ -200,9 +200,12 @@ describe('<JobTemplateForm />', () => { 'devel' ); wrapper.find('TextInputBase#template-limit').prop('onChange')(1234567890); - wrapper.find('AnsibleSelect[name="playbook"]').simulate('change', { - target: { value: 'new baz type', name: 'playbook' }, - }); + wrapper.find('Select#template-playbook').prop('onToggle')(); + wrapper.update(); + wrapper.find('Select#template-playbook').prop('onSelect')( + null, + 'new baz type' + ); }); await act(async () => { @@ -237,9 +240,9 @@ describe('<JobTemplateForm />', () => { expect(wrapper.find('input#template-limit').prop('value')).toEqual( 1234567890 ); - expect( - wrapper.find('AnsibleSelect[name="playbook"]').prop('value') - ).toEqual('new baz type'); + expect(wrapper.find('Select#template-playbook').prop('selections')).toEqual( + 'new baz type' + ); expect(wrapper.find('MultiCredentialsLookup').prop('value')).toEqual([ { id: 2, diff --git a/awx/ui_next/src/screens/Template/shared/PlaybookSelect.jsx b/awx/ui_next/src/screens/Template/shared/PlaybookSelect.jsx index 5a66cc0a78..ebd0f6dc96 100644 --- a/awx/ui_next/src/screens/Template/shared/PlaybookSelect.jsx +++ b/awx/ui_next/src/screens/Template/shared/PlaybookSelect.jsx @@ -2,12 +2,21 @@ import React, { useCallback, useEffect, useState } from 'react'; import { number, string, oneOfType } from 'prop-types'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import AnsibleSelect from '../../../components/AnsibleSelect'; +import { SelectVariant, Select, SelectOption } from '@patternfly/react-core'; import { ProjectsAPI } from '../../../api'; 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 [isOpen, setIsOpen] = useState(false); const { result: options, request: fetchOptions, @@ -20,21 +29,8 @@ function PlaybookSelect({ projectId, isValid, field, onBlur, onError, i18n }) { } const { data } = await ProjectsAPI.readPlaybooks(projectId); - const opts = (data || []).map(playbook => ({ - value: playbook, - key: playbook, - label: playbook, - isDisabled: false, - })); - - opts.unshift({ - value: '', - key: '', - label: i18n._(t`Choose a playbook`), - isDisabled: false, - }); - return opts; - }, [projectId, i18n]), + return data; + }, [projectId]), [] ); @@ -52,23 +48,26 @@ function PlaybookSelect({ projectId, isValid, field, onBlur, onError, i18n }) { } }, [error, onError]); - const isDisabledData = [ - { - value: field.value || '', - label: field.value || '', - key: 1, - isDisabled: true, - }, - ]; 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" - data={isDisabled ? isDisabledData : options} isValid={isValid} - {...field} onBlur={onBlur} isDisabled={isLoading || isDisabled} - /> + > + {options.map(opt => ( + <SelectOption key={opt} value={opt} /> + ))} + </Select> ); } PlaybookSelect.propTypes = {