mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.12] [Cases] Table Solution Filter Not Rendering Any Checked Option When All Selected (#172460) (#173244)
# Backport This will backport the following commits from `main` to `8.12`: - [[Cases] Table Solution Filter Not Rendering Any Checked Option When All Selected (#172460)](https://github.com/elastic/kibana/pull/172460) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Julian Gernun","email":"17549662+jcger@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-12-13T09:30:49Z","message":"[Cases] Table Solution Filter Not Rendering Any Checked Option When All Selected (#172460)\n\nCo-authored-by: Christos Nasikas <christos.nasikas@elastic.co>","sha":"b6d291d1034752515b56439d4b2437f085cd2147","branchLabelMapping":{"^v8.13.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","Team:ResponseOps","Feature:Cases","v8.12.0","v8.13.0"],"number":172460,"url":"https://github.com/elastic/kibana/pull/172460","mergeCommit":{"message":"[Cases] Table Solution Filter Not Rendering Any Checked Option When All Selected (#172460)\n\nCo-authored-by: Christos Nasikas <christos.nasikas@elastic.co>","sha":"b6d291d1034752515b56439d4b2437f085cd2147"}},"sourceBranch":"main","suggestedTargetBranches":["8.12"],"targetPullRequestStates":[{"branch":"8.12","label":"v8.12.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.13.0","labelRegex":"^v8.13.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/172460","number":172460,"mergeCommit":{"message":"[Cases] Table Solution Filter Not Rendering Any Checked Option When All Selected (#172460)\n\nCo-authored-by: Christos Nasikas <christos.nasikas@elastic.co>","sha":"b6d291d1034752515b56439d4b2437f085cd2147"}}]}] BACKPORT--> Co-authored-by: Julian Gernun <17549662+jcger@users.noreply.github.com>
This commit is contained in:
parent
77bcd6e612
commit
f54ca50f98
11 changed files with 207 additions and 168 deletions
|
@ -516,7 +516,6 @@ describe('AllCasesListGeneric', () => {
|
|||
filterOptions: {
|
||||
...DEFAULT_FILTER_OPTIONS,
|
||||
searchFields: ['title', 'description'],
|
||||
owner: ['securitySolution'],
|
||||
category: ['twix'],
|
||||
},
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
|
@ -645,82 +644,6 @@ describe('AllCasesListGeneric', () => {
|
|||
});
|
||||
|
||||
describe('Solutions', () => {
|
||||
it('should set the owner to all available solutions when deselecting all solutions', async () => {
|
||||
const { getByTestId } = render(
|
||||
<TestProviders owner={[]}>
|
||||
<AllCasesList />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(useGetCasesMock).toHaveBeenCalledWith({
|
||||
filterOptions: {
|
||||
search: '',
|
||||
searchFields: ['title', 'description'],
|
||||
severity: [],
|
||||
reporters: [],
|
||||
status: [],
|
||||
tags: [],
|
||||
assignees: [],
|
||||
owner: ['securitySolution', 'observability'],
|
||||
category: [],
|
||||
customFields: {},
|
||||
},
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
});
|
||||
|
||||
userEvent.click(getByTestId('options-filter-popover-button-owner'));
|
||||
|
||||
await waitForEuiPopoverOpen();
|
||||
|
||||
userEvent.click(
|
||||
getByTestId(`options-filter-popover-item-${SECURITY_SOLUTION_OWNER}`),
|
||||
undefined,
|
||||
{
|
||||
skipPointerEventsCheck: true,
|
||||
}
|
||||
);
|
||||
|
||||
expect(useGetCasesMock).toBeCalledWith({
|
||||
filterOptions: {
|
||||
search: '',
|
||||
searchFields: ['title', 'description'],
|
||||
severity: [],
|
||||
reporters: [],
|
||||
status: [],
|
||||
tags: [],
|
||||
assignees: [],
|
||||
owner: ['securitySolution'],
|
||||
category: [],
|
||||
customFields: {},
|
||||
},
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
});
|
||||
|
||||
userEvent.click(
|
||||
getByTestId(`options-filter-popover-item-${SECURITY_SOLUTION_OWNER}`),
|
||||
undefined,
|
||||
{
|
||||
skipPointerEventsCheck: true,
|
||||
}
|
||||
);
|
||||
|
||||
expect(useGetCasesMock).toHaveBeenLastCalledWith({
|
||||
filterOptions: {
|
||||
search: '',
|
||||
searchFields: ['title', 'description'],
|
||||
severity: [],
|
||||
reporters: [],
|
||||
status: [],
|
||||
tags: [],
|
||||
assignees: [],
|
||||
owner: ['securitySolution', 'observability'],
|
||||
category: [],
|
||||
customFields: {},
|
||||
},
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
});
|
||||
});
|
||||
|
||||
it('should hide the solutions filter if the owner is provided', async () => {
|
||||
const { queryByTestId } = render(
|
||||
<TestProviders owner={[SECURITY_SOLUTION_OWNER]}>
|
||||
|
@ -730,30 +653,6 @@ describe('AllCasesListGeneric', () => {
|
|||
|
||||
expect(queryByTestId('options-filter-popover-button-owner')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should call useGetCases with the correct owner on initial render', async () => {
|
||||
render(
|
||||
<TestProviders owner={[SECURITY_SOLUTION_OWNER]}>
|
||||
<AllCasesList />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(useGetCasesMock).toHaveBeenCalledWith({
|
||||
filterOptions: {
|
||||
search: '',
|
||||
searchFields: ['title', 'description'],
|
||||
severity: [],
|
||||
reporters: [],
|
||||
status: [],
|
||||
tags: [],
|
||||
assignees: [],
|
||||
owner: ['securitySolution'],
|
||||
category: [],
|
||||
customFields: {},
|
||||
},
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Actions', () => {
|
||||
|
@ -1102,7 +1001,6 @@ describe('AllCasesListGeneric', () => {
|
|||
expect(useGetCasesMock).toHaveBeenLastCalledWith({
|
||||
filterOptions: {
|
||||
...DEFAULT_FILTER_OPTIONS,
|
||||
owner: [SECURITY_SOLUTION_OWNER],
|
||||
assignees: [],
|
||||
},
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
|
|
|
@ -63,10 +63,10 @@ export const AllCasesList = React.memo<AllCasesListProps>(
|
|||
const isLoading = useIsLoadingCases();
|
||||
|
||||
const hasOwner = !!owner.length;
|
||||
|
||||
const firstAvailableStatus = head(difference(caseStatuses, hiddenStatuses));
|
||||
const initialFilterOptions = {
|
||||
...(!isEmpty(hiddenStatuses) && firstAvailableStatus && { status: [firstAvailableStatus] }),
|
||||
owner: hasOwner ? owner : availableSolutions,
|
||||
};
|
||||
|
||||
const { queryParams, setQueryParams, filterOptions, setFilterOptions } = useAllCasesState(
|
||||
|
@ -210,7 +210,6 @@ export const AllCasesList = React.memo<AllCasesListProps>(
|
|||
availableSolutions={hasOwner ? [] : availableSolutions}
|
||||
hiddenStatuses={hiddenStatuses}
|
||||
onCreateCasePressed={onCreateCasePressed}
|
||||
initialFilterOptions={initialFilterOptions}
|
||||
isSelectorView={isSelectorView}
|
||||
isLoading={isLoadingCurrentUserProfile}
|
||||
currentUserProfile={currentUserProfile}
|
||||
|
|
|
@ -100,7 +100,7 @@ describe('SolutionFilter ', () => {
|
|||
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
filterId: 'owner',
|
||||
selectedOptionKeys: [solutions[0]],
|
||||
selectedOptionKeys: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -168,7 +168,7 @@ describe('SolutionFilter ', () => {
|
|||
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
filterId: 'owner',
|
||||
selectedOptionKeys: [solutions[0], solutions[1]],
|
||||
selectedOptionKeys: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -43,37 +43,6 @@ export const SolutionFilterComponent = ({
|
|||
const options = mapToMultiSelectOption(hasOwner ? owner : availableSolutions);
|
||||
const solutions = availableSolutions.map((solution) => mapToReadableSolutionName(solution));
|
||||
|
||||
/**
|
||||
* If the user selects and deselects all solutions then the owner is set to an empty array.
|
||||
* This results in fetching all cases the user has access to including
|
||||
* the ones with read access. We want to show only the cases the user has full access to.
|
||||
* For that reason we fallback to availableSolutions if the owner is empty.
|
||||
*
|
||||
* If the consumer of cases has passed an owner we fallback to the provided owner
|
||||
*/
|
||||
const _onChange = ({
|
||||
filterId,
|
||||
selectedOptionKeys: newOptions,
|
||||
}: {
|
||||
filterId: string;
|
||||
selectedOptionKeys: string[];
|
||||
}) => {
|
||||
if (hasOwner) {
|
||||
onChange({
|
||||
filterId,
|
||||
selectedOptionKeys: newOptions.length === 0 ? owner : newOptions,
|
||||
});
|
||||
} else {
|
||||
onChange({
|
||||
filterId,
|
||||
selectedOptionKeys: newOptions.length === 0 ? availableSolutions : newOptions,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const selectedOptionsInFilter =
|
||||
selectedOptionKeys.length === availableSolutions.length ? [] : selectedOptionKeys;
|
||||
|
||||
const renderOption = (option: EuiSelectableOption) => {
|
||||
const solution = solutions.find((solutionData) => solutionData.id === option.label) as Solution;
|
||||
return (
|
||||
|
@ -90,10 +59,10 @@ export const SolutionFilterComponent = ({
|
|||
<MultiSelectFilter
|
||||
buttonLabel={i18n.SOLUTION}
|
||||
id={'owner'}
|
||||
onChange={_onChange}
|
||||
onChange={onChange}
|
||||
options={options}
|
||||
renderOption={renderOption}
|
||||
selectedOptionKeys={selectedOptionsInFilter}
|
||||
selectedOptionKeys={selectedOptionKeys}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import type { FilterOptions } from '../../../../common/ui';
|
||||
import type { CaseStatuses } from '../../../../common/types/domain';
|
||||
import { MAX_TAGS_FILTER_LENGTH, MAX_CATEGORY_FILTER_LENGTH } from '../../../../common/constants';
|
||||
import { MultiSelectFilter, mapToMultiSelectOption } from '../multi_select_filter';
|
||||
|
@ -28,7 +27,6 @@ interface UseFilterConfigProps {
|
|||
countOpenCases: number | null;
|
||||
currentUserProfile: CurrentUserProfile;
|
||||
hiddenStatuses?: CaseStatuses[];
|
||||
initialFilterOptions: Partial<FilterOptions>;
|
||||
isLoading: boolean;
|
||||
isSelectorView?: boolean;
|
||||
onFilterOptionsChange: FilterChangeHandler;
|
||||
|
@ -44,7 +42,6 @@ export const getSystemFilterConfig = ({
|
|||
countOpenCases,
|
||||
currentUserProfile,
|
||||
hiddenStatuses,
|
||||
initialFilterOptions,
|
||||
isLoading,
|
||||
isSelectorView,
|
||||
onFilterOptionsChange,
|
||||
|
@ -69,7 +66,7 @@ export const getSystemFilterConfig = ({
|
|||
isAvailable: true,
|
||||
getEmptyOptions: () => {
|
||||
return {
|
||||
severity: initialFilterOptions.severity || [],
|
||||
severity: [],
|
||||
};
|
||||
},
|
||||
render: ({ filterOptions }: FilterConfigRenderParams) => (
|
||||
|
@ -86,7 +83,7 @@ export const getSystemFilterConfig = ({
|
|||
isAvailable: true,
|
||||
getEmptyOptions: () => {
|
||||
return {
|
||||
status: initialFilterOptions.status || [],
|
||||
status: [],
|
||||
};
|
||||
},
|
||||
render: ({ filterOptions }: FilterConfigRenderParams) => (
|
||||
|
@ -107,7 +104,7 @@ export const getSystemFilterConfig = ({
|
|||
isAvailable: caseAssignmentAuthorized && !isSelectorView,
|
||||
getEmptyOptions: () => {
|
||||
return {
|
||||
assignees: initialFilterOptions.assignees || [],
|
||||
assignees: [],
|
||||
};
|
||||
},
|
||||
render: ({ filterOptions }: FilterConfigRenderParams) => {
|
||||
|
@ -128,7 +125,7 @@ export const getSystemFilterConfig = ({
|
|||
isAvailable: true,
|
||||
getEmptyOptions: () => {
|
||||
return {
|
||||
tags: initialFilterOptions.tags || [],
|
||||
tags: [],
|
||||
};
|
||||
},
|
||||
render: ({ filterOptions }: FilterConfigRenderParams) => (
|
||||
|
@ -150,7 +147,7 @@ export const getSystemFilterConfig = ({
|
|||
isAvailable: true,
|
||||
getEmptyOptions: () => {
|
||||
return {
|
||||
category: initialFilterOptions.category || [],
|
||||
category: [],
|
||||
};
|
||||
},
|
||||
render: ({ filterOptions }: FilterConfigRenderParams) => (
|
||||
|
@ -172,7 +169,7 @@ export const getSystemFilterConfig = ({
|
|||
isAvailable: availableSolutions.length > 1,
|
||||
getEmptyOptions: () => {
|
||||
return {
|
||||
owner: initialFilterOptions.owner || [],
|
||||
owner: [],
|
||||
};
|
||||
},
|
||||
render: ({ filterOptions }: FilterConfigRenderParams) => (
|
||||
|
@ -195,7 +192,6 @@ export const useSystemFilterConfig = ({
|
|||
countOpenCases,
|
||||
currentUserProfile,
|
||||
hiddenStatuses,
|
||||
initialFilterOptions,
|
||||
isLoading,
|
||||
isSelectorView,
|
||||
onFilterOptionsChange,
|
||||
|
@ -210,7 +206,6 @@ export const useSystemFilterConfig = ({
|
|||
countOpenCases,
|
||||
currentUserProfile,
|
||||
hiddenStatuses,
|
||||
initialFilterOptions,
|
||||
isLoading,
|
||||
isSelectorView,
|
||||
onFilterOptionsChange,
|
||||
|
|
|
@ -262,6 +262,9 @@ describe('CasesTableFilters ', () => {
|
|||
|
||||
describe('Solution filter', () => {
|
||||
it('shows Solution filter when provided more than 1 availableSolutions', () => {
|
||||
appMockRender = createAppMockRenderer({
|
||||
owner: [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER],
|
||||
});
|
||||
appMockRender.render(
|
||||
<CasesTableFilters
|
||||
{...props}
|
||||
|
@ -272,13 +275,17 @@ describe('CasesTableFilters ', () => {
|
|||
});
|
||||
|
||||
it('does not show Solution filter when provided less than 1 availableSolutions', () => {
|
||||
appMockRender.render(
|
||||
<CasesTableFilters {...props} availableSolutions={[OBSERVABILITY_OWNER]} />
|
||||
);
|
||||
appMockRender = createAppMockRenderer({
|
||||
owner: [],
|
||||
});
|
||||
appMockRender.render(<CasesTableFilters {...props} availableSolutions={[]} />);
|
||||
expect(screen.queryByTestId('options-filter-popover-button-owner')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not select a solution on initial render', () => {
|
||||
appMockRender = createAppMockRenderer({
|
||||
owner: [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER],
|
||||
});
|
||||
appMockRender.render(
|
||||
<CasesTableFilters
|
||||
{...props}
|
||||
|
@ -291,11 +298,22 @@ describe('CasesTableFilters ', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should reset the filter setting all available solutions when deactivated', async () => {
|
||||
it('should reset the filter when deactivated', async () => {
|
||||
appMockRender = createAppMockRenderer({
|
||||
owner: [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER],
|
||||
});
|
||||
|
||||
const overrideProps = {
|
||||
...props,
|
||||
filterOptions: {
|
||||
...props.filterOptions,
|
||||
owner: [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER],
|
||||
},
|
||||
};
|
||||
|
||||
appMockRender.render(
|
||||
<CasesTableFilters
|
||||
{...props}
|
||||
initialFilterOptions={{ owner: [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER] }}
|
||||
{...overrideProps}
|
||||
availableSolutions={[SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER]}
|
||||
/>
|
||||
);
|
||||
|
@ -306,8 +324,39 @@ describe('CasesTableFilters ', () => {
|
|||
|
||||
expect(onFilterChanged).toHaveBeenCalledWith({
|
||||
...DEFAULT_FILTER_OPTIONS,
|
||||
owner: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should check all options when all options are selected', async () => {
|
||||
appMockRender = createAppMockRenderer({
|
||||
owner: [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER],
|
||||
});
|
||||
|
||||
const overrideProps = {
|
||||
...props,
|
||||
filterOptions: {
|
||||
...props.filterOptions,
|
||||
owner: [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER],
|
||||
},
|
||||
};
|
||||
|
||||
appMockRender.render(
|
||||
<CasesTableFilters
|
||||
{...overrideProps}
|
||||
availableSolutions={[SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER]}
|
||||
/>
|
||||
);
|
||||
|
||||
userEvent.click(screen.getByRole('button', { name: 'Solution' }));
|
||||
await waitForEuiPopoverOpen();
|
||||
|
||||
const allOptions = screen.getAllByRole('option');
|
||||
expect(allOptions).toHaveLength(2);
|
||||
expect(allOptions[0]).toHaveAttribute('aria-checked', 'true');
|
||||
expect(allOptions[0]).toHaveTextContent('Security');
|
||||
expect(allOptions[1]).toHaveAttribute('aria-checked', 'true');
|
||||
expect(allOptions[1]).toHaveTextContent('Observability');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ export interface CasesTableFiltersProps {
|
|||
availableSolutions: string[];
|
||||
isSelectorView?: boolean;
|
||||
onCreateCasePressed?: () => void;
|
||||
initialFilterOptions: Partial<FilterOptions>;
|
||||
isLoading: boolean;
|
||||
currentUserProfile: CurrentUserProfile;
|
||||
filterOptions: FilterOptions;
|
||||
|
@ -49,7 +48,6 @@ const CasesTableFiltersComponent = ({
|
|||
availableSolutions,
|
||||
isSelectorView = false,
|
||||
onCreateCasePressed,
|
||||
initialFilterOptions,
|
||||
isLoading,
|
||||
currentUserProfile,
|
||||
filterOptions,
|
||||
|
@ -78,7 +76,6 @@ const CasesTableFiltersComponent = ({
|
|||
countOpenCases,
|
||||
currentUserProfile,
|
||||
hiddenStatuses,
|
||||
initialFilterOptions,
|
||||
isLoading,
|
||||
isSelectorView,
|
||||
onFilterOptionsChange,
|
||||
|
|
|
@ -11,10 +11,11 @@ import { useGetCases } from './use_get_cases';
|
|||
import * as api from './api';
|
||||
import type { AppMockRenderer } from '../common/mock';
|
||||
import { createAppMockRenderer } from '../common/mock';
|
||||
import { useToasts } from '../common/lib/kibana';
|
||||
import { useToasts } from '../common/lib/kibana/hooks';
|
||||
import { OWNERS } from '../../common/constants';
|
||||
|
||||
jest.mock('./api');
|
||||
jest.mock('../common/lib/kibana');
|
||||
jest.mock('../common/lib/kibana/hooks');
|
||||
|
||||
describe('useGetCases', () => {
|
||||
const abortCtrl = new AbortController();
|
||||
|
@ -24,8 +25,8 @@ describe('useGetCases', () => {
|
|||
let appMockRender: AppMockRenderer;
|
||||
|
||||
beforeEach(() => {
|
||||
appMockRender = createAppMockRenderer();
|
||||
jest.clearAllMocks();
|
||||
appMockRender = createAppMockRenderer();
|
||||
});
|
||||
|
||||
it('calls getCases with correct arguments', async () => {
|
||||
|
@ -33,9 +34,10 @@ describe('useGetCases', () => {
|
|||
const { waitForNextUpdate } = renderHook(() => useGetCases(), {
|
||||
wrapper: appMockRender.AppWrapper,
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
expect(spyOnGetCases).toBeCalledWith({
|
||||
filterOptions: { ...DEFAULT_FILTER_OPTIONS },
|
||||
filterOptions: { ...DEFAULT_FILTER_OPTIONS, owner: ['securitySolution'] },
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
signal: abortCtrl.signal,
|
||||
});
|
||||
|
@ -46,6 +48,7 @@ describe('useGetCases', () => {
|
|||
spyOnGetCases.mockImplementation(() => {
|
||||
throw new Error('Something went wrong');
|
||||
});
|
||||
|
||||
const addError = jest.fn();
|
||||
(useToasts as jest.Mock).mockReturnValue({ addSuccess, addError });
|
||||
|
||||
|
@ -56,4 +59,97 @@ describe('useGetCases', () => {
|
|||
await waitForNextUpdate();
|
||||
expect(addError).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set all owners when no owner is provided', async () => {
|
||||
appMockRender = createAppMockRenderer({ owner: [] });
|
||||
|
||||
appMockRender.coreStart.application.capabilities = {
|
||||
...appMockRender.coreStart.application.capabilities,
|
||||
observabilityCases: {
|
||||
create_cases: true,
|
||||
read_cases: true,
|
||||
update_cases: true,
|
||||
push_cases: true,
|
||||
cases_connectors: true,
|
||||
delete_cases: true,
|
||||
cases_settings: true,
|
||||
},
|
||||
securitySolutionCases: {
|
||||
create_cases: true,
|
||||
read_cases: true,
|
||||
update_cases: true,
|
||||
push_cases: true,
|
||||
cases_connectors: true,
|
||||
delete_cases: true,
|
||||
cases_settings: true,
|
||||
},
|
||||
};
|
||||
|
||||
const spyOnGetCases = jest.spyOn(api, 'getCases');
|
||||
const { waitForNextUpdate } = renderHook(() => useGetCases(), {
|
||||
wrapper: appMockRender.AppWrapper,
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(spyOnGetCases).toBeCalledWith({
|
||||
filterOptions: { ...DEFAULT_FILTER_OPTIONS, owner: [...OWNERS] },
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
signal: abortCtrl.signal,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set only the available owners when no owner is provided', async () => {
|
||||
appMockRender = createAppMockRenderer({ owner: [] });
|
||||
const spyOnGetCases = jest.spyOn(api, 'getCases');
|
||||
|
||||
const { waitForNextUpdate } = renderHook(() => useGetCases(), {
|
||||
wrapper: appMockRender.AppWrapper,
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(spyOnGetCases).toBeCalledWith({
|
||||
filterOptions: { ...DEFAULT_FILTER_OPTIONS, owner: ['cases'] },
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
signal: abortCtrl.signal,
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the app owner when the filter options do not specify the owner', async () => {
|
||||
appMockRender = createAppMockRenderer({ owner: ['observability'] });
|
||||
const spyOnGetCases = jest.spyOn(api, 'getCases');
|
||||
|
||||
const { waitForNextUpdate } = renderHook(() => useGetCases(), {
|
||||
wrapper: appMockRender.AppWrapper,
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(spyOnGetCases).toBeCalledWith({
|
||||
filterOptions: { ...DEFAULT_FILTER_OPTIONS, owner: ['observability'] },
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
signal: abortCtrl.signal,
|
||||
});
|
||||
});
|
||||
|
||||
it('respects the owner in the filter options if provided', async () => {
|
||||
appMockRender = createAppMockRenderer({ owner: ['observability'] });
|
||||
const spyOnGetCases = jest.spyOn(api, 'getCases');
|
||||
|
||||
const { waitForNextUpdate } = renderHook(
|
||||
() => useGetCases({ filterOptions: { owner: ['my-owner'] } }),
|
||||
{
|
||||
wrapper: appMockRender.AppWrapper,
|
||||
}
|
||||
);
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(spyOnGetCases).toBeCalledWith({
|
||||
filterOptions: { ...DEFAULT_FILTER_OPTIONS, owner: ['my-owner'] },
|
||||
queryParams: DEFAULT_QUERY_PARAMS,
|
||||
signal: abortCtrl.signal,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,6 +13,9 @@ import { useToasts } from '../common/lib/kibana';
|
|||
import * as i18n from './translations';
|
||||
import { getCases } from './api';
|
||||
import type { ServerError } from '../types';
|
||||
import { useCasesContext } from '../components/cases_context/use_cases_context';
|
||||
import { useAvailableCasesOwners } from '../components/app/use_available_owners';
|
||||
import { getAllPermissionsExceptFrom } from '../utils/permissions';
|
||||
|
||||
export const initialData: CasesFindResponseUI = {
|
||||
cases: [],
|
||||
|
@ -31,6 +34,17 @@ export const useGetCases = (
|
|||
} = {}
|
||||
): UseQueryResult<CasesFindResponseUI> => {
|
||||
const toasts = useToasts();
|
||||
const { owner } = useCasesContext();
|
||||
const availableSolutions = useAvailableCasesOwners(getAllPermissionsExceptFrom('delete'));
|
||||
|
||||
const hasOwner = !!owner.length;
|
||||
const initialOwner = hasOwner ? owner : availableSolutions;
|
||||
|
||||
const ownerFilter =
|
||||
params.filterOptions?.owner != null && params.filterOptions.owner.length > 0
|
||||
? { owner: params.filterOptions.owner }
|
||||
: { owner: initialOwner };
|
||||
|
||||
return useQuery(
|
||||
casesQueriesKeys.cases(params),
|
||||
({ signal }) => {
|
||||
|
@ -38,6 +52,7 @@ export const useGetCases = (
|
|||
filterOptions: {
|
||||
...DEFAULT_FILTER_OPTIONS,
|
||||
...(params.filterOptions ?? {}),
|
||||
...ownerFilter,
|
||||
},
|
||||
queryParams: {
|
||||
...DEFAULT_QUERY_PARAMS,
|
||||
|
|
|
@ -183,11 +183,16 @@ export function CasesTableServiceProvider(
|
|||
await casesCommon.selectFirstRowInAssigneesPopover();
|
||||
},
|
||||
|
||||
async filterByOwner(owner: string) {
|
||||
await common.clickAndValidate(
|
||||
'options-filter-popover-button-owner',
|
||||
`options-filter-popover-item-${owner}`
|
||||
);
|
||||
async filterByOwner(
|
||||
owner: string,
|
||||
options: { popupAlreadyOpen: boolean } = { popupAlreadyOpen: false }
|
||||
) {
|
||||
if (!options.popupAlreadyOpen) {
|
||||
await common.clickAndValidate(
|
||||
'options-filter-popover-button-owner',
|
||||
`options-filter-popover-item-${owner}`
|
||||
);
|
||||
}
|
||||
|
||||
await testSubjects.click(`options-filter-popover-item-${owner}`);
|
||||
},
|
||||
|
|
|
@ -318,6 +318,22 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
|
|||
}
|
||||
});
|
||||
|
||||
it('filters with multiple selection', async () => {
|
||||
await openModal();
|
||||
|
||||
let popupAlreadyOpen = false;
|
||||
for (const [owner] of createdCases.entries()) {
|
||||
await cases.casesTable.filterByOwner(owner, { popupAlreadyOpen });
|
||||
popupAlreadyOpen = true;
|
||||
}
|
||||
await cases.casesTable.waitForTableToFinishLoading();
|
||||
|
||||
for (const caseId of createdCases.values()) {
|
||||
await testSubjects.existOrFail(`cases-table-row-${caseId}`);
|
||||
}
|
||||
await closeModal();
|
||||
});
|
||||
|
||||
it('attaches correctly', async () => {
|
||||
for (const [owner, currentCaseId] of createdCases.entries()) {
|
||||
await openModal();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue