From d66f5c24a9e5a5d41c042553e28bfe6834d8b4c9 Mon Sep 17 00:00:00 2001
From: Pablo Neves Machado
Date: Thu, 19 Aug 2021 17:22:39 +0200
Subject: [PATCH 1/8] Update T-Grid to use DataGrid pagination
* It also improves the Gtid loading state
* DataGrid pagination makes sure that we display the grid with the proper height.
---
.../lib/cell_actions/default_cell_actions.tsx | 75 ++++++++-
.../components/alerts_table/index.tsx | 4 +-
.../common/types/timeline/columns/index.tsx | 2 +
.../components/t_grid/body/index.test.tsx | 4 +-
.../public/components/t_grid/body/index.tsx | 107 +++++++++---
.../t_grid/body/row_action/index.tsx | 24 ++-
.../t_grid/event_rendered_view/index.tsx | 17 +-
.../components/t_grid/integrated/index.tsx | 157 +++++++-----------
.../components/t_grid/standalone/index.tsx | 8 +-
.../timelines/public/container/index.tsx | 2 +-
.../timelines/public/methods/index.tsx | 10 +-
11 files changed, 250 insertions(+), 160 deletions(-)
diff --git a/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx b/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx
index 623957ab8b66c..33221b980e5db 100644
--- a/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx
+++ b/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx
@@ -34,13 +34,36 @@ const useKibanaServices = () => {
return { timelines, filterManager };
};
+/**
+ * rowIndex is bigger than `data.length` for pages with page numbers bigger than one.
+ * For that reason, we must calculate `rowIndex % itemsPerPage`.
+ *
+ * Ex:
+ * Given `rowIndex` is `13` and `itemsPerPage` is `10`.
+ * It means that the `activePage` is `2` and the `pageRowIndex` is `3`
+ *
+ * **Warning**:
+ * Be careful with array out of bounds. `pageRowIndex` can be bigger or equal to `data.length`
+ * in the scenario where the user changes the event status (Open, Acknowledged, Closed).
+ */
+export const getPageRowIndex = (rowIndex: number, itemsPerPage: number) => rowIndex % itemsPerPage;
+
/** the default actions shown in `EuiDataGrid` cells */
export const defaultCellActions: TGridCellAction[] = [
- ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => {
+ ({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) => ({
+ rowIndex,
+ columnId,
+ Component,
+ }) => {
const { timelines, filterManager } = useKibanaServices();
+ const pageRowIndex = getPageRowIndex(rowIndex, pageSize);
+ if (pageRowIndex >= data.length) {
+ return null;
+ }
+
const value = getMappedNonEcsValue({
- data: data[rowIndex],
+ data: data[pageRowIndex],
fieldName: columnId,
});
@@ -58,11 +81,20 @@ export const defaultCellActions: TGridCellAction[] = [
>
);
},
- ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => {
+ ({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) => ({
+ rowIndex,
+ columnId,
+ Component,
+ }) => {
const { timelines, filterManager } = useKibanaServices();
+ const pageRowIndex = getPageRowIndex(rowIndex, pageSize);
+ if (pageRowIndex >= data.length) {
+ return null;
+ }
+
const value = getMappedNonEcsValue({
- data: data[rowIndex],
+ data: data[pageRowIndex],
fieldName: columnId,
});
@@ -80,11 +112,20 @@ export const defaultCellActions: TGridCellAction[] = [
>
);
},
- ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => {
+ ({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) => ({
+ rowIndex,
+ columnId,
+ Component,
+ }) => {
const { timelines } = useKibanaServices();
+ const pageRowIndex = getPageRowIndex(rowIndex, pageSize);
+ if (pageRowIndex >= data.length) {
+ return null;
+ }
+
const value = getMappedNonEcsValue({
- data: data[rowIndex],
+ data: data[pageRowIndex],
fieldName: columnId,
});
@@ -122,16 +163,23 @@ export const defaultCellActions: TGridCellAction[] = [
browserFields,
data,
timelineId,
+ pageSize,
}: {
browserFields: BrowserFields;
data: TimelineNonEcsData[][];
timelineId: string;
+ pageSize: number;
}) => ({ rowIndex, columnId, Component }) => {
const [showTopN, setShowTopN] = useState(false);
const onClick = useCallback(() => setShowTopN(!showTopN), [showTopN]);
+ const pageRowIndex = getPageRowIndex(rowIndex, pageSize);
+ if (pageRowIndex >= data.length) {
+ return null;
+ }
+
const value = getMappedNonEcsValue({
- data: data[rowIndex],
+ data: data[pageRowIndex],
fieldName: columnId,
});
@@ -159,11 +207,20 @@ export const defaultCellActions: TGridCellAction[] = [
>
);
},
- ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => {
+ ({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) => ({
+ rowIndex,
+ columnId,
+ Component,
+ }) => {
const { timelines } = useKibanaServices();
+ const pageRowIndex = getPageRowIndex(rowIndex, pageSize);
+ if (pageRowIndex >= data.length) {
+ return null;
+ }
+
const value = getMappedNonEcsValue({
- data: data[rowIndex],
+ data: data[pageRowIndex],
fieldName: columnId,
});
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx
index 3c0bb0e38b153..4b3c792319cd1 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx
@@ -14,7 +14,6 @@ import { esQuery, Filter } from '../../../../../../../src/plugins/data/public';
import { Status } from '../../../../common/detection_engine/schemas/common/schemas';
import { RowRendererId, TimelineIdLiteral } from '../../../../common/types/timeline';
import { StatefulEventsViewer } from '../../../common/components/events_viewer';
-import { HeaderSection } from '../../../common/components/header_section';
import {
displayErrorToast,
displaySuccessToast,
@@ -371,8 +370,7 @@ export const AlertsTableComponent: React.FC = ({
if (loading || indexPatternsLoading || isEmpty(selectedPatterns)) {
return (
-
-
+
);
diff --git a/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx b/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx
index 5ca3661eb3afe..f799febf646b8 100644
--- a/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx
+++ b/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx
@@ -46,11 +46,13 @@ export type TGridCellAction = ({
browserFields,
data,
timelineId,
+ pageSize,
}: {
browserFields: BrowserFields;
/** each row of data is represented as one TimelineNonEcsData[] */
data: TimelineNonEcsData[][];
timelineId: string;
+ pageSize: number;
}) => (props: EuiDataGridColumnCellActionProps) => ReactNode;
/** The specification of a column header */
diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/index.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/index.test.tsx
index 2ab5a86fa7ddd..712184cafdd28 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/body/index.test.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/body/index.test.tsx
@@ -66,10 +66,11 @@ describe('Body', () => {
excludedRowRendererIds: [],
id: 'timeline-test',
isSelectAllChecked: false,
+ isLoading: false,
itemsPerPageOptions: [],
loadingEventIds: [],
loadPage: jest.fn(),
- querySize: 25,
+ pageSize: 25,
renderCellValue: TestCellRenderer,
rowRenderers: [],
selectedEventIds: {},
@@ -78,7 +79,6 @@ describe('Body', () => {
showCheckboxes: false,
tabType: TimelineTabs.query,
tableView: 'gridView',
- totalPages: 1,
totalItems: 1,
leadingControlColumns: [],
trailingControlColumns: [],
diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
index 001e405fc10e0..3e6a09edd2bd8 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
@@ -15,6 +15,7 @@ import {
EuiLoadingSpinner,
EuiFlexGroup,
EuiFlexItem,
+ EuiProgress,
} from '@elastic/eui';
import { getOr } from 'lodash/fp';
import memoizeOne from 'memoize-one';
@@ -28,7 +29,6 @@ import React, {
useState,
useContext,
} from 'react';
-
import { connect, ConnectedProps, useDispatch } from 'react-redux';
import { ThemeContext } from 'styled-components';
@@ -92,14 +92,13 @@ interface OwnProps {
leadingControlColumns?: ControlColumnProps[];
loadPage: (newActivePage: number) => void;
onRuleChange?: () => void;
- querySize: number;
+ pageSize: number;
refetch: Refetch;
renderCellValue: (props: CellValueElementProps) => React.ReactNode;
rowRenderers: RowRenderer[];
tableView: ViewSelection;
tabType: TimelineTabs;
totalItems: number;
- totalPages: number;
trailingControlColumns?: ControlColumnProps[];
unit?: (total: number) => React.ReactNode;
hasAlertsCrud?: boolean;
@@ -123,6 +122,21 @@ const EmptyHeaderCellRender: ComponentType = () => null;
const gridStyle: EuiDataGridStyle = { border: 'none', fontSize: 's', header: 'underline' };
+/**
+ * rowIndex is bigger than `data.length` for pages with page numbers bigger than one.
+ * For that reason, we must calculate `rowIndex % itemsPerPage`.
+ *
+ * Ex:
+ * Given `rowIndex` is `13` and `itemsPerPage` is `10`.
+ * It means that the `activePage` is `2` and the `pageRowIndex` is `3`
+ *
+ * **Warning**:
+ * Be careful with array out of bounds. `pageRowIndex` can be bigger or equal to `data.length`
+ * in the scenario where the user changes the event status (Open, Acknowledged, Closed).
+ */
+
+export const getPageRowIndex = (rowIndex: number, itemsPerPage: number) => rowIndex % itemsPerPage;
+
const transformControlColumns = ({
actionColumnsWidth,
columnHeaders,
@@ -139,6 +153,7 @@ const transformControlColumns = ({
isSelectAllChecked,
onSelectPage,
browserFields,
+ pageSize,
sort,
theme,
setEventsLoading,
@@ -159,6 +174,7 @@ const transformControlColumns = ({
isSelectAllChecked: boolean;
browserFields: BrowserFields;
onSelectPage: OnSelectAll;
+ pageSize: number;
sort: SortColumnTimeline[];
theme: EuiTheme;
setEventsLoading: SetEventsLoading;
@@ -199,7 +215,15 @@ const transformControlColumns = ({
rowIndex,
setCellProps,
}: EuiDataGridCellValueElementProps) => {
- addBuildingBlockStyle(data[rowIndex].ecs, theme, setCellProps);
+ const pageRowIndex = getPageRowIndex(rowIndex, pageSize);
+ const rowData = data[pageRowIndex];
+
+ if (rowData) {
+ addBuildingBlockStyle(data[pageRowIndex].ecs, theme, setCellProps);
+ } else {
+ // disable the cell when it has no data
+ setCellProps({ style: { display: 'none' } });
+ }
return (
(
columnHeaders,
data,
defaultCellActions,
- excludedRowRendererIds,
filterQuery,
filterStatus,
id,
@@ -258,9 +282,10 @@ export const BodyComponent = React.memo(
itemsPerPageOptions,
leadingControlColumns = EMPTY_CONTROL_COLUMNS,
loadingEventIds,
+ isLoading,
loadPage,
onRuleChange,
- querySize,
+ pageSize,
refetch,
renderCellValue,
rowRenderers,
@@ -271,7 +296,6 @@ export const BodyComponent = React.memo(
tableView = 'gridView',
tabType,
totalItems,
- totalPages,
trailingControlColumns = EMPTY_CONTROL_COLUMNS,
unit = defaultUnit,
hasAlertsCrud,
@@ -393,6 +417,7 @@ export const BodyComponent = React.memo(
() => ({
additionalControls: (
<>
+ {isLoading && }
{alertCountText}
{showBulkActions ? (
<>
@@ -451,6 +476,7 @@ export const BodyComponent = React.memo(
onAlertStatusActionSuccess,
onAlertStatusActionFailure,
refetch,
+ isLoading,
]
);
@@ -500,8 +526,8 @@ export const BodyComponent = React.memo(
}, [columnHeaders]);
const setEventsLoading = useCallback(
- ({ eventIds, isLoading }) => {
- dispatch(tGridActions.setEventsLoading({ id, eventIds, isLoading }));
+ ({ eventIds, isLoading: loading }) => {
+ dispatch(tGridActions.setEventsLoading({ id, eventIds, isLoading: loading }));
},
[dispatch, id]
);
@@ -544,6 +570,7 @@ export const BodyComponent = React.memo(
theme,
setEventsLoading,
setEventsDeleted,
+ pageSize,
})
);
}, [
@@ -564,6 +591,7 @@ export const BodyComponent = React.memo(
onSelectPage,
sort,
theme,
+ pageSize,
setEventsLoading,
setEventsDeleted,
]);
@@ -576,6 +604,7 @@ export const BodyComponent = React.memo(
data: data.map((row) => row.data),
browserFields,
timelineId: id,
+ pageSize,
});
return {
@@ -584,7 +613,7 @@ export const BodyComponent = React.memo(
header.tGridCellActions?.map(buildAction) ?? defaultCellActions?.map(buildAction),
};
}),
- [browserFields, columnHeaders, data, defaultCellActions, id]
+ [browserFields, columnHeaders, data, defaultCellActions, id, pageSize]
);
const renderTGridCellValue = useMemo(() => {
@@ -593,9 +622,13 @@ export const BodyComponent = React.memo(
rowIndex,
setCellProps,
}): React.ReactElement | null => {
- const rowData = rowIndex < data.length ? data[rowIndex].data : null;
+ const pageRowIndex = getPageRowIndex(rowIndex, pageSize);
+
+ const rowData = pageRowIndex < data.length ? data[pageRowIndex].data : null;
const header = columnHeaders.find((h) => h.id === columnId);
- const eventId = rowIndex < data.length ? data[rowIndex]._id : null;
+ const eventId = pageRowIndex < data.length ? data[pageRowIndex]._id : null;
+ const ecs = pageRowIndex < data.length ? data[pageRowIndex].ecs : null;
+
const defaultStyles = useMemo(
() => ({
overflow: 'hidden',
@@ -605,10 +638,15 @@ export const BodyComponent = React.memo(
setCellProps({ style: { ...defaultStyles } });
useEffect(() => {
- addBuildingBlockStyle(data[rowIndex].ecs, theme, setCellProps, defaultStyles);
- }, [rowIndex, setCellProps, defaultStyles]);
+ if (ecs && rowData) {
+ addBuildingBlockStyle(ecs, theme, setCellProps, defaultStyles);
+ } else {
+ // disable the cell when it has no data
+ setCellProps({ style: { display: 'none' } });
+ }
+ }, [rowIndex, setCellProps, defaultStyles, ecs, rowData]);
- if (rowData == null || header == null || eventId == null) {
+ if (rowData == null || header == null || eventId == null || ecs === null) {
return null;
}
@@ -621,17 +659,35 @@ export const BodyComponent = React.memo(
isExpandable: true,
isExpanded: false,
isDetails: false,
- linkValues: getOr([], header.linkField ?? '', data[rowIndex].ecs),
+ linkValues: getOr([], header.linkField ?? '', ecs),
rowIndex,
setCellProps,
timelineId: tabType != null ? `${id}-${tabType}` : id,
- ecsData: data[rowIndex].ecs,
+ ecsData: ecs,
browserFields,
rowRenderers,
}) as React.ReactElement;
};
return Cell;
- }, [columnHeaders, data, id, renderCellValue, tabType, theme, browserFields, rowRenderers]);
+ }, [
+ columnHeaders,
+ data,
+ id,
+ renderCellValue,
+ tabType,
+ theme,
+ browserFields,
+ rowRenderers,
+ pageSize,
+ ]);
+
+ const onChangeItemsPerPage = useCallback(
+ (itemsChangedPerPage) => {
+ dispatch(tGridActions.updateItemsPerPage({ id, itemsPerPage: itemsChangedPerPage }));
+ },
+
+ [id, dispatch]
+ );
return (
<>
@@ -645,10 +701,16 @@ export const BodyComponent = React.memo(
leadingControlColumns={leadingTGridControlColumns}
trailingControlColumns={trailingTGridControlColumns}
toolbarVisibility={toolbarVisibility}
- rowCount={data.length}
+ rowCount={totalItems}
renderCellValue={renderTGridCellValue}
- inMemory={{ level: 'sorting' }}
sorting={{ columns: sortingColumns, onSort }}
+ pagination={{
+ pageIndex: activePage,
+ pageSize,
+ pageSizeOptions: itemsPerPageOptions,
+ onChangeItemsPerPage,
+ onChangePage: loadPage,
+ }}
/>
)}
{tableView === 'eventRenderedView' && (
@@ -658,8 +720,9 @@ export const BodyComponent = React.memo(
events={data}
leadingControlColumns={leadingTGridControlColumns ?? []}
onChangePage={loadPage}
+ onChangeItemsPerPage={onChangeItemsPerPage}
pageIndex={activePage}
- pageSize={querySize}
+ pageSize={pageSize}
pageSizeOptions={itemsPerPageOptions}
rowRenderers={rowRenderers}
timelineId={id}
@@ -693,6 +756,7 @@ const makeMapStateToProps = () => {
selectedEventIds,
showCheckboxes,
sort,
+ isLoading,
} = timeline;
return {
@@ -700,6 +764,7 @@ const makeMapStateToProps = () => {
excludedRowRendererIds,
isSelectAllChecked,
loadingEventIds,
+ isLoading,
id,
selectedEventIds,
showCheckboxes: hasAlertsCrud === true && showCheckboxes,
diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/row_action/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/row_action/index.tsx
index da3152509f5cf..622ffc9763e0f 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/body/row_action/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/body/row_action/index.tsx
@@ -38,6 +38,7 @@ type Props = EuiDataGridCellValueElementProps & {
width: number;
setEventsLoading: SetEventsLoading;
setEventsDeleted: SetEventsDeleted;
+ pageRowIndex: number;
};
const RowActionComponent = ({
@@ -49,6 +50,7 @@ const RowActionComponent = ({
loadingEventIds,
onRowSelected,
onRuleChange,
+ pageRowIndex,
rowIndex,
selectedEventIds,
showCheckboxes,
@@ -58,15 +60,21 @@ const RowActionComponent = ({
setEventsDeleted,
width,
}: Props) => {
- const { data: timelineNonEcsData, ecs: ecsData, _id: eventId, _index: indexName } = useMemo(
- () => data[rowIndex],
- [data, rowIndex]
- );
+ const {
+ data: timelineNonEcsData,
+ ecs: ecsData,
+ _id: eventId,
+ _index: indexName,
+ } = useMemo(() => {
+ const rowData: Partial = data[pageRowIndex];
+ return rowData ?? {};
+ }, [data, pageRowIndex]);
const dispatch = useDispatch();
const columnValues = useMemo(
() =>
+ timelineNonEcsData &&
columnHeaders
.map(
(header) =>
@@ -83,7 +91,7 @@ const RowActionComponent = ({
const updatedExpandedDetail: TimelineExpandedDetailType = {
panelView: 'eventDetail',
params: {
- eventId,
+ eventId: eventId ?? '',
indexName: indexName ?? '',
},
};
@@ -99,7 +107,7 @@ const RowActionComponent = ({
const Action = controlColumn.rowCellRender;
- if (data.length === 0 || rowIndex >= data.length) {
+ if (!timelineNonEcsData || !ecsData || !eventId) {
return ;
}
@@ -107,10 +115,10 @@ const RowActionComponent = ({
<>
{Action && (
void;
+ onChangeItemsPerPage: (newItemsPerPage: number) => void;
pageIndex: number;
pageSize: number;
pageSizeOptions: number[];
@@ -89,6 +85,7 @@ const EventRenderedViewComponent = ({
events,
leadingControlColumns,
onChangePage,
+ onChangeItemsPerPage,
pageIndex,
pageSize,
pageSizeOptions,
@@ -96,8 +93,6 @@ const EventRenderedViewComponent = ({
timelineId,
totalItemCount,
}: EventRenderedViewProps) => {
- const dispatch = useDispatch();
-
const ActionTitle = useMemo(
() => (
@@ -220,12 +215,10 @@ const EventRenderedViewComponent = ({
onChangePage(pageChange.page.index);
}
if (pageChange.page.size !== pageSize) {
- dispatch(
- tGridActions.updateItemsPerPage({ id: timelineId, itemsPerPage: pageChange.page.size })
- );
+ onChangeItemsPerPage(pageChange.page.size);
}
},
- [dispatch, onChangePage, pageIndex, pageSize, timelineId]
+ [onChangePage, pageIndex, pageSize, onChangeItemsPerPage]
);
const pagination = useMemo(
diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
index cc34b32b048ac..8353a0068d214 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
@@ -8,9 +8,9 @@
import type { AlertConsumers as AlertConsumersTyped } from '@kbn/rule-data-utils';
// @ts-expect-error
import { AlertConsumers as AlertConsumersNonTyped } from '@kbn/rule-data-utils/target_node/alerts_as_data_rbac';
-import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiProgress } from '@elastic/eui';
+import { EuiEmptyPrompt, EuiLoadingContent, EuiPanel } from '@elastic/eui';
import { isEmpty } from 'lodash/fp';
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import { useDispatch } from 'react-redux';
@@ -39,16 +39,10 @@ import {
} from '../../../../../../../src/plugins/data/public';
import { useDeepEqualSelector } from '../../../hooks/use_selector';
import { defaultHeaders } from '../body/column_headers/default_headers';
-import {
- calculateTotalPages,
- buildCombinedQuery,
- getCombinedFilterQuery,
- resolverIsShowing,
-} from '../helpers';
+import { buildCombinedQuery, getCombinedFilterQuery, resolverIsShowing } from '../helpers';
import { tGridActions, tGridSelectors } from '../../../store/t_grid';
import { useTimelineEvents } from '../../../container';
import { StatefulBody } from '../body';
-import { Footer, footerHeight } from '../footer';
import { SELECTOR_TIMELINE_GLOBAL_CONTAINER, UpdatedFlexGroup, UpdatedFlexItem } from '../styles';
import { Sort } from '../body/sort';
import { InspectButton, InspectButtonContainer } from '../../inspect';
@@ -86,16 +80,6 @@ const EventsContainerLoading = styled.div.attrs(({ className = '' }) => ({
flex-direction: column;
`;
-const FullWidthFlexGroup = styled(EuiFlexGroup)<{ $visible: boolean }>`
- overflow: hidden;
- margin: 0;
- display: ${({ $visible }) => ($visible ? 'flex' : 'none')};
-`;
-
-const ScrollableFlexItem = styled(EuiFlexItem)`
- overflow: auto;
-`;
-
const SECURITY_ALERTS_CONSUMERS = [AlertConsumers.SIEM];
export interface TGridIntegratedProps {
@@ -157,7 +141,6 @@ const TGridIntegratedComponent: React.FC = ({
id,
indexNames,
indexPattern,
- isLive,
isLoadingIndexPattern,
itemsPerPage,
itemsPerPageOptions,
@@ -176,7 +159,7 @@ const TGridIntegratedComponent: React.FC = ({
const dispatch = useDispatch();
const columnsHeader = isEmpty(columns) ? defaultHeaders : columns;
const { uiSettings } = useKibana().services;
- const [isQueryLoading, setIsQueryLoading] = useState(false);
+ const [isQueryLoading, setIsQueryLoading] = useState(true);
const [tableView, setTableView] = useState('gridView');
const getManageTimeline = useMemo(() => tGridSelectors.getManageTimelineById(), []);
@@ -279,6 +262,13 @@ const TGridIntegratedComponent: React.FC = ({
const alignItems = tableView === 'gridView' ? 'baseline' : 'center';
+ const isFirstUpdate = useRef(true);
+ useEffect(() => {
+ if (isFirstUpdate.current && !loading) {
+ isFirstUpdate.current = false;
+ }
+ }, [loading]);
+
return (
= ({
data-test-subj="events-viewer-panel"
$isFullScreen={globalFullScreen}
>
- {loading && }
+ {isFirstUpdate.current && }
{graphOverlay}
{canQueryTimeline ? (
@@ -311,81 +301,56 @@ const TGridIntegratedComponent: React.FC = ({
)}
-
-
- {nonDeletedEvents.length === 0 && loading === false ? (
-
-
-
- }
- titleSize="s"
- body={
-
-
-
- }
- />
- ) : (
- <>
-
+
+
+ }
+ titleSize="s"
+ body={
+
+
- {tableView === 'gridView' && (
-
- )}
- >
- )}
-
-
+
+ }
+ />
+ )}
+ {totalCountMinusDeleted > 0 && (
+ <>
+
+ >
+ )}
>
) : null}
diff --git a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
index a3f8ed1f16537..83d578e1d23ad 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
@@ -31,7 +31,7 @@ import {
} from '../../../../../../../src/plugins/data/public';
import { useDeepEqualSelector } from '../../../hooks/use_selector';
import { defaultHeaders } from '../body/column_headers/default_headers';
-import { calculateTotalPages, combineQueries, getCombinedFilterQuery } from '../helpers';
+import { combineQueries, getCombinedFilterQuery } from '../helpers';
import { tGridActions, tGridSelectors } from '../../../store/t_grid';
import type { State } from '../../../store/t_grid';
import { useTimelineEvents } from '../../../container';
@@ -335,13 +335,9 @@ const TGridStandaloneComponent: React.FC = ({
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
onRuleChange={onRuleChange}
- querySize={pageInfo.querySize}
+ pageSize={pageInfo.querySize}
tabType={TimelineTabs.query}
tableView="gridView"
- totalPages={calculateTotalPages({
- itemsCount: totalCountMinusDeleted,
- itemsPerPage: itemsPerPageStore,
- })}
totalItems={totalCountMinusDeleted}
unit={unit}
filterStatus={filterStatus}
diff --git a/x-pack/plugins/timelines/public/container/index.tsx b/x-pack/plugins/timelines/public/container/index.tsx
index 81578a001f6a4..058610f932cba 100644
--- a/x-pack/plugins/timelines/public/container/index.tsx
+++ b/x-pack/plugins/timelines/public/container/index.tsx
@@ -133,7 +133,7 @@ export const useTimelineEvents = ({
const refetch = useRef(noop);
const abortCtrl = useRef(new AbortController());
const searchSubscription$ = useRef(new Subscription());
- const [loading, setLoading] = useState(false);
+ const [loading, setLoading] = useState(true);
const [activePage, setActivePage] = useState(0);
const [timelineRequest, setTimelineRequest] = useState | null>(
null
diff --git a/x-pack/plugins/timelines/public/methods/index.tsx b/x-pack/plugins/timelines/public/methods/index.tsx
index 55d15a6410fde..91802c4eb10e1 100644
--- a/x-pack/plugins/timelines/public/methods/index.tsx
+++ b/x-pack/plugins/timelines/public/methods/index.tsx
@@ -6,7 +6,7 @@
*/
import React, { lazy, Suspense } from 'react';
-import { EuiLoadingSpinner } from '@elastic/eui';
+import { EuiLoadingContent, EuiLoadingSpinner, EuiPanel } from '@elastic/eui';
import { I18nProvider } from '@kbn/i18n/react';
import type { Store } from 'redux';
import { Provider } from 'react-redux';
@@ -51,7 +51,13 @@ export const getTGridLazy = (
) => {
initializeStore({ store, storage, setStore });
return (
- }>
+
+
+
+ }
+ >
);
From 98d41251a32af353079c0309dd2314d4c372dce7 Mon Sep 17 00:00:00 2001
From: Pablo Neves Machado
Date: Tue, 24 Aug 2021 13:14:21 +0200
Subject: [PATCH 2/8] Add DataGrid height hack to t-grid
HUGE HACK!!!
DataGrtid height isn't properly calculated when the grid has horizontal scroll.
https://github.com/elastic/eui/issues/5030
In order to get around this bug we are calculating `DataGrid` height here and setting it as a prop.
Please revert this commit and allow DataGrid to calculate its height when the bug is fixed.
---
.../components/t_grid/body/height_hack.ts | 54 +++++++++++++++++++
.../public/components/t_grid/body/index.tsx | 5 ++
2 files changed, 59 insertions(+)
create mode 100644 x-pack/plugins/timelines/public/components/t_grid/body/height_hack.ts
diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/height_hack.ts b/x-pack/plugins/timelines/public/components/t_grid/body/height_hack.ts
new file mode 100644
index 0000000000000..d99d47a403b2c
--- /dev/null
+++ b/x-pack/plugins/timelines/public/components/t_grid/body/height_hack.ts
@@ -0,0 +1,54 @@
+/*
+ * 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 { useState, useLayoutEffect } from 'react';
+
+// That could be different from security and observability. Get it as parameter?
+const INITIAL_DATA_GRID_HEIGHT = 967;
+
+// It will recalculate DataGrid height after this time interval.
+const TIME_INTERVAL = 50;
+
+/**
+ * You are probably asking yourself "Why 3?". But that is the wrong mindset. You should be asking yourself "why not 3?".
+ * 3 (three) is a number, numeral and digit. It is the natural number following 2 and preceding 4, and is the smallest
+ * odd prime number and the only prime preceding a square number. It has religious or cultural significance in many societies.
+ */
+const MAGIC_GAP = 3;
+
+/**
+ * HUGE HACK!!!
+ * DataGrtid height isn't properly calculated when the grid has horizontal scroll.
+ * https://github.com/elastic/eui/issues/5030
+ *
+ * In order to get around this bug we are calculating `DataGrid` height here and setting it as a prop.
+ *
+ * Please delete me and allow DataGrid to calculate its height when the bug is fixed.
+ */
+export const useDataGridHeightHack = (pageSize: number) => {
+ const [height, setHeight] = useState(INITIAL_DATA_GRID_HEIGHT);
+
+ useLayoutEffect(() => {
+ setTimeout(() => {
+ const gridVirtualized = document.querySelector('#body-data-grid .euiDataGrid__virtualized');
+
+ if (
+ gridVirtualized &&
+ gridVirtualized.children[0].clientHeight !== gridVirtualized.clientHeight // check if it has vertical scroll
+ ) {
+ setHeight(
+ height +
+ gridVirtualized.children[0].clientHeight -
+ gridVirtualized.clientHeight +
+ MAGIC_GAP
+ );
+ }
+ }, TIME_INTERVAL);
+ }, [pageSize, height]);
+
+ return height;
+};
diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
index 3e6a09edd2bd8..52e02fb5f35e2 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
@@ -71,6 +71,7 @@ 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';
+import { useDataGridHeightHack } from './height_hack';
const StatefulAlertStatusBulkActions = lazy(
() => import('../toolbar/bulk_actions/alert_status_bulk_actions')
@@ -689,10 +690,14 @@ export const BodyComponent = React.memo(
[id, dispatch]
);
+ const height = useDataGridHeightHack(pageSize);
+
return (
<>
{tableView === 'gridView' && (
Date: Tue, 24 Aug 2021 15:59:13 +0200
Subject: [PATCH 3/8] Apply DataGrid laoding and pagination changes to
observability
---
.../components/t_grid/integrated/index.tsx | 52 ++++-----
.../components/t_grid/standalone/index.tsx | 107 +++++++++++-------
2 files changed, 88 insertions(+), 71 deletions(-)
diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
index 8353a0068d214..3cb8d6a6182bf 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
@@ -323,33 +323,31 @@ const TGridIntegratedComponent: React.FC = ({
/>
)}
{totalCountMinusDeleted > 0 && (
- <>
-
- >
+
)}
>
diff --git a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
index 83d578e1d23ad..bfa5469a19c00 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
@@ -4,15 +4,17 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiLoadingContent } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
import { isEmpty } from 'lodash/fp';
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { useEffect, useMemo, useState, useRef } from 'react';
import styled from 'styled-components';
import { useDispatch, useSelector } from 'react-redux';
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { Direction, EntityType } from '../../../../common/search_strategy';
import type { CoreStart } from '../../../../../../../src/core/public';
import { TGridCellAction, TimelineTabs } from '../../../../common/types/timeline';
+
import type {
CellValueElementProps,
ColumnHeaderOptions,
@@ -36,7 +38,6 @@ import { tGridActions, tGridSelectors } from '../../../store/t_grid';
import type { State } from '../../../store/t_grid';
import { useTimelineEvents } from '../../../container';
import { StatefulBody } from '../body';
-import { Footer, footerHeight } from '../footer';
import { LastUpdatedAt } from '../..';
import { SELECTOR_TIMELINE_GLOBAL_CONTAINER, UpdatedFlexItem, UpdatedFlexGroup } from '../styles';
import { InspectButton, InspectButtonContainer } from '../../inspect';
@@ -299,9 +300,17 @@ const TGridStandaloneComponent: React.FC = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
+ const isFirstUpdate = useRef(true);
+ useEffect(() => {
+ if (isFirstUpdate.current && !loading) {
+ isFirstUpdate.current = false;
+ }
+ }, [loading]);
+
return (
+ {isFirstUpdate.current && }
{canQueryTimeline ? (
<>
= ({
-
-
-
-
-
-
+ {totalCountMinusDeleted === 0 && loading === false && (
+
+
+
+ }
+ titleSize="s"
+ body={
+
+
+
+ }
+ />
+ )}
+ {totalCountMinusDeleted > 0 && (
+
+
+
+
+
+ )}
>
) : null}
From 06d112c8df4a5d14cee8caa67b4c8e287f1ef8b0 Mon Sep 17 00:00:00 2001
From: Pablo Neves Machado
Date: Tue, 24 Aug 2021 17:38:46 +0200
Subject: [PATCH 4/8] Fix cypress tests
---
.../plugins/security_solution/cypress/screens/hosts/events.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts b/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts
index 65778e16771e2..de4acdd721c68 100644
--- a/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts
+++ b/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts
@@ -38,4 +38,4 @@ export const LOAD_MORE =
export const SERVER_SIDE_EVENT_COUNT = '[data-test-subj="server-side-event-count"]';
export const EVENTS_VIEWER_PAGINATION =
- '[data-test-subj="events-viewer-panel"] [data-test-subj="timeline-pagination"]';
+ '[data-test-subj="events-viewer-panel"] .euiDataGrid__pagination';
From 0b642ed85dae367a00a8c674a8de83e015a9173f Mon Sep 17 00:00:00 2001
From: Pablo Neves Machado
Date: Tue, 24 Aug 2021 19:25:00 +0200
Subject: [PATCH 5/8] Fix t-grid page render bug on Observability
---
.../pages/alerts/default_cell_actions.tsx | 30 ++++++++++++++++---
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx b/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx
index 7e166ac99c05f..64f2c87f59889 100644
--- a/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx
+++ b/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx
@@ -19,6 +19,20 @@ export const FILTER_FOR_VALUE = i18n.translate('xpack.observability.hoverActions
defaultMessage: 'Filter for value',
});
+/**
+ * rowIndex is bigger than `data.length` for pages with page numbers bigger than one.
+ * For that reason, we must calculate `rowIndex % itemsPerPage`.
+ *
+ * Ex:
+ * Given `rowIndex` is `13` and `itemsPerPage` is `10`.
+ * It means that the `activePage` is `2` and the `pageRowIndex` is `3`
+ *
+ * **Warning**:
+ * Be careful with array out of bounds. `pageRowIndex` can be bigger or equal to `data.length`
+ * in the scenario where the user changes the event status (Open, Acknowledged, Closed).
+ */
+export const getPageRowIndex = (rowIndex: number, itemsPerPage: number) => rowIndex % itemsPerPage;
+
/** a hook to eliminate the verbose boilerplate required to use common services */
const useKibanaServices = () => {
const { timelines } = useKibana<{ timelines: TimelinesUIStart }>().services;
@@ -35,11 +49,15 @@ const useKibanaServices = () => {
/** actions common to all cells (e.g. copy to clipboard) */
const commonCellActions: TGridCellAction[] = [
- ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => {
+ ({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) => ({
+ rowIndex,
+ columnId,
+ Component,
+ }) => {
const { timelines } = useKibanaServices();
const value = getMappedNonEcsValue({
- data: data[rowIndex],
+ data: data[getPageRowIndex(rowIndex, pageSize)],
fieldName: columnId,
});
@@ -60,9 +78,13 @@ const commonCellActions: TGridCellAction[] = [
/** actions for adding filters to the search bar */
const buildFilterCellActions = (addToQuery: (value: string) => void): TGridCellAction[] => [
- ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => {
+ ({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) => ({
+ rowIndex,
+ columnId,
+ Component,
+ }) => {
const value = getMappedNonEcsValue({
- data: data[rowIndex],
+ data: data[getPageRowIndex(rowIndex, pageSize)],
fieldName: columnId,
});
From dd2cc6febf94c05de07d561661d7ba60d1397e8b Mon Sep 17 00:00:00 2001
From: semd
Date: Wed, 25 Aug 2021 18:41:05 +0200
Subject: [PATCH 6/8] some pagination fixes
---
.../pages/alerts/alerts_table_t_grid.tsx | 2 +-
.../components/t_grid/body/height_hack.ts | 4 +-
.../public/components/t_grid/body/index.tsx | 74 ++++++++++++-------
.../components/t_grid/standalone/index.tsx | 6 +-
4 files changed, 55 insertions(+), 31 deletions(-)
diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx
index 3b62538fa3e30..51983f0ffba04 100644
--- a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx
+++ b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx
@@ -302,7 +302,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
return [
{
id: 'expand',
- width: 96,
+ width: 120,
headerCellRender: () => {
return (
diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/height_hack.ts b/x-pack/plugins/timelines/public/components/t_grid/body/height_hack.ts
index d99d47a403b2c..542be06578d6b 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/body/height_hack.ts
+++ b/x-pack/plugins/timelines/public/components/t_grid/body/height_hack.ts
@@ -29,7 +29,7 @@ const MAGIC_GAP = 3;
*
* Please delete me and allow DataGrid to calculate its height when the bug is fixed.
*/
-export const useDataGridHeightHack = (pageSize: number) => {
+export const useDataGridHeightHack = (pageSize: number, rowCount: number) => {
const [height, setHeight] = useState(INITIAL_DATA_GRID_HEIGHT);
useLayoutEffect(() => {
@@ -48,7 +48,7 @@ export const useDataGridHeightHack = (pageSize: number) => {
);
}
}, TIME_INTERVAL);
- }, [pageSize, height]);
+ }, [pageSize, rowCount, height]);
return height;
};
diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
index d5dfb5b105aab..feafb82ec12a9 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
@@ -31,7 +31,7 @@ import React, {
} from 'react';
import { connect, ConnectedProps, useDispatch } from 'react-redux';
-import { ThemeContext } from 'styled-components';
+import styled, { ThemeContext } from 'styled-components';
import { ALERT_RULE_CONSUMER } from '@kbn/rule-data-utils';
import {
TGridCellAction,
@@ -118,6 +118,8 @@ export const hasAdditionalActions = (id: TimelineId): boolean =>
const EXTRA_WIDTH = 4; // px
+const ES_LIMIT_COUNT = 9999;
+
const MIN_ACTION_COLUMN_WIDTH = 96; // px
const EMPTY_CONTROL_COLUMNS: ControlColumnProps[] = [];
@@ -126,6 +128,14 @@ const EmptyHeaderCellRender: ComponentType = () => null;
const gridStyle: EuiDataGridStyle = { border: 'none', fontSize: 's', header: 'underline' };
+const EuiDataGridContainer = styled.div<{ hideLastPage: boolean }>`
+ ul.euiPagination__list {
+ li.euiPagination__item:last-child {
+ ${({ hideLastPage }) => `${hideLastPage ? 'display:none' : ''}`};
+ }
+ }
+`;
+
/**
* rowIndex is bigger than `data.length` for pages with page numbers bigger than one.
* For that reason, we must calculate `rowIndex % itemsPerPage`.
@@ -710,39 +720,51 @@ export const BodyComponent = React.memo(
const onChangeItemsPerPage = useCallback(
(itemsChangedPerPage) => {
+ clearSelected({ id });
+ dispatch(tGridActions.setTGridSelectAll({ id, selectAll: false }));
dispatch(tGridActions.updateItemsPerPage({ id, itemsPerPage: itemsChangedPerPage }));
},
+ [id, dispatch, clearSelected]
+ );
- [id, dispatch]
+ const onChangePage = useCallback(
+ (page) => {
+ clearSelected({ id });
+ dispatch(tGridActions.setTGridSelectAll({ id, selectAll: false }));
+ loadPage(page);
+ },
+ [id, loadPage, dispatch, clearSelected]
);
- const height = useDataGridHeightHack(pageSize);
+ const height = useDataGridHeightHack(pageSize, data.length);
return (
<>
{tableView === 'gridView' && (
-
+ ES_LIMIT_COUNT}>
+
+
)}
{tableView === 'eventRenderedView' && (
(
browserFields={browserFields}
events={data}
leadingControlColumns={leadingTGridControlColumns ?? []}
- onChangePage={loadPage}
+ onChangePage={onChangePage}
onChangeItemsPerPage={onChangeItemsPerPage}
pageIndex={activePage}
pageSize={pageSize}
diff --git a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
index 9bd97d7781e5d..ad77ad177a9fe 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx
@@ -153,6 +153,7 @@ const TGridStandaloneComponent: React.FC = ({
itemsPerPage: itemsPerPageStore,
itemsPerPageOptions: itemsPerPageOptionsStore,
queryFields,
+ sort: sortStore,
title,
} = useDeepEqualSelector((state) => getTGrid(state, STANDALONE_ID ?? ''));
@@ -195,12 +196,12 @@ const TGridStandaloneComponent: React.FC = ({
const sortField = useMemo(
() =>
- sort.map(({ columnId, columnType, sortDirection }) => ({
+ sortStore.map(({ columnId, columnType, sortDirection }) => ({
field: columnId,
type: columnType,
direction: sortDirection as Direction,
})),
- [sort]
+ [sortStore]
);
const [
@@ -313,6 +314,7 @@ const TGridStandaloneComponent: React.FC = ({
id: STANDALONE_ID,
defaultColumns: columns,
footerText,
+ sort,
loadingText,
unit,
})
From 567afb4e8f7a6b14bf4f0e2d20d594c9ec9f9d38 Mon Sep 17 00:00:00 2001
From: semd
Date: Thu, 26 Aug 2021 12:41:03 +0200
Subject: [PATCH 7/8] hide table when analyzer active
---
.../pages/alerts/default_cell_actions.tsx | 16 +-
.../lib/cell_actions/default_cell_actions.tsx | 15 +-
.../components/t_grid/integrated/index.tsx | 139 +++++++++---------
x-pack/plugins/timelines/public/index.ts | 1 +
4 files changed, 74 insertions(+), 97 deletions(-)
diff --git a/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx b/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx
index 64f2c87f59889..9c93f05196a1c 100644
--- a/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx
+++ b/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx
@@ -13,26 +13,12 @@ import FilterForValueButton from './filter_for_value';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
import { TimelineNonEcsData } from '../../../../timelines/common/search_strategy';
import { TGridCellAction } from '../../../../timelines/common/types/timeline';
-import { TimelinesUIStart } from '../../../../timelines/public';
+import { getPageRowIndex, TimelinesUIStart } from '../../../../timelines/public';
export const FILTER_FOR_VALUE = i18n.translate('xpack.observability.hoverActions.filterForValue', {
defaultMessage: 'Filter for value',
});
-/**
- * rowIndex is bigger than `data.length` for pages with page numbers bigger than one.
- * For that reason, we must calculate `rowIndex % itemsPerPage`.
- *
- * Ex:
- * Given `rowIndex` is `13` and `itemsPerPage` is `10`.
- * It means that the `activePage` is `2` and the `pageRowIndex` is `3`
- *
- * **Warning**:
- * Be careful with array out of bounds. `pageRowIndex` can be bigger or equal to `data.length`
- * in the scenario where the user changes the event status (Open, Acknowledged, Closed).
- */
-export const getPageRowIndex = (rowIndex: number, itemsPerPage: number) => rowIndex % itemsPerPage;
-
/** a hook to eliminate the verbose boilerplate required to use common services */
const useKibanaServices = () => {
const { timelines } = useKibana<{ timelines: TimelinesUIStart }>().services;
diff --git a/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx b/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx
index 33221b980e5db..1481ae3e4248c 100644
--- a/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx
+++ b/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx
@@ -12,6 +12,7 @@ import type {
TimelineNonEcsData,
} from '../../../../../timelines/common/search_strategy';
import { DataProvider, TGridCellAction } from '../../../../../timelines/common/types';
+import { getPageRowIndex } from '../../../../../timelines/public';
import { getMappedNonEcsValue } from '../../../timelines/components/timeline/body/data_driven_columns';
import { IS_OPERATOR } from '../../../timelines/components/timeline/data_providers/data_provider';
import { allowTopN, escapeDataProviderId } from '../../components/drag_and_drop/helpers';
@@ -34,20 +35,6 @@ const useKibanaServices = () => {
return { timelines, filterManager };
};
-/**
- * rowIndex is bigger than `data.length` for pages with page numbers bigger than one.
- * For that reason, we must calculate `rowIndex % itemsPerPage`.
- *
- * Ex:
- * Given `rowIndex` is `13` and `itemsPerPage` is `10`.
- * It means that the `activePage` is `2` and the `pageRowIndex` is `3`
- *
- * **Warning**:
- * Be careful with array out of bounds. `pageRowIndex` can be bigger or equal to `data.length`
- * in the scenario where the user changes the event status (Open, Acknowledged, Closed).
- */
-export const getPageRowIndex = (rowIndex: number, itemsPerPage: number) => rowIndex % itemsPerPage;
-
/** the default actions shown in `EuiDataGrid` cells */
export const defaultCellActions: TGridCellAction[] = [
({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) => ({
diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
index 3cb8d6a6182bf..779fddcad2562 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
@@ -281,77 +281,80 @@ const TGridIntegratedComponent: React.FC = ({
{isFirstUpdate.current && }
{graphOverlay}
- {canQueryTimeline ? (
- <>
-
-
-
-
-
+
+ {canQueryTimeline && (
+
+
+
+
+
+
+ {!resolverIsShowing(graphEventId) && additionalFilters}
+
+ {tGridEventRenderedViewEnabled && entityType === 'alerts' && (
- {!resolverIsShowing(graphEventId) && additionalFilters}
+
- {tGridEventRenderedViewEnabled && entityType === 'alerts' && (
-
-
-
- )}
-
-
- {totalCountMinusDeleted === 0 && loading === false && (
-
-
-
- }
- titleSize="s"
- body={
-
-
-
- }
- />
)}
- {totalCountMinusDeleted > 0 && (
-
- )}
-
- >
- ) : null}
+
+
+ {!graphEventId && graphOverlay == null && (
+ <>
+ {totalCountMinusDeleted === 0 && loading === false && (
+
+
+
+ }
+ titleSize="s"
+ body={
+
+
+
+ }
+ />
+ )}
+ {totalCountMinusDeleted > 0 && (
+
+ )}
+ >
+ )}
+
+ )}
);
diff --git a/x-pack/plugins/timelines/public/index.ts b/x-pack/plugins/timelines/public/index.ts
index c8b14b4018765..754859d62c3a4 100644
--- a/x-pack/plugins/timelines/public/index.ts
+++ b/x-pack/plugins/timelines/public/index.ts
@@ -52,6 +52,7 @@ export {
addFieldToTimelineColumns,
getTimelineIdFromColumnDroppableId,
} from './components/drag_and_drop/helpers';
+export { getPageRowIndex } from './components/t_grid/body';
export { StatefulFieldsBrowser } from './components/t_grid/toolbar/fields_browser';
export { useStatusBulkActionItems } from './hooks/use_status_bulk_action_items';
// This exports static code and TypeScript types,
From 55d67074acafd4eeea5c40536b30aac48a753302 Mon Sep 17 00:00:00 2001
From: semd
Date: Thu, 26 Aug 2021 14:20:00 +0200
Subject: [PATCH 8/8] isolate exported function
---
.../timelines/common/utils/pagination.ts | 21 +++++++++++++++++++
.../public/components/t_grid/body/index.tsx | 16 +-------------
x-pack/plugins/timelines/public/index.ts | 2 +-
3 files changed, 23 insertions(+), 16 deletions(-)
create mode 100644 x-pack/plugins/timelines/common/utils/pagination.ts
diff --git a/x-pack/plugins/timelines/common/utils/pagination.ts b/x-pack/plugins/timelines/common/utils/pagination.ts
new file mode 100644
index 0000000000000..407b62bc4c686
--- /dev/null
+++ b/x-pack/plugins/timelines/common/utils/pagination.ts
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * rowIndex is bigger than `data.length` for pages with page numbers bigger than one.
+ * For that reason, we must calculate `rowIndex % itemsPerPage`.
+ *
+ * Ex:
+ * Given `rowIndex` is `13` and `itemsPerPage` is `10`.
+ * It means that the `activePage` is `2` and the `pageRowIndex` is `3`
+ *
+ * **Warning**:
+ * Be careful with array out of bounds. `pageRowIndex` can be bigger or equal to `data.length`
+ * in the scenario where the user changes the event status (Open, Acknowledged, Closed).
+ */
+
+export const getPageRowIndex = (rowIndex: number, itemsPerPage: number) => rowIndex % itemsPerPage;
diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
index feafb82ec12a9..04bcc4cb02c70 100644
--- a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
+++ b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
@@ -62,6 +62,7 @@ import { DEFAULT_ICON_BUTTON_WIDTH } from '../helpers';
import type { BrowserFields } from '../../../../common/search_strategy/index_fields';
import type { OnRowSelected, OnSelectAll } from '../types';
import type { Refetch } from '../../../store/t_grid/inputs';
+import { getPageRowIndex } from '../../../../common/utils/pagination';
import { StatefulFieldsBrowser } from '../../../';
import { tGridActions, TGridModel, tGridSelectors, TimelineState } from '../../../store/t_grid';
import { useDeepEqualSelector } from '../../../hooks/use_selector';
@@ -136,21 +137,6 @@ const EuiDataGridContainer = styled.div<{ hideLastPage: boolean }>`
}
`;
-/**
- * rowIndex is bigger than `data.length` for pages with page numbers bigger than one.
- * For that reason, we must calculate `rowIndex % itemsPerPage`.
- *
- * Ex:
- * Given `rowIndex` is `13` and `itemsPerPage` is `10`.
- * It means that the `activePage` is `2` and the `pageRowIndex` is `3`
- *
- * **Warning**:
- * Be careful with array out of bounds. `pageRowIndex` can be bigger or equal to `data.length`
- * in the scenario where the user changes the event status (Open, Acknowledged, Closed).
- */
-
-export const getPageRowIndex = (rowIndex: number, itemsPerPage: number) => rowIndex % itemsPerPage;
-
const transformControlColumns = ({
actionColumnsWidth,
columnHeaders,
diff --git a/x-pack/plugins/timelines/public/index.ts b/x-pack/plugins/timelines/public/index.ts
index 754859d62c3a4..eab34200e1628 100644
--- a/x-pack/plugins/timelines/public/index.ts
+++ b/x-pack/plugins/timelines/public/index.ts
@@ -48,11 +48,11 @@ export {
skipFocusInContainerTo,
stopPropagationAndPreventDefault,
} from '../common/utils/accessibility';
+export { getPageRowIndex } from '../common/utils/pagination';
export {
addFieldToTimelineColumns,
getTimelineIdFromColumnDroppableId,
} from './components/drag_and_drop/helpers';
-export { getPageRowIndex } from './components/t_grid/body';
export { StatefulFieldsBrowser } from './components/t_grid/toolbar/fields_browser';
export { useStatusBulkActionItems } from './hooks/use_status_bulk_action_items';
// This exports static code and TypeScript types,