diff --git a/awx/ui_next/src/components/Lookup/CredentialLookup.jsx b/awx/ui_next/src/components/Lookup/CredentialLookup.jsx new file mode 100644 index 0000000000..4d5cf86cb0 --- /dev/null +++ b/awx/ui_next/src/components/Lookup/CredentialLookup.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { withI18n } from '@lingui/react'; +import { bool, func, number, string } from 'prop-types'; +import { CredentialsAPI } from '@api'; +import { Credential } from '@types'; +import { mergeParams } from '@util/qs'; +import { FormGroup } from '@patternfly/react-core'; +import Lookup from '@components/Lookup'; + +function CredentialLookup({ + helperTextInvalid, + label, + isValid, + onBlur, + onChange, + required, + credentialTypeId, + value, +}) { + const getCredentials = async params => + CredentialsAPI.read( + mergeParams(params, { credential_type: credentialTypeId }) + ); + + return ( + + + + ); +} + +CredentialLookup.propTypes = { + credentialTypeId: number.isRequired, + helperTextInvalid: string, + isValid: bool, + label: string.isRequired, + onBlur: func, + onChange: func.isRequired, + required: bool, + value: Credential, +}; + +CredentialLookup.defaultProps = { + helperTextInvalid: '', + isValid: true, + onBlur: () => {}, + required: false, + value: null, +}; + +export { CredentialLookup as _CredentialLookup }; +export default withI18n()(CredentialLookup); diff --git a/awx/ui_next/src/components/Lookup/CredentialLookup.test.jsx b/awx/ui_next/src/components/Lookup/CredentialLookup.test.jsx new file mode 100644 index 0000000000..797cbdf6c2 --- /dev/null +++ b/awx/ui_next/src/components/Lookup/CredentialLookup.test.jsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { mountWithContexts } from '@testUtils/enzymeHelpers'; +import CredentialLookup, { _CredentialLookup } from './CredentialLookup'; +import { CredentialsAPI } from '@api'; + +jest.mock('@api'); + +describe('CredentialLookup', () => { + let wrapper; + + beforeEach(() => { + wrapper = mountWithContexts( + {}} /> + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('initially renders successfully', () => { + expect(wrapper.find('CredentialLookup')).toHaveLength(1); + }); + test('should fetch credentials', () => { + expect(CredentialsAPI.read).toHaveBeenCalledTimes(1); + expect(CredentialsAPI.read).toHaveBeenCalledWith({ + credential_type: 1, + order_by: 'name', + page: 1, + page_size: 5, + }); + }); + test('should display label', () => { + const title = wrapper.find('FormGroup .pf-c-form__label-text'); + expect(title.text()).toEqual('Foo'); + }); + test('should define default value for function props', () => { + expect(_CredentialLookup.defaultProps.onBlur).toBeInstanceOf(Function); + expect(_CredentialLookup.defaultProps.onBlur).not.toThrow(); + }); +}); diff --git a/awx/ui_next/src/components/Lookup/OrganizationLookup.jsx b/awx/ui_next/src/components/Lookup/OrganizationLookup.jsx new file mode 100644 index 0000000000..8efb43b091 --- /dev/null +++ b/awx/ui_next/src/components/Lookup/OrganizationLookup.jsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { string, func, bool } from 'prop-types'; +import { OrganizationsAPI } from '@api'; +import { Organization } from '@types'; +import { FormGroup } from '@patternfly/react-core'; +import Lookup from '@components/Lookup'; + +const getOrganizations = async params => OrganizationsAPI.read(params); + +function OrganizationLookup({ + helperTextInvalid, + i18n, + isValid, + onBlur, + onChange, + required, + value, +}) { + return ( + + + + ); +} + +OrganizationLookup.propTypes = { + helperTextInvalid: string, + isValid: bool, + onBlur: func, + onChange: func.isRequired, + required: bool, + value: Organization, +}; + +OrganizationLookup.defaultProps = { + helperTextInvalid: '', + isValid: true, + onBlur: () => {}, + required: false, + value: null, +}; + +export default withI18n()(OrganizationLookup); +export { OrganizationLookup as _OrganizationLookup }; diff --git a/awx/ui_next/src/components/Lookup/OrganizationLookup.test.jsx b/awx/ui_next/src/components/Lookup/OrganizationLookup.test.jsx new file mode 100644 index 0000000000..fef9a90281 --- /dev/null +++ b/awx/ui_next/src/components/Lookup/OrganizationLookup.test.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { mountWithContexts } from '@testUtils/enzymeHelpers'; +import OrganizationLookup, { _OrganizationLookup } from './OrganizationLookup'; +import { OrganizationsAPI } from '@api'; + +jest.mock('@api'); + +describe('OrganizationLookup', () => { + let wrapper; + + beforeEach(() => { + wrapper = mountWithContexts( {}} />); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('initially renders successfully', () => { + expect(wrapper).toHaveLength(1); + }); + test('should fetch organizations', () => { + expect(OrganizationsAPI.read).toHaveBeenCalledTimes(1); + expect(OrganizationsAPI.read).toHaveBeenCalledWith({ + order_by: 'name', + page: 1, + page_size: 5, + }); + }); + test('should display "Organization" label', () => { + const title = wrapper.find('FormGroup .pf-c-form__label-text'); + expect(title.text()).toEqual('Organization'); + }); + test('should define default value for function props', () => { + expect(_OrganizationLookup.defaultProps.onBlur).toBeInstanceOf(Function); + expect(_OrganizationLookup.defaultProps.onBlur).not.toThrow(); + }); +});