mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 01:57:35 -03:30
Add general updates for User screen
* Add type of login used as part of UserListItem. * Add type of login used as part of UserDetail. * Hide password field, UserForm, in case login method is LDAP or Social. * Make username field, UserForm, not required in case login is LDAP or Social. See: https://github.com/ansible/awx/issues/5685
This commit is contained in:
parent
e6c124962b
commit
1dd7651d49
@ -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 (
|
||||
<CardBody>
|
||||
<DetailList>
|
||||
@ -58,6 +65,14 @@ function UserDetail({ user, i18n }) {
|
||||
<Detail label={i18n._(t`First Name`)} value={`${first_name}`} />
|
||||
<Detail label={i18n._(t`Last Name`)} value={`${last_name}`} />
|
||||
<Detail label={i18n._(t`User Type`)} value={`${user_type}`} />
|
||||
{userAuthType && (
|
||||
<Detail
|
||||
label={i18n._(t`Type`)}
|
||||
value={
|
||||
<Label aria-label={i18n._(t`login type`)}>{userAuthType}</Label>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{last_login && (
|
||||
<Detail
|
||||
label={i18n._(t`Last Login`)}
|
||||
|
||||
@ -12,7 +12,7 @@ import mockDetails from '../data.user.json';
|
||||
jest.mock('../../../api');
|
||||
|
||||
describe('<UserDetail />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
test('initially renders successfully', () => {
|
||||
mountWithContexts(<UserDetail user={mockDetails} />);
|
||||
});
|
||||
|
||||
@ -22,6 +22,7 @@ describe('<UserDetail />', () => {
|
||||
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('<UserDetail />', () => {
|
||||
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 () => {
|
||||
|
||||
@ -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 (
|
||||
<DataListItem key={user.id} aria-labelledby={labelId} id={`${user.id}`}>
|
||||
<DataListItemRow>
|
||||
@ -43,9 +47,25 @@ function UserListItem({ user, isSelected, onSelect, detailUrl, i18n }) {
|
||||
<DataListItemCells
|
||||
dataListCells={[
|
||||
<DataListCell key="username" aria-label={i18n._(t`username`)}>
|
||||
<Link to={`${detailUrl}`} id={labelId}>
|
||||
<b>{user.username}</b>
|
||||
</Link>
|
||||
<span id={labelId}>
|
||||
<Link to={`${detailUrl}`} id={labelId}>
|
||||
<b>{user.username}</b>
|
||||
</Link>
|
||||
</span>
|
||||
{ldapUser && (
|
||||
<span css="margin-left: 12px">
|
||||
<Label aria-label={i18n._(t`ldap user`)}>
|
||||
{i18n._(t`LDAP`)}
|
||||
</Label>
|
||||
</span>
|
||||
)}
|
||||
{socialAuthUser && (
|
||||
<span css="margin-left: 12px">
|
||||
<Label aria-label={i18n._(t`social login`)}>
|
||||
{i18n._(t`SOCIAL`)}
|
||||
</Label>
|
||||
</span>
|
||||
)}
|
||||
</DataListCell>,
|
||||
<DataListCell
|
||||
key="first-name"
|
||||
|
||||
@ -35,10 +35,13 @@ describe('UserListItem with full permissions', () => {
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -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"
|
||||
}]
|
||||
}
|
||||
@ -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}
|
||||
/>
|
||||
<FormField
|
||||
id="user-email"
|
||||
@ -73,28 +81,32 @@ function UserFormFields({ user, i18n }) {
|
||||
validate={requiredEmail(i18n)}
|
||||
isRequired
|
||||
/>
|
||||
<PasswordField
|
||||
id="user-password"
|
||||
label={i18n._(t`Password`)}
|
||||
name="password"
|
||||
validate={
|
||||
!user.id
|
||||
? required(i18n._(t`This field must not be blank`), i18n)
|
||||
: () => undefined
|
||||
}
|
||||
isRequired={!user.id}
|
||||
/>
|
||||
<PasswordField
|
||||
id="user-confirm-password"
|
||||
label={i18n._(t`Confirm Password`)}
|
||||
name="confirm_password"
|
||||
validate={
|
||||
!user.id
|
||||
? required(i18n._(t`This field must not be blank`), i18n)
|
||||
: () => undefined
|
||||
}
|
||||
isRequired={!user.id}
|
||||
/>
|
||||
{!ldapUser && !(socialAuthUser && externalAccount) && (
|
||||
<>
|
||||
<PasswordField
|
||||
id="user-password"
|
||||
label={i18n._(t`Password`)}
|
||||
name="password"
|
||||
validate={
|
||||
!user.id
|
||||
? required(i18n._(t`This field must not be blank`), i18n)
|
||||
: () => undefined
|
||||
}
|
||||
isRequired={!user.id}
|
||||
/>
|
||||
<PasswordField
|
||||
id="user-confirm-password"
|
||||
label={i18n._(t`Confirm Password`)}
|
||||
name="confirm_password"
|
||||
validate={
|
||||
!user.id
|
||||
? required(i18n._(t`This field must not be blank`), i18n)
|
||||
: () => undefined
|
||||
}
|
||||
isRequired={!user.id}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<FormField
|
||||
id="user-first-name"
|
||||
label={i18n._(t`First Name`)}
|
||||
|
||||
@ -111,7 +111,7 @@ describe('<UserForm />', () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<UserForm
|
||||
user={mockData}
|
||||
user={{ ...mockData, external_account: '', auth: [] }}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
/>
|
||||
@ -125,6 +125,22 @@ describe('<UserForm />', () => {
|
||||
expect(passwordFields.at(1).prop('isRequired')).toBe(false);
|
||||
});
|
||||
|
||||
test('password fields are not displayed for social/ldap login', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<UserForm
|
||||
user={mockData}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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 () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user