Skip to content

Commit

Permalink
[SECURITY SOLUTION] [RAC] Event rendered view (elastic#108644)
Browse files Browse the repository at this point in the history
* wip

* match design for selecting grid view

* wip to integrate event rendered view

* wip

* integration of the event rendered

* fix perPage action on Euibasic table

* Add bulding block background color to EventRenderedView

* styling

* remove header

* fix types

* fix unit tests

* use memo for listProps

* fix styling + add feature flag

* review I

* fix merge

* change the gutter size

Co-authored-by: Pablo Neves Machado <pablo.nevesmachado@elastic.co>
Co-authored-by: Angela Chuang <yi-chun.chuang@elastic.co>
  • Loading branch information
3 people authored and kibanamachine committed Aug 18, 2021
1 parent d9232d4 commit c0f1bf1
Show file tree
Hide file tree
Showing 14 changed files with 635 additions and 470 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const allowedExperimentalValues = Object.freeze({
metricsEntitiesEnabled: false,
ruleRegistryEnabled: false,
tGridEnabled: true,
tGridEventRenderedViewEnabled: true,
trustedAppsByPolicyEnabled: false,
excludePoliciesInFilterEnabled: false,
uebaEnabled: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const getColumns = ({
),
sortable: false,
truncateText: false,
width: '180px',
width: '132px',
render: (values: string[] | null | undefined, data: EventFieldsData) => {
const label = data.isObjectArray
? i18n.NESTED_COLUMN(data.field)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export interface OwnProps {
scopeId: SourcererScopeName;
start: string;
showTotalCount?: boolean;
headerFilterGroup?: React.ReactNode;
pageFilters?: Filter[];
currentFilter?: Status;
onRuleChange?: () => void;
Expand Down Expand Up @@ -88,7 +87,6 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
entityType,
excludedRowRendererIds,
filters,
headerFilterGroup,
id,
isLive,
itemsPerPage,
Expand Down Expand Up @@ -120,6 +118,9 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
const { globalFullScreen, setGlobalFullScreen } = useGlobalFullScreen();
// TODO: Once we are past experimental phase this code should be removed
const tGridEnabled = useIsExperimentalFeatureEnabled('tGridEnabled');
const tGridEventRenderedViewEnabled = useIsExperimentalFeatureEnabled(
'tGridEventRenderedViewEnabled'
);
useEffect(() => {
if (createTimeline != null) {
createTimeline({
Expand Down Expand Up @@ -153,6 +154,7 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
<InspectButtonContainer>
{tGridEnabled ? (
timelinesUi.getTGrid<'embedded'>({
id,
type: 'embedded',
browserFields,
columns,
Expand All @@ -165,8 +167,6 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
filters: globalFilters,
globalFullScreen,
graphOverlay,
headerFilterGroup,
id,
indexNames: selectedPatterns,
indexPattern,
isLive,
Expand All @@ -186,6 +186,7 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
filterStatus: currentFilter,
leadingControlColumns,
trailingControlColumns,
tGridEventRenderedViewEnabled,
})
) : (
<EventsViewer
Expand All @@ -198,7 +199,6 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
end={end}
isLoadingIndexPattern={isLoadingIndexPattern}
filters={globalFilters}
headerFilterGroup={headerFilterGroup}
indexNames={selectedPatterns}
indexPattern={indexPattern}
isLive={isLive}
Expand Down
51 changes: 51 additions & 0 deletions x-pack/plugins/timelines/public/components/rule_name/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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 { EuiLink } from '@elastic/eui';
import { isEmpty } from 'lodash';
import React, { useCallback, useMemo } from 'react';
import { CoreStart } from '../../../../../../src/core/public';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';

interface RuleNameProps {
name: string;
id: string;
}

const appendSearch = (search?: string) =>
isEmpty(search) ? '' : `${search?.startsWith('?') ? search : `?${search}`}`;

const RuleNameComponents = ({ name, id }: RuleNameProps) => {
const { navigateToApp, getUrlForApp } = useKibana<CoreStart>().services.application;

const hrefRuleDetails = useMemo(
() =>
getUrlForApp('securitySolution', {
deepLinkId: 'rules',
path: `/id/${id}${appendSearch(window.location.search)}`,
}),
[getUrlForApp, id]
);
const goToRuleDetails = useCallback(
(ev) => {
ev.preventDefault();
navigateToApp('securitySolution', {
deepLinkId: 'rules',
path: `/id/${id}${appendSearch(window.location.search)}`,
});
},
[navigateToApp, id]
);
return (
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink href={hrefRuleDetails} onClick={goToRuleDetails}>
{name}
</EuiLink>
);
};

export const RuleName = React.memo(RuleNameComponents);
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,18 @@ describe('Body', () => {
excludedRowRendererIds: [],
id: 'timeline-test',
isSelectAllChecked: false,
itemsPerPageOptions: [],
loadingEventIds: [],
loadPage: jest.fn(),
querySize: 25,
renderCellValue: TestCellRenderer,
rowRenderers: [],
selectedEventIds: {},
setSelected: (jest.fn() as unknown) as StatefulBodyProps['setSelected'],
sort: mockSort,
showCheckboxes: false,
tabType: TimelineTabs.query,
tableView: 'gridView',
totalPages: 1,
totalItems: 1,
leadingControlColumns: [],
Expand Down
140 changes: 103 additions & 37 deletions x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
EuiDataGridStyle,
EuiDataGridToolBarVisibilityOptions,
EuiLoadingSpinner,
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { getOr } from 'lodash/fp';
import memoizeOne from 'memoize-one';
Expand Down Expand Up @@ -67,6 +69,8 @@ import * as i18n from './translations';
import { AlertCount } from '../styles';
import { checkBoxControlColumn } from './control_columns';
import type { EuiTheme } from '../../../../../../../src/plugins/kibana_react/common';
import { ViewSelection } from '../event_rendered_view/selector';
import { EventRenderedView } from '../event_rendered_view';

const StatefulAlertStatusBulkActions = lazy(
() => import('../toolbar/bulk_actions/alert_status_bulk_actions')
Expand All @@ -76,25 +80,28 @@ interface OwnProps {
activePage: number;
additionalControls?: React.ReactNode;
browserFields: BrowserFields;
filterQuery: string;
bulkActions?: BulkActionsProp;
data: TimelineItem[];
defaultCellActions?: TGridCellAction[];
filterQuery: string;
filterStatus?: AlertStatus;
id: string;
indexNames: string[];
isEventViewer?: boolean;
itemsPerPageOptions: number[];
leadingControlColumns?: ControlColumnProps[];
loadPage: (newActivePage: number) => void;
onRuleChange?: () => void;
querySize: number;
refetch: Refetch;
renderCellValue: (props: CellValueElementProps) => React.ReactNode;
rowRenderers: RowRenderer[];
tableView: ViewSelection;
tabType: TimelineTabs;
leadingControlColumns?: ControlColumnProps[];
loadPage: (newActivePage: number) => void;
trailingControlColumns?: ControlColumnProps[];
totalPages: number;
totalItems: number;
bulkActions?: BulkActionsProp;
filterStatus?: AlertStatus;
totalPages: number;
trailingControlColumns?: ControlColumnProps[];
unit?: (total: number) => React.ReactNode;
onRuleChange?: () => void;
indexNames: string[];
refetch: Refetch;
}

const basicUnit = (n: number) => i18n.UNIT(n);
Expand Down Expand Up @@ -235,34 +242,37 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
activePage,
additionalControls,
browserFields,
filterQuery,
bulkActions = true,
clearSelected,
columnHeaders,
data,
defaultCellActions,
excludedRowRendererIds,
filterQuery,
filterStatus,
id,
indexNames,
isEventViewer = false,
isSelectAllChecked,
itemsPerPageOptions,
leadingControlColumns = EMPTY_CONTROL_COLUMNS,
loadingEventIds,
loadPage,
selectedEventIds,
setSelected,
clearSelected,
onRuleChange,
showCheckboxes,
querySize,
refetch,
renderCellValue,
rowRenderers,
selectedEventIds,
setSelected,
showCheckboxes,
sort,
tableView = 'gridView',
tabType,
totalPages,
totalItems,
filterStatus,
bulkActions = true,
unit = basicUnit,
leadingControlColumns = EMPTY_CONTROL_COLUMNS,
totalPages,
trailingControlColumns = EMPTY_CONTROL_COLUMNS,
indexNames,
refetch,
unit = basicUnit,
}) => {
const dispatch = useDispatch();
const getManageTimeline = useMemo(() => tGridSelectors.getManageTimelineById(), []);
Expand Down Expand Up @@ -336,6 +346,43 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
return bulkActions.alertStatusActions ?? true;
}, [selectedCount, showCheckboxes, bulkActions]);

const alertToolbar = useMemo(
() => (
<EuiFlexGroup gutterSize="m" alignItems="center">
<EuiFlexItem grow={false}>
<AlertCount>{alertCountText}</AlertCount>
</EuiFlexItem>
{showBulkActions && (
<Suspense fallback={<EuiLoadingSpinner />}>
<StatefulAlertStatusBulkActions
data-test-subj="bulk-actions"
id={id}
totalItems={totalItems}
filterStatus={filterStatus}
query={filterQuery}
indexName={indexNames.join()}
onActionSuccess={onAlertStatusActionSuccess}
onActionFailure={onAlertStatusActionFailure}
refetch={refetch}
/>
</Suspense>
)}
</EuiFlexGroup>
),
[
alertCountText,
filterQuery,
filterStatus,
id,
indexNames,
onAlertStatusActionFailure,
onAlertStatusActionSuccess,
refetch,
showBulkActions,
totalItems,
]
);

const toolbarVisibility: EuiDataGridToolBarVisibilityOptions = useMemo(
() => ({
additionalControls: (
Expand Down Expand Up @@ -573,20 +620,39 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
}, [columnHeaders, data, id, renderCellValue, tabType, theme, browserFields, rowRenderers]);

return (
<EuiDataGrid
data-test-subj="body-data-grid"
aria-label={i18n.TGRID_BODY_ARIA_LABEL}
columns={columnsWithCellActions}
columnVisibility={{ visibleColumns, setVisibleColumns }}
gridStyle={gridStyle}
leadingControlColumns={leadingTGridControlColumns}
trailingControlColumns={trailingTGridControlColumns}
toolbarVisibility={toolbarVisibility}
rowCount={data.length}
renderCellValue={renderTGridCellValue}
inMemory={{ level: 'sorting' }}
sorting={{ columns: sortingColumns, onSort }}
/>
<>
{tableView === 'gridView' && (
<EuiDataGrid
data-test-subj="body-data-grid"
aria-label={i18n.TGRID_BODY_ARIA_LABEL}
columns={columnsWithCellActions}
columnVisibility={{ visibleColumns, setVisibleColumns }}
gridStyle={gridStyle}
leadingControlColumns={leadingTGridControlColumns}
trailingControlColumns={trailingTGridControlColumns}
toolbarVisibility={toolbarVisibility}
rowCount={data.length}
renderCellValue={renderTGridCellValue}
inMemory={{ level: 'sorting' }}
sorting={{ columns: sortingColumns, onSort }}
/>
)}
{tableView === 'eventRenderedView' && (
<EventRenderedView
alertToolbar={alertToolbar}
browserFields={browserFields}
events={data}
leadingControlColumns={leadingTGridControlColumns ?? []}
onChangePage={loadPage}
pageIndex={activePage}
pageSize={querySize}
pageSizeOptions={itemsPerPageOptions}
rowRenderers={rowRenderers}
timelineId={id}
totalItemCount={totalItems}
/>
)}
</>
);
}
);
Expand Down Expand Up @@ -635,4 +701,4 @@ const connector = connect(makeMapStateToProps, mapDispatchToProps);

type PropsFromRedux = ConnectedProps<typeof connector>;

export const StatefulBody = connector(BodyComponent);
export const StatefulBody: React.FunctionComponent<OwnProps> = connector(BodyComponent);
Loading

0 comments on commit c0f1bf1

Please sign in to comment.