diff --git a/awx/ui_next/src/screens/User/UserDetail/UserDetail.jsx b/awx/ui_next/src/screens/User/UserDetail/UserDetail.jsx index e4c0a1adfd..83d8ea77b0 100644 --- a/awx/ui_next/src/screens/User/UserDetail/UserDetail.jsx +++ b/awx/ui_next/src/screens/User/UserDetail/UserDetail.jsx @@ -3,7 +3,7 @@ import { Link, useHistory } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { Button } from '@patternfly/react-core'; +import { Button, Label } from '@patternfly/react-core'; import AlertModal from '../../../components/AlertModal'; import { CardBody, CardActionsRow } from '../../../components/Card'; import DeleteButton from '../../../components/DeleteButton'; @@ -46,6 +46,13 @@ function UserDetail({ user, i18n }) { user_type = i18n._(t`Normal User`); } + let userAuthType; + if (user.ldap_dn) { + userAuthType = i18n._(t`LDAP`); + } else if (user.auth.length > 0) { + userAuthType = i18n._(t`SOCIAL`); + } + return ( @@ -58,6 +65,14 @@ function UserDetail({ user, i18n }) { + {userAuthType && ( + {userAuthType} + } + /> + )} {last_login && ( ', () => { - test('initially renders succesfully', () => { + test('initially renders successfully', () => { mountWithContexts(); }); @@ -22,6 +22,7 @@ describe('', () => { expect(wrapper.find(`Detail[label="${label}"] dt`).text()).toBe(label); expect(wrapper.find(`Detail[label="${label}"] dd`).text()).toBe(value); } + assertDetail('Username', mockDetails.username); assertDetail('Email', mockDetails.email); assertDetail('First Name', mockDetails.first_name); @@ -29,6 +30,7 @@ describe('', () => { assertDetail('User Type', 'System Administrator'); assertDetail('Last Login', `11/4/2019, 11:12:36 PM`); assertDetail('Created', `10/28/2019, 3:01:07 PM`); + assertDetail('Type', `SOCIAL`); }); test('User Type Detail should render expected strings', async () => { diff --git a/awx/ui_next/src/screens/User/UserList/UserListItem.jsx b/awx/ui_next/src/screens/User/UserList/UserListItem.jsx index b772a47566..9015b1675d 100644 --- a/awx/ui_next/src/screens/User/UserList/UserListItem.jsx +++ b/awx/ui_next/src/screens/User/UserList/UserListItem.jsx @@ -10,6 +10,7 @@ import { DataListItem, DataListItemCells, DataListItemRow, + Label, Tooltip, } from '@patternfly/react-core'; @@ -31,6 +32,9 @@ function UserListItem({ user, isSelected, onSelect, detailUrl, i18n }) { user_type = i18n._(t`Normal User`); } + const ldapUser = user.ldap_dn; + const socialAuthUser = user.auth.length > 0; + return ( @@ -43,9 +47,25 @@ function UserListItem({ user, isSelected, onSelect, detailUrl, i18n }) { - - {user.username} - + + + {user.username} + + + {ldapUser && ( + + + + )} + {socialAuthUser && ( + + + + )} , { expect(wrapper.find('PencilAltIcon').exists()).toBeTruthy(); }); - test('should display user type', () => { + test('should display user data', () => { expect( wrapper.find('DataListCell[aria-label="user type"]').prop('children') ).toEqual('System Administrator'); + expect( + wrapper.find('Label[aria-label="social login"]').prop('children') + ).toEqual('SOCIAL'); }); }); diff --git a/awx/ui_next/src/screens/User/data.user.json b/awx/ui_next/src/screens/User/data.user.json index fc71d1f128..c9d598f47c 100644 --- a/awx/ui_next/src/screens/User/data.user.json +++ b/awx/ui_next/src/screens/User/data.user.json @@ -30,6 +30,10 @@ "is_system_auditor": false, "ldap_dn": "", "last_login": "2019-11-04T23:12:36.777783Z", - "external_account": null, - "auth": [] + "external_account": "social", + "auth": [ + { + "provider": "github-org", + "uid": "9053044" + }] } \ No newline at end of file diff --git a/awx/ui_next/src/screens/User/shared/UserForm.jsx b/awx/ui_next/src/screens/User/shared/UserForm.jsx index 144f514c29..dbadf2d17a 100644 --- a/awx/ui_next/src/screens/User/shared/UserForm.jsx +++ b/awx/ui_next/src/screens/User/shared/UserForm.jsx @@ -18,6 +18,10 @@ function UserFormFields({ user, i18n }) { const [organization, setOrganization] = useState(null); const { setFieldValue } = useFormikContext(); + const ldapUser = user.ldap_dn; + const socialAuthUser = user.auth?.length > 0; + const externalAccount = user.external_account; + const userTypeOptions = [ { value: 'normal', @@ -63,8 +67,12 @@ function UserFormFields({ user, i18n }) { label={i18n._(t`Username`)} name="username" type="text" - validate={required(null, i18n)} - isRequired + validate={ + !ldapUser && externalAccount === null + ? required(null, i18n) + : () => undefined + } + isRequired={!ldapUser && externalAccount === null} /> - undefined - } - isRequired={!user.id} - /> - undefined - } - isRequired={!user.id} - /> + {!ldapUser && !(socialAuthUser && externalAccount) && ( + <> + undefined + } + isRequired={!user.id} + /> + undefined + } + isRequired={!user.id} + /> + + )} ', () => { await act(async () => { wrapper = mountWithContexts( @@ -125,6 +125,22 @@ describe('', () => { expect(passwordFields.at(1).prop('isRequired')).toBe(false); }); + test('password fields are not displayed for social/ldap login', async () => { + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + + const passwordFields = wrapper.find('PasswordField'); + + expect(passwordFields.length).toBe(0); + }); + test('should call handleSubmit when Submit button is clicked', async () => { const handleSubmit = jest.fn(); await act(async () => {