mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Performance][Security Solution] - Improve cell renderer performance (#212982)
## Summary Background: https://github.com/elastic/kibana/pull/212173 Based off of feedback on the work in the PRs listed in that issue, additional performance improvements can be made to the cells rendered in the alert table. The changes made in this PR involve migrating out shared context to a provider so certain hooks (some expensive... i.e. browserFieldsByName) aren't made for every cell in the UI, but once and passed down to each cell accordingly. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
ae74cc35a9
commit
4db40eacde
7 changed files with 209 additions and 109 deletions
|
@ -14,6 +14,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common';
|
|||
import type { DataViewBase } from '@kbn/es-query';
|
||||
import { buildEsQuery } from '@kbn/es-query';
|
||||
import { TableId } from '@kbn/securitysolution-data-table';
|
||||
import { AlertTableCellContextProvider } from '../../../../detections/configurations/security_solution_detections/cell_value_context';
|
||||
import { StatefulEventsViewer } from '../../../../common/components/events_viewer';
|
||||
import { defaultRowRenderers } from '../../../../timelines/components/timeline/body/renderers';
|
||||
import * as i18n from './translations';
|
||||
|
@ -142,7 +143,10 @@ const PreviewHistogramComponent = ({
|
|||
}, [config, indexPattern, previewId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<AlertTableCellContextProvider
|
||||
tableId={TableId.rulePreview}
|
||||
sourcererScope={SourcererScopeName.detections}
|
||||
>
|
||||
<Panel height={DEFAULT_HISTOGRAM_HEIGHT} data-test-subj={'preview-histogram-panel'}>
|
||||
<EuiFlexGroup gutterSize="none" direction="column">
|
||||
<EuiFlexItem grow={1}>
|
||||
|
@ -199,7 +203,7 @@ const PreviewHistogramComponent = ({
|
|||
bulkActions={false}
|
||||
/>
|
||||
</FullScreenContainer>
|
||||
</>
|
||||
</AlertTableCellContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { EuiDataGridCellValueElementProps } from '@elastic/eui';
|
||||
import { TableId } from '@kbn/securitysolution-data-table';
|
||||
import type { LegacyField } from '@kbn/alerting-types';
|
||||
|
@ -13,6 +13,8 @@ import type { CellValueElementProps } from '../../../../../common/types';
|
|||
import { SourcererScopeName } from '../../../../sourcerer/store/model';
|
||||
import { CellValue } from '../../../../detections/configurations/security_solution_detections';
|
||||
|
||||
const emptyUserProfiles = { profiles: [], isLoading: false };
|
||||
|
||||
export const PreviewRenderCellValue: React.FC<
|
||||
EuiDataGridCellValueElementProps & CellValueElementProps
|
||||
> = ({
|
||||
|
@ -28,11 +30,12 @@ export const PreviewRenderCellValue: React.FC<
|
|||
rowRenderers,
|
||||
truncate,
|
||||
}) => {
|
||||
const legacyAlert = useMemo(() => (data ?? []) as LegacyField[], [data]);
|
||||
return (
|
||||
<CellValue
|
||||
tableType={TableId.rulePreview}
|
||||
sourcererScope={SourcererScopeName.detections}
|
||||
legacyAlert={(data ?? []) as LegacyField[]}
|
||||
legacyAlert={legacyAlert}
|
||||
ecsAlert={ecsData}
|
||||
asPlainText={true}
|
||||
setCellProps={setCellProps}
|
||||
|
@ -44,7 +47,7 @@ export const PreviewRenderCellValue: React.FC<
|
|||
columnId={columnId}
|
||||
rowRenderers={rowRenderers}
|
||||
truncate={truncate}
|
||||
userProfiles={{ profiles: [], isLoading: false }}
|
||||
userProfiles={emptyUserProfiles}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -73,6 +73,7 @@ import { AdditionalToolbarControls } from './additional_toolbar_controls';
|
|||
import { useFetchUserProfilesFromAlerts } from '../../configurations/security_solution_detections/fetch_page_context';
|
||||
import { useCellActionsOptions } from '../../hooks/trigger_actions_alert_table/use_cell_actions';
|
||||
import { useAlertsTableFieldsBrowserOptions } from '../../hooks/trigger_actions_alert_table/use_trigger_actions_browser_fields_options';
|
||||
import { AlertTableCellContextProvider } from '../../configurations/security_solution_detections/cell_value_context';
|
||||
|
||||
const { updateIsLoading, updateTotalCount } = dataTableActions;
|
||||
|
||||
|
@ -172,9 +173,10 @@ const DetectionEngineAlertsTableComponent: FC<Omit<DetectionEngineAlertTableProp
|
|||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const timelineID = tableType;
|
||||
// Store context in state rather than creating object in provider value={} to prevent re-renders caused by a new object being created
|
||||
const [activeStatefulEventContext] = useState({
|
||||
timelineID: tableType,
|
||||
timelineID,
|
||||
tabType: 'query',
|
||||
enableHostDetailsFlyout: true,
|
||||
enableIpDetailsFlyout: true,
|
||||
|
@ -454,44 +456,49 @@ const DetectionEngineAlertsTableComponent: FC<Omit<DetectionEngineAlertTableProp
|
|||
<FullWidthFlexGroupTable $visible={!graphEventId && graphOverlay == null} gutterSize="none">
|
||||
<StatefulEventContext.Provider value={activeStatefulEventContext}>
|
||||
<EuiDataGridContainer hideLastPage={false}>
|
||||
<AlertsTable<SecurityAlertsTableContext>
|
||||
ref={alertsTableRef}
|
||||
// Stores separate configuration based on the view of the table
|
||||
id={id ?? `detection-engine-alert-table-${tableType}-${tableView}`}
|
||||
ruleTypeIds={SECURITY_SOLUTION_RULE_TYPE_IDS}
|
||||
consumers={ALERT_TABLE_CONSUMERS}
|
||||
query={finalBoolQuery}
|
||||
initialSort={initialSort}
|
||||
casesConfiguration={casesConfiguration}
|
||||
gridStyle={gridStyle}
|
||||
shouldHighlightRow={shouldHighlightRow}
|
||||
rowHeightsOptions={rowHeightsOptions}
|
||||
columns={finalColumns}
|
||||
browserFields={finalBrowserFields}
|
||||
onUpdate={onUpdate}
|
||||
additionalContext={additionalContext}
|
||||
height={alertTableHeight}
|
||||
initialPageSize={50}
|
||||
runtimeMappings={sourcererDataView?.runtimeFieldMap as RunTimeMappings}
|
||||
toolbarVisibility={toolbarVisibility}
|
||||
renderCellValue={CellValue}
|
||||
renderActionsCell={ActionsCell}
|
||||
renderAdditionalToolbarControls={
|
||||
tableType !== TableId.alertsOnCasePage ? AdditionalToolbarControls : undefined
|
||||
}
|
||||
actionsColumnWidth={leadingControlColumn.width}
|
||||
getBulkActions={getBulkActions}
|
||||
fieldsBrowserOptions={
|
||||
tableType === TableId.alertsOnAlertsPage ||
|
||||
tableType === TableId.alertsOnRuleDetailsPage
|
||||
? fieldsBrowserOptions
|
||||
: undefined
|
||||
}
|
||||
cellActionsOptions={cellActionsOptions}
|
||||
showInspectButton
|
||||
services={services}
|
||||
{...tablePropsOverrides}
|
||||
/>
|
||||
<AlertTableCellContextProvider
|
||||
tableId={tableType}
|
||||
sourcererScope={SourcererScopeName.detections}
|
||||
>
|
||||
<AlertsTable<SecurityAlertsTableContext>
|
||||
ref={alertsTableRef}
|
||||
// Stores separate configuration based on the view of the table
|
||||
id={id ?? `detection-engine-alert-table-${tableType}-${tableView}`}
|
||||
ruleTypeIds={SECURITY_SOLUTION_RULE_TYPE_IDS}
|
||||
consumers={ALERT_TABLE_CONSUMERS}
|
||||
query={finalBoolQuery}
|
||||
initialSort={initialSort}
|
||||
casesConfiguration={casesConfiguration}
|
||||
gridStyle={gridStyle}
|
||||
shouldHighlightRow={shouldHighlightRow}
|
||||
rowHeightsOptions={rowHeightsOptions}
|
||||
columns={finalColumns}
|
||||
browserFields={finalBrowserFields}
|
||||
onUpdate={onUpdate}
|
||||
additionalContext={additionalContext}
|
||||
height={alertTableHeight}
|
||||
initialPageSize={50}
|
||||
runtimeMappings={sourcererDataView?.runtimeFieldMap as RunTimeMappings}
|
||||
toolbarVisibility={toolbarVisibility}
|
||||
renderCellValue={CellValue}
|
||||
renderActionsCell={ActionsCell}
|
||||
renderAdditionalToolbarControls={
|
||||
tableType !== TableId.alertsOnCasePage ? AdditionalToolbarControls : undefined
|
||||
}
|
||||
actionsColumnWidth={leadingControlColumn.width}
|
||||
getBulkActions={getBulkActions}
|
||||
fieldsBrowserOptions={
|
||||
tableType === TableId.alertsOnAlertsPage ||
|
||||
tableType === TableId.alertsOnRuleDetailsPage
|
||||
? fieldsBrowserOptions
|
||||
: undefined
|
||||
}
|
||||
cellActionsOptions={cellActionsOptions}
|
||||
showInspectButton
|
||||
services={services}
|
||||
{...tablePropsOverrides}
|
||||
/>
|
||||
</AlertTableCellContextProvider>
|
||||
</EuiDataGridContainer>
|
||||
</StatefulEventContext.Provider>
|
||||
</FullWidthFlexGroupTable>
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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, { createContext, useMemo } from 'react';
|
||||
import type { FieldSpec } from '@kbn/data-views-plugin/common';
|
||||
import { tableDefaults, dataTableSelectors } from '@kbn/securitysolution-data-table';
|
||||
import type { BrowserFields } from '@kbn/timelines-plugin/common';
|
||||
import type { SourcererScopeName } from '../../../sourcerer/store/model';
|
||||
import { useLicense } from '../../../common/hooks/use_license';
|
||||
import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
|
||||
import { useSourcererDataView } from '../../../sourcerer/containers';
|
||||
import { VIEW_SELECTION } from '../../../../common/constants';
|
||||
import { getAllFieldsByName } from '../../../common/containers/source';
|
||||
import { eventRenderedViewColumns, getColumns } from './columns';
|
||||
import type { AlertColumnHeaders } from './columns';
|
||||
|
||||
interface AlertTableCellContextProps {
|
||||
browserFields: BrowserFields;
|
||||
browserFieldsByName: Record<string, Partial<FieldSpec>>;
|
||||
columnHeaders: AlertColumnHeaders;
|
||||
}
|
||||
|
||||
export const AlertTableCellContext = createContext<AlertTableCellContextProps | null>(null);
|
||||
|
||||
export const AlertTableCellContextProvider = ({
|
||||
tableId = '',
|
||||
sourcererScope,
|
||||
children,
|
||||
}: {
|
||||
tableId?: string;
|
||||
sourcererScope: SourcererScopeName;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const { browserFields } = useSourcererDataView(sourcererScope);
|
||||
const browserFieldsByName = useMemo(() => getAllFieldsByName(browserFields), [browserFields]);
|
||||
const license = useLicense();
|
||||
const gridColumns = useMemo(() => {
|
||||
return getColumns(license);
|
||||
}, [license]);
|
||||
const getTable = useMemo(() => dataTableSelectors.getTableByIdSelector(), []);
|
||||
const viewMode =
|
||||
useDeepEqualSelector((state) => (getTable(state, tableId ?? '') ?? tableDefaults).viewMode) ??
|
||||
tableDefaults.viewMode;
|
||||
const columnHeaders = useMemo(() => {
|
||||
return viewMode === VIEW_SELECTION.gridView ? gridColumns : eventRenderedViewColumns;
|
||||
}, [gridColumns, viewMode]);
|
||||
|
||||
const cellValueContext = useMemo<AlertTableCellContextProps>(
|
||||
() => ({
|
||||
browserFields,
|
||||
browserFieldsByName,
|
||||
columnHeaders,
|
||||
}),
|
||||
[browserFields, browserFieldsByName, columnHeaders]
|
||||
);
|
||||
|
||||
return (
|
||||
<AlertTableCellContext.Provider value={cellValueContext}>
|
||||
{children}
|
||||
</AlertTableCellContext.Provider>
|
||||
);
|
||||
};
|
|
@ -137,11 +137,10 @@ const getBaseColumns = (
|
|||
* columns implements a subset of `EuiDataGrid`'s `EuiDataGridColumn` interface,
|
||||
* plus additional TGrid column properties
|
||||
*/
|
||||
export const getColumns = (
|
||||
license?: LicenseService
|
||||
): Array<
|
||||
export type AlertColumnHeaders = Array<
|
||||
Pick<EuiDataGridColumn, 'display' | 'displayAsText' | 'id' | 'initialWidth'> & ColumnHeaderOptions
|
||||
> => [
|
||||
>;
|
||||
export const getColumns = (license?: LicenseService): AlertColumnHeaders => [
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: '@timestamp',
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import { cloneDeep } from 'lodash/fp';
|
||||
import type { ComponentProps } from 'react';
|
||||
import React from 'react';
|
||||
|
@ -16,9 +16,10 @@ import { DragDropContextWrapper } from '../../../common/components/drag_and_drop
|
|||
import { defaultHeaders, mockTimelineData, TestProviders } from '../../../common/mock';
|
||||
import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers';
|
||||
import type { TimelineNonEcsData } from '../../../../common/search_strategy/timeline';
|
||||
import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer';
|
||||
import type { RenderCellValueProps } from './render_cell_value';
|
||||
import { CellValue } from './render_cell_value';
|
||||
import { SourcererScopeName } from '../../../sourcerer/store/model';
|
||||
import { AlertTableCellContextProvider } from './cell_value_context';
|
||||
|
||||
jest.mock('../../../common/lib/kibana');
|
||||
jest.mock('../../../sourcerer/containers', () => ({
|
||||
|
@ -41,12 +42,12 @@ describe('RenderCellValue', () => {
|
|||
|
||||
let data: TimelineNonEcsData[];
|
||||
let header: ColumnHeaderOptions;
|
||||
let props: ComponentProps<typeof CellValue>;
|
||||
let defaultProps: RenderCellValueProps;
|
||||
|
||||
beforeEach(() => {
|
||||
data = cloneDeep(mockTimelineData[0].data);
|
||||
header = cloneDeep(defaultHeaders[0]);
|
||||
props = {
|
||||
defaultProps = {
|
||||
columnId,
|
||||
legacyAlert: data,
|
||||
eventId,
|
||||
|
@ -68,37 +69,54 @@ describe('RenderCellValue', () => {
|
|||
} as unknown as ComponentProps<typeof CellValue>;
|
||||
});
|
||||
|
||||
test('it forwards the `CellValueElementProps` to the `DefaultCellRenderer`', () => {
|
||||
const wrapper = mount(
|
||||
const RenderCellValueComponent = (props: RenderCellValueProps) => {
|
||||
return (
|
||||
<TestProviders>
|
||||
<DragDropContextWrapper browserFields={mockBrowserFields}>
|
||||
<CellValue
|
||||
{...props}
|
||||
sourcererScope={SourcererScopeName.default}
|
||||
tableType={TableId.test}
|
||||
/>
|
||||
<AlertTableCellContextProvider
|
||||
tableId={TableId.test}
|
||||
sourcererScope={SourcererScopeName.detections}
|
||||
>
|
||||
<CellValue
|
||||
{...defaultProps}
|
||||
{...props}
|
||||
sourcererScope={SourcererScopeName.detections}
|
||||
tableType={TableId.test}
|
||||
/>
|
||||
</AlertTableCellContextProvider>
|
||||
</DragDropContextWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
};
|
||||
|
||||
const { legacyAlert, ...defaultCellRendererProps } = props;
|
||||
it('should throw an error if not wrapped by the AlertTableCellContextProvider', () => {
|
||||
const renderWithError = () =>
|
||||
render(
|
||||
<TestProviders>
|
||||
<DragDropContextWrapper browserFields={mockBrowserFields}>
|
||||
<CellValue
|
||||
{...defaultProps}
|
||||
sourcererScope={SourcererScopeName.detections}
|
||||
tableType={TableId.test}
|
||||
/>
|
||||
</DragDropContextWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find(DefaultCellRenderer).props()).toEqual({
|
||||
...defaultCellRendererProps,
|
||||
data: legacyAlert,
|
||||
scopeId: SourcererScopeName.default,
|
||||
});
|
||||
expect(renderWithError).toThrow(
|
||||
'render_cell_value.tsx: CellValue must be used within AlertTableCellContextProvider'
|
||||
);
|
||||
});
|
||||
|
||||
test('it renders a GuidedOnboardingTourStep', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<DragDropContextWrapper browserFields={mockBrowserFields}>
|
||||
<CellValue {...props} scopeId={SourcererScopeName.default} tableType={TableId.test} />
|
||||
</DragDropContextWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
it('should fully render the cell value', () => {
|
||||
const { getByText } = render(<RenderCellValueComponent {...defaultProps} />);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="GuidedOnboardingTourStep"]').exists()).toEqual(true);
|
||||
expect(getByText('Nov 5, 2018 @ 19:03:25.937')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the guided onboarding step', () => {
|
||||
const { getByTestId } = render(<RenderCellValueComponent {...defaultProps} />);
|
||||
|
||||
expect(getByTestId('GuidedOnboardingTourStep')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,13 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useMemo, memo, type ComponentProps } from 'react';
|
||||
import React, { useMemo, memo, type ComponentProps, useContext } from 'react';
|
||||
import { EuiIcon, EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { find, getOr } from 'lodash/fp';
|
||||
import type { TimelineNonEcsData } from '@kbn/timelines-plugin/common';
|
||||
import { tableDefaults, dataTableSelectors } from '@kbn/securitysolution-data-table';
|
||||
import { useLicense } from '../../../common/hooks/use_license';
|
||||
import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers';
|
||||
import { GuidedOnboardingTourStep } from '../../../common/components/guided_onboarding_tour/tour_step';
|
||||
import { isDetectionsAlertsTable } from '../../../common/components/top_n/helpers';
|
||||
|
@ -20,15 +18,12 @@ import {
|
|||
SecurityStepId,
|
||||
} from '../../../common/components/guided_onboarding_tour/tour_config';
|
||||
import { SIGNAL_RULE_NAME_FIELD_NAME } from '../../../timelines/components/timeline/body/renderers/constants';
|
||||
import { useSourcererDataView } from '../../../sourcerer/containers';
|
||||
import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer';
|
||||
|
||||
import { SUPPRESSED_ALERT_TOOLTIP } from './translations';
|
||||
import { VIEW_SELECTION } from '../../../../common/constants';
|
||||
import { getAllFieldsByName } from '../../../common/containers/source';
|
||||
import { eventRenderedViewColumns, getColumns } from './columns';
|
||||
import type { GetSecurityAlertsTableProp } from '../../components/alerts_table/types';
|
||||
import type { CellValueElementProps, ColumnHeaderOptions } from '../../../../common/types';
|
||||
import { AlertTableCellContext } from './cell_value_context';
|
||||
|
||||
/**
|
||||
* This implementation of `EuiDataGrid`'s `renderCellValue`
|
||||
|
@ -36,7 +31,7 @@ import type { CellValueElementProps, ColumnHeaderOptions } from '../../../../com
|
|||
* from the TGrid
|
||||
*/
|
||||
|
||||
type RenderCellValueProps = Pick<
|
||||
export type RenderCellValueProps = Pick<
|
||||
ComponentProps<GetSecurityAlertsTableProp<'renderCellValue'>>,
|
||||
| 'columnId'
|
||||
| 'rowIndex'
|
||||
|
@ -76,6 +71,7 @@ export const CellValue = memo(function RenderCellValue({
|
|||
truncate,
|
||||
userProfiles,
|
||||
}: RenderCellValueProps) {
|
||||
const { notifications } = useKibana().services;
|
||||
const isTourAnchor = useMemo(
|
||||
() =>
|
||||
columnId === SIGNAL_RULE_NAME_FIELD_NAME &&
|
||||
|
@ -84,22 +80,21 @@ export const CellValue = memo(function RenderCellValue({
|
|||
!isDetails,
|
||||
[columnId, isDetails, rowIndex, tableType]
|
||||
);
|
||||
const { browserFields } = useSourcererDataView(sourcererScope);
|
||||
const browserFieldsByName = useMemo(() => getAllFieldsByName(browserFields), [browserFields]);
|
||||
const getTable = useMemo(() => dataTableSelectors.getTableByIdSelector(), []);
|
||||
const license = useLicense();
|
||||
const viewMode =
|
||||
useDeepEqualSelector((state) => (getTable(state, tableId ?? '') ?? tableDefaults).viewMode) ??
|
||||
tableDefaults.viewMode;
|
||||
const cellValueContext = useContext(AlertTableCellContext);
|
||||
|
||||
const gridColumns = useMemo(() => {
|
||||
return getColumns(license);
|
||||
}, [license]);
|
||||
if (!cellValueContext) {
|
||||
const contextMissingError = new Error(
|
||||
'render_cell_value.tsx: CellValue must be used within AlertTableCellContextProvider'
|
||||
);
|
||||
|
||||
const columnHeaders = useMemo(() => {
|
||||
return viewMode === VIEW_SELECTION.gridView ? gridColumns : eventRenderedViewColumns;
|
||||
}, [gridColumns, viewMode]);
|
||||
notifications.toasts.addError(contextMissingError, {
|
||||
title: 'AlertTableCellContextProvider is missing',
|
||||
toastMessage: 'CellValue must be used within AlertTableCellContextProvider',
|
||||
});
|
||||
throw new Error(contextMissingError.message);
|
||||
}
|
||||
|
||||
const { browserFields, browserFieldsByName, columnHeaders } = cellValueContext;
|
||||
/**
|
||||
* There is difference between how `triggers actions` fetched data v/s
|
||||
* how security solution fetches data via timelineSearchStrategy
|
||||
|
@ -134,11 +129,21 @@ export const CellValue = memo(function RenderCellValue({
|
|||
return ecsSuppressionCount ? parseInt(ecsSuppressionCount, 10) : dataSuppressionCount;
|
||||
}, [ecsAlert, legacyAlert]);
|
||||
|
||||
const Renderer = useMemo(() => {
|
||||
const myHeader =
|
||||
header ?? ({ id: columnId, ...browserFieldsByName[columnId] } as ColumnHeaderOptions);
|
||||
const colHeader = columnHeaders.find((col) => col.id === columnId);
|
||||
const localLinkValues = getOr([], colHeader?.linkField ?? '', ecsAlert);
|
||||
const myHeader = useMemo(
|
||||
() => header ?? ({ id: columnId, ...browserFieldsByName[columnId] } as ColumnHeaderOptions),
|
||||
[browserFieldsByName, columnId, header]
|
||||
);
|
||||
|
||||
const colHeader = useMemo(
|
||||
() => columnHeaders.find((col) => col.id === columnId),
|
||||
[columnHeaders, columnId]
|
||||
);
|
||||
const localLinkValues = useMemo(
|
||||
() => getOr([], colHeader?.linkField ?? '', ecsAlert),
|
||||
[colHeader?.linkField, ecsAlert]
|
||||
);
|
||||
|
||||
const CellRenderer = useMemo(() => {
|
||||
return (
|
||||
<GuidedOnboardingTourStep
|
||||
isTourAnchor={isTourAnchor}
|
||||
|
@ -168,20 +173,18 @@ export const CellValue = memo(function RenderCellValue({
|
|||
</GuidedOnboardingTourStep>
|
||||
);
|
||||
}, [
|
||||
header,
|
||||
columnId,
|
||||
browserFieldsByName,
|
||||
columnHeaders,
|
||||
ecsAlert,
|
||||
isTourAnchor,
|
||||
browserFields,
|
||||
columnId,
|
||||
finalData,
|
||||
ecsAlert,
|
||||
eventId,
|
||||
myHeader,
|
||||
isDetails,
|
||||
|
||||
isExpandable,
|
||||
isExpanded,
|
||||
linkValues,
|
||||
localLinkValues,
|
||||
rowIndex,
|
||||
colIndex,
|
||||
rowRenderers,
|
||||
|
@ -198,9 +201,9 @@ export const CellValue = memo(function RenderCellValue({
|
|||
<EuiIcon type="layers" />
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>{Renderer}</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>{CellRenderer}</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
) : (
|
||||
<>{Renderer}</>
|
||||
<>{CellRenderer}</>
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue