mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Security Solution] - remove styled-components and cleanup for event viewer and data table components (#206523)
## Summary This PR originally aimed at replacing the usages `styled-components` with `@emotion/react` in the `security_solution/public/common/components/events_viewer` folder. I quickly realized removing some of these would require a small refactor. This lead to making a few more changes, as many properties were actually unused so a cleanup was welcome. Only 2 small UI changes are introduced in this PR: - the inspect icon on the top right corner of the tables are now always visible instead of only visible on hover. I'm aware that this is a different behavior from the alerts table in the alerts page, but we also have other tables (like the one on threat intelligence page) where the icon is always shown. Waiting on @codearos for confirmation here - the `Grid view` and `Additional filters` button are reversed due to the simplification of the code No other UI changes are introduced. No behavior logic has been changed either. The biggest code cleanup are: - removal of a bunch of unused properties and logic - deletion of the RightTopMenu component: it was used in both `StatefulEventsViewerComponent` and `getPersistentControlsHook` but none of the internal logic was overlapping. I don't know how we got there but its current implementation was overly complex and completely unnecessary... #### Alerts page  #### Rule creation page  #### Host/User/Network events tab  #### Host session view tab  ### Checklist - [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 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
d9b9425372
commit
708789102f
11 changed files with 155 additions and 444 deletions
|
@ -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/,
|
||||
|
|
|
@ -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<EuiDataGridProps, NonCust
|
|||
|
||||
const ES_LIMIT_COUNT = 9999;
|
||||
|
||||
const gridStyle = (isEventRenderedView: boolean | undefined = false): EuiDataGridStyle => ({
|
||||
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<DataTableProps>(
|
|||
bulkActions = true,
|
||||
data,
|
||||
fieldBrowserOptions,
|
||||
hasCrudPermissions,
|
||||
id,
|
||||
leadingControlColumns,
|
||||
loadPage,
|
||||
|
@ -157,8 +154,6 @@ export const DataTableComponent = React.memo<DataTableProps>(
|
|||
pagination,
|
||||
unitCountText,
|
||||
totalItems,
|
||||
rowHeightsOptions,
|
||||
isEventRenderedView = false,
|
||||
getFieldBrowser,
|
||||
getFieldSpec,
|
||||
cellActionsTriggerId,
|
||||
|
@ -178,7 +173,7 @@ export const DataTableComponent = React.memo<DataTableProps>(
|
|||
dataViewId,
|
||||
} = dataTable;
|
||||
|
||||
const columnHeaders = memoizedGetColumnHeaders(columns, browserFields, isEventRenderedView);
|
||||
const columnHeaders = memoizedGetColumnHeaders(columns, browserFields);
|
||||
|
||||
const dataGridRef = useRef<EuiDataGridRefProps>(null);
|
||||
|
||||
|
@ -189,10 +184,6 @@ export const DataTableComponent = React.memo<DataTableProps>(
|
|||
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<DataTableProps>(
|
|||
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<DataTableProps>(
|
|||
{isLoading && <EuiProgress size="xs" position="absolute" color="accent" />}
|
||||
<UnitCount data-test-subj="server-side-event-count">{unitCountText}</UnitCount>
|
||||
{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<DataTableProps>(
|
|||
isLoading,
|
||||
unitCountText,
|
||||
additionalControls,
|
||||
isEventRenderedView,
|
||||
getFieldBrowser,
|
||||
browserFields,
|
||||
fieldBrowserOptions,
|
||||
|
@ -468,9 +454,9 @@ export const DataTableComponent = React.memo<DataTableProps>(
|
|||
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<DataTableProps>(
|
|||
onColumnResize={onColumnResize}
|
||||
pagination={pagination}
|
||||
ref={dataGridRef}
|
||||
rowHeightsOptions={rowHeightsOptions}
|
||||
rowHeightsOptions={undefined}
|
||||
/>
|
||||
</EuiDataGridContainer>
|
||||
</>
|
||||
|
|
|
@ -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;
|
||||
}) => (
|
||||
<div>
|
||||
{additionalFilters}
|
||||
{topRightMenuOptions}
|
||||
{'MockedStatefulEventsViewer'}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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<EventsQueryTabBodyComponentProps> =
|
|||
/>
|
||||
)}
|
||||
<StatefulEventsViewer
|
||||
additionalFilters={toggleExternalAlertsCheckbox}
|
||||
topRightMenuOptions={toggleExternalAlertsCheckbox}
|
||||
cellActionsTriggerId={SecurityCellActionsTrigger.DEFAULT}
|
||||
start={startDate}
|
||||
end={endDate}
|
||||
|
|
|
@ -5,13 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { ViewSelection } from '@kbn/securitysolution-data-table';
|
||||
import { TableId } from '@kbn/securitysolution-data-table';
|
||||
import type { CombineQueries } from '../../lib/kuery';
|
||||
import { buildTimeRangeFilter, combineQueries } from '../../lib/kuery';
|
||||
|
||||
import { EVENTS_TABLE_CLASS_NAME } from './styles';
|
||||
|
||||
export const getCombinedFilterQuery = ({
|
||||
from,
|
||||
to,
|
||||
|
@ -25,41 +21,3 @@ export const getCombinedFilterQuery = ({
|
|||
|
||||
return combinedQueries ? combinedQueries.filterQuery : undefined;
|
||||
};
|
||||
|
||||
export const resolverIsShowing = (graphEventId: string | undefined): boolean =>
|
||||
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<HTMLDivElement>(`.${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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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', () => {
|
|||
</TestProviders>
|
||||
);
|
||||
|
||||
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', () => {
|
|||
<TestProviders>
|
||||
<StatefulEventsViewer
|
||||
{...testProps}
|
||||
additionalRightMenuOptions={[<p data-test-subj="right-option" />]}
|
||||
topRightMenuOptions={[<p data-test-subj="right-option" />]}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
|
|
@ -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<CellValueElementProps>;
|
||||
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<EventsViewerProps & PropsFromRedux> = ({
|
||||
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<EventsViewerProps & PropsFromRedux
|
|||
sourcererScope,
|
||||
start,
|
||||
tableId,
|
||||
topRightMenuOptions,
|
||||
unit = defaultUnit,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
@ -162,6 +136,7 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
title,
|
||||
} = defaultModel,
|
||||
} = useSelector((state: State) => eventsViewerSelector(state, tableId));
|
||||
const inspectModalTitle = useMemo(() => <span data-test-subj="title">{title}</span>, [title]);
|
||||
|
||||
const {
|
||||
uiSettings,
|
||||
|
@ -169,13 +144,6 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
triggersActionsUi: { getFieldBrowser },
|
||||
} = useKibana().services;
|
||||
|
||||
const [tableView, setTableView] = useState<ViewSelection>(
|
||||
getDefaultViewSelection({
|
||||
tableId,
|
||||
value: storage.get(ALERTS_TABLE_VIEW_SELECTION_KEY),
|
||||
})
|
||||
);
|
||||
|
||||
const {
|
||||
browserFields,
|
||||
dataViewId,
|
||||
|
@ -187,8 +155,6 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
|
||||
const getFieldSpec = useGetFieldSpec(sourcererScope);
|
||||
|
||||
const { globalFullScreen } = useGlobalFullScreen();
|
||||
|
||||
const editorActionsRef = useRef<FieldEditorActions>(null);
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
|
@ -215,14 +181,13 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
|
||||
const globalFilters = useMemo(() => [...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<EventsViewerProps & PropsFromRedux
|
|||
<GraphOverlay scopeId={tableId} SessionView={SessionView} Navigation={Navigation} />
|
||||
) : null;
|
||||
}, [graphEventId, tableId, sessionViewConfig, SessionView, Navigation]);
|
||||
|
||||
const setQuery = useCallback(
|
||||
({ id, inspect, loading, refetch }: SetQuery) =>
|
||||
dispatch(
|
||||
|
@ -320,7 +286,7 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
skip: !canQueryTimeline,
|
||||
sort: sortField,
|
||||
startDate: start,
|
||||
filterStatus: currentFilter,
|
||||
filterStatus: undefined,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -411,17 +377,12 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
({ eventIds, isSelected }: { eventIds: string[]; isSelected: boolean }) => {
|
||||
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<EventsViewerProps & PropsFromRedux
|
|||
nonDeletedEvents,
|
||||
nonDeletedEvents.map((event) => 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<EventsViewerProps & PropsFromRedux
|
|||
fieldBrowserOptions,
|
||||
loadingEventIds,
|
||||
onRowSelected,
|
||||
onRuleChange,
|
||||
onRuleChange: undefined,
|
||||
selectedEventIds,
|
||||
showCheckboxes,
|
||||
tabType: 'query',
|
||||
|
@ -483,7 +444,6 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
fieldBrowserOptions,
|
||||
loadingEventIds,
|
||||
onRowSelected,
|
||||
onRuleChange,
|
||||
selectedEventIds,
|
||||
tableId,
|
||||
isSelectAllChecked,
|
||||
|
@ -500,9 +460,9 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
tableId,
|
||||
data: nonDeletedEvents,
|
||||
totalItems: totalCountMinusDeleted,
|
||||
hasAlertsCrud: hasCrudPermissions,
|
||||
hasAlertsCrud: true,
|
||||
showCheckboxes,
|
||||
filterStatus: currentFilter,
|
||||
filterStatus: undefined,
|
||||
filterQuery,
|
||||
bulkActions,
|
||||
selectedCount,
|
||||
|
@ -521,15 +481,6 @@ const StatefulEventsViewerComponent: React.FC<EventsViewerProps & PropsFromRedux
|
|||
[totalCountMinusDeleted, unit]
|
||||
);
|
||||
|
||||
const rowHeightsOptions: EuiDataGridRowHeightsOptions | undefined = useMemo(() => {
|
||||
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<EventsViewerProps & PropsFromRedux
|
|||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FullScreenContainer $isFullScreen={globalFullScreen}>
|
||||
<InspectButtonContainer>
|
||||
<StyledEuiPanel
|
||||
hasBorder={false}
|
||||
hasShadow={false}
|
||||
paddingSize="none"
|
||||
data-test-subj="events-viewer-panel"
|
||||
$isFullScreen={globalFullScreen}
|
||||
<div data-test-subj="events-viewer-panel">
|
||||
{showFullLoading && <TableLoading height="short" />}
|
||||
|
||||
{graphOverlay}
|
||||
|
||||
{canQueryTimeline && (
|
||||
<TableContext.Provider value={tableContext}>
|
||||
<div
|
||||
data-timeline-id={tableId}
|
||||
data-test-subj={`events-container-loading-${loading}`}
|
||||
css={css`
|
||||
position: relative;
|
||||
`}
|
||||
>
|
||||
{showFullLoading && <TableLoading height="short" />}
|
||||
|
||||
{graphOverlay}
|
||||
|
||||
{canQueryTimeline && (
|
||||
<TableContext.Provider value={tableContext}>
|
||||
<EventsContainerLoading
|
||||
data-timeline-id={tableId}
|
||||
data-test-subj={`events-container-loading-${loading}`}
|
||||
>
|
||||
<RightTopMenu
|
||||
tableView={tableView}
|
||||
loading={loading}
|
||||
tableId={tableId}
|
||||
title={title}
|
||||
onViewChange={(selectedView) => setTableView(selectedView)}
|
||||
additionalFilters={additionalFilters}
|
||||
hasRightOffset={tableView === 'gridView' && nonDeletedEvents.length > 0}
|
||||
additionalMenuOptions={additionalRightMenuOptions}
|
||||
/>
|
||||
|
||||
{!hasAlerts && !loading && !graphOverlay && <EmptyTable />}
|
||||
{hasAlerts && (
|
||||
<FullWidthFlexGroupTable
|
||||
$visible={!graphEventId && graphOverlay == null}
|
||||
gutterSize="none"
|
||||
>
|
||||
<ScrollableFlexItem grow={1}>
|
||||
<StatefulEventContext.Provider value={activeStatefulEventContext}>
|
||||
<DataTableComponent
|
||||
cellActionsTriggerId={cellActionsTriggerId}
|
||||
additionalControls={alertBulkActions}
|
||||
unitCountText={unitCountText}
|
||||
browserFields={browserFields}
|
||||
data={nonDeletedEvents}
|
||||
id={tableId}
|
||||
loadPage={loadPage}
|
||||
// TODO: migrate away from deprecated type
|
||||
renderCellValue={
|
||||
renderCellValue as (
|
||||
props: DeprecatedCellValueElementProps
|
||||
) => 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}
|
||||
/>
|
||||
</StatefulEventContext.Provider>
|
||||
</ScrollableFlexItem>
|
||||
</FullWidthFlexGroupTable>
|
||||
{!loading && !graphOverlay && (
|
||||
<div
|
||||
css={css`
|
||||
position: absolute;
|
||||
top: ${theme.eui.euiSizeXS};
|
||||
z-index: ${theme.eui.euiZLevel1 - 3};
|
||||
right: ${nonDeletedEvents.length > 0 ? '72px' : theme.eui.euiSizeXS};
|
||||
`}
|
||||
>
|
||||
<EuiFlexGroup data-test-subj="events-viewer-updated" gutterSize="m">
|
||||
<EuiFlexItem grow={false}>
|
||||
<InspectButton title={inspectModalTitle} queryId={tableId} />
|
||||
</EuiFlexItem>
|
||||
{topRightMenuOptions && (
|
||||
<EuiFlexItem grow={false}>{topRightMenuOptions}</EuiFlexItem>
|
||||
)}
|
||||
</EventsContainerLoading>
|
||||
</TableContext.Provider>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
)}
|
||||
</StyledEuiPanel>
|
||||
</InspectButtonContainer>
|
||||
</FullScreenContainer>
|
||||
</>
|
||||
|
||||
{!hasAlerts && !loading && !graphOverlay && <EmptyTable />}
|
||||
|
||||
{hasAlerts && (
|
||||
<EuiFlexItem
|
||||
css={css`
|
||||
display: ${!graphEventId && graphOverlay == null ? 'flex' : 'none'};
|
||||
overflow: auto;
|
||||
`}
|
||||
>
|
||||
<StatefulEventContext.Provider value={activeStatefulEventContext}>
|
||||
<DataTableComponent
|
||||
additionalControls={alertBulkActions}
|
||||
browserFields={browserFields}
|
||||
bulkActions={bulkActions}
|
||||
data={nonDeletedEvents}
|
||||
fieldBrowserOptions={fieldBrowserOptions}
|
||||
id={tableId}
|
||||
leadingControlColumns={transformedLeadingControlColumns}
|
||||
loadPage={loadPage}
|
||||
// TODO: migrate away from deprecated type
|
||||
renderCellValue={
|
||||
renderCellValue as (props: DeprecatedCellValueElementProps) => 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}
|
||||
/>
|
||||
</StatefulEventContext.Provider>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</div>
|
||||
</TableContext.Provider>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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(() => <TitleText data-test-subj="title">{title}</TitleText>, [title]);
|
||||
|
||||
const menuOptions = useMemo(
|
||||
() =>
|
||||
additionalMenuOptions.length
|
||||
? additionalMenuOptions.map((additionalMenuOption, i) => (
|
||||
<UpdatedFlexItem grow={false} $show={!loading} key={i}>
|
||||
{additionalMenuOption}
|
||||
</UpdatedFlexItem>
|
||||
))
|
||||
: null,
|
||||
[additionalMenuOptions, loading]
|
||||
);
|
||||
|
||||
return (
|
||||
<UpdatedFlexGroup
|
||||
alignItems={alignItems}
|
||||
data-test-subj="events-viewer-updated"
|
||||
gutterSize="m"
|
||||
component="span"
|
||||
justifyContent="flexEnd"
|
||||
direction="row"
|
||||
$hasRightOffset={hasRightOffset}
|
||||
position={position}
|
||||
>
|
||||
{showInspect ? (
|
||||
<UpdatedFlexItem grow={false} $show={!loading}>
|
||||
<InspectButton title={justTitle} queryId={tableId} />
|
||||
</UpdatedFlexItem>
|
||||
) : null}
|
||||
<UpdatedFlexItem grow={false} $show={!loading}>
|
||||
{additionalFilters}
|
||||
</UpdatedFlexItem>
|
||||
{[TableId.alertsOnRuleDetailsPage, TableId.alertsOnAlertsPage].includes(tableId) && (
|
||||
<UpdatedFlexItem grow={false} $show={!loading} data-test-subj="summary-view-selector">
|
||||
<SummaryViewSelector viewSelected={tableView} onViewChange={onViewChange} />
|
||||
</UpdatedFlexItem>
|
||||
)}
|
||||
{menuOptions}
|
||||
</UpdatedFlexGroup>
|
||||
);
|
||||
};
|
|
@ -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;
|
||||
`}
|
||||
`;
|
|
@ -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(<TestProviders store={store}>{groupSelector}</TestProviders>);
|
||||
|
||||
fireEvent.click(getByTestId('group-selector-dropdown'));
|
||||
|
|
|
@ -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(
|
||||
() => (
|
||||
<RightTopMenu
|
||||
position="relative"
|
||||
tableView={tableView}
|
||||
loading={false}
|
||||
tableId={tableId}
|
||||
title={'Some Title'}
|
||||
onViewChange={handleChangeTableView}
|
||||
hasRightOffset={false}
|
||||
additionalFilters={additionalFiltersComponent}
|
||||
showInspect={false}
|
||||
additionalMenuOptions={groupSelector != null ? [groupSelector] : []}
|
||||
/>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
{[TableId.alertsOnRuleDetailsPage, TableId.alertsOnAlertsPage].includes(tableId) && (
|
||||
<EuiFlexItem grow={false} data-test-subj="summary-view-selector">
|
||||
<SummaryViewSelector viewSelected={tableView} onViewChange={handleChangeTableView} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiFlexItem grow={false}>{additionalFiltersComponent}</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>{groupSelector}</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
[tableView, handleChangeTableView, additionalFiltersComponent, groupSelector]
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue