Skip to content

Commit

Permalink
[Security solution] Stops page from crashing when there is a fields e…
Browse files Browse the repository at this point in the history
…rror in the stackBy component (#168411)
  • Loading branch information
stephmilovic authored Oct 10, 2023
1 parent e52e6ee commit 7776ac4
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jest.mock('../../../../common/components/visualization_actions/lens_embeddable')
jest.mock('../../../../common/components/page/use_refetch_by_session');
jest.mock('../common/hooks', () => ({
useInspectButton: jest.fn(),
useStackByFields: jest.fn(),
useStackByFields: jest.fn().mockReturnValue(() => []),
}));
const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock;
const getMockUseIsExperimentalFeatureEnabled =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,13 @@ export const StackByComboBox = React.forwardRef(
return [{ label: selected, value: selected }];
}, [selected]);

const stackOptions = useStackByFields(useLensCompatibleFields);
const getExpensiveFields = useStackByFields(useLensCompatibleFields);

const options = useMemo(
() => dropDownoptions ?? getExpensiveFields(),
[dropDownoptions, getExpensiveFields]
);

const singleSelection = useMemo(() => {
return { asPlainText: true };
}, []);
Expand All @@ -115,7 +121,7 @@ export const StackByComboBox = React.forwardRef(
singleSelection={singleSelection}
isClearable={false}
sortMatchesBy="startsWith"
options={dropDownoptions ?? stackOptions}
options={options}
selectedOptions={selectedOptions}
compressed
onChange={onChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ describe('hooks', () => {
<TestProviders>{children}</TestProviders>
);
const { result, unmount } = renderHook(() => useStackByFields(), { wrapper });
const aggregateableFields = result.current;
const aggregateableFields = result.current();
unmount();
expect(aggregateableFields?.find((field) => field.label === 'agent.id')).toBeTruthy();
expect(aggregateableFields!.find((field) => field.label === 'agent.id')).toBeTruthy();
expect(
aggregateableFields?.find((field) => field.label === 'nestedField.firstAttributes')
aggregateableFields!.find((field) => field.label === 'nestedField.firstAttributes')
).toBe(undefined);
});

Expand All @@ -144,10 +144,10 @@ describe('hooks', () => {
const { result, unmount } = renderHook(() => useStackByFields(useLensCompatibleFields), {
wrapper,
});
const aggregateableFields = result.current;
const aggregateableFields = result.current();
unmount();
expect(aggregateableFields?.find((field) => field.label === '@timestamp')).toBeUndefined();
expect(aggregateableFields?.find((field) => field.label === '_id')).toBeUndefined();
expect(aggregateableFields!.find((field) => field.label === '@timestamp')).toBeUndefined();
expect(aggregateableFields!.find((field) => field.label === '_id')).toBeUndefined();
});

it('returns only Lens compatible fields (check if it is a nested field)', () => {
Expand All @@ -162,7 +162,7 @@ describe('hooks', () => {
const { result, unmount } = renderHook(() => useStackByFields(useLensCompatibleFields), {
wrapper,
});
const aggregateableFields = result.current;
const aggregateableFields = result.current();
unmount();
expect(aggregateableFields).toHaveLength(0);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
* 2.0.
*/

import { useEffect, useState, useMemo } from 'react';
import { useCallback, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import type { EuiComboBoxOptionOption } from '@elastic/eui';
import type { IFieldSubTypeNested } from '@kbn/es-query';

import type { BrowserField } from '@kbn/timelines-plugin/common';
import { i18n } from '@kbn/i18n';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import type { GlobalTimeArgs } from '../../../../common/containers/use_global_time';
import { getScopeFromPath, useSourcererDataView } from '../../../../common/containers/sourcerer';
import { getAllFieldsByName } from '../../../../common/containers/source';
Expand Down Expand Up @@ -95,14 +97,22 @@ export function getAggregatableFields(

export const useStackByFields = (useLensCompatibleFields?: boolean) => {
const { pathname } = useLocation();

const { addError } = useAppToasts();
const { browserFields } = useSourcererDataView(getScopeFromPath(pathname));
const allFields = useMemo(() => getAllFieldsByName(browserFields), [browserFields]);
const [stackByFieldOptions, setStackByFieldOptions] = useState(() =>
getAggregatableFields(allFields, useLensCompatibleFields)
);
useEffect(() => {
setStackByFieldOptions(getAggregatableFields(allFields, useLensCompatibleFields));
}, [allFields, useLensCompatibleFields]);
return useMemo(() => stackByFieldOptions, [stackByFieldOptions]);

return useCallback(() => {
try {
return getAggregatableFields(getAllFieldsByName(browserFields), useLensCompatibleFields);
} catch (err) {
addError(err, {
title: i18n.translate('xpack.securitySolution.useStackByFields.error.title', {
defaultMessage: 'Error fetching fields',
}),
toastMessage: i18n.translate('xpack.securitySolution.useStackByFields.error.toastMessage', {
defaultMessage: 'This error indicates an exceedingly large number of fields in an index',
}),
});
return [];
}
}, [addError, browserFields, useLensCompatibleFields]);
};

0 comments on commit 7776ac4

Please sign in to comment.