[Cases] Assignees enhancements (#144836)

WIP

This PR implements some enhancements for the assignees feature that
wasn't completed in 8.5.

Issue: https://github.com/elastic/kibana/issues/141057
Fixes: https://github.com/elastic/kibana/issues/140889

### List sorting

The current user is not brought to the front of lists (only in the
popovers). Unknown users are still placed at the end of the list.

<details><summary>Current user is sorted like other users</summary>

#### Case View Page


![image](https://user-images.githubusercontent.com/56361221/200646181-9744622f-fe11-41c5-97ac-ce7b777d47a1.png)

#### Case List Page Avatars


![image](https://user-images.githubusercontent.com/56361221/200646269-b637743f-35f1-48d0-91bd-faee32784613.png)


</details>

### Limit assignee selection

Leverage the `limit` prop exposed by the `UserProfilesSelectable` here:
https://github.com/elastic/kibana/pull/144618

<details><summary>Adding limit message</summary>


![image](https://user-images.githubusercontent.com/56361221/200653672-9c195031-3117-4ac9-b6e9-98ac11ee170e.png)


</details>

### Show the selected count

Show the selected count even when it is zero so the component doesn't
jump around.

<details><summary>Selected count</summary>

#### View case page


![image](https://user-images.githubusercontent.com/56361221/200659972-a6eca466-0d4c-4736-9a2e-62b422f99944.png)

#### All cases filter


![image](https://user-images.githubusercontent.com/56361221/200660181-da13092b-6f6a-4b2d-98cd-325ebf8d75b1.png)


</details>

### Expandable assignees column

Added a button to expand/collapse the assignee avatars column on the all
cases list page

<details><summary>Cases list page assignees column</summary>


![image](https://user-images.githubusercontent.com/56361221/200891826-08f15531-3a47-40c1-9cc6-12558b645083.png)


![image](https://user-images.githubusercontent.com/56361221/200892014-92cd3142-15d0-4250-b83e-b32b1c9dd03f.png)


</details>

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Jonathan Buttner 2022-11-14 08:27:10 -05:00 committed by GitHub
parent ec849e5bd8
commit 1e77d8d10d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 373 additions and 150 deletions

View file

@ -199,7 +199,6 @@ export const AllCasesList = React.memo<AllCasesListProps>(
const { columns } = useCasesColumns({
filterStatus: filterOptions.status ?? StatusAll,
userProfiles: userProfiles ?? new Map(),
currentUserProfile,
isSelectorView,
connectors,
onRowClick,

View file

@ -0,0 +1,154 @@
/*
* 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 { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer } from '../../common/mock';
import { userProfiles, userProfilesMap } from '../../containers/user_profiles/api.mock';
import type { AssigneesColumnProps } from './assignees_column';
import { AssigneesColumn } from './assignees_column';
describe('AssigneesColumn', () => {
const defaultProps: AssigneesColumnProps = {
assignees: userProfiles,
userProfiles: userProfilesMap,
compressedDisplayLimit: 2,
};
let appMockRender: AppMockRenderer;
beforeEach(() => {
jest.clearAllMocks();
appMockRender = createAppMockRenderer();
});
it('renders a long dash if the assignees is an empty array', async () => {
const props = {
...defaultProps,
assignees: [],
};
appMockRender.render(<AssigneesColumn {...props} />);
expect(
screen.queryByTestId('case-table-column-assignee-damaged_raccoon')
).not.toBeInTheDocument();
expect(screen.queryByTestId('case-table-column-expand-button')).not.toBeInTheDocument();
// u2014 is the unicode for a long dash
expect(screen.getByText('\u2014')).toBeInTheDocument();
});
it('only renders 2 avatars when the limit is 2', async () => {
const props = {
...defaultProps,
};
appMockRender.render(<AssigneesColumn {...props} />);
expect(screen.getByTestId('case-table-column-assignee-damaged_raccoon')).toBeInTheDocument();
expect(screen.getByTestId('case-table-column-assignee-physical_dinosaur')).toBeInTheDocument();
});
it('renders all 3 avatars when the limit is 5', async () => {
const props = {
...defaultProps,
compressedDisplayLimit: 5,
};
appMockRender.render(<AssigneesColumn {...props} />);
expect(screen.getByTestId('case-table-column-assignee-damaged_raccoon')).toBeInTheDocument();
expect(screen.getByTestId('case-table-column-assignee-physical_dinosaur')).toBeInTheDocument();
expect(screen.getByTestId('case-table-column-assignee-wet_dingo')).toBeInTheDocument();
});
it('shows the show more avatars button when the limit is 2', async () => {
const props = {
...defaultProps,
compressedDisplayLimit: 2,
};
appMockRender.render(<AssigneesColumn {...props} />);
expect(screen.getByTestId('case-table-column-expand-button')).toBeInTheDocument();
expect(screen.getByText('+1 more')).toBeInTheDocument();
});
it('does not show the show more button when the limit is 5', async () => {
const props = {
...defaultProps,
compressedDisplayLimit: 5,
};
appMockRender.render(<AssigneesColumn {...props} />);
expect(screen.queryByTestId('case-table-column-expand-button')).not.toBeInTheDocument();
});
it('does not show the show more button when the limit is the same number of the assignees', async () => {
const props = {
...defaultProps,
compressedDisplayLimit: userProfiles.length,
};
appMockRender.render(<AssigneesColumn {...props} />);
expect(screen.queryByTestId('case-table-column-expand-button')).not.toBeInTheDocument();
});
it('displays the show less avatars button when the show more is clicked', async () => {
const props = {
...defaultProps,
compressedDisplayLimit: 2,
};
appMockRender.render(<AssigneesColumn {...props} />);
expect(screen.queryByTestId('case-table-column-assignee-wet_dingo')).not.toBeInTheDocument();
expect(screen.getByTestId('case-table-column-expand-button')).toBeInTheDocument();
expect(screen.getByText('+1 more')).toBeInTheDocument();
userEvent.click(screen.getByTestId('case-table-column-expand-button'));
await waitFor(() => {
expect(screen.getByText('show less')).toBeInTheDocument();
expect(screen.getByTestId('case-table-column-assignee-wet_dingo')).toBeInTheDocument();
});
});
it('shows more avatars and then hides them when the expand row button is clicked multiple times', async () => {
const props = {
...defaultProps,
compressedDisplayLimit: 2,
};
appMockRender.render(<AssigneesColumn {...props} />);
expect(screen.queryByTestId('case-table-column-assignee-wet_dingo')).not.toBeInTheDocument();
expect(screen.getByTestId('case-table-column-expand-button')).toBeInTheDocument();
expect(screen.getByText('+1 more')).toBeInTheDocument();
userEvent.click(screen.getByTestId('case-table-column-expand-button'));
await waitFor(() => {
expect(screen.getByText('show less')).toBeInTheDocument();
expect(screen.getByTestId('case-table-column-assignee-wet_dingo')).toBeInTheDocument();
});
userEvent.click(screen.getByTestId('case-table-column-expand-button'));
await waitFor(() => {
expect(screen.getByText('+1 more')).toBeInTheDocument();
expect(screen.queryByTestId('case-table-column-assignee-wet_dingo')).not.toBeInTheDocument();
});
});
});

View file

@ -0,0 +1,97 @@
/*
* 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, { useCallback, useMemo, useState } from 'react';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import type { UserProfileWithAvatar } from '@kbn/user-profile-components';
import type { Case } from '../../../common/ui/types';
import { getEmptyTagValue } from '../empty_value';
import { UserToolTip } from '../user_profiles/user_tooltip';
import { useAssignees } from '../../containers/user_profiles/use_assignees';
import { getUsernameDataTestSubj } from '../user_profiles/data_test_subject';
import { SmallUserAvatar } from '../user_profiles/small_user_avatar';
import * as i18n from './translations';
const COMPRESSED_AVATAR_LIMIT = 3;
export interface AssigneesColumnProps {
assignees: Case['assignees'];
userProfiles: Map<string, UserProfileWithAvatar>;
compressedDisplayLimit?: number;
}
const AssigneesColumnComponent: React.FC<AssigneesColumnProps> = ({
assignees,
userProfiles,
compressedDisplayLimit = COMPRESSED_AVATAR_LIMIT,
}) => {
const [isAvatarListExpanded, setIsAvatarListExpanded] = useState<boolean>(false);
const { allAssignees } = useAssignees({
caseAssignees: assignees,
userProfiles,
});
const toggleExpandedAvatars = useCallback(
() => setIsAvatarListExpanded((prevState) => !prevState),
[]
);
const numHiddenAvatars = allAssignees.length - compressedDisplayLimit;
const shouldShowExpandListButton = numHiddenAvatars > 0;
const limitedAvatars = useMemo(
() => allAssignees.slice(0, compressedDisplayLimit),
[allAssignees, compressedDisplayLimit]
);
const avatarsToDisplay = useMemo(() => {
if (isAvatarListExpanded || !shouldShowExpandListButton) {
return allAssignees;
}
return limitedAvatars;
}, [allAssignees, isAvatarListExpanded, limitedAvatars, shouldShowExpandListButton]);
if (allAssignees.length <= 0) {
return getEmptyTagValue();
}
return (
<EuiFlexGroup gutterSize="xs" data-test-subj="case-table-column-assignee" wrap>
{avatarsToDisplay.map((assignee) => {
const dataTestSubjName = getUsernameDataTestSubj(assignee);
return (
<EuiFlexItem
grow={false}
key={assignee.uid}
data-test-subj={`case-table-column-assignee-${dataTestSubjName}`}
>
<UserToolTip userInfo={assignee.profile}>
<SmallUserAvatar userInfo={assignee.profile} />
</UserToolTip>
</EuiFlexItem>
);
})}
{shouldShowExpandListButton ? (
<EuiButtonEmpty
size="xs"
data-test-subj="case-table-column-expand-button"
onClick={toggleExpandedAvatars}
style={{ alignSelf: 'center' }}
>
{isAvatarListExpanded ? i18n.SHOW_LESS : i18n.SHOW_MORE(numHiddenAvatars)}
</EuiButtonEmpty>
) : null}
</EuiFlexGroup>
);
};
AssigneesColumnComponent.displayName = 'AssigneesColumn';
export const AssigneesColumn = React.memo(AssigneesColumnComponent);

View file

@ -15,7 +15,6 @@ import { useCasesContext } from '../cases_context/use_cases_context';
import type { CurrentUserProfile } from '../types';
import { EmptyMessage } from '../user_profiles/empty_message';
import { NoMatches } from '../user_profiles/no_matches';
import { SelectedStatusMessage } from '../user_profiles/selected_status_message';
import { bringCurrentUserToFrontAndSort, orderAssigneesIncludingNone } from '../user_profiles/sort';
import type { AssigneesFilteringSelection } from '../user_profiles/types';
import * as i18n from './translations';
@ -53,12 +52,7 @@ const AssigneesFilterPopoverComponent: React.FC<AssigneesFilterPopoverProps> = (
);
const selectedStatusMessage = useCallback(
(selectedCount: number) => (
<SelectedStatusMessage
selectedCount={selectedCount}
message={i18n.TOTAL_ASSIGNEES_FILTERED(selectedCount)}
/>
),
(selectedCount: number) => i18n.TOTAL_ASSIGNEES_FILTERED(selectedCount),
[]
);

View file

@ -137,3 +137,13 @@ export const NO_ASSIGNEES = i18n.translate(
defaultMessage: 'No assignees',
}
);
export const SHOW_LESS = i18n.translate('xpack.cases.allCasesView.showLessAvatars', {
defaultMessage: 'show less',
});
export const SHOW_MORE = (count: number) =>
i18n.translate('xpack.cases.allCasesView.showMoreAvatars', {
defaultMessage: '+{count} more',
values: { count },
});

View file

@ -18,14 +18,13 @@ import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer, readCasesPermissions, TestProviders } from '../../common/mock';
import { renderHook } from '@testing-library/react-hooks';
import { CaseStatuses } from '../../../common';
import { userProfilesMap, userProfiles } from '../../containers/user_profiles/api.mock';
import { userProfilesMap } from '../../containers/user_profiles/api.mock';
describe('useCasesColumns ', () => {
let appMockRender: AppMockRenderer;
const useCasesColumnsProps: GetCasesColumn = {
filterStatus: CaseStatuses.open,
userProfiles: userProfilesMap,
currentUserProfile: userProfiles[0],
isSelectorView: false,
showSolutionColumn: true,
};
@ -58,6 +57,7 @@ describe('useCasesColumns ', () => {
"field": "assignees",
"name": "Assignees",
"render": [Function],
"width": "180px",
},
Object {
"field": "tags",
@ -112,6 +112,86 @@ describe('useCasesColumns ', () => {
`);
});
it('returns the assignees column without the width specified when in the modal view', async () => {
const license = licensingMock.createLicense({
license: { type: 'platinum' },
});
appMockRender = createAppMockRenderer({ license });
const { result } = renderHook(
() => useCasesColumns({ ...useCasesColumnsProps, isSelectorView: true }),
{
wrapper: appMockRender.AppWrapper,
}
);
expect(result.current).toMatchInlineSnapshot(`
Object {
"columns": Array [
Object {
"name": "Name",
"render": [Function],
"width": "20%",
},
Object {
"field": "assignees",
"name": "Assignees",
"render": [Function],
"width": undefined,
},
Object {
"field": "tags",
"name": "Tags",
"render": [Function],
"width": "15%",
},
Object {
"align": "right",
"field": "totalAlerts",
"name": "Alerts",
"render": [Function],
"width": "80px",
},
Object {
"align": "right",
"field": "owner",
"name": "Solution",
"render": [Function],
},
Object {
"align": "right",
"field": "totalComment",
"name": "Comments",
"render": [Function],
},
Object {
"field": "createdAt",
"name": "Created on",
"render": [Function],
"sortable": true,
},
Object {
"name": "External Incident",
"render": [Function],
},
Object {
"name": "Status",
"render": [Function],
},
Object {
"name": "Severity",
"render": [Function],
},
Object {
"align": "right",
"render": [Function],
},
],
}
`);
});
it('does not render the solution columns', async () => {
const license = licensingMock.createLicense({
license: { type: 'platinum' },
@ -138,6 +218,7 @@ describe('useCasesColumns ', () => {
"field": "assignees",
"name": "Assignees",
"render": [Function],
"width": "180px",
},
Object {
"field": "tags",
@ -209,6 +290,7 @@ describe('useCasesColumns ', () => {
"field": "assignees",
"name": "Assignees",
"render": [Function],
"width": "180px",
},
Object {
"field": "tags",

View file

@ -43,12 +43,8 @@ import { TruncatedText } from '../truncated_text';
import { getConnectorIcon } from '../utils';
import type { CasesOwners } from '../../client/helpers/can_use_cases';
import { severities } from '../severity/config';
import { UserToolTip } from '../user_profiles/user_tooltip';
import { useAssignees } from '../../containers/user_profiles/use_assignees';
import { getUsernameDataTestSubj } from '../user_profiles/data_test_subject';
import type { CurrentUserProfile } from '../types';
import { SmallUserAvatar } from '../user_profiles/small_user_avatar';
import { useCasesFeatures } from '../../common/use_cases_features';
import { AssigneesColumn } from './assignees_column';
type CasesColumns =
| EuiTableActionsColumnType<Case>
@ -76,47 +72,9 @@ const StyledEuiBadge = euiStyled(EuiBadge)`
const renderStringField = (field: string, dataTestSubj: string) =>
field != null ? <span data-test-subj={dataTestSubj}>{field}</span> : getEmptyTagValue();
const AssigneesColumn: React.FC<{
assignees: Case['assignees'];
userProfiles: Map<string, UserProfileWithAvatar>;
currentUserProfile: CurrentUserProfile;
}> = ({ assignees, userProfiles, currentUserProfile }) => {
const { allAssignees } = useAssignees({
caseAssignees: assignees,
userProfiles,
currentUserProfile,
});
if (allAssignees.length <= 0) {
return getEmptyTagValue();
}
return (
<EuiFlexGroup gutterSize="none" data-test-subj="case-table-column-assignee" wrap>
{allAssignees.map((assignee) => {
const dataTestSubjName = getUsernameDataTestSubj(assignee);
return (
<EuiFlexItem
grow={false}
key={assignee.uid}
data-test-subj={`case-table-column-assignee-${dataTestSubjName}`}
>
<UserToolTip userInfo={assignee.profile}>
<SmallUserAvatar userInfo={assignee.profile} />
</UserToolTip>
</EuiFlexItem>
);
})}
</EuiFlexGroup>
);
};
AssigneesColumn.displayName = 'AssigneesColumn';
export interface GetCasesColumn {
filterStatus: string;
userProfiles: Map<string, UserProfileWithAvatar>;
currentUserProfile: CurrentUserProfile;
isSelectorView: boolean;
connectors?: ActionConnector[];
onRowClick?: (theCase: Case) => void;
@ -131,7 +89,6 @@ export interface UseCasesColumnsReturnValue {
export const useCasesColumns = ({
filterStatus,
userProfiles,
currentUserProfile,
isSelectorView,
connectors = [],
onRowClick,
@ -184,12 +141,9 @@ export const useCasesColumns = ({
field: 'assignees',
name: i18n.ASSIGNEES,
render: (assignees: Case['assignees']) => (
<AssigneesColumn
assignees={assignees}
userProfiles={userProfiles}
currentUserProfile={currentUserProfile}
/>
<AssigneesColumn assignees={assignees} userProfiles={userProfiles} />
),
width: !isSelectorView ? '180px' : undefined,
});
}

View file

@ -104,7 +104,6 @@ const AssignUsersComponent: React.FC<AssignUsersProps> = ({
const { assigneesWithProfiles, assigneesWithoutProfiles, allAssignees } = useAssignees({
caseAssignees,
userProfiles,
currentUserProfile,
});
const [selectedAssignees, setSelectedAssignees] = useState<Assignee[] | undefined>();

View file

@ -36,7 +36,7 @@ describe('SuggestUsersPopover', () => {
};
});
it.skip('calls onUsersChange when 1 user is selected', async () => {
it('calls onUsersChange when 1 user is selected', async () => {
const onUsersChange = jest.fn();
const props = { ...defaultProps, onUsersChange };
appMockRender.render(<SuggestUsersPopover {...props} />);
@ -182,7 +182,7 @@ describe('SuggestUsersPopover', () => {
expect(screen.getByText('1 assigned')).toBeInTheDocument();
});
it.skip('shows the 1 assigned total after clicking on a user', async () => {
it('shows the 1 assigned total after clicking on a user', async () => {
appMockRender.render(<SuggestUsersPopover {...defaultProps} />);
await waitForEuiPopoverOpen();

View file

@ -11,12 +11,12 @@ import { UserProfilesPopover } from '@kbn/user-profile-components';
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
import { isEmpty } from 'lodash';
import { MAX_ASSIGNEES_PER_CASE } from '../../../../common/constants';
import { useSuggestUserProfiles } from '../../../containers/user_profiles/use_suggest_user_profiles';
import { useCasesContext } from '../../cases_context/use_cases_context';
import type { AssigneeWithProfile } from '../../user_profiles/types';
import * as i18n from '../translations';
import { bringCurrentUserToFrontAndSort } from '../../user_profiles/sort';
import { SelectedStatusMessage } from '../../user_profiles/selected_status_message';
import { EmptyMessage } from '../../user_profiles/empty_message';
import { NoMatches } from '../../user_profiles/no_matches';
import type { CurrentUserProfile } from '../../types';
@ -79,12 +79,12 @@ const SuggestUsersPopoverComponent: React.FC<SuggestUsersPopoverProps> = ({
);
const selectedStatusMessage = useCallback(
(selectedCount: number) => (
<SelectedStatusMessage
selectedCount={selectedCount}
message={i18n.TOTAL_USERS_ASSIGNED(selectedCount)}
/>
),
(selectedCount: number) => i18n.TOTAL_USERS_ASSIGNED(selectedCount),
[]
);
const limitReachedMessage = useCallback(
(limit: number) => i18n.MAX_SELECTED_ASSIGNEES(limit),
[]
);
@ -131,6 +131,8 @@ const SuggestUsersPopoverComponent: React.FC<SuggestUsersPopoverProps> = ({
selectedOptions: selectedUsers ?? selectedProfiles,
isLoading: isLoadingData,
height: 'full',
limit: MAX_ASSIGNEES_PER_CASE,
limitReachedMessage,
searchPlaceholder: i18n.SEARCH_USERS,
clearButtonLabel: i18n.REMOVE_ASSIGNEES,
emptyMessage: <EmptyMessage />,

View file

@ -1,24 +0,0 @@
/*
* 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 { render, screen } from '@testing-library/react';
import { SelectedStatusMessage } from './selected_status_message';
describe('SelectedStatusMessage', () => {
it('does not render if the count is 0', () => {
const { container } = render(<SelectedStatusMessage selectedCount={0} message={'hello'} />);
expect(container.firstChild).toBeNull();
expect(screen.queryByText('hello')).not.toBeInTheDocument();
});
it('renders the message when the count is great than 0', () => {
render(<SelectedStatusMessage selectedCount={1} message={'hello'} />);
expect(screen.getByText('hello')).toBeInTheDocument();
});
});

View file

@ -1,22 +0,0 @@
/*
* 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';
const SelectedStatusMessageComponent: React.FC<{
selectedCount: number;
message: string;
}> = ({ selectedCount, message }) => {
if (selectedCount <= 0) {
return null;
}
return <>{message}</>;
};
SelectedStatusMessageComponent.displayName = 'SelectedStatusMessage';
export const SelectedStatusMessage = React.memo(SelectedStatusMessageComponent);

View file

@ -65,3 +65,10 @@ export const INVALID_ASSIGNEES = i18n.translate('xpack.cases.create.invalidAssig
maxAssignees: MAX_ASSIGNEES_PER_CASE,
},
});
export const MAX_SELECTED_ASSIGNEES = (limit: number) =>
i18n.translate('xpack.cases.userProfile.maxSelectedAssignees', {
defaultMessage:
"You've selected the maximum number of {count, plural, one {# assignee} other {# assignees}}",
values: { count: limit },
});

View file

@ -13,7 +13,7 @@ import { useAssignees } from './use_assignees';
describe('useAssignees', () => {
it('returns an empty array when the caseAssignees is empty', () => {
const { result } = renderHook(() =>
useAssignees({ caseAssignees: [], userProfiles: new Map(), currentUserProfile: undefined })
useAssignees({ caseAssignees: [], userProfiles: new Map() })
);
expect(result.current.allAssignees).toHaveLength(0);
@ -26,7 +26,6 @@ describe('useAssignees', () => {
useAssignees({
caseAssignees: userProfiles.map((profile) => ({ uid: profile.uid })),
userProfiles: userProfilesMap,
currentUserProfile: undefined,
})
);
@ -41,7 +40,6 @@ describe('useAssignees', () => {
useAssignees({
caseAssignees: unsorted.map((profile) => ({ uid: profile.uid })),
userProfiles: userProfilesMap,
currentUserProfile: undefined,
})
);
@ -56,7 +54,6 @@ describe('useAssignees', () => {
useAssignees({
caseAssignees: unknownProfiles,
userProfiles: userProfilesMap,
currentUserProfile: undefined,
})
);
@ -71,7 +68,6 @@ describe('useAssignees', () => {
useAssignees({
caseAssignees: assignees,
userProfiles: userProfilesMap,
currentUserProfile: undefined,
})
);
@ -86,28 +82,6 @@ describe('useAssignees', () => {
{ uid: '1' },
]);
});
it('returns assignees with profiles with the current user at the front', () => {
const { result } = renderHook(() =>
useAssignees({
caseAssignees: userProfiles,
userProfiles: userProfilesMap,
currentUserProfile: userProfiles[2],
})
);
expect(result.current.assigneesWithProfiles).toHaveLength(3);
expect(result.current.allAssignees).toHaveLength(3);
const asAssignees = userProfiles.map(asAssigneeWithProfile);
expect(result.current.assigneesWithProfiles).toEqual([
asAssignees[2],
asAssignees[0],
asAssignees[1],
]);
expect(result.current.allAssignees).toEqual([asAssignees[2], asAssignees[0], asAssignees[1]]);
});
});
const asAssigneeWithProfile = (profile: UserProfileWithAvatar) => ({ uid: profile.uid, profile });

View file

@ -8,8 +8,7 @@
import type { UserProfileWithAvatar } from '@kbn/user-profile-components';
import { useMemo } from 'react';
import type { CaseAssignees } from '../../../common/api';
import type { CurrentUserProfile } from '../../components/types';
import { bringCurrentUserToFrontAndSort } from '../../components/user_profiles/sort';
import { sortProfiles } from '../../components/user_profiles/sort';
import type { Assignee, AssigneeWithProfile } from '../../components/user_profiles/types';
interface PartitionedAssignees {
@ -20,11 +19,9 @@ interface PartitionedAssignees {
export const useAssignees = ({
caseAssignees,
userProfiles,
currentUserProfile,
}: {
caseAssignees: CaseAssignees;
userProfiles: Map<string, UserProfileWithAvatar>;
currentUserProfile: CurrentUserProfile;
}): {
assigneesWithProfiles: AssigneeWithProfile[];
assigneesWithoutProfiles: Assignee[];
@ -46,14 +43,14 @@ export const useAssignees = ({
{ usersWithProfiles: [], usersWithoutProfiles: [] }
);
const orderedProf = bringCurrentUserToFrontAndSort(currentUserProfile, usersWithProfiles);
const orderedProf = sortProfiles(usersWithProfiles);
const assigneesWithProfile2 = orderedProf?.map((profile) => ({ uid: profile.uid, profile }));
const withProfiles = orderedProf?.map((profile) => ({ uid: profile.uid, profile }));
return {
assigneesWithProfiles: assigneesWithProfile2 ?? [],
assigneesWithProfiles: withProfiles ?? [],
assigneesWithoutProfiles: usersWithoutProfiles,
};
}, [caseAssignees, currentUserProfile, userProfiles]);
}, [caseAssignees, userProfiles]);
const allAssignees = useMemo(
() => [...assigneesWithProfiles, ...assigneesWithoutProfiles],