From 38b830f17ffa03faf1b95bdb20140d621bb74fa5 Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Tue, 18 Jun 2019 15:21:50 -0600
Subject: [PATCH 01/29] paginated table
---
.../__snapshots__/index.test.tsx.snap | 108 +++++
.../components/paginated_table/index.mock.tsx | 118 ++++++
.../components/paginated_table/index.test.tsx | 390 ++++++++++++++++++
.../components/paginated_table/index.tsx | 315 ++++++++++++++
.../paginated_table/translations.ts | 23 ++
5 files changed, 954 insertions(+)
create mode 100644 x-pack/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
create mode 100644 x-pack/plugins/siem/public/components/paginated_table/index.mock.tsx
create mode 100644 x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
create mode 100644 x-pack/plugins/siem/public/components/paginated_table/index.tsx
create mode 100644 x-pack/plugins/siem/public/components/paginated_table/translations.ts
diff --git a/x-pack/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
new file mode 100644
index 0000000000000..c6c213857bfd8
--- /dev/null
+++ b/x-pack/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,108 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Load More Table Component rendering it renders the default load more table 1`] = `
+
+
+ My test supplement.
+
+ }
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={
+ Array [
+ Object {
+ "numberOfRow": 2,
+ "text": "2 rows",
+ },
+ Object {
+ "numberOfRow": 5,
+ "text": "5 rows",
+ },
+ Object {
+ "numberOfRow": 10,
+ "text": "10 rows",
+ },
+ Object {
+ "numberOfRow": 20,
+ "text": "20 rows",
+ },
+ Object {
+ "numberOfRow": 50,
+ "text": "50 rows",
+ },
+ ]
+ }
+ limit={1}
+ loadPage={[Function]}
+ loading={false}
+ loadingTitle="Hosts"
+ pageOfItems={
+ Array [
+ Object {
+ "cursor": Object {
+ "value": "98966fa2013c396155c460d35c0902be",
+ },
+ "host": Object {
+ "_id": "cPsuhGcB0WOhS6qyTKC0",
+ "firstSeen": "2018-12-06T15:40:53.319Z",
+ "name": "elrond.elstc.co",
+ "os": "Ubuntu",
+ "version": "18.04.1 LTS (Bionic Beaver)",
+ },
+ },
+ Object {
+ "cursor": Object {
+ "value": "aa7ca589f1b8220002f2fc61c64cfbf1",
+ },
+ "host": Object {
+ "_id": "KwQDiWcB0WOhS6qyXmrW",
+ "firstSeen": "2018-12-07T14:12:38.560Z",
+ "name": "siem-kibana",
+ "os": "Debian GNU/Linux",
+ "version": "9 (stretch)",
+ },
+ },
+ ]
+ }
+ totalCount={10}
+ updateActivePage={[Function]}
+ updateLimitPagination={[Function]}
+ />
+
+`;
diff --git a/x-pack/plugins/siem/public/components/paginated_table/index.mock.tsx b/x-pack/plugins/siem/public/components/paginated_table/index.mock.tsx
new file mode 100644
index 0000000000000..513747c70036a
--- /dev/null
+++ b/x-pack/plugins/siem/public/components/paginated_table/index.mock.tsx
@@ -0,0 +1,118 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { getOrEmptyTagFromValue } from '../empty_value';
+
+import { Columns, ItemsPerRow } from './index';
+
+export const mockData = {
+ Hosts: {
+ totalCount: 4,
+ edges: [
+ {
+ host: {
+ _id: 'cPsuhGcB0WOhS6qyTKC0',
+ name: 'elrond.elstc.co',
+ os: 'Ubuntu',
+ version: '18.04.1 LTS (Bionic Beaver)',
+ firstSeen: '2018-12-06T15:40:53.319Z',
+ },
+ cursor: {
+ value: '98966fa2013c396155c460d35c0902be',
+ },
+ },
+ {
+ host: {
+ _id: 'KwQDiWcB0WOhS6qyXmrW',
+ name: 'siem-kibana',
+ os: 'Debian GNU/Linux',
+ version: '9 (stretch)',
+ firstSeen: '2018-12-07T14:12:38.560Z',
+ },
+ cursor: {
+ value: 'aa7ca589f1b8220002f2fc61c64cfbf1',
+ },
+ },
+ ],
+ pageInfo: {
+ activePage: 0,
+ endCursor: {
+ value: 'aa7ca589f1b8220002f2fc61c64cfbf1',
+ },
+ },
+ },
+};
+
+export const getHostsColumns = (): [
+ Columns,
+ Columns,
+ Columns,
+ Columns
+] => [
+ {
+ field: 'node.host.name',
+ name: 'Host',
+ truncateText: false,
+ hideForMobile: false,
+ render: (name: string) => getOrEmptyTagFromValue(name),
+ },
+ {
+ field: 'node.host.firstSeen',
+ name: 'First seen',
+ truncateText: false,
+ hideForMobile: false,
+ render: (firstSeen: string) => getOrEmptyTagFromValue(firstSeen),
+ },
+ {
+ field: 'node.host.os',
+ name: 'OS',
+ truncateText: false,
+ hideForMobile: false,
+ render: (os: string) => getOrEmptyTagFromValue(os),
+ },
+ {
+ field: 'node.host.version',
+ name: 'Version',
+ truncateText: false,
+ hideForMobile: false,
+ render: (version: string) => getOrEmptyTagFromValue(version),
+ },
+];
+
+export const sortedHosts: [
+ Columns,
+ Columns,
+ Columns,
+ Columns
+] = getHostsColumns().map(h => ({ ...h, sortable: true })) as [
+ Columns,
+ Columns,
+ Columns,
+ Columns
+];
+
+export const rowItems: ItemsPerRow[] = [
+ {
+ text: '2 rows',
+ numberOfRow: 2,
+ },
+ {
+ text: '5 rows',
+ numberOfRow: 5,
+ },
+ {
+ text: '10 rows',
+ numberOfRow: 10,
+ },
+ {
+ text: '20 rows',
+ numberOfRow: 20,
+ },
+ {
+ text: '50 rows',
+ numberOfRow: 50,
+ },
+];
diff --git a/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx b/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
new file mode 100644
index 0000000000000..ca483b42889b3
--- /dev/null
+++ b/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
@@ -0,0 +1,390 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { mount, shallow } from 'enzyme';
+import toJson from 'enzyme-to-json';
+import * as React from 'react';
+
+import { Direction } from '../../graphql/types';
+
+import { PaginatedTable } from './index';
+import { getHostsColumns, mockData, rowItems, sortedHosts } from './index.mock';
+
+jest.mock('react', () => {
+ const r = jest.requireActual('react');
+ return { ...r, memo: (x: any) => x };
+});
+
+describe('Load More Table Component', () => {
+ let loadPage: jest.Mock;
+ let updateLimitPagination: jest.Mock;
+ let updateActivePage: jest.Mock;
+ beforeEach(() => {
+ loadPage = jest.fn();
+ updateLimitPagination = jest.fn();
+ updateActivePage = jest.fn();
+ });
+
+ describe('rendering', () => {
+ test('it renders the default load more table', () => {
+ const wrapper = shallow(
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
+ );
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+
+ test('it renders the loading panel at the beginning ', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={true}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={[]}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+
+ expect(
+ wrapper.find('[data-test-subj="InitialLoadingPanelPaginatedTable"]').exists()
+ ).toBeTruthy();
+ });
+
+ test('it renders the over loading panel after data has been in the table ', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={true}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+
+ expect(wrapper.find('[data-test-subj="LoadingPanelPaginatedTable"]').exists()).toBeTruthy();
+ });
+
+ test('it renders the correct amount of pages and starts at activePage: 0', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={updateActivePage}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+
+ const paginiationProps = wrapper
+ .find('[data-test-subj="numberedPagination"]')
+ .first()
+ .props();
+
+ const expectedPaginationProps = {
+ 'data-test-subj': 'numberedPagination',
+ pageCount: 10,
+ activePage: 0,
+ };
+ expect(JSON.stringify(paginiationProps)).toEqual(JSON.stringify(expectedPaginationProps));
+ });
+
+ test('it render popover to select new limit in table', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+
+ wrapper
+ .find('[data-test-subj="loadingMoreSizeRowPopover"] button')
+ .first()
+ .simulate('click');
+ expect(wrapper.find('[data-test-subj="loadingMorePickSizeRow"]').exists()).toBeTruthy();
+ });
+
+ test('it will NOT render popover to select new limit in table if props itemsPerRow is empty', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={[]}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+
+ expect(wrapper.find('[data-test-subj="loadingMoreSizeRowPopover"]').exists()).toBeFalsy();
+ });
+
+ test('It should render a sort icon if sorting is defined', () => {
+ const mockOnChange = jest.fn();
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={jest.fn()}
+ onChange={mockOnChange}
+ pageOfItems={mockData.Hosts.edges}
+ sorting={{ direction: Direction.asc, field: 'node.host.name' }}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+
+ expect(wrapper.find('.euiTable thead tr th button svg')).toBeTruthy();
+ });
+ });
+
+ describe('Events', () => {
+ test('should call updateActivePage with 1 when clicking to the first page', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+ wrapper
+ .find('[data-test-subj="pagination-button-next"]')
+ .first()
+ .simulate('click');
+ expect(updateActivePage.mock.calls[0][0]).toEqual(1);
+ });
+
+ test('Should call updateActivePage with 0 when you pick a new limit', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+ wrapper
+ .find('[data-test-subj="pagination-button-next"]')
+ .first()
+ .simulate('click');
+
+ wrapper
+ .find('[data-test-subj="loadingMoreSizeRowPopover"] button')
+ .first()
+ .simulate('click');
+
+ wrapper
+ .find('[data-test-subj="loadingMorePickSizeRow"] button')
+ .first()
+ .simulate('click');
+ expect(updateActivePage.mock.calls[1][0]).toEqual(0);
+ });
+
+ test('should call updateActivePage with 0 when an update prop changes', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ updateProps={{ isThisAwesome: false }}
+ />
+ );
+ wrapper
+ .find('[data-test-subj="pagination-button-next"]')
+ .first()
+ .simulate('click');
+ wrapper.setProps({ updateProps: { isThisAwesome: true } });
+ // enzyme does not have full support for react.memo
+ // wrapper will not update without the click below
+ wrapper
+ .find('[data-test-subj="pagination-button-4"]')
+ .first()
+ .simulate('click');
+ expect(updateActivePage.mock.calls[1][0]).toEqual(0);
+ });
+
+ test('Should call updateLimitPagination when you pick a new limit', () => {
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+
+ wrapper
+ .find('[data-test-subj="loadingMoreSizeRowPopover"] button')
+ .first()
+ .simulate('click');
+
+ wrapper
+ .find('[data-test-subj="loadingMorePickSizeRow"] button')
+ .first()
+ .simulate('click');
+ expect(updateLimitPagination).toBeCalled();
+ });
+
+ test('Should call onChange when you choose a new sort in the table', () => {
+ const mockOnChange = jest.fn();
+ const wrapper = mount(
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={jest.fn()}
+ onChange={mockOnChange}
+ pageOfItems={mockData.Hosts.edges}
+ sorting={{ direction: Direction.asc, field: 'node.host.name' }}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+ );
+
+ wrapper
+ .find('.euiTable thead tr th button')
+ .first()
+ .simulate('click');
+
+ expect(mockOnChange).toBeCalled();
+ expect(mockOnChange.mock.calls[0]).toEqual([
+ { page: undefined, sort: { direction: 'desc', field: 'node.host.name' } },
+ ]);
+ });
+ });
+});
diff --git a/x-pack/plugins/siem/public/components/paginated_table/index.tsx b/x-pack/plugins/siem/public/components/paginated_table/index.tsx
new file mode 100644
index 0000000000000..07656207ab0c7
--- /dev/null
+++ b/x-pack/plugins/siem/public/components/paginated_table/index.tsx
@@ -0,0 +1,315 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import {
+ EuiBasicTable,
+ EuiButtonEmpty,
+ EuiContextMenuItem,
+ EuiContextMenuPanel,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiPagination,
+ EuiPanel,
+ EuiPopover,
+} from '@elastic/eui';
+import { isEmpty, noop, getOr } from 'lodash/fp';
+import React, { memo, useState, useEffect } from 'react';
+import styled from 'styled-components';
+
+import { Direction } from '../../graphql/types';
+import { HeaderPanel } from '../header_panel';
+import { LoadingPanel } from '../loading';
+
+import * as i18n from './translations';
+
+export interface ItemsPerRow {
+ text: string;
+ numberOfRow: number;
+}
+
+export interface SortingBasicTable {
+ field: string;
+ direction: Direction;
+ allowNeutralSort?: boolean;
+}
+
+export interface Criteria {
+ page?: { index: number; size: number };
+ sort?: SortingBasicTable;
+}
+
+// Using telescoping templates to remove 'any' that was polluting downstream column type checks
+interface BasicTableProps {
+ columns:
+ | [Columns]
+ | [Columns, Columns]
+ | [Columns, Columns, Columns]
+ | [Columns, Columns, Columns, Columns]
+ | [Columns, Columns, Columns, Columns, Columns]
+ | [Columns, Columns, Columns, Columns, Columns, Columns]
+ | [Columns, Columns, Columns, Columns, Columns, Columns, Columns]
+ | [
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns
+ ]
+ | [
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns
+ ];
+ headerCount: number;
+ headerSupplement?: React.ReactElement;
+ headerTitle: string | React.ReactElement;
+ headerTooltip?: string;
+ headerUnit: string | React.ReactElement;
+ itemsPerRow?: ItemsPerRow[];
+ limit: number;
+ loading: boolean;
+ loadingTitle?: string;
+ loadPage: (activePage: number) => void;
+ onChange?: (criteria: Criteria) => void;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ pageOfItems: any[];
+ sorting?: SortingBasicTable;
+ totalCount: number;
+ updateActivePage: (activePage: number) => void;
+ updateLimitPagination: (limit: number) => void;
+ updateProps?: { [key: string]: any };
+}
+
+export interface Columns {
+ field?: string;
+ name: string | React.ReactNode;
+ isMobileHeader?: boolean;
+ sortable?: boolean;
+ truncateText?: boolean;
+ hideForMobile?: boolean;
+ render?: (item: T) => void;
+ width?: string;
+}
+
+export const PaginatedTable = memo>(
+ ({
+ columns,
+ headerCount,
+ headerSupplement,
+ headerTitle,
+ headerTooltip,
+ headerUnit,
+ itemsPerRow,
+ limit,
+ loading,
+ loadingTitle,
+ loadPage,
+ onChange = noop,
+ pageOfItems,
+ sorting = null,
+ totalCount,
+ updateActivePage,
+ updateLimitPagination,
+ updateProps,
+ }) => {
+ const [activePage, setActivePage] = useState(0);
+ const [isEmptyTable, setEmptyTable] = useState(pageOfItems.length === 0);
+ const [isPopoverOpen, setPopoverOpen] = useState(false);
+ const pageCount = Math.ceil(totalCount / limit);
+ const effectDeps = updateProps ? [limit, ...Object.values(updateProps)] : [limit];
+ useEffect(() => {
+ if (activePage !== 0) {
+ setActivePage(0);
+ updateActivePage(0);
+ }
+ }, effectDeps);
+
+ const onButtonClick = () => {
+ setPopoverOpen(!isPopoverOpen);
+ };
+
+ const closePopover = () => {
+ setPopoverOpen(false);
+ };
+
+ const goToPage = (newActivePage: number) => {
+ setActivePage(newActivePage);
+ loadPage(newActivePage);
+ updateActivePage(newActivePage);
+ };
+ if (!isEmpty(pageOfItems) && isEmptyTable) {
+ setEmptyTable(false);
+ }
+ if (loading && isEmptyTable) {
+ return (
+
+
+
+ );
+ }
+
+ const button = (
+
+ Rows: {limit}
+
+ );
+
+ const rowItems =
+ itemsPerRow &&
+ itemsPerRow.map((item: ItemsPerRow) => (
+ {
+ closePopover();
+ updateLimitPagination(item.numberOfRow);
+ updateActivePage(0); // reset results to first page
+ }}
+ >
+ {item.text}
+
+ ));
+ return (
+
+
+ {loading && (
+ <>
+
+
+ >
+ )}
+
+
+ {headerSupplement}
+
+
+
+
+
+
+ {!isEmpty(itemsPerRow) && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+);
+
+export const BasicTableContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ height: auto;
+ position: relative;
+`;
+
+const FooterAction = styled.div`
+ margin-top: 0.5rem;
+ width: 100%;
+`;
+
+/*
+ * The getOr is just there to simplify the test
+ * So we do NOT need to wrap it around TestProvider
+ */
+const BackgroundRefetch = styled.div`
+ background-color: ${props => getOr('#ffffff', 'theme.eui.euiColorLightShade', props)};
+ margin: -5px;
+ height: calc(100% + 10px);
+ opacity: 0.7;
+ width: calc(100% + 10px);
+ position: absolute;
+ z-index: 3;
+ border-radius: 5px;
+`;
+
+const BasicTable = styled(EuiBasicTable)`
+ tbody {
+ th,
+ td {
+ vertical-align: top;
+ }
+ }
+`;
diff --git a/x-pack/plugins/siem/public/components/paginated_table/translations.ts b/x-pack/plugins/siem/public/components/paginated_table/translations.ts
new file mode 100644
index 0000000000000..3d2d24362ce1f
--- /dev/null
+++ b/x-pack/plugins/siem/public/components/paginated_table/translations.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+export const LOADING = i18n.translate('xpack.siem.loadingMoreTable.loadingDescription', {
+ defaultMessage: 'Loading…',
+});
+
+export const LOAD_MORE = i18n.translate('xpack.siem.loadingMoreTable.loadMoreDescription', {
+ defaultMessage: 'Load More',
+});
+
+export const SHOWING = i18n.translate('xpack.siem.loadingMoreTable.showing', {
+ defaultMessage: 'Showing',
+});
+
+export const ROWS = i18n.translate('xpack.siem.loadingMoreTable.rows', {
+ defaultMessage: 'Rows',
+});
From 024a3ff439566908074fb3c2ab1f32ed5ee2ce8d Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Tue, 18 Jun 2019 15:23:41 -0600
Subject: [PATCH 02/29] more
---
.../plugins/siem/public/components/paginated_table/index.tsx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/x-pack/plugins/siem/public/components/paginated_table/index.tsx b/x-pack/plugins/siem/public/components/paginated_table/index.tsx
index 07656207ab0c7..74a3a33996828 100644
--- a/x-pack/plugins/siem/public/components/paginated_table/index.tsx
+++ b/x-pack/plugins/siem/public/components/paginated_table/index.tsx
@@ -88,6 +88,7 @@ interface BasicTableProps void;
updateLimitPagination: (limit: number) => void;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
updateProps?: { [key: string]: any };
}
@@ -102,6 +103,7 @@ export interface Columns {
width?: string;
}
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const PaginatedTable = memo>(
({
columns,
@@ -172,7 +174,7 @@ export const PaginatedTable = memo>(
iconSide="right"
onClick={onButtonClick}
>
- Rows: {limit}
+ {`${i18n.ROWS}: ${limit}`}
);
From 4ef79ce6d8cc935029585180c9896610de493719 Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Tue, 18 Jun 2019 16:18:29 -0600
Subject: [PATCH 03/29] get unit tests passing
---
.../__snapshots__/index.test.tsx.snap | 198 ++++----
.../components/paginated_table/index.test.tsx | 435 ++++++++++--------
.../components/paginated_table/index.tsx | 2 +-
3 files changed, 331 insertions(+), 304 deletions(-)
diff --git a/x-pack/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
index c6c213857bfd8..f072b8ca92c1d 100644
--- a/x-pack/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
+++ b/x-pack/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
@@ -1,108 +1,106 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Load More Table Component rendering it renders the default load more table 1`] = `
-
-
+ My test supplement.
+
+ }
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={
+ Array [
+ Object {
+ "numberOfRow": 2,
+ "text": "2 rows",
+ },
+ Object {
+ "numberOfRow": 5,
+ "text": "5 rows",
+ },
+ Object {
+ "numberOfRow": 10,
+ "text": "10 rows",
+ },
+ Object {
+ "numberOfRow": 20,
+ "text": "20 rows",
+ },
+ Object {
+ "numberOfRow": 50,
+ "text": "50 rows",
+ },
+ ]
+ }
+ limit={1}
+ loadPage={[Function]}
+ loading={false}
+ loadingTitle="Hosts"
+ pageOfItems={
+ Array [
+ Object {
+ "cursor": Object {
+ "value": "98966fa2013c396155c460d35c0902be",
},
- Object {
- "field": "node.host.firstSeen",
- "hideForMobile": false,
- "name": "First seen",
- "render": [Function],
- "truncateText": false,
+ "host": Object {
+ "_id": "cPsuhGcB0WOhS6qyTKC0",
+ "firstSeen": "2018-12-06T15:40:53.319Z",
+ "name": "elrond.elstc.co",
+ "os": "Ubuntu",
+ "version": "18.04.1 LTS (Bionic Beaver)",
},
- Object {
- "field": "node.host.os",
- "hideForMobile": false,
- "name": "OS",
- "render": [Function],
- "truncateText": false,
+ },
+ Object {
+ "cursor": Object {
+ "value": "aa7ca589f1b8220002f2fc61c64cfbf1",
},
- Object {
- "field": "node.host.version",
- "hideForMobile": false,
- "name": "Version",
- "render": [Function],
- "truncateText": false,
+ "host": Object {
+ "_id": "KwQDiWcB0WOhS6qyXmrW",
+ "firstSeen": "2018-12-07T14:12:38.560Z",
+ "name": "siem-kibana",
+ "os": "Debian GNU/Linux",
+ "version": "9 (stretch)",
},
- ]
- }
- headerCount={1}
- headerSupplement={
-
- My test supplement.
-
- }
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={
- Array [
- Object {
- "numberOfRow": 2,
- "text": "2 rows",
- },
- Object {
- "numberOfRow": 5,
- "text": "5 rows",
- },
- Object {
- "numberOfRow": 10,
- "text": "10 rows",
- },
- Object {
- "numberOfRow": 20,
- "text": "20 rows",
- },
- Object {
- "numberOfRow": 50,
- "text": "50 rows",
- },
- ]
- }
- limit={1}
- loadPage={[Function]}
- loading={false}
- loadingTitle="Hosts"
- pageOfItems={
- Array [
- Object {
- "cursor": Object {
- "value": "98966fa2013c396155c460d35c0902be",
- },
- "host": Object {
- "_id": "cPsuhGcB0WOhS6qyTKC0",
- "firstSeen": "2018-12-06T15:40:53.319Z",
- "name": "elrond.elstc.co",
- "os": "Ubuntu",
- "version": "18.04.1 LTS (Bionic Beaver)",
- },
- },
- Object {
- "cursor": Object {
- "value": "aa7ca589f1b8220002f2fc61c64cfbf1",
- },
- "host": Object {
- "_id": "KwQDiWcB0WOhS6qyXmrW",
- "firstSeen": "2018-12-07T14:12:38.560Z",
- "name": "siem-kibana",
- "os": "Debian GNU/Linux",
- "version": "9 (stretch)",
- },
- },
- ]
- }
- totalCount={10}
- updateActivePage={[Function]}
- updateLimitPagination={[Function]}
- />
-
+ },
+ ]
+ }
+ totalCount={10}
+ updateActivePage={[Function]}
+ updateLimitPagination={[Function]}
+/>
`;
diff --git a/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx b/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
index ca483b42889b3..c465549ecaec2 100644
--- a/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
+++ b/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
@@ -10,8 +10,10 @@ import * as React from 'react';
import { Direction } from '../../graphql/types';
-import { PaginatedTable } from './index';
+import { BasicTableProps, PaginatedTable } from './index';
import { getHostsColumns, mockData, rowItems, sortedHosts } from './index.mock';
+import { ThemeProvider } from 'styled-components';
+import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
jest.mock('react', () => {
const r = jest.requireActual('react');
@@ -19,6 +21,7 @@ jest.mock('react', () => {
});
describe('Load More Table Component', () => {
+ const theme = () => ({ eui: euiDarkVars, darkMode: true });
let loadPage: jest.Mock;
let updateLimitPagination: jest.Mock;
let updateActivePage: jest.Mock;
@@ -31,7 +34,7 @@ describe('Load More Table Component', () => {
describe('rendering', () => {
test('it renders the default load more table', () => {
const wrapper = shallow(
-
+
{
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
/>
-
+
);
expect(toJson(wrapper)).toMatchSnapshot();
@@ -57,23 +60,25 @@ describe('Load More Table Component', () => {
test('it renders the loading panel at the beginning ', () => {
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={1}
- loading={true}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={[]}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={true}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={[]}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
expect(
@@ -83,23 +88,25 @@ describe('Load More Table Component', () => {
test('it renders the over loading panel after data has been in the table ', () => {
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={1}
- loading={true}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={mockData.Hosts.edges}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={true}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
expect(wrapper.find('[data-test-subj="LoadingPanelPaginatedTable"]').exists()).toBeTruthy();
@@ -107,23 +114,25 @@ describe('Load More Table Component', () => {
test('it renders the correct amount of pages and starts at activePage: 0', () => {
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={1}
- loading={false}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={mockData.Hosts.edges}
- totalCount={10}
- updateActivePage={updateActivePage}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={updateActivePage}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
const paginiationProps = wrapper
@@ -141,23 +150,25 @@ describe('Load More Table Component', () => {
test('it render popover to select new limit in table', () => {
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={2}
- loading={false}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={mockData.Hosts.edges}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
wrapper
@@ -169,23 +180,25 @@ describe('Load More Table Component', () => {
test('it will NOT render popover to select new limit in table if props itemsPerRow is empty', () => {
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={[]}
- limit={2}
- loading={false}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={mockData.Hosts.edges}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={[]}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
expect(wrapper.find('[data-test-subj="loadingMoreSizeRowPopover"]').exists()).toBeFalsy();
@@ -194,25 +207,27 @@ describe('Load More Table Component', () => {
test('It should render a sort icon if sorting is defined', () => {
const mockOnChange = jest.fn();
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={2}
- loading={false}
- loadingTitle="Hosts"
- loadPage={jest.fn()}
- onChange={mockOnChange}
- pageOfItems={mockData.Hosts.edges}
- sorting={{ direction: Direction.asc, field: 'node.host.name' }}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={jest.fn()}
+ onChange={mockOnChange}
+ pageOfItems={mockData.Hosts.edges}
+ sorting={{ direction: Direction.asc, field: 'node.host.name' }}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
expect(wrapper.find('.euiTable thead tr th button svg')).toBeTruthy();
@@ -222,23 +237,25 @@ describe('Load More Table Component', () => {
describe('Events', () => {
test('should call updateActivePage with 1 when clicking to the first page', () => {
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={1}
- loading={false}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={mockData.Hosts.edges}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={1}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
wrapper
.find('[data-test-subj="pagination-button-next"]')
@@ -249,23 +266,25 @@ describe('Load More Table Component', () => {
test('Should call updateActivePage with 0 when you pick a new limit', () => {
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={2}
- loading={false}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={mockData.Hosts.edges}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
wrapper
.find('[data-test-subj="pagination-button-next"]')
@@ -285,59 +304,67 @@ describe('Load More Table Component', () => {
});
test('should call updateActivePage with 0 when an update prop changes', () => {
- const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={1}
- loading={false}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={mockData.Hosts.edges}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- updateProps={{ isThisAwesome: false }}
- />
- );
+ const ourProps: BasicTableProps = {
+ columns: getHostsColumns(),
+ headerCount: 1,
+ headerSupplement: {'My test supplement.'}
,
+ headerTitle: 'Hosts',
+ headerTooltip: 'My test tooltip',
+ headerUnit: 'Test Unit',
+ itemsPerRow: rowItems,
+ limit: 1,
+ loading: false,
+ loadingTitle: 'Hosts',
+ loadPage: newActivePage => loadPage(newActivePage),
+ pageOfItems: mockData.Hosts.edges,
+ totalCount: 10,
+ updateActivePage: activePage => updateActivePage(activePage),
+ updateLimitPagination: limit => updateLimitPagination({ limit }),
+ updateProps: { isThisAwesome: false },
+ };
+
+ // enzyme does not allow us to pass props to child of HOC
+ // so we make a component to pass it the props context
+ // ComponentWithContext will pass the changed props to Component
+ // https://github.com/airbnb/enzyme/issues/1853#issuecomment-443475903
+ const ComponentWithContext = (props: BasicTableProps) => {
+ return (
+
+
+
+ );
+ };
+
+ const wrapper = mount();
wrapper
.find('[data-test-subj="pagination-button-next"]')
.first()
.simulate('click');
wrapper.setProps({ updateProps: { isThisAwesome: true } });
- // enzyme does not have full support for react.memo
- // wrapper will not update without the click below
- wrapper
- .find('[data-test-subj="pagination-button-4"]')
- .first()
- .simulate('click');
expect(updateActivePage.mock.calls[1][0]).toEqual(0);
});
test('Should call updateLimitPagination when you pick a new limit', () => {
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={2}
- loading={false}
- loadingTitle="Hosts"
- loadPage={newActivePage => loadPage(newActivePage)}
- pageOfItems={mockData.Hosts.edges}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={newActivePage => loadPage(newActivePage)}
+ pageOfItems={mockData.Hosts.edges}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
wrapper
@@ -355,25 +382,27 @@ describe('Load More Table Component', () => {
test('Should call onChange when you choose a new sort in the table', () => {
const mockOnChange = jest.fn();
const wrapper = mount(
- {'My test supplement.'}}
- headerTitle="Hosts"
- headerTooltip="My test tooltip"
- headerUnit="Test Unit"
- itemsPerRow={rowItems}
- limit={2}
- loading={false}
- loadingTitle="Hosts"
- loadPage={jest.fn()}
- onChange={mockOnChange}
- pageOfItems={mockData.Hosts.edges}
- sorting={{ direction: Direction.asc, field: 'node.host.name' }}
- totalCount={10}
- updateActivePage={activePage => updateActivePage(activePage)}
- updateLimitPagination={limit => updateLimitPagination({ limit })}
- />
+
+ {'My test supplement.'}}
+ headerTitle="Hosts"
+ headerTooltip="My test tooltip"
+ headerUnit="Test Unit"
+ itemsPerRow={rowItems}
+ limit={2}
+ loading={false}
+ loadingTitle="Hosts"
+ loadPage={jest.fn()}
+ onChange={mockOnChange}
+ pageOfItems={mockData.Hosts.edges}
+ sorting={{ direction: Direction.asc, field: 'node.host.name' }}
+ totalCount={10}
+ updateActivePage={activePage => updateActivePage(activePage)}
+ updateLimitPagination={limit => updateLimitPagination({ limit })}
+ />
+
);
wrapper
diff --git a/x-pack/plugins/siem/public/components/paginated_table/index.tsx b/x-pack/plugins/siem/public/components/paginated_table/index.tsx
index 74a3a33996828..7ea2bf0b60973 100644
--- a/x-pack/plugins/siem/public/components/paginated_table/index.tsx
+++ b/x-pack/plugins/siem/public/components/paginated_table/index.tsx
@@ -41,7 +41,7 @@ export interface Criteria {
}
// Using telescoping templates to remove 'any' that was polluting downstream column type checks
-interface BasicTableProps {
+export interface BasicTableProps {
columns:
| [Columns]
| [Columns, Columns]
From c84d712f41ba7dc1de4551fe9c47313d247f1963 Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Tue, 18 Jun 2019 16:55:25 -0600
Subject: [PATCH 04/29] hooked up auth table
---
.../siem/common/graphql/shared/schema.gql.ts | 17 ++++
.../components/paginated_table/helpers.ts | 19 ++++
.../authentications/index.gql_query.ts | 3 +-
.../containers/authentications/index.tsx | 34 ++++----
.../containers/query_template_paginated.tsx | 66 ++++++++++++++
.../siem/public/graphql/introspection.json | 86 ++++++++++++++++++-
x-pack/plugins/siem/public/graphql/types.ts | 31 +++++--
x-pack/plugins/siem/public/store/constants.ts | 1 +
.../siem/public/store/hosts/actions.ts | 15 +++-
.../plugins/siem/public/store/hosts/model.ts | 14 ++-
.../siem/public/store/hosts/reducer.ts | 6 +-
.../graphql/authentications/schema.gql.ts | 4 +-
x-pack/plugins/siem/server/graphql/types.ts | 65 +++++++++++---
.../authentications/elasticsearch_adapter.ts | 3 +-
14 files changed, 318 insertions(+), 46 deletions(-)
create mode 100644 x-pack/plugins/siem/public/components/paginated_table/helpers.ts
create mode 100644 x-pack/plugins/siem/public/containers/query_template_paginated.tsx
diff --git a/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts b/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
index e8847ac14bbfe..ca617b7fbe9fa 100644
--- a/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
+++ b/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
@@ -30,6 +30,17 @@ export const sharedSchema = gql`
tiebreaker: String
}
+ input PaginationInputPaginated {
+ "The active page parameter defines the page of results you want to fetch"
+ activePage: Float
+ "The limit parameter allows you to configure the maximum amount of items to be returned"
+ limit: Float!
+ "The cursor parameter defines the next result you want to fetch"
+ cursor: String
+ "The tiebreaker parameter allow to be more precise to fetch the next item"
+ tiebreaker: String
+ }
+
enum Direction {
asc
desc
@@ -56,4 +67,10 @@ export const sharedSchema = gql`
endCursor: CursorType
hasNextPage: Boolean
}
+
+ type PageInfoPaginated {
+ activePage: Float
+ endCursor: CursorType
+ hasNextPage: Boolean
+ }
`;
diff --git a/x-pack/plugins/siem/public/components/paginated_table/helpers.ts b/x-pack/plugins/siem/public/components/paginated_table/helpers.ts
new file mode 100644
index 0000000000000..bf2b55a6ecd68
--- /dev/null
+++ b/x-pack/plugins/siem/public/components/paginated_table/helpers.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export const generateTablePaginationOptions = (
+ activePage: number,
+ limit: number,
+ tiebreaker?: string | null
+) => {
+ const cursorStart = activePage * limit;
+ return {
+ activePage,
+ cursor: String(cursorStart),
+ limit: limit + cursorStart,
+ tiebreaker,
+ };
+};
diff --git a/x-pack/plugins/siem/public/containers/authentications/index.gql_query.ts b/x-pack/plugins/siem/public/containers/authentications/index.gql_query.ts
index 976dc8c0181e7..0d88175bf0c6c 100644
--- a/x-pack/plugins/siem/public/containers/authentications/index.gql_query.ts
+++ b/x-pack/plugins/siem/public/containers/authentications/index.gql_query.ts
@@ -10,7 +10,7 @@ export const authenticationsQuery = gql`
query GetAuthenticationsQuery(
$sourceId: ID!
$timerange: TimerangeInput!
- $pagination: PaginationInput!
+ $pagination: PaginationInputPaginated!
$filterQuery: String
$defaultIndex: [String!]!
) {
@@ -57,6 +57,7 @@ export const authenticationsQuery = gql`
}
}
pageInfo {
+ activePage
endCursor {
value
}
diff --git a/x-pack/plugins/siem/public/containers/authentications/index.tsx b/x-pack/plugins/siem/public/containers/authentications/index.tsx
index 9545913af966c..c95747579b856 100644
--- a/x-pack/plugins/siem/public/containers/authentications/index.tsx
+++ b/x-pack/plugins/siem/public/containers/authentications/index.tsx
@@ -14,7 +14,8 @@ import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import { AuthenticationsEdges, GetAuthenticationsQuery, PageInfo } from '../../graphql/types';
import { hostsModel, hostsSelectors, inputsModel, State } from '../../store';
import { createFilter, getDefaultFetchPolicy } from '../helpers';
-import { QueryTemplate, QueryTemplateProps } from '../query_template';
+import { generateTablePaginationOptions } from '../../components/paginated_table/helpers';
+import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated';
import { authenticationsQuery } from './index.gql_query';
@@ -24,36 +25,38 @@ export interface AuthenticationArgs {
totalCount: number;
pageInfo: PageInfo;
loading: boolean;
- loadMore: (cursor: string) => void;
+ loadPage: (newActivePage: number, cursor: string) => void;
refetch: inputsModel.Refetch;
}
-export interface OwnProps extends QueryTemplateProps {
+export interface OwnProps extends QueryTemplatePaginatedProps {
children: (args: AuthenticationArgs) => React.ReactNode;
type: hostsModel.HostsType;
}
export interface AuthenticationsComponentReduxProps {
+ activePage: number;
limit: number;
}
type AuthenticationsProps = OwnProps & AuthenticationsComponentReduxProps;
-class AuthenticationsComponentQuery extends QueryTemplate<
+class AuthenticationsComponentQuery extends QueryTemplatePaginated<
AuthenticationsProps,
GetAuthenticationsQuery.Query,
GetAuthenticationsQuery.Variables
> {
public render() {
const {
- id = 'authenticationQuery',
+ activePage,
children,
+ endDate,
filterQuery,
+ id = 'authenticationQuery',
+ limit,
skip,
sourceId,
startDate,
- endDate,
- limit,
} = this.props;
return (
@@ -68,11 +71,7 @@ class AuthenticationsComponentQuery extends QueryTemplate<
from: startDate!,
to: endDate!,
},
- pagination: {
- limit,
- cursor: null,
- tiebreaker: null,
- },
+ pagination: generateTablePaginationOptions(activePage, limit),
filterQuery: createFilter(filterQuery),
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
}}
@@ -80,9 +79,10 @@ class AuthenticationsComponentQuery extends QueryTemplate<
{({ data, loading, fetchMore, refetch }) => {
const authentications = getOr([], 'source.Authentications.edges', data);
this.setFetchMore(fetchMore);
- this.setFetchMoreOptions((newCursor: string) => ({
+ this.setFetchMoreOptions((newActivePage: number, newCursor: string) => ({
variables: {
pagination: {
+ ...generateTablePaginationOptions(activePage, limit),
cursor: newCursor,
limit: limit + parseInt(newCursor, 10),
},
@@ -107,13 +107,13 @@ class AuthenticationsComponentQuery extends QueryTemplate<
},
}));
return children({
+ authentications,
id,
- refetch,
loading,
- totalCount: getOr(0, 'source.Authentications.totalCount', data),
- authentications,
+ loadPage: this.wrappedLoadMore,
pageInfo: getOr({}, 'source.Authentications.pageInfo', data),
- loadMore: this.wrappedLoadMore,
+ refetch,
+ totalCount: getOr(0, 'source.Authentications.totalCount', data),
});
}}
diff --git a/x-pack/plugins/siem/public/containers/query_template_paginated.tsx b/x-pack/plugins/siem/public/containers/query_template_paginated.tsx
new file mode 100644
index 0000000000000..1244962edf208
--- /dev/null
+++ b/x-pack/plugins/siem/public/containers/query_template_paginated.tsx
@@ -0,0 +1,66 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { ApolloQueryResult } from 'apollo-client';
+import React from 'react';
+import { FetchMoreOptions, FetchMoreQueryOptions, OperationVariables } from 'react-apollo';
+
+import { ESQuery } from '../../common/typed_json';
+
+export interface QueryTemplatePaginatedProps {
+ id?: string;
+ endDate?: number;
+ filterQuery?: ESQuery | string;
+ skip?: boolean;
+ sourceId: string;
+ startDate?: number;
+}
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+type FetchMoreOptionsArgs = FetchMoreQueryOptions &
+ FetchMoreOptions;
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+type PromiseApolloQueryResult = Promise>;
+
+export class QueryTemplatePaginated<
+ T extends QueryTemplatePaginatedProps,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ TData = any,
+ TVariables = OperationVariables
+> extends React.PureComponent {
+ private fetchMore!: (
+ fetchMoreOptions: FetchMoreOptionsArgs
+ ) => PromiseApolloQueryResult;
+
+ private fetchMoreOptions!: (
+ newActivePage: number,
+ newCursor: string,
+ tiebreaker?: string
+ ) => FetchMoreOptionsArgs;
+
+ public constructor(props: T) {
+ super(props);
+ }
+
+ public setFetchMore = (
+ val: (fetchMoreOptions: FetchMoreOptionsArgs) => PromiseApolloQueryResult
+ ) => {
+ this.fetchMore = val;
+ };
+
+ public setFetchMoreOptions = (
+ val: (
+ newActivePage: number,
+ newCursor: string,
+ tiebreaker?: string
+ ) => FetchMoreOptionsArgs
+ ) => {
+ this.fetchMoreOptions = val;
+ };
+
+ public wrappedLoadMore = (newActivePage: number, newCursor: string, tiebreaker?: string) =>
+ this.fetchMore(this.fetchMoreOptions(newActivePage, newCursor, tiebreaker));
+}
diff --git a/x-pack/plugins/siem/public/graphql/introspection.json b/x-pack/plugins/siem/public/graphql/introspection.json
index 18eca421fb0fe..17c7e72c851dd 100644
--- a/x-pack/plugins/siem/public/graphql/introspection.json
+++ b/x-pack/plugins/siem/public/graphql/introspection.json
@@ -670,7 +670,11 @@
"type": {
"kind": "NON_NULL",
"name": null,
- "ofType": { "kind": "INPUT_OBJECT", "name": "PaginationInput", "ofType": null }
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "PaginationInputPaginated",
+ "ofType": null
+ }
},
"defaultValue": null
},
@@ -2347,10 +2351,16 @@
},
{
"kind": "INPUT_OBJECT",
- "name": "PaginationInput",
+ "name": "PaginationInputPaginated",
"description": "",
"fields": null,
"inputFields": [
+ {
+ "name": "activePage",
+ "description": "The active page parameter defines the page of results you want to fetch",
+ "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
+ "defaultValue": null
+ },
{
"name": "limit",
"description": "The limit parameter allows you to configure the maximum amount of items to be returned",
@@ -2422,7 +2432,7 @@
"type": {
"kind": "NON_NULL",
"name": null,
- "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null }
+ "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
@@ -2975,9 +2985,17 @@
},
{
"kind": "OBJECT",
- "name": "PageInfo",
+ "name": "PageInfoPaginated",
"description": "",
"fields": [
+ {
+ "name": "activePage",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "endCursor",
"description": "",
@@ -3000,6 +3018,39 @@
"enumValues": null,
"possibleTypes": null
},
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "PaginationInput",
+ "description": "",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "limit",
+ "description": "The limit parameter allows you to configure the maximum amount of items to be returned",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "cursor",
+ "description": "The cursor parameter defines the next result you want to fetch",
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "defaultValue": null
+ },
+ {
+ "name": "tiebreaker",
+ "description": "The tiebreaker parameter allow to be more precise to fetch the next item",
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
{
"kind": "INPUT_OBJECT",
"name": "SortField",
@@ -5111,6 +5162,33 @@
"enumValues": null,
"possibleTypes": null
},
+ {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "description": "",
+ "fields": [
+ {
+ "name": "endCursor",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "CursorType", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasNextPage",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
{
"kind": "OBJECT",
"name": "TimelineData",
diff --git a/x-pack/plugins/siem/public/graphql/types.ts b/x-pack/plugins/siem/public/graphql/types.ts
index a3b87c438a6fe..c3f8bc0e2e466 100644
--- a/x-pack/plugins/siem/public/graphql/types.ts
+++ b/x-pack/plugins/siem/public/graphql/types.ts
@@ -200,7 +200,7 @@ export interface AuthenticationsData {
totalCount: number;
- pageInfo: PageInfo;
+ pageInfo: PageInfoPaginated;
}
export interface AuthenticationsEdges {
@@ -317,7 +317,9 @@ export interface CursorType {
tiebreaker?: string | null;
}
-export interface PageInfo {
+export interface PageInfoPaginated {
+ activePage?: number | null;
+
endCursor?: CursorType | null;
hasNextPage?: boolean | null;
@@ -797,6 +799,12 @@ export interface SshEcsFields {
signature?: ToStringArray | null;
}
+export interface PageInfo {
+ endCursor?: CursorType | null;
+
+ hasNextPage?: boolean | null;
+}
+
export interface TimelineData {
edges: TimelineEdges[];
@@ -1484,6 +1492,17 @@ export interface TimerangeInput {
from: number;
}
+export interface PaginationInputPaginated {
+ /** The active page parameter defines the page of results you want to fetch */
+ activePage?: number | null;
+ /** The limit parameter allows you to configure the maximum amount of items to be returned */
+ limit: number;
+ /** The cursor parameter defines the next result you want to fetch */
+ cursor?: string | null;
+ /** The tiebreaker parameter allow to be more precise to fetch the next item */
+ tiebreaker?: string | null;
+}
+
export interface PaginationInput {
/** The limit parameter allows you to configure the maximum amount of items to be returned */
limit: number;
@@ -1709,7 +1728,7 @@ export interface GetAllTimelineQueryArgs {
export interface AuthenticationsSourceArgs {
timerange: TimerangeInput;
- pagination: PaginationInput;
+ pagination: PaginationInputPaginated;
filterQuery?: string | null;
@@ -2083,7 +2102,7 @@ export namespace GetAuthenticationsQuery {
export type Variables = {
sourceId: string;
timerange: TimerangeInput;
- pagination: PaginationInput;
+ pagination: PaginationInputPaginated;
filterQuery?: string | null;
defaultIndex: string[];
};
@@ -2197,7 +2216,9 @@ export namespace GetAuthenticationsQuery {
};
export type PageInfo = {
- __typename?: 'PageInfo';
+ __typename?: 'PageInfoPaginated';
+
+ activePage?: number | null;
endCursor?: EndCursor | null;
diff --git a/x-pack/plugins/siem/public/store/constants.ts b/x-pack/plugins/siem/public/store/constants.ts
index 27718a809154f..d8f13efd12dc4 100644
--- a/x-pack/plugins/siem/public/store/constants.ts
+++ b/x-pack/plugins/siem/public/store/constants.ts
@@ -5,3 +5,4 @@
*/
export const DEFAULT_TABLE_LIMIT = 10;
+export const DEFAULT_TABLE_ACTIVE_PAGE = 0;
diff --git a/x-pack/plugins/siem/public/store/hosts/actions.ts b/x-pack/plugins/siem/public/store/hosts/actions.ts
index 0d6e74c0103e2..2d1d5bd35e1b7 100644
--- a/x-pack/plugins/siem/public/store/hosts/actions.ts
+++ b/x-pack/plugins/siem/public/store/hosts/actions.ts
@@ -9,10 +9,21 @@ import actionCreatorFactory from 'typescript-fsa';
import { HostsSortField } from '../../graphql/types';
import { KueryFilterQuery, SerializedFilterQuery } from '../model';
-import { HostsType } from './model';
-
+import { HostsTableType, HostsType } from './model';
const actionCreator = actionCreatorFactory('x-pack/siem/local/hosts');
+export const updateTableActivePage = actionCreator<{
+ activePage: number;
+ hostsType: HostsType;
+ tableType: HostsTableType;
+}>('UPDATE_HOST_TABLE_ACTIVE_PAGE');
+
+export const updateTableLimit = actionCreator<{
+ hostsType: HostsType;
+ limit: number;
+ tableType: HostsTableType;
+}>('UPDATE_HOST_TABLE_LIMIT');
+
export const updateAuthenticationsLimit = actionCreator<{ limit: number; hostsType: HostsType }>(
'UPDATE_AUTHENTICATIONS_LIMIT'
);
diff --git a/x-pack/plugins/siem/public/store/hosts/model.ts b/x-pack/plugins/siem/public/store/hosts/model.ts
index 3cd00c7315c5c..e9a587727d207 100644
--- a/x-pack/plugins/siem/public/store/hosts/model.ts
+++ b/x-pack/plugins/siem/public/store/hosts/model.ts
@@ -12,17 +12,29 @@ export enum HostsType {
details = 'details',
}
+export enum HostsTableType {
+ authentications = 'authentications',
+ hosts = 'hosts',
+ events = 'events',
+ uncommonProcesses = 'uncommonProcesses',
+}
+
export interface BasicQuery {
limit: number;
}
+export interface BasicQueryPaginated {
+ activePage: number;
+ limit: number;
+}
+
export interface HostsQuery extends BasicQuery {
direction: Direction;
sortField: HostsFields;
}
interface Queries {
- authentications: BasicQuery;
+ authentications: BasicQueryPaginated;
hosts: HostsQuery;
events: BasicQuery;
uncommonProcesses: BasicQuery;
diff --git a/x-pack/plugins/siem/public/store/hosts/reducer.ts b/x-pack/plugins/siem/public/store/hosts/reducer.ts
index 2790b86c913d1..cb1a321268a7c 100644
--- a/x-pack/plugins/siem/public/store/hosts/reducer.ts
+++ b/x-pack/plugins/siem/public/store/hosts/reducer.ts
@@ -7,7 +7,7 @@
import { reducerWithInitialState } from 'typescript-fsa-reducers';
import { Direction, HostsFields } from '../../graphql/types';
-import { DEFAULT_TABLE_LIMIT } from '../constants';
+import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../constants';
import {
applyHostsFilterQuery,
@@ -25,7 +25,7 @@ export type HostsState = HostsModel;
export const initialHostsState: HostsState = {
page: {
queries: {
- authentications: { limit: DEFAULT_TABLE_LIMIT },
+ authentications: { limit: DEFAULT_TABLE_LIMIT, activePage: DEFAULT_TABLE_ACTIVE_PAGE },
hosts: {
limit: DEFAULT_TABLE_LIMIT,
direction: Direction.desc,
@@ -39,7 +39,7 @@ export const initialHostsState: HostsState = {
},
details: {
queries: {
- authentications: { limit: DEFAULT_TABLE_LIMIT },
+ authentications: { limit: DEFAULT_TABLE_LIMIT, activePage: DEFAULT_TABLE_ACTIVE_PAGE },
hosts: {
limit: DEFAULT_TABLE_LIMIT,
direction: Direction.desc,
diff --git a/x-pack/plugins/siem/server/graphql/authentications/schema.gql.ts b/x-pack/plugins/siem/server/graphql/authentications/schema.gql.ts
index d8a66522e892f..a1db0beb8c2f0 100644
--- a/x-pack/plugins/siem/server/graphql/authentications/schema.gql.ts
+++ b/x-pack/plugins/siem/server/graphql/authentications/schema.gql.ts
@@ -30,14 +30,14 @@ export const authenticationsSchema = gql`
type AuthenticationsData {
edges: [AuthenticationsEdges!]!
totalCount: Float!
- pageInfo: PageInfo!
+ pageInfo: PageInfoPaginated!
}
extend type Source {
"Gets Authentication success and failures based on a timerange"
Authentications(
timerange: TimerangeInput!
- pagination: PaginationInput!
+ pagination: PaginationInputPaginated!
filterQuery: String
defaultIndex: [String!]!
): AuthenticationsData!
diff --git a/x-pack/plugins/siem/server/graphql/types.ts b/x-pack/plugins/siem/server/graphql/types.ts
index b3cca9aa67960..4b37b5f2435b2 100644
--- a/x-pack/plugins/siem/server/graphql/types.ts
+++ b/x-pack/plugins/siem/server/graphql/types.ts
@@ -229,7 +229,7 @@ export interface AuthenticationsData {
totalCount: number;
- pageInfo: PageInfo;
+ pageInfo: PageInfoPaginated;
}
export interface AuthenticationsEdges {
@@ -346,7 +346,9 @@ export interface CursorType {
tiebreaker?: string | null;
}
-export interface PageInfo {
+export interface PageInfoPaginated {
+ activePage?: number | null;
+
endCursor?: CursorType | null;
hasNextPage?: boolean | null;
@@ -826,6 +828,12 @@ export interface SshEcsFields {
signature?: ToStringArray | null;
}
+export interface PageInfo {
+ endCursor?: CursorType | null;
+
+ hasNextPage?: boolean | null;
+}
+
export interface TimelineData {
edges: TimelineEdges[];
@@ -1513,6 +1521,17 @@ export interface TimerangeInput {
from: number;
}
+export interface PaginationInputPaginated {
+ /** The active page parameter defines the page of results you want to fetch */
+ activePage?: number | null;
+ /** The limit parameter allows you to configure the maximum amount of items to be returned */
+ limit: number;
+ /** The cursor parameter defines the next result you want to fetch */
+ cursor?: string | null;
+ /** The tiebreaker parameter allow to be more precise to fetch the next item */
+ tiebreaker?: string | null;
+}
+
export interface PaginationInput {
/** The limit parameter allows you to configure the maximum amount of items to be returned */
limit: number;
@@ -1738,7 +1757,7 @@ export interface GetAllTimelineQueryArgs {
export interface AuthenticationsSourceArgs {
timerange: TimerangeInput;
- pagination: PaginationInput;
+ pagination: PaginationInputPaginated;
filterQuery?: string | null;
@@ -2461,7 +2480,7 @@ export namespace SourceResolvers {
export interface AuthenticationsArgs {
timerange: TimerangeInput;
- pagination: PaginationInput;
+ pagination: PaginationInputPaginated;
filterQuery?: string | null;
@@ -2972,7 +2991,7 @@ export namespace AuthenticationsDataResolvers {
totalCount?: TotalCountResolver;
- pageInfo?: PageInfoResolver;
+ pageInfo?: PageInfoResolver;
}
export type EdgesResolver<
@@ -2986,7 +3005,7 @@ export namespace AuthenticationsDataResolvers {
Context = SiemContext
> = Resolver;
export type PageInfoResolver<
- R = PageInfo,
+ R = PageInfoPaginated,
Parent = AuthenticationsData,
Context = SiemContext
> = Resolver;
@@ -3371,21 +3390,28 @@ export namespace CursorTypeResolvers {
> = Resolver;
}
-export namespace PageInfoResolvers {
- export interface Resolvers {
+export namespace PageInfoPaginatedResolvers {
+ export interface Resolvers {
+ activePage?: ActivePageResolver;
+
endCursor?: EndCursorResolver;
hasNextPage?: HasNextPageResolver;
}
+ export type ActivePageResolver<
+ R = number | null,
+ Parent = PageInfoPaginated,
+ Context = SiemContext
+ > = Resolver;
export type EndCursorResolver<
R = CursorType | null,
- Parent = PageInfo,
+ Parent = PageInfoPaginated,
Context = SiemContext
> = Resolver;
export type HasNextPageResolver<
R = boolean | null,
- Parent = PageInfo,
+ Parent = PageInfoPaginated,
Context = SiemContext
> = Resolver;
}
@@ -4977,6 +5003,25 @@ export namespace SshEcsFieldsResolvers {
> = Resolver;
}
+export namespace PageInfoResolvers {
+ export interface Resolvers {
+ endCursor?: EndCursorResolver;
+
+ hasNextPage?: HasNextPageResolver;
+ }
+
+ export type EndCursorResolver<
+ R = CursorType | null,
+ Parent = PageInfo,
+ Context = SiemContext
+ > = Resolver;
+ export type HasNextPageResolver<
+ R = boolean | null,
+ Parent = PageInfo,
+ Context = SiemContext
+ > = Resolver;
+}
+
export namespace TimelineDataResolvers {
export interface Resolvers {
edges?: EdgesResolver;
diff --git a/x-pack/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts b/x-pack/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
index a3d1daf410c07..2f156ead21532 100644
--- a/x-pack/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
+++ b/x-pack/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
@@ -31,7 +31,7 @@ export class ElasticsearchAuthenticationAdapter implements AuthenticationsAdapte
'search',
buildQuery(options)
);
- const { cursor, limit } = options.pagination;
+ const { activePage, cursor, limit } = options.pagination;
const totalCount = getOr(0, 'aggregations.user_count.value', response);
const hits: AuthenticationHit[] = getOr(
[],
@@ -60,6 +60,7 @@ export class ElasticsearchAuthenticationAdapter implements AuthenticationsAdapte
edges,
totalCount,
pageInfo: {
+ activePage: activePage ? activePage : 0,
hasNextPage,
endCursor: {
value: String(limit),
From 54d351bcf922e9655abb19e56b153df52348017e Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Thu, 20 Jun 2019 10:07:38 -0600
Subject: [PATCH 05/29] auth table paginated
---
.../hosts/authentications_table/index.tsx | 40 ++++++++++++++++---
.../containers/authentications/index.tsx | 5 +--
.../plugins/siem/public/pages/hosts/hosts.tsx | 4 +-
3 files changed, 37 insertions(+), 12 deletions(-)
diff --git a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.tsx b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
index 0f4126b861ed4..48d5fcc489656 100644
--- a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
+++ b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
@@ -19,20 +19,22 @@ import { DragEffects, DraggableWrapper } from '../../../drag_and_drop/draggable_
import { escapeDataProviderId } from '../../../drag_and_drop/helpers';
import { getEmptyTagValue } from '../../../empty_value';
import { HostDetailsLink, IPDetailsLink } from '../../../links';
-import { Columns, ItemsPerRow, LoadMoreTable } from '../../../load_more_table';
+import { Columns, ItemsPerRow, PaginatedTable } from '../../../paginated_table';
import { IS_OPERATOR } from '../../../timeline/data_providers/data_provider';
import { Provider } from '../../../timeline/data_providers/provider';
import * as i18n from './translations';
import { getRowItemDraggables } from '../../../tables/helpers';
+const tableType = hostsModel.HostsTableType.authentications;
+
interface OwnProps {
data: AuthenticationsEdges[];
loading: boolean;
hasNextPage: boolean;
nextCursor: string;
totalCount: number;
- loadMore: (cursor: string) => void;
+ loadPage: (newActivePage: number, cursor: string) => void;
type: hostsModel.HostsType;
}
@@ -42,6 +44,16 @@ interface AuthenticationTableReduxProps {
interface AuthenticationTableDispatchProps {
updateLimitPagination: ActionCreator<{ limit: number; hostsType: hostsModel.HostsType }>;
+ updateTableActivePage: ActionCreator<{
+ activePage: number;
+ hostsType: hostsModel.HostsType;
+ tableType: hostsModel.HostsTableType;
+ }>;
+ updateTableLimit: ActionCreator<{
+ limit: number;
+ hostsType: hostsModel.HostsType;
+ tableType: hostsModel.HostsTableType;
+ }>;
}
type AuthenticationTableProps = OwnProps &
@@ -73,13 +85,15 @@ const AuthenticationTableComponent = pure(
hasNextPage,
limit,
loading,
- loadMore,
+ loadPage,
totalCount,
nextCursor,
updateLimitPagination,
+ updateTableActivePage,
+ updateTableLimit,
type,
}) => (
- (
limit={limit}
loading={loading}
loadingTitle={i18n.AUTHENTICATIONS}
- loadMore={() => loadMore(nextCursor)}
+ loadPage={newActivePage => loadPage(newActivePage, nextCursor)}
pageOfItems={data}
+ totalCount={totalCount}
updateLimitPagination={newLimit =>
- updateLimitPagination({ limit: newLimit, hostsType: type })
+ updateTableLimit({
+ hostsType: type,
+ limit: newLimit,
+ tableType,
+ })
+ }
+ updateActivePage={newPage =>
+ updateTableActivePage({
+ activePage: newPage,
+ hostsType: type,
+ tableType,
+ })
}
/>
)
@@ -109,6 +135,8 @@ export const AuthenticationTable = connect(
makeMapStateToProps,
{
updateLimitPagination: hostsActions.updateAuthenticationsLimit,
+ updateTableActivePage: hostsActions.updateTableActivePage,
+ updateTableLimit: hostsActions.updateTableLimit,
}
)(AuthenticationTableComponent);
diff --git a/x-pack/plugins/siem/public/containers/authentications/index.tsx b/x-pack/plugins/siem/public/containers/authentications/index.tsx
index c95747579b856..6ac2ad1c4c9d4 100644
--- a/x-pack/plugins/siem/public/containers/authentications/index.tsx
+++ b/x-pack/plugins/siem/public/containers/authentications/index.tsx
@@ -97,10 +97,7 @@ class AuthenticationsComponentQuery extends QueryTemplatePaginated<
...fetchMoreResult.source,
Authentications: {
...fetchMoreResult.source.Authentications,
- edges: [
- ...prev.source.Authentications.edges,
- ...fetchMoreResult.source.Authentications.edges,
- ],
+ edges: [...fetchMoreResult.source.Authentications.edges],
},
},
};
diff --git a/x-pack/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/plugins/siem/public/pages/hosts/hosts.tsx
index 76b937983dd11..3d8980d0980ec 100644
--- a/x-pack/plugins/siem/public/pages/hosts/hosts.tsx
+++ b/x-pack/plugins/siem/public/pages/hosts/hosts.tsx
@@ -127,7 +127,7 @@ const HostsComponent = pure(({ filterQuery }) => (
totalCount,
loading,
pageInfo,
- loadMore,
+ loadPage,
id,
refetch,
}) => (
@@ -140,7 +140,7 @@ const HostsComponent = pure(({ filterQuery }) => (
totalCount={totalCount}
nextCursor={getOr(null, 'endCursor.value', pageInfo)}
hasNextPage={getOr(false, 'hasNextPage', pageInfo)!}
- loadMore={loadMore}
+ loadPage={loadPage}
type={hostsModel.HostsType.page}
/>
)}
From 17d41c8d3f5ca9eac38e8468588bdf592ba7be43 Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Fri, 21 Jun 2019 14:42:47 -0600
Subject: [PATCH 06/29] fixing types
---
.../siem/common/graphql/shared/schema.gql.ts | 23 +++----
.../authentications_table/index.test.tsx | 9 ++-
.../hosts/authentications_table/index.tsx | 16 ++---
.../page/hosts/authentications_table/mock.ts | 8 +--
.../components/paginated_table/helpers.ts | 13 ++--
.../components/paginated_table/index.test.tsx | 9 ++-
.../authentications/index.gql_query.ts | 5 +-
.../containers/authentications/index.tsx | 8 +--
.../containers/query_template_paginated.tsx | 17 ++---
.../siem/public/graphql/introspection.json | 64 +++++++++++++------
x-pack/plugins/siem/public/graphql/types.ts | 36 ++++-------
.../plugins/siem/public/mock/global_state.ts | 4 +-
.../siem/public/pages/hosts/host_details.tsx | 11 ++--
.../plugins/siem/public/pages/hosts/hosts.tsx | 9 ++-
.../siem/public/store/hosts/reducer.ts | 28 ++++++++
.../graphql/authentications/resolvers.ts | 4 +-
x-pack/plugins/siem/server/graphql/types.ts | 41 +++++-------
.../authentications/elasticsearch_adapter.ts | 27 ++++----
.../siem/server/lib/authentications/index.ts | 4 +-
.../server/lib/authentications/query.dsl.ts | 10 +--
.../siem/server/lib/authentications/types.ts | 7 +-
.../siem/server/lib/framework/types.ts | 7 ++
.../utils/build_query/create_options.ts | 32 +++++++++-
x-pack/test/api_integration/apis/index.js | 36 +++++------
.../apis/siem/authentications.ts | 2 +-
.../test/api_integration/apis/siem/index.js | 32 +++++-----
26 files changed, 257 insertions(+), 205 deletions(-)
diff --git a/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts b/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
index ca617b7fbe9fa..e14a3932813cf 100644
--- a/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
+++ b/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
@@ -31,14 +31,16 @@ export const sharedSchema = gql`
}
input PaginationInputPaginated {
- "The active page parameter defines the page of results you want to fetch"
- activePage: Float
- "The limit parameter allows you to configure the maximum amount of items to be returned"
- limit: Float!
- "The cursor parameter defines the next result you want to fetch"
- cursor: String
- "The tiebreaker parameter allow to be more precise to fetch the next item"
- tiebreaker: String
+ "The activePage parameter defines the page of results you want to fetch"
+ activePage: Float!
+ "The querySize parameter is the number of items to be returned"
+ querySize: Float!
+ "The cursorStart parameter defines the start of the results to be displayed"
+ cursorStart: Float!
+ "The nextCursor parameter is next cursorStart"
+ nextCursor: Float!
+ "The fakePossibleCount parameter determines the total count in order to show 5 additional pages"
+ fakePossibleCount: Float!
}
enum Direction {
@@ -69,8 +71,7 @@ export const sharedSchema = gql`
}
type PageInfoPaginated {
- activePage: Float
- endCursor: CursorType
- hasNextPage: Boolean
+ activePage: Float!
+ fakeTotalCount: Float!
}
`;
diff --git a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.test.tsx b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.test.tsx
index 61a57b9c28288..27f5c525c2c6d 100644
--- a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.test.tsx
+++ b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.test.tsx
@@ -20,7 +20,7 @@ import * as i18n from './translations';
import { AuthenticationTable, getAuthenticationColumnsCurated } from '.';
describe('Authentication Table Component', () => {
- const loadMore = jest.fn();
+ const loadPage = jest.fn();
const state: State = mockGlobalState;
let store = createStore(state, apolloClientObservable);
@@ -34,12 +34,11 @@ describe('Authentication Table Component', () => {
const wrapper = shallow(
diff --git a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.tsx b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
index 48d5fcc489656..d275c1bf375a3 100644
--- a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
+++ b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
@@ -30,11 +30,10 @@ const tableType = hostsModel.HostsTableType.authentications;
interface OwnProps {
data: AuthenticationsEdges[];
+ fakeTotalCount: number;
loading: boolean;
- hasNextPage: boolean;
- nextCursor: string;
+ loadPage: (newActivePage: number) => void;
totalCount: number;
- loadPage: (newActivePage: number, cursor: string) => void;
type: hostsModel.HostsType;
}
@@ -81,21 +80,18 @@ const rowItems: ItemsPerRow[] = [
const AuthenticationTableComponent = pure(
({
+ fakeTotalCount,
data,
- hasNextPage,
limit,
loading,
loadPage,
totalCount,
- nextCursor,
- updateLimitPagination,
+ type,
updateTableActivePage,
updateTableLimit,
- type,
}) => (
(
limit={limit}
loading={loading}
loadingTitle={i18n.AUTHENTICATIONS}
- loadPage={newActivePage => loadPage(newActivePage, nextCursor)}
+ loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={data}
- totalCount={totalCount}
+ totalCount={fakeTotalCount}
updateLimitPagination={newLimit =>
updateTableLimit({
hostsType: type,
diff --git a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/mock.ts b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/mock.ts
index 29d1a3ce97375..295d68ee09273 100644
--- a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/mock.ts
+++ b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/mock.ts
@@ -8,7 +8,7 @@ import { AuthenticationsData } from '../../../../graphql/types';
export const mockData: { Authentications: AuthenticationsData } = {
Authentications: {
- totalCount: 4,
+ totalCount: 54,
edges: [
{
node: {
@@ -74,10 +74,8 @@ export const mockData: { Authentications: AuthenticationsData } = {
},
],
pageInfo: {
- endCursor: {
- value: 'aa7ca589f1b8220002f2fc61c64cfbf1',
- },
- hasNextPage: true,
+ activePage: 1,
+ fakeTotalCount: 50,
},
},
};
diff --git a/x-pack/plugins/siem/public/components/paginated_table/helpers.ts b/x-pack/plugins/siem/public/components/paginated_table/helpers.ts
index bf2b55a6ecd68..0ca957c6dfacc 100644
--- a/x-pack/plugins/siem/public/components/paginated_table/helpers.ts
+++ b/x-pack/plugins/siem/public/components/paginated_table/helpers.ts
@@ -4,16 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export const generateTablePaginationOptions = (
- activePage: number,
- limit: number,
- tiebreaker?: string | null
-) => {
+export const generateTablePaginationOptions = (activePage: number, limit: number) => {
const cursorStart = activePage * limit;
return {
activePage,
- cursor: String(cursorStart),
- limit: limit + cursorStart,
- tiebreaker,
+ cursorStart,
+ fakePossibleCount: 4 <= activePage && activePage > 0 ? limit * (activePage + 2) : limit * 5,
+ querySize: limit + cursorStart,
+ nextCursor: limit + cursorStart + 1,
};
};
diff --git a/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx b/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
index c465549ecaec2..943c90f1eb67d 100644
--- a/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
+++ b/x-pack/plugins/siem/public/components/paginated_table/index.test.tsx
@@ -17,14 +17,15 @@ import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
jest.mock('react', () => {
const r = jest.requireActual('react');
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
return { ...r, memo: (x: any) => x };
});
describe('Load More Table Component', () => {
const theme = () => ({ eui: euiDarkVars, darkMode: true });
- let loadPage: jest.Mock;
- let updateLimitPagination: jest.Mock;
- let updateActivePage: jest.Mock;
+ let loadPage: jest.Mock;
+ let updateLimitPagination: jest.Mock;
+ let updateActivePage: jest.Mock;
beforeEach(() => {
loadPage = jest.fn();
updateLimitPagination = jest.fn();
@@ -304,6 +305,7 @@ describe('Load More Table Component', () => {
});
test('should call updateActivePage with 0 when an update prop changes', () => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const ourProps: BasicTableProps = {
columns: getHostsColumns(),
headerCount: 1,
@@ -327,6 +329,7 @@ describe('Load More Table Component', () => {
// so we make a component to pass it the props context
// ComponentWithContext will pass the changed props to Component
// https://github.com/airbnb/enzyme/issues/1853#issuecomment-443475903
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const ComponentWithContext = (props: BasicTableProps) => {
return (
diff --git a/x-pack/plugins/siem/public/containers/authentications/index.gql_query.ts b/x-pack/plugins/siem/public/containers/authentications/index.gql_query.ts
index 0d88175bf0c6c..6f308a23f0041 100644
--- a/x-pack/plugins/siem/public/containers/authentications/index.gql_query.ts
+++ b/x-pack/plugins/siem/public/containers/authentications/index.gql_query.ts
@@ -58,10 +58,7 @@ export const authenticationsQuery = gql`
}
pageInfo {
activePage
- endCursor {
- value
- }
- hasNextPage
+ fakeTotalCount
}
}
}
diff --git a/x-pack/plugins/siem/public/containers/authentications/index.tsx b/x-pack/plugins/siem/public/containers/authentications/index.tsx
index 6ac2ad1c4c9d4..38477f49411eb 100644
--- a/x-pack/plugins/siem/public/containers/authentications/index.tsx
+++ b/x-pack/plugins/siem/public/containers/authentications/index.tsx
@@ -25,7 +25,7 @@ export interface AuthenticationArgs {
totalCount: number;
pageInfo: PageInfo;
loading: boolean;
- loadPage: (newActivePage: number, cursor: string) => void;
+ loadPage: (newActivePage: number) => void;
refetch: inputsModel.Refetch;
}
@@ -79,12 +79,10 @@ class AuthenticationsComponentQuery extends QueryTemplatePaginated<
{({ data, loading, fetchMore, refetch }) => {
const authentications = getOr([], 'source.Authentications.edges', data);
this.setFetchMore(fetchMore);
- this.setFetchMoreOptions((newActivePage: number, newCursor: string) => ({
+ this.setFetchMoreOptions((newActivePage: number) => ({
variables: {
pagination: {
- ...generateTablePaginationOptions(activePage, limit),
- cursor: newCursor,
- limit: limit + parseInt(newCursor, 10),
+ ...generateTablePaginationOptions(newActivePage, limit),
},
},
updateQuery: (prev, { fetchMoreResult }) => {
diff --git a/x-pack/plugins/siem/public/containers/query_template_paginated.tsx b/x-pack/plugins/siem/public/containers/query_template_paginated.tsx
index 1244962edf208..00cd8d21fb4e8 100644
--- a/x-pack/plugins/siem/public/containers/query_template_paginated.tsx
+++ b/x-pack/plugins/siem/public/containers/query_template_paginated.tsx
@@ -35,11 +35,7 @@ export class QueryTemplatePaginated<
fetchMoreOptions: FetchMoreOptionsArgs
) => PromiseApolloQueryResult;
- private fetchMoreOptions!: (
- newActivePage: number,
- newCursor: string,
- tiebreaker?: string
- ) => FetchMoreOptionsArgs;
+ private fetchMoreOptions!: (newActivePage: number) => FetchMoreOptionsArgs;
public constructor(props: T) {
super(props);
@@ -52,15 +48,12 @@ export class QueryTemplatePaginated<
};
public setFetchMoreOptions = (
- val: (
- newActivePage: number,
- newCursor: string,
- tiebreaker?: string
- ) => FetchMoreOptionsArgs
+ val: (newActivePage: number) => FetchMoreOptionsArgs
) => {
this.fetchMoreOptions = val;
};
- public wrappedLoadMore = (newActivePage: number, newCursor: string, tiebreaker?: string) =>
- this.fetchMore(this.fetchMoreOptions(newActivePage, newCursor, tiebreaker));
+ public wrappedLoadMore = (newActivePage: number) => {
+ return this.fetchMore(this.fetchMoreOptions(newActivePage));
+ };
}
diff --git a/x-pack/plugins/siem/public/graphql/introspection.json b/x-pack/plugins/siem/public/graphql/introspection.json
index 17c7e72c851dd..7c2c8693fb532 100644
--- a/x-pack/plugins/siem/public/graphql/introspection.json
+++ b/x-pack/plugins/siem/public/graphql/introspection.json
@@ -2357,13 +2357,17 @@
"inputFields": [
{
"name": "activePage",
- "description": "The active page parameter defines the page of results you want to fetch",
- "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
+ "description": "The activePage parameter defines the page of results you want to fetch",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
"defaultValue": null
},
{
- "name": "limit",
- "description": "The limit parameter allows you to configure the maximum amount of items to be returned",
+ "name": "querySize",
+ "description": "The querySize parameter is the number of items to be returned",
"type": {
"kind": "NON_NULL",
"name": null,
@@ -2372,15 +2376,33 @@
"defaultValue": null
},
{
- "name": "cursor",
- "description": "The cursor parameter defines the next result you want to fetch",
- "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "name": "cursorStart",
+ "description": "The cursorStart parameter defines the start of the results to be displayed",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
"defaultValue": null
},
{
- "name": "tiebreaker",
- "description": "The tiebreaker parameter allow to be more precise to fetch the next item",
- "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "name": "nextCursor",
+ "description": "The nextCursor parameter is next cursorStart",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "fakePossibleCount",
+ "description": "The fakePossibleCount parameter determines the total count in order to show 5 additional pages",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
"defaultValue": null
}
],
@@ -2992,23 +3014,23 @@
"name": "activePage",
"description": "",
"args": [],
- "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
- "isDeprecated": false,
- "deprecationReason": null
- },
- {
- "name": "endCursor",
- "description": "",
- "args": [],
- "type": { "kind": "OBJECT", "name": "CursorType", "ofType": null },
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "hasNextPage",
+ "name": "fakeTotalCount",
"description": "",
"args": [],
- "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null },
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
"isDeprecated": false,
"deprecationReason": null
}
diff --git a/x-pack/plugins/siem/public/graphql/types.ts b/x-pack/plugins/siem/public/graphql/types.ts
index c3f8bc0e2e466..4968c2dc94f65 100644
--- a/x-pack/plugins/siem/public/graphql/types.ts
+++ b/x-pack/plugins/siem/public/graphql/types.ts
@@ -318,11 +318,9 @@ export interface CursorType {
}
export interface PageInfoPaginated {
- activePage?: number | null;
+ activePage: number;
- endCursor?: CursorType | null;
-
- hasNextPage?: boolean | null;
+ fakeTotalCount: number;
}
export interface EventsData {
@@ -1493,14 +1491,16 @@ export interface TimerangeInput {
}
export interface PaginationInputPaginated {
- /** The active page parameter defines the page of results you want to fetch */
- activePage?: number | null;
- /** The limit parameter allows you to configure the maximum amount of items to be returned */
- limit: number;
- /** The cursor parameter defines the next result you want to fetch */
- cursor?: string | null;
- /** The tiebreaker parameter allow to be more precise to fetch the next item */
- tiebreaker?: string | null;
+ /** The activePage parameter defines the page of results you want to fetch */
+ activePage: number;
+ /** The querySize parameter is the number of items to be returned */
+ querySize: number;
+ /** The cursorStart parameter defines the start of the results to be displayed */
+ cursorStart: number;
+ /** The nextCursor parameter is next cursorStart */
+ nextCursor: number;
+ /** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */
+ fakePossibleCount: number;
}
export interface PaginationInput {
@@ -2218,17 +2218,9 @@ export namespace GetAuthenticationsQuery {
export type PageInfo = {
__typename?: 'PageInfoPaginated';
- activePage?: number | null;
+ activePage: number;
- endCursor?: EndCursor | null;
-
- hasNextPage?: boolean | null;
- };
-
- export type EndCursor = {
- __typename?: 'CursorType';
-
- value?: string | null;
+ fakeTotalCount: number;
};
}
diff --git a/x-pack/plugins/siem/public/mock/global_state.ts b/x-pack/plugins/siem/public/mock/global_state.ts
index 115804d0e4cd0..e52d3d95dd1f0 100644
--- a/x-pack/plugins/siem/public/mock/global_state.ts
+++ b/x-pack/plugins/siem/public/mock/global_state.ts
@@ -31,7 +31,7 @@ export const mockGlobalState: State = {
hosts: {
page: {
queries: {
- authentications: { limit: 10 },
+ authentications: { activePage: 0, limit: 10 },
hosts: {
limit: 10,
direction: Direction.desc,
@@ -45,7 +45,7 @@ export const mockGlobalState: State = {
},
details: {
queries: {
- authentications: { limit: 10 },
+ authentications: { activePage: 0, limit: 10 },
hosts: {
limit: 10,
direction: Direction.desc,
diff --git a/x-pack/plugins/siem/public/pages/hosts/host_details.tsx b/x-pack/plugins/siem/public/pages/hosts/host_details.tsx
index 937aeda5d35b1..3bafcd36a5b2b 100644
--- a/x-pack/plugins/siem/public/pages/hosts/host_details.tsx
+++ b/x-pack/plugins/siem/public/pages/hosts/host_details.tsx
@@ -110,20 +110,19 @@ const HostDetailsComponent = pure(
totalCount,
loading,
pageInfo,
- loadMore,
+ loadPage,
id,
refetch,
}) => (
)}
diff --git a/x-pack/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/plugins/siem/public/pages/hosts/hosts.tsx
index 3d8980d0980ec..a00cb8b49e90e 100644
--- a/x-pack/plugins/siem/public/pages/hosts/hosts.tsx
+++ b/x-pack/plugins/siem/public/pages/hosts/hosts.tsx
@@ -132,15 +132,14 @@ const HostsComponent = pure(({ filterQuery }) => (
refetch,
}) => (
)}
diff --git a/x-pack/plugins/siem/public/store/hosts/reducer.ts b/x-pack/plugins/siem/public/store/hosts/reducer.ts
index cb1a321268a7c..99df07758a4a1 100644
--- a/x-pack/plugins/siem/public/store/hosts/reducer.ts
+++ b/x-pack/plugins/siem/public/store/hosts/reducer.ts
@@ -17,6 +17,8 @@ import {
updateHostsLimit,
updateHostsSort,
updateUncommonProcessesLimit,
+ updateTableActivePage,
+ updateTableLimit,
} from './actions';
import { HostsModel } from './model';
@@ -54,6 +56,32 @@ export const initialHostsState: HostsState = {
};
export const hostsReducer = reducerWithInitialState(initialHostsState)
+ .case(updateTableActivePage, (state, { activePage, hostsType, tableType }) => ({
+ ...state,
+ [hostsType]: {
+ ...state[hostsType],
+ queries: {
+ ...state[hostsType].queries,
+ [tableType]: {
+ ...state[hostsType].queries[tableType],
+ activePage,
+ },
+ },
+ },
+ }))
+ .case(updateTableLimit, (state, { limit, hostsType, tableType }) => ({
+ ...state,
+ [hostsType]: {
+ ...state[hostsType],
+ queries: {
+ ...state[hostsType].queries,
+ [tableType]: {
+ ...state[hostsType].queries[tableType],
+ limit,
+ },
+ },
+ },
+ }))
.case(updateAuthenticationsLimit, (state, { limit, hostsType }) => ({
...state,
[hostsType]: {
diff --git a/x-pack/plugins/siem/server/graphql/authentications/resolvers.ts b/x-pack/plugins/siem/server/graphql/authentications/resolvers.ts
index f60a870c8d160..b66ccd9a111b7 100644
--- a/x-pack/plugins/siem/server/graphql/authentications/resolvers.ts
+++ b/x-pack/plugins/siem/server/graphql/authentications/resolvers.ts
@@ -7,7 +7,7 @@
import { SourceResolvers } from '../../graphql/types';
import { Authentications } from '../../lib/authentications';
import { AppResolverOf, ChildResolverOf } from '../../lib/framework';
-import { createOptions } from '../../utils/build_query/create_options';
+import { createOptionsPaginated } from '../../utils/build_query/create_options';
import { QuerySourceResolver } from '../sources/resolvers';
type QueryAuthenticationsResolver = ChildResolverOf<
@@ -28,7 +28,7 @@ export const createAuthenticationsResolvers = (
} => ({
Source: {
async Authentications(source, args, { req }, info) {
- const options = createOptions(source, args, info);
+ const options = createOptionsPaginated(source, args, info);
return libs.authentications.getAuthentications(req, options);
},
},
diff --git a/x-pack/plugins/siem/server/graphql/types.ts b/x-pack/plugins/siem/server/graphql/types.ts
index 4b37b5f2435b2..1ba2acfecbce0 100644
--- a/x-pack/plugins/siem/server/graphql/types.ts
+++ b/x-pack/plugins/siem/server/graphql/types.ts
@@ -347,11 +347,9 @@ export interface CursorType {
}
export interface PageInfoPaginated {
- activePage?: number | null;
+ activePage: number;
- endCursor?: CursorType | null;
-
- hasNextPage?: boolean | null;
+ fakeTotalCount: number;
}
export interface EventsData {
@@ -1522,14 +1520,16 @@ export interface TimerangeInput {
}
export interface PaginationInputPaginated {
- /** The active page parameter defines the page of results you want to fetch */
- activePage?: number | null;
- /** The limit parameter allows you to configure the maximum amount of items to be returned */
- limit: number;
- /** The cursor parameter defines the next result you want to fetch */
- cursor?: string | null;
- /** The tiebreaker parameter allow to be more precise to fetch the next item */
- tiebreaker?: string | null;
+ /** The activePage parameter defines the page of results you want to fetch */
+ activePage: number;
+ /** The querySize parameter is the number of items to be returned */
+ querySize: number;
+ /** The cursorStart parameter defines the start of the results to be displayed */
+ cursorStart: number;
+ /** The nextCursor parameter is next cursorStart */
+ nextCursor: number;
+ /** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */
+ fakePossibleCount: number;
}
export interface PaginationInput {
@@ -3392,25 +3392,18 @@ export namespace CursorTypeResolvers {
export namespace PageInfoPaginatedResolvers {
export interface Resolvers {
- activePage?: ActivePageResolver;
-
- endCursor?: EndCursorResolver;
+ activePage?: ActivePageResolver;
- hasNextPage?: HasNextPageResolver;
+ fakeTotalCount?: FakeTotalCountResolver;
}
export type ActivePageResolver<
- R = number | null,
- Parent = PageInfoPaginated,
- Context = SiemContext
- > = Resolver;
- export type EndCursorResolver<
- R = CursorType | null,
+ R = number,
Parent = PageInfoPaginated,
Context = SiemContext
> = Resolver;
- export type HasNextPageResolver<
- R = boolean | null,
+ export type FakeTotalCountResolver<
+ R = number,
Parent = PageInfoPaginated,
Context = SiemContext
> = Resolver;
diff --git a/x-pack/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts b/x-pack/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
index 2f156ead21532..e4c1d7efe22d2 100644
--- a/x-pack/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
+++ b/x-pack/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
@@ -8,7 +8,7 @@ import { getOr } from 'lodash/fp';
import { AuthenticationsData, AuthenticationsEdges } from '../../graphql/types';
import { mergeFieldsWithHit } from '../../utils/build_query';
-import { FrameworkAdapter, FrameworkRequest, RequestOptions } from '../framework';
+import { FrameworkAdapter, FrameworkRequest, RequestOptionsPaginated } from '../framework';
import { TermAggregation } from '../types';
import { auditdFieldsMap, buildQuery } from './query.dsl';
@@ -24,15 +24,22 @@ export class ElasticsearchAuthenticationAdapter implements AuthenticationsAdapte
public async getAuthentications(
request: FrameworkRequest,
- options: RequestOptions
+ options: RequestOptionsPaginated
): Promise {
+ const builtQuery = buildQuery(options);
const response = await this.framework.callWithRequest(
request,
'search',
- buildQuery(options)
+ builtQuery
);
- const { activePage, cursor, limit } = options.pagination;
+ const {
+ activePage,
+ cursorStart,
+ fakePossibleCount,
+ querySize,
+ } = options.pagination;
const totalCount = getOr(0, 'aggregations.user_count.value', response);
+ const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount;
const hits: AuthenticationHit[] = getOr(
[],
'aggregations.group_by_users.buckets',
@@ -44,28 +51,20 @@ export class ElasticsearchAuthenticationAdapter implements AuthenticationsAdapte
lastFailure: getOr(null, 'failures.lastFailure.hits.hits[0]._source', bucket),
},
user: bucket.key,
- cursor: bucket.key.user_uid,
failures: bucket.failures.doc_count,
successes: bucket.successes.doc_count,
}));
-
const authenticationEdges: AuthenticationsEdges[] = hits.map(hit =>
formatAuthenticationData(options.fields, hit, auditdFieldsMap)
);
- const hasNextPage = authenticationEdges.length === limit + 1;
- const beginning = cursor != null ? parseInt(cursor!, 10) : 0;
- const edges = authenticationEdges.splice(beginning, limit - beginning);
+ const edges = authenticationEdges.splice(cursorStart, querySize - cursorStart);
return {
edges,
totalCount,
pageInfo: {
activePage: activePage ? activePage : 0,
- hasNextPage,
- endCursor: {
- value: String(limit),
- tiebreaker: null,
- },
+ fakeTotalCount,
},
};
}
diff --git a/x-pack/plugins/siem/server/lib/authentications/index.ts b/x-pack/plugins/siem/server/lib/authentications/index.ts
index 4ed0c9b1ed146..d64f820de2392 100644
--- a/x-pack/plugins/siem/server/lib/authentications/index.ts
+++ b/x-pack/plugins/siem/server/lib/authentications/index.ts
@@ -5,7 +5,7 @@
*/
import { AuthenticationsData } from '../../graphql/types';
-import { FrameworkRequest, RequestOptions } from '../framework';
+import { FrameworkRequest, RequestOptionsPaginated } from '../framework';
import { AuthenticationsAdapter } from './types';
@@ -14,7 +14,7 @@ export class Authentications {
public async getAuthentications(
req: FrameworkRequest,
- options: RequestOptions
+ options: RequestOptionsPaginated
): Promise {
return await this.adapter.getAuthentications(req, options);
}
diff --git a/x-pack/plugins/siem/server/lib/authentications/query.dsl.ts b/x-pack/plugins/siem/server/lib/authentications/query.dsl.ts
index b2216861de378..da4aad52a7af1 100644
--- a/x-pack/plugins/siem/server/lib/authentications/query.dsl.ts
+++ b/x-pack/plugins/siem/server/lib/authentications/query.dsl.ts
@@ -8,7 +8,7 @@ import { createQueryFilterClauses } from '../../utils/build_query';
import { reduceFields } from '../../utils/build_query/reduce_fields';
import { hostFieldsMap, sourceFieldsMap } from '../ecs_fields';
import { extendMap } from '../ecs_fields/extend_map';
-import { RequestOptions } from '../framework';
+import { RequestOptionsPaginated } from '../framework';
export const auditdFieldsMap: Readonly> = {
latest: '@timestamp',
@@ -24,12 +24,12 @@ export const buildQuery = ({
fields,
filterQuery,
timerange: { from, to },
- pagination: { limit },
+ pagination: { querySize },
defaultIndex,
sourceConfiguration: {
fields: { timestamp },
},
-}: RequestOptions) => {
+}: RequestOptionsPaginated) => {
const esFields = reduceFields(fields, { ...hostFieldsMap, ...sourceFieldsMap });
const filter = [
@@ -62,7 +62,7 @@ export const buildQuery = ({
...agg,
group_by_users: {
terms: {
- size: limit + 1,
+ size: querySize,
field: 'user.name',
order: [{ 'successes.doc_count': 'desc' }, { 'failures.doc_count': 'desc' }],
},
@@ -114,8 +114,8 @@ export const buildQuery = ({
filter,
},
},
+ size: 0,
},
- size: 0,
track_total_hits: false,
};
diff --git a/x-pack/plugins/siem/server/lib/authentications/types.ts b/x-pack/plugins/siem/server/lib/authentications/types.ts
index f120bcdfbf506..2d2c7ba547c09 100644
--- a/x-pack/plugins/siem/server/lib/authentications/types.ts
+++ b/x-pack/plugins/siem/server/lib/authentications/types.ts
@@ -5,11 +5,14 @@
*/
import { AuthenticationsData, LastSourceHost } from '../../graphql/types';
-import { FrameworkRequest, RequestOptions } from '../framework';
+import { FrameworkRequest, RequestOptionsPaginated } from '../framework';
import { Hit, SearchHit, TotalHit } from '../types';
export interface AuthenticationsAdapter {
- getAuthentications(req: FrameworkRequest, options: RequestOptions): Promise;
+ getAuthentications(
+ req: FrameworkRequest,
+ options: RequestOptionsPaginated
+ ): Promise;
}
type StringOrNumber = string | number;
diff --git a/x-pack/plugins/siem/server/lib/framework/types.ts b/x-pack/plugins/siem/server/lib/framework/types.ts
index 9b353e04f7736..be527700f4bd2 100644
--- a/x-pack/plugins/siem/server/lib/framework/types.ts
+++ b/x-pack/plugins/siem/server/lib/framework/types.ts
@@ -12,6 +12,7 @@ import { Legacy } from 'kibana';
import { ESQuery } from '../../../common/typed_json';
import {
PaginationInput,
+ PaginationInputPaginated,
SortField,
SourceConfiguration,
TimerangeInput,
@@ -159,3 +160,9 @@ export interface RequestOptions extends RequestBasicOptions {
fields: ReadonlyArray;
sortField?: SortField;
}
+
+export interface RequestOptionsPaginated extends RequestBasicOptions {
+ pagination: PaginationInputPaginated;
+ fields: ReadonlyArray;
+ sortField?: SortField;
+}
diff --git a/x-pack/plugins/siem/server/utils/build_query/create_options.ts b/x-pack/plugins/siem/server/utils/build_query/create_options.ts
index f3c7832fb6094..a705c95a847d0 100644
--- a/x-pack/plugins/siem/server/utils/build_query/create_options.ts
+++ b/x-pack/plugins/siem/server/utils/build_query/create_options.ts
@@ -7,8 +7,8 @@
import { GraphQLResolveInfo } from 'graphql';
import { getOr } from 'lodash/fp';
-import { PaginationInput, SortField, Source, TimerangeInput } from '../../graphql/types';
-import { RequestOptions } from '../../lib/framework';
+import { PaginationInput, PaginationInputPaginated, SortField, Source, TimerangeInput } from '../../graphql/types';
+import { RequestOptions, RequestOptionsPaginated } from '../../lib/framework';
import { parseFilterQuery } from '../serialized_query';
import { getFields } from '.';
@@ -27,6 +27,13 @@ export interface Args {
sortField?: SortField | null;
defaultIndex: string[];
}
+export interface ArgsPaginated {
+ timerange?: TimerangeInput | null;
+ pagination?: PaginationInputPaginated | null;
+ filterQuery?: string | null;
+ sortField?: SortField | null;
+ defaultIndex: string[];
+}
export const createOptions = (
source: Configuration,
@@ -47,3 +54,24 @@ export const createOptions = (
.map(field => field.replace(fieldReplacement, '')),
};
};
+
+
+export const createOptionsPaginated = (
+ source: Configuration,
+ args: ArgsPaginated,
+ info: FieldNodes,
+ fieldReplacement: string = 'edges.node.'
+): RequestOptionsPaginated => {
+ const fields = getFields(getOr([], 'fieldNodes[0]', info));
+ return {
+ defaultIndex: args.defaultIndex,
+ sourceConfiguration: source.configuration,
+ timerange: args.timerange!,
+ pagination: args.pagination!,
+ sortField: args.sortField!,
+ filterQuery: parseFilterQuery(args.filterQuery || ''),
+ fields: fields
+ .filter(field => !field.includes('__typename'))
+ .map(field => field.replace(fieldReplacement, '')),
+ };
+};
diff --git a/x-pack/test/api_integration/apis/index.js b/x-pack/test/api_integration/apis/index.js
index 9378a47aee2de..61050a8b8a082 100644
--- a/x-pack/test/api_integration/apis/index.js
+++ b/x-pack/test/api_integration/apis/index.js
@@ -6,24 +6,24 @@
export default function ({ loadTestFile }) {
describe('apis', function () {
- this.tags('ciGroup6');
-
- loadTestFile(require.resolve('./es'));
- loadTestFile(require.resolve('./security'));
- loadTestFile(require.resolve('./monitoring'));
- loadTestFile(require.resolve('./xpack_main'));
- loadTestFile(require.resolve('./telemetry'));
- loadTestFile(require.resolve('./logstash'));
- loadTestFile(require.resolve('./kibana'));
- loadTestFile(require.resolve('./infra'));
- loadTestFile(require.resolve('./beats'));
- loadTestFile(require.resolve('./console'));
- loadTestFile(require.resolve('./management'));
- loadTestFile(require.resolve('./uptime'));
- loadTestFile(require.resolve('./maps'));
- loadTestFile(require.resolve('./apm'));
+ // this.tags('ciGroup6');
+ //
+ // loadTestFile(require.resolve('./es'));
+ // loadTestFile(require.resolve('./security'));
+ // loadTestFile(require.resolve('./monitoring'));
+ // loadTestFile(require.resolve('./xpack_main'));
+ // loadTestFile(require.resolve('./telemetry'));
+ // loadTestFile(require.resolve('./logstash'));
+ // loadTestFile(require.resolve('./kibana'));
+ // loadTestFile(require.resolve('./infra'));
+ // loadTestFile(require.resolve('./beats'));
+ // loadTestFile(require.resolve('./console'));
+ // loadTestFile(require.resolve('./management'));
+ // loadTestFile(require.resolve('./uptime'));
+ // loadTestFile(require.resolve('./maps'));
+ // loadTestFile(require.resolve('./apm'));
loadTestFile(require.resolve('./siem'));
- loadTestFile(require.resolve('./code'));
- loadTestFile(require.resolve('./short_urls'));
+ // loadTestFile(require.resolve('./code'));
+ // loadTestFile(require.resolve('./short_urls'));
});
}
diff --git a/x-pack/test/api_integration/apis/siem/authentications.ts b/x-pack/test/api_integration/apis/siem/authentications.ts
index 251500ddfd42c..6995f26b73d17 100644
--- a/x-pack/test/api_integration/apis/siem/authentications.ts
+++ b/x-pack/test/api_integration/apis/siem/authentications.ts
@@ -48,7 +48,7 @@ const authenticationsTests: KbnTestProvider = ({ getService }) => {
const authentications = resp.data.source.Authentications;
expect(authentications.edges.length).to.be(EDGE_LENGTH);
expect(authentications.totalCount).to.be(TOTAL_COUNT);
- expect(authentications.pageInfo.endCursor!.value).to.equal('1');
+ expect(authentications.pageInfo.fakeTotalCount).to.equal(50);
});
});
diff --git a/x-pack/test/api_integration/apis/siem/index.js b/x-pack/test/api_integration/apis/siem/index.js
index 3c16d36ac92c9..dcfcb9bd83b28 100644
--- a/x-pack/test/api_integration/apis/siem/index.js
+++ b/x-pack/test/api_integration/apis/siem/index.js
@@ -7,21 +7,21 @@
export default function ({ loadTestFile }) {
describe('Siem GraphQL Endpoints', () => {
loadTestFile(require.resolve('./authentications'));
- loadTestFile(require.resolve('./domains'));
- loadTestFile(require.resolve('./events'));
- loadTestFile(require.resolve('./hosts'));
- loadTestFile(require.resolve('./kpi_network'));
- loadTestFile(require.resolve('./kpi_hosts'));
- loadTestFile(require.resolve('./network_dns'));
- loadTestFile(require.resolve('./network_top_n_flow'));
- loadTestFile(require.resolve('./overview_host'));
- loadTestFile(require.resolve('./sources'));
- loadTestFile(require.resolve('./overview_network'));
- loadTestFile(require.resolve('./timeline'));
- loadTestFile(require.resolve('./timeline_details'));
- loadTestFile(require.resolve('./uncommon_processes'));
- loadTestFile(require.resolve('./users'));
- loadTestFile(require.resolve('./tls'));
- loadTestFile(require.resolve('./feature_controls'));
+ // loadTestFile(require.resolve('./domains'));
+ // loadTestFile(require.resolve('./events'));
+ // loadTestFile(require.resolve('./hosts'));
+ // loadTestFile(require.resolve('./kpi_network'));
+ // loadTestFile(require.resolve('./kpi_hosts'));
+ // loadTestFile(require.resolve('./network_dns'));
+ // loadTestFile(require.resolve('./network_top_n_flow'));
+ // loadTestFile(require.resolve('./overview_host'));
+ // loadTestFile(require.resolve('./sources'));
+ // loadTestFile(require.resolve('./overview_network'));
+ // loadTestFile(require.resolve('./timeline'));
+ // loadTestFile(require.resolve('./timeline_details'));
+ // loadTestFile(require.resolve('./uncommon_processes'));
+ // loadTestFile(require.resolve('./users'));
+ // loadTestFile(require.resolve('./tls'));
+ // loadTestFile(require.resolve('./feature_controls'));
});
}
From 0cad2ed2253b36437dd1d02ed13414663b002b8c Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Fri, 21 Jun 2019 15:07:50 -0600
Subject: [PATCH 07/29] tests
---
.../siem/common/graphql/shared/schema.gql.ts | 6 +--
.../components/page/add_to_kql/index.test.tsx | 1 +
.../__snapshots__/index.test.tsx.snap | 7 ++-
.../paginated_table/helpers.test.ts | 45 +++++++++++++++++++
.../components/paginated_table/helpers.ts | 1 -
.../siem/public/graphql/introspection.json | 10 -----
x-pack/plugins/siem/public/graphql/types.ts | 2 -
x-pack/plugins/siem/server/graphql/types.ts | 2 -
.../apis/siem/authentications.ts | 8 ++--
9 files changed, 55 insertions(+), 27 deletions(-)
create mode 100644 x-pack/plugins/siem/public/components/paginated_table/helpers.test.ts
diff --git a/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts b/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
index e14a3932813cf..b40dc406c53a3 100644
--- a/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
+++ b/x-pack/plugins/siem/common/graphql/shared/schema.gql.ts
@@ -33,14 +33,12 @@ export const sharedSchema = gql`
input PaginationInputPaginated {
"The activePage parameter defines the page of results you want to fetch"
activePage: Float!
- "The querySize parameter is the number of items to be returned"
- querySize: Float!
"The cursorStart parameter defines the start of the results to be displayed"
cursorStart: Float!
- "The nextCursor parameter is next cursorStart"
- nextCursor: Float!
"The fakePossibleCount parameter determines the total count in order to show 5 additional pages"
fakePossibleCount: Float!
+ "The querySize parameter is the number of items to be returned"
+ querySize: Float!
}
enum Direction {
diff --git a/x-pack/plugins/siem/public/components/page/add_to_kql/index.test.tsx b/x-pack/plugins/siem/public/components/page/add_to_kql/index.test.tsx
index 3888ab3651950..6f4f7d953cb8f 100644
--- a/x-pack/plugins/siem/public/components/page/add_to_kql/index.test.tsx
+++ b/x-pack/plugins/siem/public/components/page/add_to_kql/index.test.tsx
@@ -87,6 +87,7 @@ describe('AddToKql Component', async () => {
expect(store.getState().hosts.page).toEqual({
queries: {
authentications: {
+ activePage: 0,
limit: 10,
},
hosts: {
diff --git a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/__snapshots__/index.test.tsx.snap
index adecb066bde5f..bfcdd7d082328 100644
--- a/x-pack/plugins/siem/public/components/page/hosts/authentications_table/__snapshots__/index.test.tsx.snap
+++ b/x-pack/plugins/siem/public/components/page/hosts/authentications_table/__snapshots__/index.test.tsx.snap
@@ -100,11 +100,10 @@ exports[`Authentication Table Component rendering it renders the authentication
},
]
}
- hasNextPage={true}
- loadMore={[MockFunction]}
+ fakeTotalCount={50}
+ loadPage={[MockFunction]}
loading={false}
- nextCursor="aa7ca589f1b8220002f2fc61c64cfbf1"
- totalCount={4}
+ totalCount={54}
type="page"
/>
`;
diff --git a/x-pack/plugins/siem/public/components/paginated_table/helpers.test.ts b/x-pack/plugins/siem/public/components/paginated_table/helpers.test.ts
new file mode 100644
index 0000000000000..f3a5b87fc5a32
--- /dev/null
+++ b/x-pack/plugins/siem/public/components/paginated_table/helpers.test.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { generateTablePaginationOptions } from './helpers';
+
+describe('generateTablePaginationOptions pagination helper function', () => {
+ let activePage;
+ let limit;
+ test('generates 5 pages when activePage 0', () => {
+ activePage = 0;
+ limit = 10;
+ const result = generateTablePaginationOptions(activePage, limit);
+ expect(result).toEqual({
+ activePage,
+ cursorStart: 0,
+ fakePossibleCount: 50,
+ querySize: 10,
+ });
+ });
+ test('generates 6 pages when activePage 4', () => {
+ activePage = 4;
+ limit = 10;
+ const result = generateTablePaginationOptions(activePage, limit);
+ expect(result).toEqual({
+ activePage,
+ cursorStart: 40,
+ fakePossibleCount: 60,
+ querySize: 50,
+ });
+ });
+ test('generates 5 pages when activePage 2', () => {
+ activePage = 2;
+ limit = 10;
+ const result = generateTablePaginationOptions(activePage, limit);
+ expect(result).toEqual({
+ activePage,
+ cursorStart: 20,
+ fakePossibleCount: 50,
+ querySize: 30,
+ });
+ });
+});
diff --git a/x-pack/plugins/siem/public/components/paginated_table/helpers.ts b/x-pack/plugins/siem/public/components/paginated_table/helpers.ts
index 0ca957c6dfacc..cc8f1cf205e1f 100644
--- a/x-pack/plugins/siem/public/components/paginated_table/helpers.ts
+++ b/x-pack/plugins/siem/public/components/paginated_table/helpers.ts
@@ -11,6 +11,5 @@ export const generateTablePaginationOptions = (activePage: number, limit: number
cursorStart,
fakePossibleCount: 4 <= activePage && activePage > 0 ? limit * (activePage + 2) : limit * 5,
querySize: limit + cursorStart,
- nextCursor: limit + cursorStart + 1,
};
};
diff --git a/x-pack/plugins/siem/public/graphql/introspection.json b/x-pack/plugins/siem/public/graphql/introspection.json
index 7c2c8693fb532..906b9c2e31c8f 100644
--- a/x-pack/plugins/siem/public/graphql/introspection.json
+++ b/x-pack/plugins/siem/public/graphql/introspection.json
@@ -2385,16 +2385,6 @@
},
"defaultValue": null
},
- {
- "name": "nextCursor",
- "description": "The nextCursor parameter is next cursorStart",
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
- },
- "defaultValue": null
- },
{
"name": "fakePossibleCount",
"description": "The fakePossibleCount parameter determines the total count in order to show 5 additional pages",
diff --git a/x-pack/plugins/siem/public/graphql/types.ts b/x-pack/plugins/siem/public/graphql/types.ts
index 4968c2dc94f65..e10887bfa85e9 100644
--- a/x-pack/plugins/siem/public/graphql/types.ts
+++ b/x-pack/plugins/siem/public/graphql/types.ts
@@ -1497,8 +1497,6 @@ export interface PaginationInputPaginated {
querySize: number;
/** The cursorStart parameter defines the start of the results to be displayed */
cursorStart: number;
- /** The nextCursor parameter is next cursorStart */
- nextCursor: number;
/** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */
fakePossibleCount: number;
}
diff --git a/x-pack/plugins/siem/server/graphql/types.ts b/x-pack/plugins/siem/server/graphql/types.ts
index 1ba2acfecbce0..5d39748fb6b83 100644
--- a/x-pack/plugins/siem/server/graphql/types.ts
+++ b/x-pack/plugins/siem/server/graphql/types.ts
@@ -1526,8 +1526,6 @@ export interface PaginationInputPaginated {
querySize: number;
/** The cursorStart parameter defines the start of the results to be displayed */
cursorStart: number;
- /** The nextCursor parameter is next cursorStart */
- nextCursor: number;
/** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */
fakePossibleCount: number;
}
diff --git a/x-pack/test/api_integration/apis/siem/authentications.ts b/x-pack/test/api_integration/apis/siem/authentications.ts
index 6995f26b73d17..e3acef842e9d7 100644
--- a/x-pack/test/api_integration/apis/siem/authentications.ts
+++ b/x-pack/test/api_integration/apis/siem/authentications.ts
@@ -39,7 +39,7 @@ const authenticationsTests: KbnTestProvider = ({ getService }) => {
},
pagination: {
limit: 1,
- cursor: null,
+ activePage: 0,
},
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
},
@@ -48,7 +48,7 @@ const authenticationsTests: KbnTestProvider = ({ getService }) => {
const authentications = resp.data.source.Authentications;
expect(authentications.edges.length).to.be(EDGE_LENGTH);
expect(authentications.totalCount).to.be(TOTAL_COUNT);
- expect(authentications.pageInfo.fakeTotalCount).to.equal(50);
+ expect(authentications.pageInfo.fakeTotalCount).to.equal(5);
});
});
@@ -64,8 +64,8 @@ const authenticationsTests: KbnTestProvider = ({ getService }) => {
from: FROM,
},
pagination: {
- limit: 2,
- cursor: '1',
+ limit: 1,
+ activePage: 2,
},
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
},
From 4e41e4619d4ab52059dd0df05fd1650e8df88087 Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Fri, 21 Jun 2019 15:34:32 -0600
Subject: [PATCH 08/29] fix api tests
---
x-pack/test/api_integration/apis/index.js | 40 +++++++++----------
.../apis/siem/authentications.ts | 4 +-
2 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/x-pack/test/api_integration/apis/index.js b/x-pack/test/api_integration/apis/index.js
index 9e726862e9615..4dd380a15c63a 100644
--- a/x-pack/test/api_integration/apis/index.js
+++ b/x-pack/test/api_integration/apis/index.js
@@ -6,26 +6,26 @@
export default function ({ loadTestFile }) {
describe('apis', function () {
- // this.tags('ciGroup6');
- //
- // loadTestFile(require.resolve('./actions'));
- // loadTestFile(require.resolve('./alerting'));
- // loadTestFile(require.resolve('./es'));
- // loadTestFile(require.resolve('./security'));
- // loadTestFile(require.resolve('./monitoring'));
- // loadTestFile(require.resolve('./xpack_main'));
- // loadTestFile(require.resolve('./telemetry'));
- // loadTestFile(require.resolve('./logstash'));
- // loadTestFile(require.resolve('./kibana'));
- // loadTestFile(require.resolve('./infra'));
- // loadTestFile(require.resolve('./beats'));
- // loadTestFile(require.resolve('./console'));
- // loadTestFile(require.resolve('./management'));
- // loadTestFile(require.resolve('./uptime'));
- // loadTestFile(require.resolve('./maps'));
- // loadTestFile(require.resolve('./apm'));
+ this.tags('ciGroup6');
+
+ loadTestFile(require.resolve('./actions'));
+ loadTestFile(require.resolve('./alerting'));
+ loadTestFile(require.resolve('./es'));
+ loadTestFile(require.resolve('./security'));
+ loadTestFile(require.resolve('./monitoring'));
+ loadTestFile(require.resolve('./xpack_main'));
+ loadTestFile(require.resolve('./telemetry'));
+ loadTestFile(require.resolve('./logstash'));
+ loadTestFile(require.resolve('./kibana'));
+ loadTestFile(require.resolve('./infra'));
+ loadTestFile(require.resolve('./beats'));
+ loadTestFile(require.resolve('./console'));
+ loadTestFile(require.resolve('./management'));
+ loadTestFile(require.resolve('./uptime'));
+ loadTestFile(require.resolve('./maps'));
+ loadTestFile(require.resolve('./apm'));
loadTestFile(require.resolve('./siem'));
- // loadTestFile(require.resolve('./code'));
- // loadTestFile(require.resolve('./short_urls'));
+ loadTestFile(require.resolve('./code'));
+ loadTestFile(require.resolve('./short_urls'));
});
}
diff --git a/x-pack/test/api_integration/apis/siem/authentications.ts b/x-pack/test/api_integration/apis/siem/authentications.ts
index ebfa5f59b1cef..aa7e3cf2febe2 100644
--- a/x-pack/test/api_integration/apis/siem/authentications.ts
+++ b/x-pack/test/api_integration/apis/siem/authentications.ts
@@ -40,7 +40,7 @@ const authenticationsTests: KbnTestProvider = ({ getService }) => {
pagination: {
activePage: 0,
cursorStart: 0,
- fakePossibleCount: 5,
+ fakePossibleCount: 3,
querySize: 1,
},
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
@@ -50,7 +50,7 @@ const authenticationsTests: KbnTestProvider = ({ getService }) => {
const authentications = resp.data.source.Authentications;
expect(authentications.edges.length).to.be(EDGE_LENGTH);
expect(authentications.totalCount).to.be(TOTAL_COUNT);
- expect(authentications.pageInfo.fakeTotalCount).to.equal(5);
+ expect(authentications.pageInfo.fakeTotalCount).to.equal(3);
});
});
From e7c955d8d75b4fb89c77c493d8ab2773c13dbc6f Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Fri, 21 Jun 2019 15:47:08 -0600
Subject: [PATCH 09/29] readd tests
---
.../test/api_integration/apis/siem/index.js | 32 +++++++++----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/x-pack/test/api_integration/apis/siem/index.js b/x-pack/test/api_integration/apis/siem/index.js
index dcfcb9bd83b28..3c16d36ac92c9 100644
--- a/x-pack/test/api_integration/apis/siem/index.js
+++ b/x-pack/test/api_integration/apis/siem/index.js
@@ -7,21 +7,21 @@
export default function ({ loadTestFile }) {
describe('Siem GraphQL Endpoints', () => {
loadTestFile(require.resolve('./authentications'));
- // loadTestFile(require.resolve('./domains'));
- // loadTestFile(require.resolve('./events'));
- // loadTestFile(require.resolve('./hosts'));
- // loadTestFile(require.resolve('./kpi_network'));
- // loadTestFile(require.resolve('./kpi_hosts'));
- // loadTestFile(require.resolve('./network_dns'));
- // loadTestFile(require.resolve('./network_top_n_flow'));
- // loadTestFile(require.resolve('./overview_host'));
- // loadTestFile(require.resolve('./sources'));
- // loadTestFile(require.resolve('./overview_network'));
- // loadTestFile(require.resolve('./timeline'));
- // loadTestFile(require.resolve('./timeline_details'));
- // loadTestFile(require.resolve('./uncommon_processes'));
- // loadTestFile(require.resolve('./users'));
- // loadTestFile(require.resolve('./tls'));
- // loadTestFile(require.resolve('./feature_controls'));
+ loadTestFile(require.resolve('./domains'));
+ loadTestFile(require.resolve('./events'));
+ loadTestFile(require.resolve('./hosts'));
+ loadTestFile(require.resolve('./kpi_network'));
+ loadTestFile(require.resolve('./kpi_hosts'));
+ loadTestFile(require.resolve('./network_dns'));
+ loadTestFile(require.resolve('./network_top_n_flow'));
+ loadTestFile(require.resolve('./overview_host'));
+ loadTestFile(require.resolve('./sources'));
+ loadTestFile(require.resolve('./overview_network'));
+ loadTestFile(require.resolve('./timeline'));
+ loadTestFile(require.resolve('./timeline_details'));
+ loadTestFile(require.resolve('./uncommon_processes'));
+ loadTestFile(require.resolve('./users'));
+ loadTestFile(require.resolve('./tls'));
+ loadTestFile(require.resolve('./feature_controls'));
});
}
From 9275a4744329cefe555d9cca49779517c6823681 Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Fri, 21 Jun 2019 15:48:20 -0600
Subject: [PATCH 10/29] readd tests
---
.../test/api_integration/apis/siem/authentications.ts | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/x-pack/test/api_integration/apis/siem/authentications.ts b/x-pack/test/api_integration/apis/siem/authentications.ts
index aa7e3cf2febe2..7638ae6557d18 100644
--- a/x-pack/test/api_integration/apis/siem/authentications.ts
+++ b/x-pack/test/api_integration/apis/siem/authentications.ts
@@ -86,14 +86,3 @@ const authenticationsTests: KbnTestProvider = ({ getService }) => {
// eslint-disable-next-line import/no-default-export
export default authenticationsTests;
-
-/**
- "The activePage parameter defines the page of results you want to fetch"
- activePage: Float!
- "The cursorStart parameter defines the start of the results to be displayed"
- cursorStart: Float!
- "The fakePossibleCount parameter determines the total count in order to show 5 additional pages"
- fakePossibleCount: Float!
- "The querySize parameter is the number of items to be returned"
- querySize: Float!
- **/
From c8e7edee8174fc969241307a5c34bf9d94202b1e Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Thu, 27 Jun 2019 08:24:22 -0600
Subject: [PATCH 11/29] limit paginated table to 10 items
---
.../components/page/hosts/authentications_table/index.tsx | 8 --------
1 file changed, 8 deletions(-)
diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
index d275c1bf375a3..f488085b48441 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
@@ -68,14 +68,6 @@ const rowItems: ItemsPerRow[] = [
text: i18n.ROWS_10,
numberOfRow: 10,
},
- {
- text: i18n.ROWS_20,
- numberOfRow: 20,
- },
- {
- text: i18n.ROWS_50,
- numberOfRow: 50,
- },
];
const AuthenticationTableComponent = pure(
From 8b956c46b6c743f8cecc34ebd401cb28fd8d416b Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Wed, 3 Jul 2019 11:16:07 -0600
Subject: [PATCH 12/29] accomodate inspect'
---
.../components/paginated_table/index.tsx | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
index 7ea2bf0b60973..9f1bd27d3c26e 100644
--- a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
@@ -24,6 +24,8 @@ import { LoadingPanel } from '../loading';
import * as i18n from './translations';
+const DEFAULT_DATA_TEST_SUBJ = 'paginated-table';
+
export interface ItemsPerRow {
text: string;
numberOfRow: number;
@@ -71,11 +73,13 @@ export interface BasicTableProps,
Columns
];
+ dataTestSubj?: string;
headerCount: number;
headerSupplement?: React.ReactElement;
headerTitle: string | React.ReactElement;
headerTooltip?: string;
headerUnit: string | React.ReactElement;
+ id?: string;
itemsPerRow?: ItemsPerRow[];
limit: number;
loading: boolean;
@@ -107,11 +111,13 @@ export interface Columns {
export const PaginatedTable = memo>(
({
columns,
+ dataTestSubj = DEFAULT_DATA_TEST_SUBJ,
headerCount,
headerSupplement,
headerTitle,
headerTooltip,
headerUnit,
+ id,
itemsPerRow,
limit,
loading,
@@ -126,6 +132,7 @@ export const PaginatedTable = memo>(
updateProps,
}) => {
const [activePage, setActivePage] = useState(0);
+ const [showInspect, setShowInspect] = useState(false);
const [isEmptyTable, setEmptyTable] = useState(pageOfItems.length === 0);
const [isPopoverOpen, setPopoverOpen] = useState(false);
const pageCount = Math.ceil(totalCount / limit);
@@ -194,7 +201,11 @@ export const PaginatedTable = memo>(
));
return (
-
+ setShowInspect(true)}
+ onMouseLeave={() => setShowInspect(false)}
+ >
{loading && (
<>
@@ -211,6 +222,8 @@ export const PaginatedTable = memo>(
)}
>(
From 4ed7852ac7fccff26a73364faf37c853db01b8ad Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Mon, 8 Jul 2019 15:52:11 -0600
Subject: [PATCH 13/29] design changes
---
.../siem/common/graphql/shared/schema.gql.ts | 1 +
.../__snapshots__/index.test.tsx.snap | 3 ++-
.../authentications_table/index.test.tsx | 5 +++++
.../hosts/authentications_table/index.tsx | 3 +++
.../page/hosts/authentications_table/mock.ts | 1 +
.../__snapshots__/index.test.tsx.snap | 1 +
.../components/paginated_table/index.test.tsx | 12 +++++++++++
.../components/paginated_table/index.tsx | 21 +++++++++++++++++--
.../authentications/index.gql_query.ts | 1 +
.../containers/authentications/index.tsx | 8 +++++--
.../siem/public/graphql/introspection.json | 12 +++++++++++
.../plugins/siem/public/graphql/types.ts | 4 ++++
.../siem/public/pages/hosts/host_details.tsx | 5 +++++
.../plugins/siem/public/pages/hosts/hosts.tsx | 1 +
.../plugins/siem/server/graphql/types.ts | 9 ++++++++
.../authentications/elasticsearch_adapter.ts | 2 ++
16 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/x-pack/legacy/plugins/siem/common/graphql/shared/schema.gql.ts b/x-pack/legacy/plugins/siem/common/graphql/shared/schema.gql.ts
index 4e1db66bc6d90..a3c597c3772f5 100644
--- a/x-pack/legacy/plugins/siem/common/graphql/shared/schema.gql.ts
+++ b/x-pack/legacy/plugins/siem/common/graphql/shared/schema.gql.ts
@@ -76,5 +76,6 @@ export const sharedSchema = gql`
type PageInfoPaginated {
activePage: Float!
fakeTotalCount: Float!
+ showMorePagesIndicator: Boolean!
}
`;
diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/__snapshots__/index.test.tsx.snap
index ef1349192fffb..23392c5880f7e 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/__snapshots__/index.test.tsx.snap
+++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/__snapshots__/index.test.tsx.snap
@@ -101,9 +101,10 @@ exports[`Authentication Table Component rendering it renders the authentication
]
}
fakeTotalCount={50}
- loadPage={[MockFunction]}
id="authentication"
+ loadPage={[MockFunction]}
loading={false}
+ showMorePagesIndicator={true}
totalCount={54}
type="page"
/>
diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.test.tsx
index 36b8c7d0c6e82..d373c5725421d 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.test.tsx
@@ -39,6 +39,11 @@ describe('Authentication Table Component', () => {
id="authentication"
loading={false}
loadPage={loadPage}
+ showMorePagesIndicator={getOr(
+ false,
+ 'showMorePagesIndicator',
+ mockData.Authentications.pageInfo
+ )}
totalCount={mockData.Authentications.totalCount}
type={hostsModel.HostsType.page}
/>
diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
index b5e6af9fa7e42..8c6e7be6e5c92 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
@@ -34,6 +34,7 @@ interface OwnProps {
loading: boolean;
loadPage: (newActivePage: number) => void;
id: string;
+ showMorePagesIndicator: boolean;
totalCount: number;
type: hostsModel.HostsType;
}
@@ -79,6 +80,7 @@ const AuthenticationTableComponent = pure(
limit,
loading,
loadPage,
+ showMorePagesIndicator,
totalCount,
type,
updateTableActivePage,
@@ -96,6 +98,7 @@ const AuthenticationTableComponent = pure(
loadingTitle={i18n.AUTHENTICATIONS}
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={data}
+ showMorePagesIndicator={showMorePagesIndicator}
totalCount={fakeTotalCount}
updateLimitPagination={newLimit =>
updateTableLimit({
diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/mock.ts b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/mock.ts
index 295d68ee09273..50a1fa8eb7d72 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/mock.ts
+++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/mock.ts
@@ -76,6 +76,7 @@ export const mockData: { Authentications: AuthenticationsData } = {
pageInfo: {
activePage: 1,
fakeTotalCount: 50,
+ showMorePagesIndicator: true,
},
},
};
diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
index f072b8ca92c1d..a3dd561ba36dc 100644
--- a/x-pack/legacy/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
+++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/__snapshots__/index.test.tsx.snap
@@ -99,6 +99,7 @@ exports[`Load More Table Component rendering it renders the default load more ta
},
]
}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={[Function]}
updateLimitPagination={[Function]}
diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.test.tsx
index 943c90f1eb67d..a18b996d145e6 100644
--- a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.test.tsx
@@ -49,6 +49,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -75,6 +76,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={[]}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -103,6 +105,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -129,6 +132,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={updateActivePage}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -165,6 +169,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -195,6 +200,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -223,6 +229,7 @@ describe('Load More Table Component', () => {
loadPage={jest.fn()}
onChange={mockOnChange}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
sorting={{ direction: Direction.asc, field: 'node.host.name' }}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
@@ -252,6 +259,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -281,6 +289,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -319,6 +328,7 @@ describe('Load More Table Component', () => {
loadingTitle: 'Hosts',
loadPage: newActivePage => loadPage(newActivePage),
pageOfItems: mockData.Hosts.edges,
+ showMorePagesIndicator: true,
totalCount: 10,
updateActivePage: activePage => updateActivePage(activePage),
updateLimitPagination: limit => updateLimitPagination({ limit }),
@@ -363,6 +373,7 @@ describe('Load More Table Component', () => {
loadingTitle="Hosts"
loadPage={newActivePage => loadPage(newActivePage)}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
updateLimitPagination={limit => updateLimitPagination({ limit })}
@@ -400,6 +411,7 @@ describe('Load More Table Component', () => {
loadPage={jest.fn()}
onChange={mockOnChange}
pageOfItems={mockData.Hosts.edges}
+ showMorePagesIndicator={true}
sorting={{ direction: Direction.asc, field: 'node.host.name' }}
totalCount={10}
updateActivePage={activePage => updateActivePage(activePage)}
diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
index 9f1bd27d3c26e..8dff03f797c4d 100644
--- a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
@@ -88,6 +88,7 @@ export interface BasicTableProps void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
pageOfItems: any[];
+ showMorePagesIndicator: boolean;
sorting?: SortingBasicTable;
totalCount: number;
updateActivePage: (activePage: number) => void;
@@ -125,6 +126,7 @@ export const PaginatedTable = memo>(
loadPage,
onChange = noop,
pageOfItems,
+ showMorePagesIndicator,
sorting = null,
totalCount,
updateActivePage,
@@ -200,6 +202,7 @@ export const PaginatedTable = memo>(
{item.text}
));
+ const PaginationWrapper = showMorePagesIndicator ? PaginationEuiFlexItem : EuiFlexItem;
return (
>(
justifyContent="flexEnd"
direction="row"
>
-
+
-
+
@@ -328,3 +331,17 @@ const BasicTable = styled(EuiBasicTable)`
}
}
`;
+
+const PaginationEuiFlexItem = styled(EuiFlexItem)`
+ button.euiButtonIcon.euiButtonIcon--text {
+ margin-left: 20px;
+ }
+ .euiPagination::before {
+ content: '...';
+ bottom: 13px;
+ color: #c2c3c6;
+ font-size: 14px;
+ position: absolute;
+ right: 30px;
+ }
+`;
diff --git a/x-pack/legacy/plugins/siem/public/containers/authentications/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/authentications/index.gql_query.ts
index 9b543f1ab147a..eee35730cfdbb 100644
--- a/x-pack/legacy/plugins/siem/public/containers/authentications/index.gql_query.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/authentications/index.gql_query.ts
@@ -60,6 +60,7 @@ export const authenticationsQuery = gql`
pageInfo {
activePage
fakeTotalCount
+ showMorePagesIndicator
}
inspect @include(if: $inspect) {
dsl
diff --git a/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx b/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx
index ec8dc106ad016..c18eaf7942b10 100644
--- a/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx
@@ -11,7 +11,11 @@ import { connect } from 'react-redux';
import chrome from 'ui/chrome';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
-import { AuthenticationsEdges, GetAuthenticationsQuery, PageInfo } from '../../graphql/types';
+import {
+ AuthenticationsEdges,
+ GetAuthenticationsQuery,
+ PageInfoPaginated,
+} from '../../graphql/types';
import { hostsModel, hostsSelectors, inputsModel, State, inputsSelectors } from '../../store';
import { createFilter, getDefaultFetchPolicy } from '../helpers';
import { generateTablePaginationOptions } from '../../components/paginated_table/helpers';
@@ -26,7 +30,7 @@ export interface AuthenticationArgs {
inspect: inputsModel.InspectQuery;
authentications: AuthenticationsEdges[];
totalCount: number;
- pageInfo: PageInfo;
+ pageInfo: PageInfoPaginated;
loading: boolean;
loadPage: (newActivePage: number) => void;
refetch: inputsModel.Refetch;
diff --git a/x-pack/legacy/plugins/siem/public/graphql/introspection.json b/x-pack/legacy/plugins/siem/public/graphql/introspection.json
index 8cb49bb93783b..d654fdaa79aa4 100644
--- a/x-pack/legacy/plugins/siem/public/graphql/introspection.json
+++ b/x-pack/legacy/plugins/siem/public/graphql/introspection.json
@@ -3084,6 +3084,18 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "showMorePagesIndicator",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
diff --git a/x-pack/legacy/plugins/siem/public/graphql/types.ts b/x-pack/legacy/plugins/siem/public/graphql/types.ts
index 9709172cfb45c..03c645e0886c5 100644
--- a/x-pack/legacy/plugins/siem/public/graphql/types.ts
+++ b/x-pack/legacy/plugins/siem/public/graphql/types.ts
@@ -325,6 +325,8 @@ export interface PageInfoPaginated {
activePage: number;
fakeTotalCount: number;
+
+ showMorePagesIndicator: boolean;
}
export interface Inspect {
@@ -2297,6 +2299,8 @@ export namespace GetAuthenticationsQuery {
activePage: number;
fakeTotalCount: number;
+
+ showMorePagesIndicator: boolean;
};
export type Inspect = {
diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx
index 178807313ca5e..ea1e7fd19836a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx
@@ -181,6 +181,11 @@ const HostDetailsComponent = pure(
loading={loading}
loadPage={loadPage}
refetch={refetch}
+ showMorePagesIndicator={getOr(
+ false,
+ 'showMorePagesIndicator',
+ pageInfo
+ )}
setQuery={setQuery}
totalCount={totalCount}
type={type}
diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx
index 3502aabdc74e2..afca4966ac21e 100644
--- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx
@@ -164,6 +164,7 @@ const HostsComponent = pure(({ filterQuery, setAbsoluteRang
loading={loading}
loadPage={loadPage}
refetch={refetch}
+ showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', pageInfo)}
setQuery={setQuery}
totalCount={totalCount}
type={hostsModel.HostsType.page}
diff --git a/x-pack/legacy/plugins/siem/server/graphql/types.ts b/x-pack/legacy/plugins/siem/server/graphql/types.ts
index 995786267bfa7..d6904fa55b0ec 100644
--- a/x-pack/legacy/plugins/siem/server/graphql/types.ts
+++ b/x-pack/legacy/plugins/siem/server/graphql/types.ts
@@ -354,6 +354,8 @@ export interface PageInfoPaginated {
activePage: number;
fakeTotalCount: number;
+
+ showMorePagesIndicator: boolean;
}
export interface Inspect {
@@ -3492,6 +3494,8 @@ export namespace PageInfoPaginatedResolvers {
activePage?: ActivePageResolver;
fakeTotalCount?: FakeTotalCountResolver;
+
+ showMorePagesIndicator?: ShowMorePagesIndicatorResolver;
}
export type ActivePageResolver<
@@ -3504,6 +3508,11 @@ export namespace PageInfoPaginatedResolvers {
Parent = PageInfoPaginated,
Context = SiemContext
> = Resolver;
+ export type ShowMorePagesIndicatorResolver<
+ R = boolean,
+ Parent = PageInfoPaginated,
+ Context = SiemContext
+ > = Resolver;
}
export namespace InspectResolvers {
diff --git a/x-pack/legacy/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts b/x-pack/legacy/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
index c058f11e000c4..4ac1fbecfc4e8 100644
--- a/x-pack/legacy/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/authentications/elasticsearch_adapter.ts
@@ -58,6 +58,7 @@ export class ElasticsearchAuthenticationAdapter implements AuthenticationsAdapte
dsl: [inspectStringifyObject(dsl)],
response: [inspectStringifyObject(response)],
};
+ const showMorePagesIndicator = totalCount > fakeTotalCount;
return {
inspect,
edges,
@@ -65,6 +66,7 @@ export class ElasticsearchAuthenticationAdapter implements AuthenticationsAdapte
pageInfo: {
activePage: activePage ? activePage : 0,
fakeTotalCount,
+ showMorePagesIndicator,
},
};
}
From c154817ac134394421de6a8c7b63c6cb2d44ba6c Mon Sep 17 00:00:00 2001
From: stephmilovic
Date: Mon, 8 Jul 2019 16:08:11 -0600
Subject: [PATCH 14/29] better types
---
.../hosts/authentications_table/index.tsx | 24 ++++++-----
.../page/hosts/hosts_table/index.tsx | 20 ++++-----
.../components/paginated_table/index.tsx | 41 ++++---------------
3 files changed, 30 insertions(+), 55 deletions(-)
diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
index 8c6e7be6e5c92..a417d55584c61 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx
@@ -57,6 +57,18 @@ interface AuthenticationTableDispatchProps {
}>;
}
+export declare type AuthTableColumns = [
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns
+];
+
type AuthenticationTableProps = OwnProps &
AuthenticationTableReduxProps &
AuthenticationTableDispatchProps;
@@ -134,17 +146,7 @@ export const AuthenticationTable = connect(
}
)(AuthenticationTableComponent);
-const getAuthenticationColumns = (): [
- Columns,
- Columns,
- Columns,
- Columns,
- Columns,
- Columns,
- Columns,
- Columns,
- Columns
-] => [
+const getAuthenticationColumns = (): AuthTableColumns => [
{
name: i18n.USER,
truncateText: false,
diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.tsx
index 2d773b22722d6..4aad85e1ac6f1 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.tsx
@@ -78,17 +78,18 @@ const rowItems: ItemsPerRow[] = [
numberOfRow: 50,
},
];
+export declare type HostsTableColumns = [
+ Columns,
+ Columns,
+ Columns,
+ Columns
+];
class HostsTableComponent extends React.PureComponent {
private memoizedColumns: (
type: hostsModel.HostsType,
indexPattern: StaticIndexPattern
- ) => [
- Columns,
- Columns,
- Columns,
- Columns
- ];
+ ) => HostsTableColumns;
private memoizedSorting: (
trigger: string,
sortField: HostsFields,
@@ -150,12 +151,7 @@ class HostsTableComponent extends React.PureComponent {
private getMemoizeHostsColumns = (
type: hostsModel.HostsType,
indexPattern: StaticIndexPattern
- ): [
- Columns,
- Columns,
- Columns,
- Columns
- ] => getHostsColumns(type, indexPattern);
+ ): HostsTableColumns => getHostsColumns(type, indexPattern);
private onChange = (criteria: Criteria) => {
if (criteria.sort != null) {
diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
index 8dff03f797c4d..2e34cc1fe212c 100644
--- a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
@@ -19,6 +19,8 @@ import React, { memo, useState, useEffect } from 'react';
import styled from 'styled-components';
import { Direction } from '../../graphql/types';
+import { HostsTableColumns } from '../page/hosts/hosts_table';
+import { AuthTableColumns } from '../page/hosts/authentications_table';
import { HeaderPanel } from '../header_panel';
import { LoadingPanel } from '../loading';
@@ -42,37 +44,13 @@ export interface Criteria {
sort?: SortingBasicTable;
}
+declare type BasicTableColumns = AuthTableColumns | HostsTableColumns;
+
+declare type SiemTables = BasicTableProps;
+
// Using telescoping templates to remove 'any' that was polluting downstream column type checks
-export interface BasicTableProps {
- columns:
- | [Columns]
- | [Columns, Columns]
- | [Columns, Columns, Columns]
- | [Columns, Columns, Columns, Columns]
- | [Columns, Columns, Columns, Columns, Columns]
- | [Columns, Columns, Columns, Columns, Columns