Skip to content

Commit

Permalink
Port elastic#3904 to Kibana
Browse files Browse the repository at this point in the history
  • Loading branch information
scottybollinger committed Jun 24, 2021
1 parent 4e38dfe commit 37832fe
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import React from 'react';

import { shallow } from 'enzyme';

import { UserFlyout, UserAddedInfo, UserInvitationCallout } from '../../../shared/role_mapping';
import {
UserFlyout,
UserAddedInfo,
UserInvitationCallout,
DeactivatedUserCallout,
} from '../../../shared/role_mapping';
import { elasticsearchUsers } from '../../../shared/role_mapping/__mocks__/elasticsearch_users';
import { wsSingleUserRoleMapping } from '../../../shared/role_mapping/__mocks__/roles';

Expand Down Expand Up @@ -91,6 +96,23 @@ describe('User', () => {
expect(wrapper.find(UserAddedInfo)).toHaveLength(1);
});

it('renders DeactivatedUserCallout', () => {
setMockValues({
...mockValues,
singleUserRoleMapping: {
...wsSingleUserRoleMapping,
invitation: null,
elasticsearchUser: {
...wsSingleUserRoleMapping.elasticsearchUser,
enabled: false,
},
},
});
const wrapper = shallow(<User />);

expect(wrapper.find(DeactivatedUserCallout)).toHaveLength(1);
});

it('disables form when username value not present', () => {
setMockValues({
...mockValues,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
UserSelector,
UserAddedInfo,
UserInvitationCallout,
DeactivatedUserCallout,
} from '../../../shared/role_mapping';
import { RoleTypes } from '../../types';

Expand Down Expand Up @@ -55,6 +56,11 @@ export const User: React.FC = () => {
const showEngineAssignmentSelector = hasEngines && hasAdvancedRoles;
const flyoutDisabled =
!userFormUserIsExisting && (!elasticsearchUser.email || !elasticsearchUser.username);
const userIsDeactivated = !!(
singleUserRoleMapping &&
!singleUserRoleMapping.invitation &&
!singleUserRoleMapping.elasticsearchUser.enabled
);

const userAddedInfo = singleUserRoleMapping && (
<UserAddedInfo
Expand Down Expand Up @@ -101,6 +107,7 @@ export const User: React.FC = () => {
>
{userCreated ? userAddedInfo : createUserForm}
{userInvitationCallout}
{userIsDeactivated && <DeactivatedUserCallout isNew={userFormIsNewUser} />}
</UserFlyout>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export const elasticsearchUsers = [
{
email: 'user1@user.com',
username: 'user1',
enabled: true,
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,13 @@ export const UPDATE_USER_DESCRIPTION = i18n.translate(
}
);

export const DEACTIVATED_LABEL = i18n.translate(
'xpack.enterpriseSearch.roleMapping.deactivatedLabel',
{
defaultMessage: 'Deactivated',
}
);

export const INVITATION_PENDING_LABEL = i18n.translate(
'xpack.enterpriseSearch.roleMapping.invitationPendingLabel',
{
Expand Down Expand Up @@ -422,3 +429,18 @@ export const AUTH_PROVIDER_TOOLTIP = i18n.translate(
'Provider-specific role mapping is still applied, but configuration is now deprecated.',
}
);

export const DEACTIVATED_USER_CALLOUT_LABEL = i18n.translate(
'xpack.enterpriseSearch.roleMapping.deactivatedUserCalloutLabel',
{
defaultMessage: 'User deactivated',
}
);

export const DEACTIVATED_USER_CALLOUT_DESCRIPTION = i18n.translate(
'xpack.enterpriseSearch.roleMapping.deactivatedUserCalloutDescription',
{
defaultMessage:
'This user is not currently active, and access has been temporarily revoked. Users can be re-activated via the User Management area of the Kibana console.',
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { shallow } from 'enzyme';

import { DeactivatedUserCallout } from './';

describe('DeactivatedUserCallout', () => {
it('renders with new', () => {
const wrapper = shallow(<DeactivatedUserCallout isNew />);

expect(wrapper).toMatchInlineSnapshot(`
<Fragment>
<EuiText
size="s"
>
<EuiIcon
color="warning"
type="alert"
/>

<strong>
User deactivated
</strong>
</EuiText>
<EuiSpacer
size="xs"
/>
<EuiText
size="s"
>
This user is not currently active, and access has been temporarily revoked. Users can be re-activated via the User Management area of the Kibana console.
</EuiText>
<EuiSpacer />
</Fragment>
`);
});

it('renders with existing', () => {
const wrapper = shallow(<DeactivatedUserCallout isNew={false} />);

expect(wrapper).toMatchInlineSnapshot(`
<Fragment>
<EuiSpacer />
<EuiText
size="s"
>
<EuiIcon
color="warning"
type="alert"
/>

<strong>
User deactivated
</strong>
</EuiText>
<EuiSpacer
size="xs"
/>
<EuiText
size="s"
>
This user is not currently active, and access has been temporarily revoked. Users can be re-activated via the User Management area of the Kibana console.
</EuiText>
<EuiSpacer />
</Fragment>
`);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { EuiSpacer, EuiText, EuiIcon } from '@elastic/eui';

interface Props {
isNew: boolean;
}

import { DEACTIVATED_USER_CALLOUT_LABEL, DEACTIVATED_USER_CALLOUT_DESCRIPTION } from './constants';

export const DeactivatedUserCallout: React.FC<Props> = ({ isNew }) => (
<>
{!isNew && <EuiSpacer />}
<EuiText size="s">
<EuiIcon type="alert" color="warning" /> <strong>{DEACTIVATED_USER_CALLOUT_LABEL}</strong>
</EuiText>
<EuiSpacer size="xs" />
<EuiText size="s">{DEACTIVATED_USER_CALLOUT_DESCRIPTION}</EuiText>
<EuiSpacer />
</>
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

export { AttributeSelector } from './attribute_selector';
export { DeactivatedUserCallout } from './deactivated_user_callout';
export { RolesEmptyPrompt } from './roles_empty_prompt';
export { RoleMappingsTable } from './role_mappings_table';
export { RoleOptionLabel } from './role_option_label';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import React from 'react';

import { shallow, mount } from 'enzyme';

import { EuiInMemoryTable, EuiTextColor } from '@elastic/eui';
import { EuiInMemoryTable, EuiTextColor, EuiBadge } from '@elastic/eui';

import { engines } from '../../app_search/__mocks__/engines.mock';

Expand All @@ -27,6 +27,7 @@ describe('UsersTable', () => {
singleUserRoleMappings: [wsSingleUserRoleMapping],
initializeSingleUserRoleMapping,
handleDeleteMapping,
enabled: true,
};

it('renders', () => {
Expand Down Expand Up @@ -55,6 +56,7 @@ describe('UsersTable', () => {
elasticsearchUser: {
email: null,
username: 'foo',
enabled: true,
},
};
const wrapper = mount(<UsersTable {...props} singleUserRoleMappings={[userWithNoEmail]} />);
Expand Down Expand Up @@ -97,4 +99,20 @@ describe('UsersTable', () => {
`${engines[0].name}, ${engines[1].name} + 1`
);
});

it('renders deactivatedBadge', () => {
const disabledUser = {
...wsSingleUserRoleMapping,
elasticsearchUser: {
email: 'email@user.com',
username: 'foo',
enabled: false,
},
invitation: null,
};
const wrapper = mount(<UsersTable {...props} singleUserRoleMappings={[disabledUser]} />);
const cell = wrapper.find('[data-test-subj="UsernameCell"]');

expect(cell.find(EuiBadge)).toHaveLength(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { WSRoleMapping } from '../../workplace_search/types';

import {
INVITATION_PENDING_LABEL,
DEACTIVATED_LABEL,
ALL_LABEL,
FILTER_USERS_LABEL,
NO_USERS_LABEL,
Expand All @@ -37,6 +38,7 @@ interface SharedUser extends SingleUserRoleMapping<ASRoleMapping | WSRoleMapping
email: string | null;
roleType: string;
id: string;
enabled: boolean;
}

interface SharedRoleMapping extends ASRoleMapping, WSRoleMapping {
Expand All @@ -52,6 +54,7 @@ interface Props {

const noItemsPlaceholder = <EuiTextColor color="subdued">&mdash;</EuiTextColor>;
const invitationBadge = <EuiBadge color="hollow">{INVITATION_PENDING_LABEL}</EuiBadge>;
const deactivatedBadge = <EuiBadge color="hollow">{DEACTIVATED_LABEL}</EuiBadge>;

export const UsersTable: React.FC<Props> = ({
accessItemKey,
Expand All @@ -63,6 +66,7 @@ export const UsersTable: React.FC<Props> = ({
const users = ((singleUserRoleMappings as SharedUser[]).map((user) => ({
username: user.elasticsearchUser.username,
email: user.elasticsearchUser.email,
enabled: user.elasticsearchUser.enabled,
roleType: user.roleMapping.roleType,
id: user.roleMapping.id,
accessItems: (user.roleMapping as SharedRoleMapping)[accessItemKey],
Expand All @@ -73,7 +77,11 @@ export const UsersTable: React.FC<Props> = ({
{
field: 'username',
name: USERNAME_LABEL,
render: (_, { username }: SharedUser) => username,
render: (_, { username, invitation, enabled }: SharedUser) => (
<div data-test-subj="UsernameCell">
{username} {!invitation && !enabled && deactivatedBadge}
</div>
),
},
{
field: 'email',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ export interface Invitation {
export interface ElasticsearchUser {
email: string | null;
username: string;
enabled: boolean;
}

export interface SingleUserRoleMapping<T> {
invitation: Invitation;
invitation: Invitation | null;
elasticsearchUser: ElasticsearchUser;
roleMapping: T;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import React from 'react';

import { shallow } from 'enzyme';

import { UserFlyout, UserAddedInfo, UserInvitationCallout } from '../../../shared/role_mapping';
import {
UserFlyout,
UserAddedInfo,
UserInvitationCallout,
DeactivatedUserCallout,
} from '../../../shared/role_mapping';
import { elasticsearchUsers } from '../../../shared/role_mapping/__mocks__/elasticsearch_users';
import { wsSingleUserRoleMapping } from '../../../shared/role_mapping/__mocks__/roles';

Expand Down Expand Up @@ -90,6 +95,23 @@ describe('User', () => {
expect(wrapper.find(UserAddedInfo)).toHaveLength(1);
});

it('renders DeactivatedUserCallout', () => {
setMockValues({
...mockValues,
singleUserRoleMapping: {
...wsSingleUserRoleMapping,
invitation: null,
elasticsearchUser: {
...wsSingleUserRoleMapping.elasticsearchUser,
enabled: false,
},
},
});
const wrapper = shallow(<User />);

expect(wrapper.find(DeactivatedUserCallout)).toHaveLength(1);
});

it('disables form when username value not present', () => {
setMockValues({
...mockValues,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
UserSelector,
UserAddedInfo,
UserInvitationCallout,
DeactivatedUserCallout,
} from '../../../shared/role_mapping';
import { Role } from '../../types';

Expand Down Expand Up @@ -52,6 +53,11 @@ export const User: React.FC = () => {
const hasAvailableUsers = elasticsearchUsers.length > 0;
const flyoutDisabled =
(!userFormUserIsExisting || !hasAvailableUsers) && !elasticsearchUser.username;
const userIsDeactivated = !!(
singleUserRoleMapping &&
!singleUserRoleMapping.invitation &&
!singleUserRoleMapping.elasticsearchUser.enabled
);

const userAddedInfo = singleUserRoleMapping && (
<UserAddedInfo
Expand Down Expand Up @@ -98,6 +104,7 @@ export const User: React.FC = () => {
>
{userCreated ? userAddedInfo : createUserForm}
{userInvitationCallout}
{userIsDeactivated && <DeactivatedUserCallout isNew={userFormIsNewUser} />}
</UserFlyout>
);
};

0 comments on commit 37832fe

Please sign in to comment.