diff --git a/packages/kbn-babel-preset/styled_components_files.js b/packages/kbn-babel-preset/styled_components_files.js index 311b2f71da181..6739213b4e19d 100644 --- a/packages/kbn-babel-preset/styled_components_files.js +++ b/packages/kbn-babel-preset/styled_components_files.js @@ -196,8 +196,6 @@ module.exports = { /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]public[\/\\]common[\/\\]components[\/\\]empty_value[\/\\]index.tsx/, /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]public[\/\\]common[\/\\]components[\/\\]endpoint[\/\\]agents[\/\\]agent_status[\/\\]agent_status.tsx/, /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]public[\/\\]common[\/\\]components[\/\\]events_viewer[\/\\]index.tsx/, - /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]public[\/\\]common[\/\\]components[\/\\]events_viewer[\/\\]right_top_menu.tsx/, - /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]public[\/\\]common[\/\\]components[\/\\]events_viewer[\/\\]styles.tsx/, /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]public[\/\\]common[\/\\]components[\/\\]events_viewer[\/\\]summary_view_select[\/\\]index.tsx/, /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]public[\/\\]common[\/\\]components[\/\\]field_selection[\/\\]index.tsx/, /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]public[\/\\]common[\/\\]components[\/\\]filters_global[\/\\]filters_global.tsx/, diff --git a/x-pack/solutions/security/packages/data_table/components/data_table/index.tsx b/x-pack/solutions/security/packages/data_table/components/data_table/index.tsx index 0b1a728284a7f..4c3bdd0dd5334 100644 --- a/x-pack/solutions/security/packages/data_table/components/data_table/index.tsx +++ b/x-pack/solutions/security/packages/data_table/components/data_table/index.tsx @@ -6,20 +6,19 @@ */ import type { - EuiDataGridRefProps, - EuiDataGridColumn, EuiDataGridCellValueElementProps, - EuiDataGridStyle, - EuiDataGridToolBarVisibilityOptions, + EuiDataGridColumn, EuiDataGridControlColumn, EuiDataGridPaginationProps, - EuiDataGridRowHeightsOptions, EuiDataGridProps, + EuiDataGridRefProps, + EuiDataGridStyle, + EuiDataGridToolBarVisibilityOptions, } from '@elastic/eui'; import { EuiDataGrid, EuiProgress } from '@elastic/eui'; import { getOr } from 'lodash/fp'; import memoizeOne from 'memoize-one'; -import React, { useCallback, useEffect, useMemo, useContext, useRef } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useRef } from 'react'; import { useDispatch } from 'react-redux'; import styled, { ThemeContext } from 'styled-components'; @@ -31,8 +30,8 @@ import type { import { i18n } from '@kbn/i18n'; import { BrowserFields, - DeprecatedCellValueElementProps, ColumnHeaderOptions, + DeprecatedCellValueElementProps, DeprecatedRowRenderer, TimelineItem, } from '@kbn/timelines-plugin/common'; @@ -88,12 +87,9 @@ interface BaseDataTableProps { loadPage: (newActivePage: number) => void; renderCellValue: (props: DeprecatedCellValueElementProps) => React.ReactNode; rowRenderers: DeprecatedRowRenderer[]; - hasCrudPermissions?: boolean; unitCountText: string; pagination: EuiDataGridPaginationProps & { pageSize: number }; totalItems: number; - rowHeightsOptions?: EuiDataGridRowHeightsOptions; - isEventRenderedView?: boolean; getFieldBrowser: GetFieldBrowser; getFieldSpec: (fieldName: string) => FieldSpec | undefined; cellActionsTriggerId?: string; @@ -103,12 +99,11 @@ export type DataTableProps = BaseDataTableProps & Omit ({ +const gridStyle: EuiDataGridStyle = { border: 'none', fontSize: 's', header: 'underline', - stripes: isEventRenderedView === true, -}); +}; const EuiDataGridContainer = styled.div<{ hideLastPage: boolean }>` ul.euiPagination__list { @@ -116,19 +111,23 @@ const EuiDataGridContainer = styled.div<{ hideLastPage: boolean }>` ${({ hideLastPage }) => `${hideLastPage ? 'display:none' : ''}`}; } } + div .euiDataGridRowCell { display: flex; align-items: center; } + div .euiDataGridRowCell > [data-focus-lock-disabled] { display: flex; align-items: center; flex-grow: 1; width: 100%; } + div .euiDataGridRowCell__content { flex-grow: 1; } + div .siemEventsTable__trSupplement--summary { display: block; } @@ -136,8 +135,7 @@ const EuiDataGridContainer = styled.div<{ hideLastPage: boolean }>` const memoizedGetColumnHeaders: ( headers: ColumnHeaderOptions[], - browserFields: BrowserFields, - isEventRenderedView: boolean + browserFields: BrowserFields ) => ColumnHeaderOptions[] = memoizeOne(getColumnHeaders); // eslint-disable-next-line react/display-name @@ -148,7 +146,6 @@ export const DataTableComponent = React.memo( bulkActions = true, data, fieldBrowserOptions, - hasCrudPermissions, id, leadingControlColumns, loadPage, @@ -157,8 +154,6 @@ export const DataTableComponent = React.memo( pagination, unitCountText, totalItems, - rowHeightsOptions, - isEventRenderedView = false, getFieldBrowser, getFieldSpec, cellActionsTriggerId, @@ -178,7 +173,7 @@ export const DataTableComponent = React.memo( dataViewId, } = dataTable; - const columnHeaders = memoizedGetColumnHeaders(columns, browserFields, isEventRenderedView); + const columnHeaders = memoizedGetColumnHeaders(columns, browserFields); const dataGridRef = useRef(null); @@ -189,10 +184,6 @@ export const DataTableComponent = React.memo( const theme: EuiTheme = useContext(ThemeContext); const showBulkActions = useMemo(() => { - if (!hasCrudPermissions) { - return false; - } - if (selectedCount === 0 || !showCheckboxes) { return false; } @@ -200,7 +191,7 @@ export const DataTableComponent = React.memo( return bulkActions; } return (bulkActions?.customBulkActions?.length || bulkActions?.alertStatusActions) ?? true; - }, [hasCrudPermissions, selectedCount, showCheckboxes, bulkActions]); + }, [selectedCount, showCheckboxes, bulkActions]); const onResetColumns = useCallback(() => { dispatch(dataTableActions.updateColumns({ id, columns: defaultColumns })); @@ -237,22 +228,18 @@ export const DataTableComponent = React.memo( {isLoading && } {unitCountText} {additionalControls ?? null} - {!isEventRenderedView ? ( - getFieldBrowser({ - browserFields, - options: fieldBrowserOptions, - columnIds: columnHeaders.map(({ id: columnId }) => columnId), - onResetColumns, - onToggleColumn, - }) - ) : ( - <> - )} + {getFieldBrowser({ + browserFields, + options: fieldBrowserOptions, + columnIds: columnHeaders.map(({ id: columnId }) => columnId), + onResetColumns, + onToggleColumn, + })} ), }, }, - ...(showBulkActions || isEventRenderedView + ...(showBulkActions ? { showColumnSelector: false, showSortSelector: false, @@ -269,7 +256,6 @@ export const DataTableComponent = React.memo( isLoading, unitCountText, additionalControls, - isEventRenderedView, getFieldBrowser, browserFields, fieldBrowserOptions, @@ -468,9 +454,9 @@ export const DataTableComponent = React.memo( id={'body-data-grid'} data-test-subj="body-data-grid" aria-label={DATA_TABLE_ARIA_LABEL} - columns={isEventRenderedView ? columnHeaders : columnsWithCellActions} + columns={columnsWithCellActions} columnVisibility={{ visibleColumns, setVisibleColumns: onSetVisibleColumns }} - gridStyle={gridStyle(isEventRenderedView)} + gridStyle={gridStyle} leadingControlColumns={leadingControlColumns} toolbarVisibility={toolbarVisibility} rowCount={totalItems} @@ -479,7 +465,7 @@ export const DataTableComponent = React.memo( onColumnResize={onColumnResize} pagination={pagination} ref={dataGridRef} - rowHeightsOptions={rowHeightsOptions} + rowHeightsOptions={undefined} /> diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx index 0a5156bddcc99..3d93dd19cf691 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx @@ -7,11 +7,11 @@ import { render } from '@testing-library/react'; import React from 'react'; -import { TableId, dataTableActions } from '@kbn/securitysolution-data-table'; +import { dataTableActions, TableId } from '@kbn/securitysolution-data-table'; import { HostsType } from '../../../explore/hosts/store/model'; import { TestProviders } from '../../mock'; import type { EventsQueryTabBodyComponentProps } from './events_query_tab_body'; -import { EventsQueryTabBody, ALERTS_EVENTS_HISTOGRAM_ID } from './events_query_tab_body'; +import { ALERTS_EVENTS_HISTOGRAM_ID, EventsQueryTabBody } from './events_query_tab_body'; import { useGlobalFullScreen } from '../../containers/use_full_screen'; import { licenseService } from '../../hooks/use_license'; import { mockHistory } from '../../mock/router'; @@ -59,9 +59,13 @@ jest.mock('react-router-dom', () => ({ useLocation: jest.fn().mockReturnValue({ pathname: '/test' }), })); -const FakeStatefulEventsViewer = ({ additionalFilters }: { additionalFilters: JSX.Element }) => ( +const FakeStatefulEventsViewer = ({ + topRightMenuOptions, +}: { + topRightMenuOptions: JSX.Element; +}) => (
- {additionalFilters} + {topRightMenuOptions} {'MockedStatefulEventsViewer'}
); diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx index 70e56f4a8b4d2..2bb51df635380 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx @@ -10,8 +10,8 @@ import { useDispatch } from 'react-redux'; import { EuiCheckbox } from '@elastic/eui'; import type { Filter } from '@kbn/es-query'; -import { dataTableActions } from '@kbn/securitysolution-data-table'; import type { TableId } from '@kbn/securitysolution-data-table'; +import { dataTableActions } from '@kbn/securitysolution-data-table'; import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; import type { CustomBulkAction } from '../../../../common/types'; import { RowRendererValues } from '../../../../common/api/timeline'; @@ -177,7 +177,7 @@ const EventsQueryTabBodyComponent: React.FC = /> )} - graphEventId != null && graphEventId !== ''; - -export const EVENTS_COUNT_BUTTON_CLASS_NAME = 'local-events-count-button'; - -/** Returns `true` when the element, or one of it's children has focus */ -export const elementOrChildrenHasFocus = (element: HTMLElement | null | undefined): boolean => - element === document.activeElement || element?.querySelector(':focus-within') != null; - -/** Returns true if the events table has focus */ -export const tableHasFocus = (containerElement: HTMLElement | null): boolean => - elementOrChildrenHasFocus( - containerElement?.querySelector(`.${EVENTS_TABLE_CLASS_NAME}`) - ); - -export const isSelectableView = (tableId: string): boolean => - tableId === TableId.alertsOnAlertsPage || tableId === TableId.alertsOnRuleDetailsPage; - -export const isViewSelection = (value: unknown): value is ViewSelection => - value === 'gridView' || value === 'eventRenderedView'; - -/** always returns a valid default `ViewSelection` */ -export const getDefaultViewSelection = ({ - tableId, - value, -}: { - tableId: string; - value: unknown; -}): ViewSelection => { - const defaultViewSelection = 'gridView'; - - if (!isSelectableView(tableId)) { - return defaultViewSelection; - } else { - return isViewSelection(value) ? value : defaultViewSelection; - } -}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.test.tsx index 162bb6bee5ece..a9c23c415a44a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.test.tsx @@ -12,7 +12,7 @@ import { render } from '@testing-library/react'; import { TestProviders } from '../../mock'; import { mockEventViewerResponse } from './mock'; -import { StatefulEventsViewer, type EventsViewerProps } from '.'; +import { type EventsViewerProps, StatefulEventsViewer } from '.'; import { eventsDefaultModel } from './default_model'; import { EntityType } from '@kbn/timelines-plugin/common'; import { SourcererScopeName } from '../../../sourcerer/store/model'; @@ -54,18 +54,17 @@ const to = '2019-08-26T22:10:56.791Z'; const ACTION_BUTTON_COUNT = 4; const testProps: EventsViewerProps = { + bulkActions: false, defaultModel: eventsDefaultModel, end: to, entityType: EntityType.EVENTS, indexNames: [], - tableId: TableId.test, leadingControlColumns: getDefaultControlColumn(ACTION_BUTTON_COUNT), renderCellValue: DefaultCellRenderer, rowRenderers: defaultRowRenderers, sourcererScope: SourcererScopeName.default, start: from, - bulkActions: false, - hasCrudPermissions: true, + tableId: TableId.test, }; describe('StatefulEventsViewer', () => { beforeAll(() => { @@ -93,7 +92,7 @@ describe('StatefulEventsViewer', () => { ); - expect(wrapper.find(`[data-test-subj="hoverVisibilityContainer"]`).exists()).toBeTruthy(); + expect(wrapper.find(`[data-test-subj="inspect-icon-button"]`).exists()).toBeTruthy(); }); test('it closes field editor when unmounted', () => { @@ -119,7 +118,7 @@ describe('StatefulEventsViewer', () => { ]} + topRightMenuOptions={[

]} /> ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.tsx index adae56f752273..ac400984db6b9 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -5,20 +5,16 @@ * 2.0. */ +import { css } from '@emotion/react'; +import type { SubsetDataTableModel, TableId } from '@kbn/securitysolution-data-table'; import { dataTableActions, DataTableComponent, defaultHeaders, getEventIdToDataMapping, } from '@kbn/securitysolution-data-table'; -import type { - SubsetDataTableModel, - TableId, - ViewSelection, -} from '@kbn/securitysolution-data-table'; -import { Storage } from '@kbn/kibana-utils-plugin/public'; import { AlertConsumers } from '@kbn/rule-data-utils'; -import React, { useRef, useCallback, useMemo, useEffect, useState, useContext } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import type { ConnectedProps } from 'react-redux'; import { connect, useDispatch, useSelector } from 'react-redux'; import { ThemeContext } from 'styled-components'; @@ -33,9 +29,9 @@ import type { import { isEmpty } from 'lodash'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { EuiTheme } from '@kbn/kibana-react-plugin/common'; -import type { EuiDataGridRowHeightsOptions } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; -import { ALERTS_TABLE_VIEW_SELECTION_KEY } from '../../../../common/constants'; +import { InspectButton } from '../inspect'; import type { ControlColumnProps, OnRowSelected, @@ -47,8 +43,6 @@ import type { RowRenderer, SortColumnTimeline as Sort } from '../../../../common import { InputsModelId } from '../../store/inputs/constants'; import type { State } from '../../store'; import { inputsActions } from '../../store/actions'; -import { InspectButtonContainer } from '../inspect'; -import { useGlobalFullScreen } from '../../containers/use_full_screen'; import { eventsViewerSelector } from './selectors'; import type { SourcererScopeName } from '../../../sourcerer/store/model'; import { useSourcererDataView } from '../../../sourcerer/containers'; @@ -58,55 +52,39 @@ import { GraphOverlay } from '../../../timelines/components/graph_overlay'; import type { FieldEditorActions } from '../../../timelines/components/fields_browser'; import { useFieldBrowserOptions } from '../../../timelines/components/fields_browser'; import { - useSessionViewNavigation, useSessionView, + useSessionViewNavigation, } from '../../../timelines/components/timeline/tabs/session/use_session_view'; -import { - EventsContainerLoading, - FullScreenContainer, - FullWidthFlexGroupTable, - ScrollableFlexItem, - StyledEuiPanel, -} from './styles'; -import { getDefaultViewSelection, getCombinedFilterQuery } from './helpers'; +import { getCombinedFilterQuery } from './helpers'; import { useTimelineEvents } from './use_timelines_events'; -import { TableContext, EmptyTable, TableLoading } from './shared'; -import type { AlertWorkflowStatus } from '../../types'; +import { EmptyTable, TableContext, TableLoading } from './shared'; import { useQueryInspector } from '../page/manage_query'; import type { SetQuery } from '../../containers/use_global_time/types'; import { checkBoxControlColumn, transformControlColumns } from '../control_columns'; -import { RightTopMenu } from './right_top_menu'; import { useAlertBulkActions } from './use_alert_bulk_actions'; import type { BulkActionsProp } from '../toolbar/bulk_actions/types'; import { StatefulEventContext } from './stateful_event_context'; import { defaultUnit } from '../toolbar/unit'; import { useGetFieldSpec } from '../../hooks/use_get_field_spec'; -const storage = new Storage(localStorage); - const SECURITY_ALERTS_CONSUMERS = [AlertConsumers.SIEM]; export interface EventsViewerProps { + bulkActions: boolean | BulkActionsProp; + cellActionsTriggerId?: string; defaultModel: SubsetDataTableModel; end: string; entityType?: EntityType; - tableId: TableId; + indexNames?: string[]; leadingControlColumns: ControlColumnProps[]; - sourcererScope: SourcererScopeName; - start: string; - showTotalCount?: boolean; // eslint-disable-line react/no-unused-prop-types pageFilters?: Filter[]; - currentFilter?: AlertWorkflowStatus; - onRuleChange?: () => void; renderCellValue: React.FC; rowRenderers: RowRenderer[]; - additionalFilters?: React.ReactNode; - hasCrudPermissions?: boolean; + sourcererScope: SourcererScopeName; + start: string; + tableId: TableId; + topRightMenuOptions?: React.ReactNode; unit?: (n: number) => string; - indexNames?: string[]; - bulkActions: boolean | BulkActionsProp; - additionalRightMenuOptions?: React.ReactNode[]; - cellActionsTriggerId?: string; } /** @@ -115,19 +93,14 @@ export interface EventsViewerProps { * NOTE: As of writting, it is not used in the Case_View component */ const StatefulEventsViewerComponent: React.FC = ({ - additionalFilters, - additionalRightMenuOptions, bulkActions, cellActionsTriggerId, clearSelected, - currentFilter, defaultModel, end, entityType = 'events', - hasCrudPermissions = true, indexNames, leadingControlColumns, - onRuleChange, pageFilters, renderCellValue, rowRenderers, @@ -135,6 +108,7 @@ const StatefulEventsViewerComponent: React.FC { const dispatch = useDispatch(); @@ -162,6 +136,7 @@ const StatefulEventsViewerComponent: React.FC eventsViewerSelector(state, tableId)); + const inspectModalTitle = useMemo(() => {title}, [title]); const { uiSettings, @@ -169,13 +144,6 @@ const StatefulEventsViewerComponent: React.FC( - getDefaultViewSelection({ - tableId, - value: storage.get(ALERTS_TABLE_VIEW_SELECTION_KEY), - }) - ); - const { browserFields, dataViewId, @@ -187,8 +155,6 @@ const StatefulEventsViewerComponent: React.FC(null); useEffect(() => { dispatch( @@ -215,14 +181,13 @@ const StatefulEventsViewerComponent: React.FC [...filters, ...(pageFilters ?? [])], [filters, pageFilters]); + // TODO remove this when session view is fully migrated to the flyout and the advanced settings is removed const { Navigation } = useSessionViewNavigation({ scopeId: tableId, }); - const { SessionView } = useSessionView({ scopeId: tableId, }); - const graphOverlay = useMemo(() => { const shouldShowOverlay = (graphEventId != null && graphEventId.length > 0) || sessionViewConfig != null; @@ -230,6 +195,7 @@ const StatefulEventsViewerComponent: React.FC ) : null; }, [graphEventId, tableId, sessionViewConfig, SessionView, Navigation]); + const setQuery = useCallback( ({ id, inspect, loading, refetch }: SetQuery) => dispatch( @@ -320,7 +286,7 @@ const StatefulEventsViewerComponent: React.FC { @@ -411,17 +377,12 @@ const StatefulEventsViewerComponent: React.FC { setSelected({ id: tableId, - eventIds: getEventIdToDataMapping( - nonDeletedEvents, - eventIds, - queryFields, - hasCrudPermissions - ), + eventIds: getEventIdToDataMapping(nonDeletedEvents, eventIds, queryFields, true), isSelected, isSelectAllChecked: isSelected && selectedCount + 1 === nonDeletedEvents.length, }); }, - [setSelected, tableId, nonDeletedEvents, queryFields, hasCrudPermissions, selectedCount] + [setSelected, tableId, nonDeletedEvents, queryFields, selectedCount] ); const onSelectPage: OnSelectAll = useCallback( @@ -433,13 +394,13 @@ const StatefulEventsViewerComponent: React.FC event._id), queryFields, - hasCrudPermissions + true ), isSelected, isSelectAllChecked: isSelected, }) : clearSelected({ id: tableId }), - [setSelected, tableId, nonDeletedEvents, queryFields, hasCrudPermissions, clearSelected] + [setSelected, tableId, nonDeletedEvents, queryFields, clearSelected] ); // Sync to selectAll so parent components can select all events @@ -460,7 +421,7 @@ const StatefulEventsViewerComponent: React.FC { - if (tableView === 'eventRenderedView') { - return { - defaultHeight: 'auto' as const, - }; - } - return undefined; - }, [tableView]); - const pagination = useMemo( () => ({ pageIndex: pageInfo.activePage, @@ -542,83 +493,79 @@ const StatefulEventsViewerComponent: React.FC - - - + {showFullLoading && } + + {graphOverlay} + + {canQueryTimeline && ( + +

- {showFullLoading && } - - {graphOverlay} - - {canQueryTimeline && ( - - - setTableView(selectedView)} - additionalFilters={additionalFilters} - hasRightOffset={tableView === 'gridView' && nonDeletedEvents.length > 0} - additionalMenuOptions={additionalRightMenuOptions} - /> - - {!hasAlerts && !loading && !graphOverlay && } - {hasAlerts && ( - - - - React.ReactNode - } - // TODO: migrate away from deprecated type - rowRenderers={rowRenderers as unknown as DeprecatedRowRenderer[]} - totalItems={totalCountMinusDeleted} - bulkActions={bulkActions} - fieldBrowserOptions={fieldBrowserOptions} - hasCrudPermissions={hasCrudPermissions} - leadingControlColumns={transformedLeadingControlColumns} - pagination={pagination} - isEventRenderedView={tableView === 'eventRenderedView'} - rowHeightsOptions={rowHeightsOptions} - getFieldBrowser={getFieldBrowser} - getFieldSpec={getFieldSpec} - /> - - - + {!loading && !graphOverlay && ( +
0 ? '72px' : theme.eui.euiSizeXS}; + `} + > + + + + + {topRightMenuOptions && ( + {topRightMenuOptions} )} - - + +
+ )} + + {!hasAlerts && !loading && !graphOverlay && } + + {hasAlerts && ( + + + React.ReactNode + } + // TODO: migrate away from deprecated type + rowRenderers={rowRenderers as unknown as DeprecatedRowRenderer[]} + unitCountText={unitCountText} + pagination={pagination} + totalItems={totalCountMinusDeleted} + getFieldBrowser={getFieldBrowser} + getFieldSpec={getFieldSpec} + cellActionsTriggerId={cellActionsTriggerId} + /> + + )} - - - - +
+ + )} + ); }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/right_top_menu.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/right_top_menu.tsx deleted file mode 100644 index 40c6181f43a29..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/right_top_menu.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 type { ViewSelection } from '@kbn/securitysolution-data-table'; -import { TableId } from '@kbn/securitysolution-data-table'; -import React, { useMemo } from 'react'; -import type { CSSProperties } from 'styled-components'; -import styled from 'styled-components'; -import { InspectButton } from '../inspect'; -import { UpdatedFlexGroup, UpdatedFlexItem } from './styles'; -import { SummaryViewSelector } from './summary_view_select'; - -const TitleText = styled.span` - margin-right: 12px; -`; - -interface Props { - tableView: ViewSelection; - loading: boolean; - tableId: TableId; - title: string; - onViewChange: (viewSelection: ViewSelection) => void; - additionalFilters?: React.ReactNode; - hasRightOffset?: boolean; - showInspect?: boolean; - position?: CSSProperties['position']; - additionalMenuOptions?: React.ReactNode[]; -} - -export const RightTopMenu = ({ - tableView, - loading, - tableId, - title, - onViewChange, - additionalFilters, - hasRightOffset, - showInspect = true, - position = 'absolute', - additionalMenuOptions = [], -}: Props) => { - const alignItems = tableView === 'gridView' ? 'baseline' : 'center'; - const justTitle = useMemo(() => {title}, [title]); - - const menuOptions = useMemo( - () => - additionalMenuOptions.length - ? additionalMenuOptions.map((additionalMenuOption, i) => ( - - {additionalMenuOption} - - )) - : null, - [additionalMenuOptions, loading] - ); - - return ( - - {showInspect ? ( - - - - ) : null} - - {additionalFilters} - - {[TableId.alertsOnRuleDetailsPage, TableId.alertsOnAlertsPage].includes(tableId) && ( - - - - )} - {menuOptions} - - ); -}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/styles.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/styles.tsx deleted file mode 100644 index e7eecc27c2255..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/styles.tsx +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; -import type { CSSProperties } from 'styled-components'; -import styled from 'styled-components'; -export const SELECTOR_TIMELINE_GLOBAL_CONTAINER = 'securitySolutionTimeline__container'; -export const EVENTS_TABLE_CLASS_NAME = 'siemEventsTable'; - -export const FullScreenContainer = styled.div<{ $isFullScreen: boolean }>` - height: ${({ $isFullScreen }) => ($isFullScreen ? '100%' : undefined)}; - flex: 1 1 auto; - display: flex; - width: 100%; -`; - -export const FullWidthFlexGroupTable = styled(EuiFlexGroup)<{ $visible: boolean }>` - overflow: hidden; - margin: 0; - display: ${({ $visible }) => ($visible ? 'flex' : 'none')}; -`; - -export const ScrollableFlexItem = styled(EuiFlexItem)` - overflow: auto; -`; - -export const FullWidthFlexGroup = styled(EuiFlexGroup)<{ $visible?: boolean }>` - overflow: hidden; - margin: 0; - min-height: 490px; - display: ${({ $visible = true }) => ($visible ? 'flex' : 'none')}; -`; - -export const UpdatedFlexGroup = styled(EuiFlexGroup)<{ - $hasRightOffset?: boolean; - position: CSSProperties['position']; -}>` - ${({ $hasRightOffset, theme, position }) => - position === 'relative' - ? `margin-right: ${theme.eui.euiSizeXS}; margin-left: ` - : $hasRightOffset && position === 'absolute' - ? `margin-right: ${theme.eui.euiSizeXL};` - : `margin-right: ${theme.eui.euiSizeXS};`} - ${({ position }) => { - return position === 'absolute' - ? `position: absolute` - : `display: flex; justify-content:center; align-items:center`; - }}; - display: inline-flex; - z-index: ${({ theme }) => theme.eui.euiZLevel1 - 3}; - ${({ $hasRightOffset, theme, position }) => - position === 'relative' - ? `right: 0;` - : $hasRightOffset && position === 'absolute' - ? `right: ${theme.eui.euiSizeXL};` - : `right: ${theme.eui.euiSizeL};`} -`; - -export const UpdatedFlexItem = styled(EuiFlexItem)<{ $show: boolean }>` - ${({ $show }) => ($show ? '' : 'visibility: hidden;')} -`; - -export const EventsContainerLoading = styled.div.attrs(({ className = '' }) => ({ - className: `${SELECTOR_TIMELINE_GLOBAL_CONTAINER} ${className}`, -}))` - position: relative; - width: 100%; - overflow: hidden; - flex: 1; - display: flex; - flex-direction: column; -`; - -export const StyledEuiPanel = styled(EuiPanel)<{ $isFullScreen: boolean }>` - display: flex; - flex-direction: column; - position: relative; - width: 100%; - - ${({ $isFullScreen }) => - $isFullScreen && - ` - border: 0; - box-shadow: none; - padding-top: 0; - padding-bottom: 0; -`} -`; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.test.tsx index 1fe2e617f3616..dfe69f6254873 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { getPersistentControlsHook } from './use_persistent_controls'; import { TableId } from '@kbn/securitysolution-data-table'; -import { render, fireEvent, renderHook } from '@testing-library/react'; +import { fireEvent, render, renderHook } from '@testing-library/react'; import { createMockStore, mockGlobalState, TestProviders } from '../../../common/mock'; import { useSourcererDataView } from '../../../sourcerer/containers'; import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector'; @@ -93,7 +93,7 @@ describe('usePersistentControls', () => { ), }); - const groupSelector = result.current.right.props.additionalMenuOptions[0]; + const groupSelector = result.current.right.props.children[2]; const { getByTestId } = render({groupSelector}); fireEvent.click(getByTestId('group-selector-dropdown')); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx index 484162cbf7d42..26628c860f5d2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx @@ -7,23 +7,25 @@ import React, { useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; +import type { ViewSelection } from '@kbn/securitysolution-data-table'; import { + dataTableActions, dataTableSelectors, tableDefaults, - dataTableActions, + TableId, } from '@kbn/securitysolution-data-table'; -import type { ViewSelection, TableId } from '@kbn/securitysolution-data-table'; import { useGetGroupSelectorStateless } from '@kbn/grouping/src/hooks/use_get_group_selector'; import { getTelemetryEvent } from '@kbn/grouping/src/telemetry/const'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { SummaryViewSelector } from '../../../common/components/events_viewer/summary_view_select'; import { groupIdSelector } from '../../../common/store/grouping/selectors'; import { useSourcererDataView } from '../../../sourcerer/containers'; import { SourcererScopeName } from '../../../sourcerer/store/model'; import { updateGroups } from '../../../common/store/grouping/actions'; import { useKibana } from '../../../common/lib/kibana'; -import { METRIC_TYPE, AlertsEventTypes, track } from '../../../common/lib/telemetry'; +import { AlertsEventTypes, METRIC_TYPE, track } from '../../../common/lib/telemetry'; import { useDataTableFilters } from '../../../common/hooks/use_data_table_filters'; import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector'; -import { RightTopMenu } from '../../../common/components/events_viewer/right_top_menu'; import { AdditionalFiltersAction } from '../../components/alerts_table/additional_filters_action'; const { changeViewMode } = dataTableActions; @@ -120,18 +122,15 @@ export const getPersistentControlsHook = (tableId: TableId) => { const rightTopMenu = useMemo( () => ( - + + {[TableId.alertsOnRuleDetailsPage, TableId.alertsOnAlertsPage].includes(tableId) && ( + + + + )} + {additionalFiltersComponent} + {groupSelector} + ), [tableView, handleChangeTableView, additionalFiltersComponent, groupSelector] );