mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[RAC] [Alerts] Add highlight to building block alerts (#107727)
* [rac] [Alerts] Add highlight to building block alerts * Pull back 'additional filters' button to t-grid
This commit is contained in:
parent
78e2bd2788
commit
eca7146a9f
7 changed files with 223 additions and 117 deletions
|
@ -14,8 +14,12 @@ import {
|
|||
mapSortDirectionToDirection,
|
||||
mapSortingColumns,
|
||||
stringifyEvent,
|
||||
addBuildingBlockStyle,
|
||||
} from './helpers';
|
||||
|
||||
import { euiThemeVars } from '@kbn/ui-shared-deps/theme';
|
||||
import { mockDnsEvent } from '../../../mock';
|
||||
|
||||
describe('helpers', () => {
|
||||
describe('stringifyEvent', () => {
|
||||
test('it omits __typename when it appears at arbitrary levels', () => {
|
||||
|
@ -388,4 +392,32 @@ describe('helpers', () => {
|
|||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addBuildingBlockStyle', () => {
|
||||
const THEME = { eui: euiThemeVars, darkMode: false };
|
||||
|
||||
test('it calls `setCellProps` with background color when event is a building block', () => {
|
||||
const mockedSetCellProps = jest.fn();
|
||||
const ecs = {
|
||||
...mockDnsEvent,
|
||||
...{ signal: { rule: { building_block_type: ['default'] } } },
|
||||
};
|
||||
|
||||
addBuildingBlockStyle(ecs, THEME, mockedSetCellProps);
|
||||
|
||||
expect(mockedSetCellProps).toBeCalledWith({
|
||||
style: {
|
||||
backgroundColor: euiThemeVars.euiColorHighlight,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('it call `setCellProps` reseting the background color when event is not a building block', () => {
|
||||
const mockedSetCellProps = jest.fn();
|
||||
|
||||
addBuildingBlockStyle(mockDnsEvent, THEME, mockedSetCellProps);
|
||||
|
||||
expect(mockedSetCellProps).toBeCalledWith({ style: { backgroundColor: 'inherit' } });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
|
||||
import { EuiDataGridCellValueElementProps } from '@elastic/eui';
|
||||
import type { Ecs } from '../../../../common/ecs';
|
||||
import type {
|
||||
BrowserField,
|
||||
|
@ -20,6 +21,8 @@ import type {
|
|||
TimelineEventsType,
|
||||
} from '../../../../common/types/timeline';
|
||||
|
||||
import type { EuiTheme } from '../../../../../../../src/plugins/kibana_react/common';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const omitTypenameAndEmpty = (k: string, v: any): any | undefined =>
|
||||
k !== '__typename' && v != null ? v : undefined;
|
||||
|
@ -185,3 +188,23 @@ export const allowSorting = ({
|
|||
|
||||
return isAllowlistedNonBrowserField || isAggregatable;
|
||||
};
|
||||
export const addBuildingBlockStyle = (
|
||||
ecs: Ecs,
|
||||
theme: EuiTheme,
|
||||
setCellProps: EuiDataGridCellValueElementProps['setCellProps']
|
||||
) => {
|
||||
if (isEventBuildingBlockType(ecs)) {
|
||||
setCellProps({
|
||||
style: {
|
||||
backgroundColor: `${theme.eui.euiColorHighlight}`,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// reset cell style
|
||||
setCellProps({
|
||||
style: {
|
||||
backgroundColor: 'inherit',
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -24,28 +24,34 @@ import React, {
|
|||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import { connect, ConnectedProps, useDispatch } from 'react-redux';
|
||||
|
||||
import { ThemeContext } from 'styled-components';
|
||||
import {
|
||||
TGridCellAction,
|
||||
TimelineId,
|
||||
TimelineTabs,
|
||||
BulkActionsProp,
|
||||
SortColumnTimeline,
|
||||
} from '../../../../common/types/timeline';
|
||||
|
||||
import type {
|
||||
CellValueElementProps,
|
||||
ColumnHeaderOptions,
|
||||
ControlColumnProps,
|
||||
RowRenderer,
|
||||
AlertStatus,
|
||||
SortColumnTimeline,
|
||||
TimelineId,
|
||||
TimelineTabs,
|
||||
} from '../../../../common/types/timeline';
|
||||
|
||||
import type { TimelineItem, TimelineNonEcsData } from '../../../../common/search_strategy/timeline';
|
||||
|
||||
import { getActionsColumnWidth, getColumnHeaders } from './column_headers/helpers';
|
||||
import { getEventIdToDataMapping, mapSortDirectionToDirection, mapSortingColumns } from './helpers';
|
||||
import {
|
||||
addBuildingBlockStyle,
|
||||
getEventIdToDataMapping,
|
||||
mapSortDirectionToDirection,
|
||||
mapSortingColumns,
|
||||
} from './helpers';
|
||||
|
||||
import { DEFAULT_ICON_BUTTON_WIDTH } from '../helpers';
|
||||
import type { BrowserFields } from '../../../../common/search_strategy/index_fields';
|
||||
|
@ -58,6 +64,7 @@ import { RowAction } from './row_action';
|
|||
import * as i18n from './translations';
|
||||
import { AlertCount } from '../styles';
|
||||
import { checkBoxControlColumn } from './control_columns';
|
||||
import type { EuiTheme } from '../../../../../../../src/plugins/kibana_react/common';
|
||||
|
||||
const StatefulAlertStatusBulkActions = lazy(
|
||||
() => import('../toolbar/bulk_actions/alert_status_bulk_actions')
|
||||
|
@ -121,6 +128,7 @@ const transformControlColumns = ({
|
|||
onSelectPage,
|
||||
browserFields,
|
||||
sort,
|
||||
theme,
|
||||
}: {
|
||||
actionColumnsWidth: number;
|
||||
columnHeaders: ColumnHeaderOptions[];
|
||||
|
@ -138,6 +146,7 @@ const transformControlColumns = ({
|
|||
browserFields: BrowserFields;
|
||||
onSelectPage: OnSelectAll;
|
||||
sort: SortColumnTimeline[];
|
||||
theme: EuiTheme;
|
||||
}): EuiDataGridControlColumn[] =>
|
||||
controlColumns.map(
|
||||
({ id: columnId, headerCellRender = EmptyHeaderCellRender, rowCellRender, width }, i) => ({
|
||||
|
@ -173,29 +182,33 @@ const transformControlColumns = ({
|
|||
isExpanded,
|
||||
rowIndex,
|
||||
setCellProps,
|
||||
}: EuiDataGridCellValueElementProps) => (
|
||||
<RowAction
|
||||
columnId={columnId ?? ''}
|
||||
columnHeaders={columnHeaders}
|
||||
controlColumn={controlColumns[i]}
|
||||
data={data}
|
||||
index={i}
|
||||
isDetails={isDetails}
|
||||
isExpanded={isExpanded}
|
||||
isEventViewer={isEventViewer}
|
||||
isExpandable={isExpandable}
|
||||
loadingEventIds={loadingEventIds}
|
||||
onRowSelected={onRowSelected}
|
||||
onRuleChange={onRuleChange}
|
||||
rowIndex={rowIndex}
|
||||
selectedEventIds={selectedEventIds}
|
||||
setCellProps={setCellProps}
|
||||
showCheckboxes={showCheckboxes}
|
||||
tabType={tabType}
|
||||
timelineId={timelineId}
|
||||
width={width ?? MIN_ACTION_COLUMN_WIDTH}
|
||||
/>
|
||||
),
|
||||
}: EuiDataGridCellValueElementProps) => {
|
||||
addBuildingBlockStyle(data[rowIndex].ecs, theme, setCellProps);
|
||||
|
||||
return (
|
||||
<RowAction
|
||||
columnId={columnId ?? ''}
|
||||
columnHeaders={columnHeaders}
|
||||
controlColumn={controlColumns[i]}
|
||||
data={data}
|
||||
index={i}
|
||||
isDetails={isDetails}
|
||||
isExpanded={isExpanded}
|
||||
isEventViewer={isEventViewer}
|
||||
isExpandable={isExpandable}
|
||||
loadingEventIds={loadingEventIds}
|
||||
onRowSelected={onRowSelected}
|
||||
onRuleChange={onRuleChange}
|
||||
rowIndex={rowIndex}
|
||||
selectedEventIds={selectedEventIds}
|
||||
setCellProps={setCellProps}
|
||||
showCheckboxes={showCheckboxes}
|
||||
tabType={tabType}
|
||||
timelineId={timelineId}
|
||||
width={width ?? MIN_ACTION_COLUMN_WIDTH}
|
||||
/>
|
||||
);
|
||||
},
|
||||
width: width ?? actionColumnsWidth,
|
||||
})
|
||||
);
|
||||
|
@ -252,6 +265,7 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
|
|||
|
||||
const selectedCount = useMemo(() => Object.keys(selectedEventIds).length, [selectedEventIds]);
|
||||
|
||||
const theme: EuiTheme = useContext(ThemeContext);
|
||||
const onRowSelected: OnRowSelected = useCallback(
|
||||
({ eventIds, isSelected }: { eventIds: string[]; isSelected: boolean }) => {
|
||||
setSelected({
|
||||
|
@ -444,6 +458,7 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
|
|||
sort,
|
||||
browserFields,
|
||||
onSelectPage,
|
||||
theme,
|
||||
})
|
||||
);
|
||||
}, [
|
||||
|
@ -463,6 +478,7 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
|
|||
browserFields,
|
||||
onSelectPage,
|
||||
sort,
|
||||
theme,
|
||||
]);
|
||||
|
||||
const columnsWithCellActions: EuiDataGridColumn[] = useMemo(
|
||||
|
@ -483,34 +499,37 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
|
|||
[browserFields, columnHeaders, data, defaultCellActions]
|
||||
);
|
||||
|
||||
const renderTGridCellValue: (x: EuiDataGridCellValueElementProps) => React.ReactNode = ({
|
||||
columnId,
|
||||
rowIndex,
|
||||
setCellProps,
|
||||
}) => {
|
||||
const rowData = rowIndex < data.length ? data[rowIndex].data : null;
|
||||
const header = columnHeaders.find((h) => h.id === columnId);
|
||||
const eventId = rowIndex < data.length ? data[rowIndex]._id : null;
|
||||
const renderTGridCellValue: (
|
||||
x: EuiDataGridCellValueElementProps
|
||||
) => React.ReactNode = useCallback(
|
||||
({ columnId, rowIndex, setCellProps }) => {
|
||||
const rowData = rowIndex < data.length ? data[rowIndex].data : null;
|
||||
const header = columnHeaders.find((h) => h.id === columnId);
|
||||
const eventId = rowIndex < data.length ? data[rowIndex]._id : null;
|
||||
|
||||
if (rowData == null || header == null || eventId == null) {
|
||||
return null;
|
||||
}
|
||||
addBuildingBlockStyle(data[rowIndex].ecs, theme, setCellProps);
|
||||
|
||||
return renderCellValue({
|
||||
columnId: header.id,
|
||||
eventId,
|
||||
data: rowData,
|
||||
header,
|
||||
isDraggable: false,
|
||||
isExpandable: true,
|
||||
isExpanded: false,
|
||||
isDetails: false,
|
||||
linkValues: getOr([], header.linkField ?? '', data[rowIndex].ecs),
|
||||
rowIndex,
|
||||
setCellProps,
|
||||
timelineId: tabType != null ? `${id}-${tabType}` : id,
|
||||
});
|
||||
};
|
||||
if (rowData == null || header == null || eventId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return renderCellValue({
|
||||
columnId: header.id,
|
||||
eventId,
|
||||
data: rowData,
|
||||
header,
|
||||
isDraggable: false,
|
||||
isExpandable: true,
|
||||
isExpanded: false,
|
||||
isDetails: false,
|
||||
linkValues: getOr([], header.linkField ?? '', data[rowIndex].ecs),
|
||||
rowIndex,
|
||||
setCellProps,
|
||||
timelineId: tabType != null ? `${id}-${tabType}` : id,
|
||||
});
|
||||
},
|
||||
[columnHeaders, data, id, renderCellValue, tabType, theme]
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiDataGrid
|
||||
|
|
|
@ -34,7 +34,6 @@ import {
|
|||
DataPublicPluginStart,
|
||||
} from '../../../../../../../src/plugins/data/public';
|
||||
import { useDeepEqualSelector } from '../../../hooks/use_selector';
|
||||
import { Refetch } from '../../../store/t_grid/inputs';
|
||||
import { defaultHeaders } from '../body/column_headers/default_headers';
|
||||
import { calculateTotalPages, combineQueries, resolverIsShowing } from '../helpers';
|
||||
import { tGridActions, tGridSelectors } from '../../../store/t_grid';
|
||||
|
@ -42,7 +41,6 @@ import { useTimelineEvents } from '../../../container';
|
|||
import { HeaderSection } from '../header_section';
|
||||
import { StatefulBody } from '../body';
|
||||
import { Footer, footerHeight } from '../footer';
|
||||
import { LastUpdatedAt } from '../..';
|
||||
import { SELECTOR_TIMELINE_GLOBAL_CONTAINER, UpdatedFlexItem } from '../styles';
|
||||
import * as i18n from '../translations';
|
||||
import { ExitFullScreen } from '../../exit_full_screen';
|
||||
|
@ -132,7 +130,7 @@ export interface TGridIntegratedProps {
|
|||
setGlobalFullScreen: (fullscreen: boolean) => void;
|
||||
start: string;
|
||||
sort: Sort[];
|
||||
utilityBar?: (refetch: Refetch, totalCount: number) => React.ReactNode;
|
||||
additionalFilters: React.ReactNode;
|
||||
// If truthy, the graph viewer (Resolver) is showing
|
||||
graphEventId: string | undefined;
|
||||
leadingControlColumns?: ControlColumnProps[];
|
||||
|
@ -167,7 +165,7 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
|
|||
setGlobalFullScreen,
|
||||
start,
|
||||
sort,
|
||||
utilityBar,
|
||||
additionalFilters,
|
||||
graphEventId,
|
||||
leadingControlColumns,
|
||||
trailingControlColumns,
|
||||
|
@ -239,7 +237,7 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
|
|||
|
||||
const [
|
||||
loading,
|
||||
{ events, updatedAt, loadPage, pageInfo, refetch, totalCount = 0, inspect },
|
||||
{ events, loadPage, pageInfo, refetch, totalCount = 0, inspect },
|
||||
] = useTimelineEvents({
|
||||
alertConsumers: SECURITY_ALERTS_CONSUMERS,
|
||||
docValueFields,
|
||||
|
@ -294,19 +292,17 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
|
|||
height={
|
||||
headerFilterGroup == null ? COMPACT_HEADER_HEIGHT : EVENTS_VIEWER_HEADER_HEIGHT
|
||||
}
|
||||
subtitle={utilityBar}
|
||||
title={globalFullScreen ? titleWithExitFullScreen : justTitle}
|
||||
>
|
||||
{HeaderSectionContent}
|
||||
</HeaderSection>
|
||||
|
||||
<EventsContainerLoading
|
||||
data-timeline-id={id}
|
||||
data-test-subj={`events-container-loading-${loading}`}
|
||||
>
|
||||
<EuiFlexGroup gutterSize="none" justifyContent="flexEnd">
|
||||
<UpdatedFlexItem grow={false} show={!loading}>
|
||||
<LastUpdatedAt updatedAt={updatedAt} />
|
||||
{!resolverIsShowing(graphEventId) && additionalFilters}
|
||||
</UpdatedFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue