From 59ddb37fae5922993ced8172a09fab46804d975e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Sun, 2 Feb 2020 15:24:00 +0100 Subject: [PATCH 01/12] [SIEM] WIP --- .../public/components/auto_sizer/index.tsx | 7 +- .../public/components/charts/areachart.tsx | 10 +- .../public/components/charts/barchart.tsx | 33 +- .../siem/public/components/charts/common.tsx | 12 +- .../drag_and_drop/droppable_wrapper.tsx | 4 +- .../components/embeddables/embeddable.tsx | 14 +- .../embeddables/embeddable_header.tsx | 36 +- .../filters_global/filters_global.tsx | 22 +- .../siem/public/components/flyout/index.tsx | 63 +-- .../public/components/flyout/pane/index.tsx | 5 +- .../public/components/header_page/index.tsx | 3 +- .../components/header_section/index.tsx | 3 +- .../siem/public/components/inspect/index.tsx | 11 +- .../components/matrix_histogram/index.tsx | 3 +- .../hosts/authentications_table/index.tsx | 4 +- .../page/hosts/hosts_table/index.tsx | 11 +- .../components/page/hosts/kpi_hosts/index.tsx | 4 +- .../hosts/uncommon_process_table/index.tsx | 6 +- .../public/components/page/manage_query.tsx | 7 +- .../page/network/kpi_network/index.tsx | 5 +- .../network/network_dns_table/columns.tsx | 2 +- .../page/network/network_dns_table/index.tsx | 19 +- .../page/network/network_http_table/index.tsx | 18 +- .../network_top_countries_table/index.tsx | 16 +- .../network_top_n_flow_table/index.tsx | 15 +- .../page/network/tls_table/index.tsx | 17 +- .../page/network/users_table/index.tsx | 9 +- .../overview/overview_host_stats/index.tsx | 5 +- .../overview/overview_network_stats/index.tsx | 7 +- .../components/paginated_table/index.tsx | 3 +- .../public/components/query_bar/index.tsx | 4 +- .../public/components/search_bar/index.tsx | 379 +++++++++--------- .../components/timeline/header/index.tsx | 11 +- .../components/timeline/query_bar/index.tsx | 4 +- .../components/timeline/refetch_timeline.tsx | 8 +- .../public/components/timeline/timeline.tsx | 7 +- .../public/components/wrapper_page/index.tsx | 3 +- .../public/containers/global_time/index.tsx | 28 +- .../public/containers/kpi_hosts/index.tsx | 4 +- .../public/containers/kpi_network/index.tsx | 4 +- .../siem/public/containers/source/index.tsx | 8 +- .../signals_histogram_panel/helpers.tsx | 20 +- .../signals_histogram_panel/index.tsx | 6 +- .../signals_histogram.tsx | 111 ++--- .../plugins/siem/public/pages/home/index.tsx | 48 +-- .../pages/hosts/details/details_tabs.tsx | 48 +-- .../siem/public/pages/hosts/details/index.tsx | 10 +- .../plugins/siem/public/pages/hosts/hosts.tsx | 15 +- .../siem/public/pages/hosts/hosts_tabs.tsx | 78 ++-- .../network/navigation/network_routes.tsx | 97 ++--- .../siem/public/pages/overview/overview.tsx | 6 +- x-pack/legacy/plugins/siem/public/routes.tsx | 8 +- .../siem/public/utils/route/spy_routes.tsx | 132 +++--- 53 files changed, 757 insertions(+), 656 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/auto_sizer/index.tsx b/x-pack/legacy/plugins/siem/public/components/auto_sizer/index.tsx index 8b3a85b28b8fe..489a0e16448eb 100644 --- a/x-pack/legacy/plugins/siem/public/components/auto_sizer/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/auto_sizer/index.tsx @@ -7,6 +7,7 @@ import isEqual from 'lodash/fp/isEqual'; import React from 'react'; import ResizeObserver from 'resize-observer-polyfill'; +import deepEqual from 'fast-deep-equal/react'; interface Measurement { width?: number; @@ -37,7 +38,7 @@ interface AutoSizerState { } /** A hard-fork of the `infra` `AutoSizer` ಠ_ಠ */ -export class AutoSizer extends React.PureComponent { +export class AutoSizer extends React.Component { public element: HTMLElement | null = null; public resizeObserver: ResizeObserver | null = null; public windowWidth: number = -1; @@ -71,6 +72,10 @@ export class AutoSizer extends React.PureComponent series != null && !!get('value.length', series) && @@ -58,12 +64,12 @@ export const BarChartBaseComponent = ({ }; return chartConfigs.width && chartConfigs.height ? ( - - + + {data.map(series => { const barSeriesKey = series.key; return checkIfAllTheDataInTheSeriesAreValid ? ( - - - + + ) : null; }; BarChartBaseComponent.displayName = 'BarChartBaseComponent'; -export const BarChartBase = React.memo(BarChartBaseComponent); +export const BarChartBase = React.memo(BarChartBaseComponent, deepEqual); BarChartBase.displayName = 'BarChartBase'; @@ -131,8 +142,6 @@ export const BarChartComponent = ({ ); }; -BarChartComponent.displayName = 'BarChartComponent'; - -export const BarChart = React.memo(BarChartComponent); - -BarChart.displayName = 'BarChart'; +export const BarChart = React.memo(BarChartComponent, (prevProps, nextProps) => + deepEqual(nextProps.barChart, prevProps.barChart) +); diff --git a/x-pack/legacy/plugins/siem/public/components/charts/common.tsx b/x-pack/legacy/plugins/siem/public/components/charts/common.tsx index 62f1ac56890ca..ac0292214a038 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/common.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/common.tsx @@ -16,7 +16,10 @@ import { TickFormatter, Position, } from '@elastic/charts'; +import React, { useMemo } from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; + import { useUiSetting } from '../../lib/kibana'; import { DEFAULT_DARK_MODE } from '../../../common/constants'; @@ -54,7 +57,7 @@ export interface ChartSeriesData { color?: string | undefined; } -export const WrappedByAutoSizer = styled.div<{ height?: string }>` +const WrappedByAutoSizerComponent = styled.div<{ height?: string }>` ${style => ` height: ${style.height != null ? style.height : defaultChartHeight}; @@ -66,7 +69,9 @@ export const WrappedByAutoSizer = styled.div<{ height?: string }>` } `; -WrappedByAutoSizer.displayName = 'WrappedByAutoSizer'; +WrappedByAutoSizerComponent.displayName = 'WrappedByAutoSizer'; + +export const WrappedByAutoSizer = React.memo(WrappedByAutoSizerComponent, deepEqual); export enum SeriesType { BAR = 'bar', @@ -96,8 +101,9 @@ const theme: PartialTheme = { export const useTheme = () => { const isDarkMode = useUiSetting(DEFAULT_DARK_MODE); const defaultTheme = isDarkMode ? DARK_THEME : LIGHT_THEME; + const themeValue = useMemo(() => mergeWithDefaultTheme(theme, defaultTheme), []); - return mergeWithDefaultTheme(theme, defaultTheme); + return themeValue; }; export const chartDefaultSettings = { diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.tsx index 821ef9be10e8d..d94780baa3d93 100644 --- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.tsx +++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.tsx @@ -8,6 +8,7 @@ import { rgba } from 'polished'; import React from 'react'; import { Droppable } from 'react-beautiful-dnd'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; interface Props { children?: React.ReactNode; @@ -113,6 +114,7 @@ export const DroppableWrapper = React.memo( )} - ) + ), + deepEqual ); DroppableWrapper.displayName = 'DroppableWrapper'; diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/embeddable.tsx b/x-pack/legacy/plugins/siem/public/components/embeddables/embeddable.tsx index b9a2d01ee0a70..a8e8b65b31c2c 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/embeddable.tsx +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/embeddable.tsx @@ -7,6 +7,7 @@ import { EuiPanel } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; const Panel = styled(EuiPanel)` overflow: hidden; @@ -17,9 +18,12 @@ export interface EmbeddableProps { children: React.ReactNode; } -export const Embeddable = React.memo(({ children }) => ( -
- {children} -
-)); +export const Embeddable = React.memo( + ({ children }) => ( +
+ {children} +
+ ), + deepEqual +); Embeddable.displayName = 'Embeddable'; diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/embeddable_header.tsx b/x-pack/legacy/plugins/siem/public/components/embeddables/embeddable_header.tsx index f2abfdf307fa3..9b99c7d05b3b4 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/embeddable_header.tsx +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/embeddable_header.tsx @@ -7,6 +7,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; const Header = styled.header.attrs(({ className }) => ({ className: `siemEmbeddable__header ${className}`, @@ -21,21 +22,24 @@ export interface EmbeddableHeaderProps { title: string | React.ReactNode; } -export const EmbeddableHeader = React.memo(({ children, title }) => ( -
- - - -
{title}
-
-
- - {children && ( - - {children} +export const EmbeddableHeader = React.memo( + ({ children, title }) => ( +
+ + + +
{title}
+
- )} -
-
-)); + + {children && ( + + {children} + + )} +
+
+ ), + deepEqual +); EmbeddableHeader.displayName = 'EmbeddableHeader'; diff --git a/x-pack/legacy/plugins/siem/public/components/filters_global/filters_global.tsx b/x-pack/legacy/plugins/siem/public/components/filters_global/filters_global.tsx index b4d8c790002b2..66dffa7b6a5ff 100644 --- a/x-pack/legacy/plugins/siem/public/components/filters_global/filters_global.tsx +++ b/x-pack/legacy/plugins/siem/public/components/filters_global/filters_global.tsx @@ -8,6 +8,7 @@ import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import React from 'react'; import { Sticky } from 'react-sticky'; import styled, { css } from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { gutterTimeline } from '../../lib/helpers'; @@ -41,13 +42,16 @@ export interface FiltersGlobalProps { children: React.ReactNode; } -export const FiltersGlobal = React.memo(({ children }) => ( - - {({ style, isSticky }) => ( - - {children} - - )} - -)); +export const FiltersGlobal = React.memo( + ({ children }) => ( + + {({ style, isSticky }) => ( + + {children} + + )} + + ), + deepEqual +); FiltersGlobal.displayName = 'FiltersGlobal'; diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx index 9fb59e2034b08..3dcdf697c23d0 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx @@ -6,10 +6,11 @@ import { EuiBadge } from '@elastic/eui'; import { defaultTo, getOr } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import styled from 'styled-components'; import { ActionCreator } from 'typescript-fsa'; +import deepEqual from 'fast-deep-equal/react'; import { State, timelineSelectors } from '../../store'; import { DataProvider } from '../timeline/data_providers/data_provider'; @@ -82,28 +83,40 @@ export const FlyoutComponent = React.memo( timelineId, usersViewing, width, - }) => ( - <> - - showTimeline({ id: timelineId, show: false })} + }) => { + const handleClose = useCallback(() => showTimeline({ id: timelineId, show: false }), [ + showTimeline, + timelineId, + ]); + const handleOpen = useCallback(() => showTimeline({ id: timelineId, show: true }), [ + showTimeline, + timelineId, + ]); + + return ( + <> + + + {children} + + + - {children} - - - showTimeline({ id: timelineId, show: true })} - /> - - ) + onOpen={handleOpen} + /> + + ); + }, + deepEqual ); FlyoutComponent.displayName = 'FlyoutComponent'; @@ -117,8 +130,8 @@ const mapStateToProps = (state: State, { timelineId }: OwnProps) => { return { dataProviders, show, width }; }; -export const Flyout = connect(mapStateToProps, { +const mapDispatchToProps = { showTimeline: timelineActions.showTimeline, -})(FlyoutComponent); +}; -Flyout.displayName = 'Flyout'; +export const Flyout = connect(mapStateToProps, mapDispatchToProps)(FlyoutComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/pane/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/pane/index.tsx index 00ac15092a6ec..8c4d4228969b5 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/pane/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/pane/index.tsx @@ -183,8 +183,9 @@ const FlyoutPaneComponent: React.FC = ({ ); }; -export const Pane = connect(null, { +const mapDispatchToProps = { applyDeltaToWidth: timelineActions.applyDeltaToWidth, -})(React.memo(FlyoutPaneComponent)); +}; +export const Pane = connect(null, mapDispatchToProps)(React.memo(FlyoutPaneComponent)); Pane.displayName = 'Pane'; diff --git a/x-pack/legacy/plugins/siem/public/components/header_page/index.tsx b/x-pack/legacy/plugins/siem/public/components/header_page/index.tsx index d694aad3dd896..ca4a82f008e67 100644 --- a/x-pack/legacy/plugins/siem/public/components/header_page/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/header_page/index.tsx @@ -14,6 +14,7 @@ import { } from '@elastic/eui'; import React from 'react'; import styled, { css } from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { DefaultDraggable } from '../draggables'; import { LinkIcon, LinkIconProps } from '../link_icon'; @@ -161,4 +162,4 @@ const HeaderPageComponent: React.FC = ({ ); -export const HeaderPage = React.memo(HeaderPageComponent); +export const HeaderPage = React.memo(HeaderPageComponent, deepEqual); diff --git a/x-pack/legacy/plugins/siem/public/components/header_section/index.tsx b/x-pack/legacy/plugins/siem/public/components/header_section/index.tsx index 3153e785a8a32..3a6230aaae813 100644 --- a/x-pack/legacy/plugins/siem/public/components/header_section/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/header_section/index.tsx @@ -7,6 +7,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiIconTip, EuiTitle } from '@elastic/eui'; import React from 'react'; import styled, { css } from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { InspectButton } from '../inspect'; import { Subtitle } from '../subtitle'; @@ -85,4 +86,4 @@ const HeaderSectionComponent: React.FC = ({ ); -export const HeaderSection = React.memo(HeaderSectionComponent); +export const HeaderSection = React.memo(HeaderSectionComponent, deepEqual); diff --git a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx index 405a8f060948e..1c06372252dcb 100644 --- a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx @@ -5,11 +5,12 @@ */ import { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; -import { getOr } from 'lodash/fp'; +import { getOr, omit } from 'lodash/fp'; import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; import styled, { css } from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { inputsModel, inputsSelectors, State } from '../../store'; import { InputsModelId } from '../../store/inputs/constants'; @@ -162,7 +163,11 @@ const makeMapStateToProps = () => { const getGlobalQuery = inputsSelectors.globalQueryByIdSelector(); const getTimelineQuery = inputsSelectors.timelineQueryByIdSelector(); const mapStateToProps = (state: State, { inputId = 'global', queryId }: OwnProps) => { - return inputId === 'global' ? getGlobalQuery(state, queryId) : getTimelineQuery(state, queryId); + const props = + inputId === 'global' ? getGlobalQuery(state, queryId) : getTimelineQuery(state, queryId); + // refetch caused unnecessary component rerender and it was even not used + const propsWithoutRefetch = omit('refetch', props); + return propsWithoutRefetch; }; return mapStateToProps; }; @@ -174,4 +179,4 @@ const mapDispatchToProps = { export const InspectButton = connect( makeMapStateToProps, mapDispatchToProps -)(React.memo(InspectButtonComponent)); +)(React.memo(InspectButtonComponent, deepEqual)); diff --git a/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx b/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx index 04b988f8270f3..dbe47d4b0ebaa 100644 --- a/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx @@ -7,6 +7,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { ScaleType } from '@elastic/charts'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { EuiFlexGroup, EuiFlexItem, EuiProgress, EuiSelect, EuiSpacer } from '@elastic/eui'; import { noop } from 'lodash/fp'; @@ -223,4 +224,4 @@ export const MatrixHistogramComponent: React.FC( [type, updateTableActivePage] ); + const columns = useMemo(() => getAuthenticationColumnsCurated(type), [type]); + return ( ( updateActivePage={updateActivePage} /> ); - } + }, + deepEqual ); HostsTableComponent.displayName = 'HostsTableComponent'; @@ -217,10 +220,12 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const HostsTable = connect(makeMapStateToProps, { +const mapDispatchToProps = { updateHostsSort: hostsActions.updateHostsSort, updateTableActivePage: hostsActions.updateTableActivePage, updateTableLimit: hostsActions.updateTableLimit, -})(HostsTableComponent); +}; + +export const HostsTable = connect(makeMapStateToProps, mapDispatchToProps)(HostsTableComponent); HostsTable.displayName = 'HostsTable'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx index 73cd79c064c95..9ed02e40238d1 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx @@ -7,6 +7,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; + import { KpiHostsData, KpiHostDetailsData } from '../../../../graphql/types'; import { StatItemsComponent, StatItemsProps, useKpiMatrixStatus } from '../../../stat_items'; import { kpiHostsMapping } from './kpi_hosts_mapping'; @@ -74,6 +76,6 @@ export const KpiHostsComponentBase = ({ KpiHostsComponentBase.displayName = 'KpiHostsComponentBase'; -export const KpiHostsComponent = React.memo(KpiHostsComponentBase); +export const KpiHostsComponent = React.memo(KpiHostsComponentBase, deepEqual); KpiHostsComponent.displayName = 'KpiHostsComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx index b4c01053f0e9c..03573631b88cc 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx @@ -6,7 +6,7 @@ /* eslint-disable react/display-name */ -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; @@ -119,10 +119,12 @@ const UncommonProcessTableComponent = React.memo( [type, updateTableActivePage] ); + const columns = useMemo(() => getUncommonColumnsCurated(type), [type]); + return ( (WrappedComponent: React.ComponentClass | React.ComponentType) { - class ManageQuery extends React.PureComponent { + class ManageQuery extends React.Component { static displayName: string; public componentDidUpdate(prevProps: OwnProps) { const { loading, id, refetch, setQuery, inspect = null } = this.props; setQuery({ id, inspect, loading, refetch }); } + public shouldComponentUpdate(nextProps: OwnProps) { + return !deepEqual(this.props, nextProps); + } + public componentWillUnmount() { const { deleteQuery, id } = this.props; if (deleteQuery) { diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.tsx index 876df35b7414a..76f7e50e363fe 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.tsx @@ -15,6 +15,8 @@ import { } from '@elastic/eui'; import styled from 'styled-components'; import { chunk as _chunk } from 'lodash/fp'; +import deepEqual from 'fast-deep-equal/react'; + import { StatItemsComponent, StatItemsProps, @@ -192,7 +194,8 @@ export const KpiNetworkComponent = React.memo( ); - } + }, + deepEqual ); KpiNetworkComponent.displayName = 'KpiNetworkComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/columns.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/columns.tsx index b1c1b26cd498d..9316b66f82a84 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/columns.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/columns.tsx @@ -26,7 +26,7 @@ export type NetworkDnsColumns = [ Columns ]; -export const getNetworkDnsColumns = (type: networkModel.NetworkType): NetworkDnsColumns => [ +export const getNetworkDnsColumns = (): NetworkDnsColumns => [ { field: `node.${NetworkDnsFields.dnsName}`, name: i18n.REGISTERED_DOMAIN, diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx index e316f951a0363..ac12ade0504a2 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx @@ -5,9 +5,10 @@ */ import { isEqual } from 'lodash/fp'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; +import deepEqual from 'fast-deep-equal/react'; import { networkActions } from '../../../../store/actions'; import { @@ -131,10 +132,12 @@ export const NetworkDnsTableComponent = React.memo( [type, updateNetworkTable, isPtrIncluded] ); + const columns = useMemo(() => getNetworkDnsColumns(), []); + return ( ( updateLimitPagination={updateLimitPagination} /> ); - } + }, + deepEqual ); NetworkDnsTableComponent.displayName = 'NetworkDnsTableComponent'; @@ -172,6 +176,11 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -export const NetworkDnsTable = connect(makeMapStateToProps, { +const mapDispatchToProps = { updateNetworkTable: networkActions.updateNetworkTable, -})(NetworkDnsTableComponent); +}; + +export const NetworkDnsTable = connect( + makeMapStateToProps, + mapDispatchToProps +)(NetworkDnsTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx index 58adc971b0101..c5aacecfce51a 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; -import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; import { networkActions } from '../../../../store/actions'; @@ -121,10 +120,12 @@ const NetworkHttpTableComponent = React.memo( const sorting = { field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }; + const columns = useMemo(() => getNetworkHttpColumns(tableType), [tableType]); + return ( { return mapStateToProps; }; -export const NetworkHttpTable = compose>( - connect(makeMapStateToProps, { - updateNetworkTable: networkActions.updateNetworkTable, - }) +const mapDispatchToProps = { + updateNetworkTable: networkActions.updateNetworkTable, +}; + +export const NetworkHttpTable = connect( + makeMapStateToProps, + mapDispatchToProps )(NetworkHttpTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx index 6d14b52d3586d..6427ac74df759 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx @@ -7,8 +7,8 @@ import { isEqual, last } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; -import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; +import deepEqual from 'fast-deep-equal/react'; import { IIndexPattern } from 'src/plugins/data/public'; import { networkActions } from '../../../../store/actions'; @@ -186,7 +186,8 @@ const NetworkTopCountriesTableComponent = React.memo ); - } + }, + deepEqual ); NetworkTopCountriesTableComponent.displayName = 'NetworkTopCountriesTableComponent'; @@ -197,8 +198,11 @@ const makeMapStateToProps = () => { getTopCountriesSelector(state, type, flowTargeted); }; -export const NetworkTopCountriesTable = compose>( - connect(makeMapStateToProps, { - updateNetworkTable: networkActions.updateNetworkTable, - }) +const mapDispatchToProps = { + updateNetworkTable: networkActions.updateNetworkTable, +}; + +export const NetworkTopCountriesTable = connect( + makeMapStateToProps, + mapDispatchToProps )(NetworkTopCountriesTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx index 7c1fcb2681a8c..976d1dc5d5988 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx @@ -6,8 +6,8 @@ import { isEqual, last } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; -import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; +import deepEqual from 'fast-deep-equal/react'; import { networkActions } from '../../../../store/actions'; import { @@ -180,8 +180,11 @@ const makeMapStateToProps = () => { getTopNFlowSelector(state, type, flowTargeted); }; -export const NetworkTopNFlowTable = compose>( - connect(makeMapStateToProps, { - updateNetworkTable: networkActions.updateNetworkTable, - }) -)(React.memo(NetworkTopNFlowTableComponent)); +const mapDispatchToProps = { + updateNetworkTable: networkActions.updateNetworkTable, +}; + +export const NetworkTopNFlowTable = connect( + makeMapStateToProps, + mapDispatchToProps +)(React.memo(NetworkTopNFlowTableComponent, deepEqual)); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx index 95c0fff054440..7cef983a0e1fc 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx @@ -5,9 +5,8 @@ */ import { isEqual } from 'lodash/fp'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; -import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; import { networkActions } from '../../../../store/network'; @@ -119,10 +118,12 @@ const TlsTableComponent = React.memo( [sort, type, tableType, updateNetworkTable] ); + const columns = useMemo(() => getTlsColumns(tlsTableId), [tlsTableId]); + return ( { return (state: State, { type }: OwnProps) => getTlsSelector(state, type); }; -export const TlsTable = compose>( - connect(makeMapStateToProps, { - updateNetworkTable: networkActions.updateNetworkTable, - }) -)(TlsTableComponent); +const mapDispatchToProps = { + updateNetworkTable: networkActions.updateNetworkTable, +}; + +export const TlsTable = connect(makeMapStateToProps, mapDispatchToProps)(TlsTableComponent); const getSortField = (sortField: TlsSortField): SortingBasicTable => ({ field: `node.${sortField.field}`, diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx index f4f14c7c009dc..ef5e311cd8165 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx @@ -5,7 +5,7 @@ */ import { isEqual } from 'lodash/fp'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; @@ -124,10 +124,15 @@ const UsersTableComponent = React.memo( [sort, type, updateNetworkTable] ); + const columns = useMemo(() => getUsersColumns(flowTarget, usersTableId), [ + flowTarget, + usersTableId, + ]); + return ( = ({ data, loading ); }; -OverviewHostStatsComponent.displayName = 'OverviewHostStatsComponent'; - -export const OverviewHostStats = React.memo(OverviewHostStatsComponent); +export const OverviewHostStats = React.memo(OverviewHostStatsComponent, deepEqual); diff --git a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network_stats/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network_stats/index.tsx index 260b1d6895140..72be02ba255a9 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network_stats/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network_stats/index.tsx @@ -8,6 +8,7 @@ import { EuiAccordion, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiText } f import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { OverviewNetworkData } from '../../../../graphql/types'; import { FormattedStat, StatGroup } from '../types'; @@ -130,7 +131,7 @@ const AccordionContent = styled.div` margin-top: 8px; `; -export const OverviewNetworkStats = React.memo(({ data, loading }) => { +const OverviewNetworkStatsComponent: React.FC = ({ data, loading }) => { const allNetworkStats = getOverviewNetworkStats(data); const allNetworkStatsCount = allNetworkStats.reduce((total, stat) => total + stat.count, 0); @@ -190,6 +191,6 @@ export const OverviewNetworkStats = React.memo(({ data, lo })} ); -}); +}; -OverviewNetworkStats.displayName = 'OverviewNetworkStats'; +export const OverviewNetworkStats = React.memo(OverviewNetworkStatsComponent, deepEqual); 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 5cd200cbb41b7..adde235d9517c 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 @@ -20,6 +20,7 @@ import { import { noop } from 'lodash/fp'; import React, { FC, memo, useState, useEffect, ComponentType } from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { AuthTableColumns } from '../page/hosts/authentications_table'; import { HostsTableColumns } from '../page/hosts/hosts_table'; @@ -302,7 +303,7 @@ const PaginatedTableComponent: FC = ({ ); }; -export const PaginatedTable = memo(PaginatedTableComponent); +export const PaginatedTable = memo(PaginatedTableComponent, deepEqual); type BasicTableType = ComponentType>; // eslint-disable-line @typescript-eslint/no-explicit-any const BasicTable: typeof EuiBasicTable & { displayName: string } = styled( diff --git a/x-pack/legacy/plugins/siem/public/components/query_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/query_bar/index.tsx index b2843348cc2e3..c63384e2b9325 100644 --- a/x-pack/legacy/plugins/siem/public/components/query_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/query_bar/index.tsx @@ -6,6 +6,7 @@ import { isEqual } from 'lodash/fp'; import React, { memo, useState, useEffect, useMemo, useCallback } from 'react'; +import deepEqual from 'fast-deep-equal/react'; import { esFilters, @@ -149,5 +150,6 @@ export const QueryBar = memo( {...searchBarProps} /> ); - } + }, + deepEqual ); diff --git a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx index 089bade4a4144..28557a3c9463e 100644 --- a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx @@ -5,11 +5,12 @@ */ import { getOr, isEqual, set } from 'lodash/fp'; -import React, { memo, useEffect, useCallback, useMemo } from 'react'; +import React, { FC, memo, useEffect, useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; import { Subscription } from 'rxjs'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { IIndexPattern } from 'src/plugins/data/public'; import { SavedQuery } from 'src/legacy/core_plugins/data/public'; @@ -75,209 +76,206 @@ const SearchBarContainer = styled.div` } `; -const SearchBarComponent = memo( - ({ - end, - filterQuery, - fromStr, - id, - indexPattern, - isLoading = false, - queries, - savedQuery, - setSavedQuery, - setSearchBarFilter, - start, - timelineId, - toStr, - updateSearch, - dataTestSubj, - }) => { - const { timefilter } = npStart.plugins.data.query.timefilter; - if (fromStr != null && toStr != null) { - timefilter.setTime({ from: fromStr, to: toStr }); - } else if (start != null && end != null) { - timefilter.setTime({ - from: new Date(start).toISOString(), - to: new Date(end).toISOString(), - }); - } +const SearchBarComponent: FC = ({ + end, + filterQuery, + fromStr, + id, + indexPattern, + isLoading = false, + queries, + savedQuery, + setSavedQuery, + setSearchBarFilter, + start, + toStr, + updateSearch, + dataTestSubj, +}) => { + const { timefilter } = npStart.plugins.data.query.timefilter; + if (fromStr != null && toStr != null) { + timefilter.setTime({ from: fromStr, to: toStr }); + } else if (start != null && end != null) { + timefilter.setTime({ + from: new Date(start).toISOString(), + to: new Date(end).toISOString(), + }); + } - const onQuerySubmit = useCallback( - (payload: { dateRange: TimeRange; query?: Query }) => { - const isQuickSelection = - payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now'); - let updateSearchBar: UpdateReduxSearchBar = { - id, - end: toStr != null ? toStr : new Date(end).toISOString(), - start: fromStr != null ? fromStr : new Date(start).toISOString(), - isInvalid: false, - isQuickSelection, - updateTime: false, - }; - let isStateUpdated = false; - - if ( - (isQuickSelection && - (fromStr !== payload.dateRange.from || toStr !== payload.dateRange.to)) || - (!isQuickSelection && - (start !== formatDate(payload.dateRange.from) || - end !== formatDate(payload.dateRange.to))) - ) { - isStateUpdated = true; + const onQuerySubmit = useCallback( + (payload: { dateRange: TimeRange; query?: Query }) => { + const isQuickSelection = + payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now'); + let updateSearchBar: UpdateReduxSearchBar = { + id, + end: toStr != null ? toStr : new Date(end).toISOString(), + start: fromStr != null ? fromStr : new Date(start).toISOString(), + isInvalid: false, + isQuickSelection, + updateTime: false, + }; + let isStateUpdated = false; + + if ( + (isQuickSelection && + (fromStr !== payload.dateRange.from || toStr !== payload.dateRange.to)) || + (!isQuickSelection && + (start !== formatDate(payload.dateRange.from) || + end !== formatDate(payload.dateRange.to))) + ) { + isStateUpdated = true; + updateSearchBar.updateTime = true; + updateSearchBar.end = payload.dateRange.to; + updateSearchBar.start = payload.dateRange.from; + } + + if (payload.query != null && !isEqual(payload.query, filterQuery)) { + isStateUpdated = true; + updateSearchBar = set('query', payload.query, updateSearchBar); + } + + if (!isStateUpdated) { + // That mean we are doing a refresh! + if (isQuickSelection) { updateSearchBar.updateTime = true; updateSearchBar.end = payload.dateRange.to; updateSearchBar.start = payload.dateRange.from; - } - - if (payload.query != null && !isEqual(payload.query, filterQuery)) { - isStateUpdated = true; - updateSearchBar = set('query', payload.query, updateSearchBar); - } - - if (!isStateUpdated) { - // That mean we are doing a refresh! - if (isQuickSelection) { - updateSearchBar.updateTime = true; - updateSearchBar.end = payload.dateRange.to; - updateSearchBar.start = payload.dateRange.from; - } else { - queries.forEach(q => q.refetch && (q.refetch as inputsModel.Refetch)()); - } - } - - window.setTimeout(() => updateSearch(updateSearchBar), 0); - }, - [id, end, filterQuery, fromStr, queries, start, toStr] - ); - - const onRefresh = useCallback( - (payload: { dateRange: TimeRange }) => { - if (payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now')) { - updateSearch({ - id, - end: payload.dateRange.to, - start: payload.dateRange.from, - isInvalid: false, - isQuickSelection: true, - updateTime: true, - }); } else { queries.forEach(q => q.refetch && (q.refetch as inputsModel.Refetch)()); } - }, - [id, queries] - ); - - const onSaved = useCallback( - (newSavedQuery: SavedQuery) => { - setSavedQuery({ id, savedQuery: newSavedQuery }); - }, - [id] - ); - - const onSavedQueryUpdated = useCallback( - (savedQueryUpdated: SavedQuery) => { - const isQuickSelection = savedQueryUpdated.attributes.timefilter - ? savedQueryUpdated.attributes.timefilter.from.includes('now') || - savedQueryUpdated.attributes.timefilter.to.includes('now') - : false; - - let updateSearchBar: UpdateReduxSearchBar = { - id, - filters: savedQueryUpdated.attributes.filters || [], - end: toStr != null ? toStr : new Date(end).toISOString(), - start: fromStr != null ? fromStr : new Date(start).toISOString(), - isInvalid: false, - isQuickSelection, - updateTime: false, - }; - - if (savedQueryUpdated.attributes.timefilter) { - updateSearchBar.end = savedQueryUpdated.attributes.timefilter - ? savedQueryUpdated.attributes.timefilter.to - : updateSearchBar.end; - updateSearchBar.start = savedQueryUpdated.attributes.timefilter - ? savedQueryUpdated.attributes.timefilter.from - : updateSearchBar.start; - updateSearchBar.updateTime = true; - } - - updateSearchBar = set('query', savedQueryUpdated.attributes.query, updateSearchBar); - updateSearchBar = set('savedQuery', savedQueryUpdated, updateSearchBar); + } - updateSearch(updateSearchBar); - }, - [id, end, fromStr, start, toStr] - ); + window.setTimeout(() => updateSearch(updateSearchBar), 0); + }, + [id, end, filterQuery, fromStr, queries, start, toStr] + ); - const onClearSavedQuery = useCallback(() => { - if (savedQuery != null) { + const onRefresh = useCallback( + (payload: { dateRange: TimeRange }) => { + if (payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now')) { updateSearch({ id, - filters: [], - end: toStr != null ? toStr : new Date(end).toISOString(), - start: fromStr != null ? fromStr : new Date(start).toISOString(), + end: payload.dateRange.to, + start: payload.dateRange.from, isInvalid: false, - isQuickSelection: false, - updateTime: false, - query: { - query: '', - language: savedQuery.attributes.query.language, - }, - resetSavedQuery: true, - savedQuery: undefined, + isQuickSelection: true, + updateTime: true, }); + } else { + queries.forEach(q => q.refetch && (q.refetch as inputsModel.Refetch)()); } - }, [id, end, fromStr, start, toStr, savedQuery]); - - useEffect(() => { - let isSubscribed = true; - const subscriptions = new Subscription(); - - subscriptions.add( - siemFilterManager.getUpdates$().subscribe({ - next: () => { - if (isSubscribed) { - setSearchBarFilter({ - id, - filters: siemFilterManager.getFilters(), - }); - } - }, - }) - ); - - return () => { - isSubscribed = false; - subscriptions.unsubscribe(); + }, + [id, queries] + ); + + const onSaved = useCallback( + (newSavedQuery: SavedQuery) => { + setSavedQuery({ id, savedQuery: newSavedQuery }); + }, + [id] + ); + + const onSavedQueryUpdated = useCallback( + (savedQueryUpdated: SavedQuery) => { + const isQuickSelection = savedQueryUpdated.attributes.timefilter + ? savedQueryUpdated.attributes.timefilter.from.includes('now') || + savedQueryUpdated.attributes.timefilter.to.includes('now') + : false; + + let updateSearchBar: UpdateReduxSearchBar = { + id, + filters: savedQueryUpdated.attributes.filters || [], + end: toStr != null ? toStr : new Date(end).toISOString(), + start: fromStr != null ? fromStr : new Date(start).toISOString(), + isInvalid: false, + isQuickSelection, + updateTime: false, }; - }, []); - const indexPatterns = useMemo(() => [indexPattern], [indexPattern]); - return ( - - - + + if (savedQueryUpdated.attributes.timefilter) { + updateSearchBar.end = savedQueryUpdated.attributes.timefilter + ? savedQueryUpdated.attributes.timefilter.to + : updateSearchBar.end; + updateSearchBar.start = savedQueryUpdated.attributes.timefilter + ? savedQueryUpdated.attributes.timefilter.from + : updateSearchBar.start; + updateSearchBar.updateTime = true; + } + + updateSearchBar = set('query', savedQueryUpdated.attributes.query, updateSearchBar); + updateSearchBar = set('savedQuery', savedQueryUpdated, updateSearchBar); + + updateSearch(updateSearchBar); + }, + [id, end, fromStr, start, toStr] + ); + + const onClearSavedQuery = useCallback(() => { + if (savedQuery != null) { + updateSearch({ + id, + filters: [], + end: toStr != null ? toStr : new Date(end).toISOString(), + start: fromStr != null ? fromStr : new Date(start).toISOString(), + isInvalid: false, + isQuickSelection: false, + updateTime: false, + query: { + query: '', + language: savedQuery.attributes.query.language, + }, + resetSavedQuery: true, + savedQuery: undefined, + }); + } + }, [id, end, fromStr, start, toStr, savedQuery]); + + useEffect(() => { + let isSubscribed = true; + const subscriptions = new Subscription(); + + subscriptions.add( + siemFilterManager.getUpdates$().subscribe({ + next: () => { + if (isSubscribed) { + setSearchBarFilter({ + id, + filters: siemFilterManager.getFilters(), + }); + } + }, + }) ); - } -); + + return () => { + isSubscribed = false; + subscriptions.unsubscribe(); + }; + }, []); + const indexPatterns = useMemo(() => [indexPattern], [indexPattern]); + return ( + + + + ); +}; const makeMapStateToProps = () => { const getEndSelector = endSelector(); @@ -397,4 +395,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ dispatch(inputsActions.setSearchBarFilter({ id, filters })), }); -export const SiemSearchBar = connect(makeMapStateToProps, mapDispatchToProps)(SearchBarComponent); +export const SiemSearchBar = connect( + makeMapStateToProps, + mapDispatchToProps +)(memo(SearchBarComponent, deepEqual)); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/header/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/header/index.tsx index 7e570d613ca5a..661f08c7a3239 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/header/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/header/index.tsx @@ -8,6 +8,7 @@ import { EuiCallOut } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; import { IIndexPattern } from 'src/plugins/data/public'; +import deepEqual from 'fast-deep-equal/react'; import { Sort } from '../body/sort'; import { DataProviders } from '../data_providers'; @@ -47,7 +48,7 @@ const TimelineHeaderContainer = styled.div` TimelineHeaderContainer.displayName = 'TimelineHeaderContainer'; -export const TimelineHeaderComponent = ({ +export const TimelineHeaderComponent: React.FC = ({ browserFields, id, indexPattern, @@ -60,7 +61,7 @@ export const TimelineHeaderComponent = ({ onToggleDataProviderExcluded, show, showCallOutUnauthorizedMsg, -}: Props) => ( +}) => ( {showCallOutUnauthorizedMsg && ( ); -TimelineHeaderComponent.displayName = 'TimelineHeaderComponent'; - -export const TimelineHeader = React.memo(TimelineHeaderComponent); - -TimelineHeader.displayName = 'TimelineHeader'; +export const TimelineHeader = React.memo(TimelineHeaderComponent, deepEqual); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/query_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/query_bar/index.tsx index c3b46c6cd0f72..8a199cb95a82c 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/query_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/query_bar/index.tsx @@ -7,6 +7,7 @@ import { isEqual, isEmpty } from 'lodash/fp'; import React, { memo, useCallback, useState, useEffect } from 'react'; import { Subscription } from 'rxjs'; +import deepEqual from 'fast-deep-equal/react'; import { IIndexPattern, @@ -295,7 +296,8 @@ export const QueryBarTimeline = memo( dataTestSubj={'timelineQueryInput'} /> ); - } + }, + deepEqual ); export const getDataProviderFilter = (dataProviderDsl: string): esFilters.Filter => { diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/refetch_timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/refetch_timeline.tsx index c804ccf658296..14ef8f593c36d 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/refetch_timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/refetch_timeline.tsx @@ -48,8 +48,10 @@ const TimelineRefetchComponent: React.FC = ({ return null; }; +const mapDispatchToProps = { + setTimelineQuery: inputsActions.setQuery, +}; + export const TimelineRefetch = compose>( - connect(null, { - setTimelineQuery: inputsActions.setQuery, - }) + connect(null, mapDispatchToProps) )(React.memo(TimelineRefetchComponent)); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx index 11886b45b0bec..efa293348e2d2 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx @@ -8,6 +8,7 @@ import { EuiFlexGroup } from '@elastic/eui'; import { getOr, isEmpty } from 'lodash/fp'; import React from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal//react'; import { BrowserFields } from '../../containers/source'; import { TimelineQuery } from '../../containers/timeline'; @@ -230,8 +231,4 @@ export const TimelineComponent = ({ ); }; -TimelineComponent.displayName = 'TimelineComponent'; - -export const Timeline = React.memo(TimelineComponent); - -Timeline.displayName = 'Timeline'; +export const Timeline = React.memo(TimelineComponent, deepEqual); diff --git a/x-pack/legacy/plugins/siem/public/components/wrapper_page/index.tsx b/x-pack/legacy/plugins/siem/public/components/wrapper_page/index.tsx index bac0357def942..bf5bb045faf5e 100644 --- a/x-pack/legacy/plugins/siem/public/components/wrapper_page/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/wrapper_page/index.tsx @@ -7,6 +7,7 @@ import classNames from 'classnames'; import React from 'react'; import styled, { css } from 'styled-components'; +import deepEqual from 'fast-deep-equal/react'; import { gutterTimeline } from '../../lib/helpers'; import { AppGlobalStyle } from '../page/index'; @@ -65,4 +66,4 @@ const WrapperPageComponent: React.FC = ({ ); }; -export const WrapperPage = React.memo(WrapperPageComponent); +export const WrapperPage = React.memo(WrapperPageComponent, deepEqual); diff --git a/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx b/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx index d77e0215f8353..fd06be76a3815 100644 --- a/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, useEffect } from 'react'; +import React, { useCallback, useState, useEffect } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; +import deepEqual from 'fast-deep-equal/react'; import { inputsModel, inputsSelectors, State } from '../../store'; import { inputsActions } from '../../store/actions'; @@ -57,6 +58,17 @@ export const GlobalTimeComponent: React.FC = ({ }) => { const [isInitializing, setIsInitializing] = useState(true); + const setQuery = useCallback( + ({ id, inspect, loading, refetch }: SetQuery) => + setGlobalQuery({ inputId: 'global', id, inspect, loading, refetch }), + [setGlobalQuery] + ); + + const deleteQuery = useCallback( + ({ id }: { id: string }) => deleteOneQuery({ inputId: 'global', id }), + [deleteOneQuery] + ); + useEffect(() => { if (isInitializing) { setIsInitializing(false); @@ -72,9 +84,8 @@ export const GlobalTimeComponent: React.FC = ({ isInitializing, from, to, - setQuery: ({ id, inspect, loading, refetch }: SetQuery) => - setGlobalQuery({ inputId: 'global', id, inspect, loading, refetch }), - deleteQuery: ({ id }: { id: string }) => deleteOneQuery({ inputId: 'global', id }), + setQuery, + deleteQuery, })} ); @@ -88,8 +99,13 @@ const mapStateToProps = (state: State) => { }; }; -export const GlobalTime = connect(mapStateToProps, { +const mapDispatchToProps = { deleteAllQuery: inputsActions.deleteAllQuery, deleteOneQuery: inputsActions.deleteOneQuery, setGlobalQuery: inputsActions.setQuery, -})(React.memo(GlobalTimeComponent)); +}; + +export const GlobalTime = connect( + mapStateToProps, + mapDispatchToProps +)(React.memo(GlobalTimeComponent, deepEqual)); diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx index 32472ba6deedf..1c46b5dbacbf0 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx @@ -8,6 +8,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; import { connect } from 'react-redux'; +import deepEqual from 'fast-deep-equal/react'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetKpiHostsQuery, KpiHostsData } from '../../graphql/types'; @@ -66,7 +67,8 @@ const KpiHostsComponentQuery = React.memo( }); }} - ) + ), + deepEqual ); KpiHostsComponentQuery.displayName = 'KpiHostsComponentQuery'; diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx index 52b8814958ba0..3b7c1b300d063 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx @@ -8,6 +8,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import { Query } from 'react-apollo'; import { connect } from 'react-redux'; +import deepEqual from 'fast-deep-equal/react'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetKpiNetworkQuery, KpiNetworkData } from '../../graphql/types'; @@ -66,7 +67,8 @@ const KpiNetworkComponentQuery = React.memo }); }} - ) + ), + deepEqual ); KpiNetworkComponentQuery.displayName = 'KpiNetworkComponentQuery'; diff --git a/x-pack/legacy/plugins/siem/public/containers/source/index.tsx b/x-pack/legacy/plugins/siem/public/containers/source/index.tsx index 0336e4a9a977b..ba36ce1a4de24 100644 --- a/x-pack/legacy/plugins/siem/public/containers/source/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/source/index.tsx @@ -10,6 +10,8 @@ import { Query } from 'react-apollo'; import React, { useEffect, useMemo, useState } from 'react'; import memoizeOne from 'memoize-one'; import { IIndexPattern } from 'src/plugins/data/public'; +import deepEqual from 'fast-deep-equal/react'; + import { useUiSetting$ } from '../../lib/kibana'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; @@ -82,7 +84,7 @@ export const getBrowserFields = memoizeOne( : {} ); -export const WithSource = React.memo(({ children, indexToAdd, sourceId }) => { +const WithSourceComponent: React.FC = ({ children, indexToAdd, sourceId }) => { const [configIndex] = useUiSetting$(DEFAULT_INDEX_KEY); const defaultIndex = useMemo(() => { if (indexToAdd != null && !isEmpty(indexToAdd)) { @@ -113,9 +115,9 @@ export const WithSource = React.memo(({ children, indexToAdd, s } ); -}); +}; -WithSource.displayName = 'WithSource'; +export const WithSource = React.memo(WithSourceComponent, deepEqual); export const indicesExistOrDataTemporarilyUnavailable = (indicesExist: boolean | undefined) => indicesExist || isUndefined(indicesExist); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/helpers.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/helpers.tsx index 551850fa610db..ab3747f7bdc77 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/helpers.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/helpers.tsx @@ -4,15 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HistogramData, SignalsAggregation, SignalsBucket, SignalsGroupBucket } from './types'; -import { SignalSearchResponse } from '../../../../containers/detection_engine/signals/types'; +import memoizeOne from 'memoize-one'; +import deepEqual from 'fast-deep-equal'; + +import { HistogramData, SignalsBucket, SignalsGroupBucket } from './types'; import * as i18n from './translations'; -export const formatSignalsData = ( - signalsData: SignalSearchResponse<{}, SignalsAggregation> | null -) => { - const groupBuckets: SignalsGroupBucket[] = - signalsData?.aggregations?.signalsByGrouping?.buckets ?? []; +export const formatSignalsData = (groupBuckets: SignalsGroupBucket[] | undefined) => { + const emptyResult: HistogramData[] = []; + + if (!groupBuckets) { + return emptyResult; + } + return groupBuckets.reduce((acc, { key: group, signals }) => { const signalsBucket: SignalsBucket[] = signals.buckets ?? []; @@ -27,6 +31,8 @@ export const formatSignalsData = ( }, []); }; +export const memoFormatSignalsData = memoizeOne(formatSignalsData, deepEqual); + export const getSignalsHistogramQuery = ( stackByField: string, from: number, diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx index 29aaa951ff71a..c16a6aa37ca04 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx @@ -23,7 +23,7 @@ import { InspectButtonContainer } from '../../../../components/inspect'; import { useQuerySignals } from '../../../../containers/detection_engine/signals/use_query'; import { MatrixLoader } from '../../../../components/matrix_histogram/matrix_loader'; -import { formatSignalsData, getSignalsHistogramQuery } from './helpers'; +import { memoFormatSignalsData, getSignalsHistogramQuery } from './helpers'; import * as i18n from './translations'; const DEFAULT_PANEL_HEIGHT = 300; @@ -121,7 +121,9 @@ export const SignalsHistogramPanel = memo( ); }, []); - const formattedSignalsData = useMemo(() => formatSignalsData(signalsData), [signalsData]); + const formattedSignalsData = memoFormatSignalsData( + signalsData?.aggregations?.signalsByGrouping?.buckets + ); useEffect(() => { if (!loadingInitial && isInitialLoading && !isLoadingSignals && signalsData) { diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx index 92f6740e4d767..413e22be73024 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx @@ -13,8 +13,11 @@ import { Position, Settings, } from '@elastic/charts'; -import React from 'react'; +import React, { useMemo } from 'react'; import { EuiProgress } from '@elastic/eui'; +import deepEqual from 'fast-deep-equal/react'; +import memoizeOne from 'memoize-one'; + import { useTheme } from '../../../../components/charts/common'; import { histogramDateTimeFormatter } from '../../../../components/utils'; import { HistogramData } from './types'; @@ -31,57 +34,65 @@ interface HistogramSignalsProps { updateDateRange: (min: number, max: number) => void; } -export const SignalsHistogram = React.memo( - ({ - chartHeight = DEFAULT_CHART_HEIGHT, - data, - from, - legendPosition = 'right', - loading, - to, - updateDateRange, - }) => { - const theme = useTheme(); +const MemoChart = React.memo(Chart, deepEqual); +const MemoSettings = React.memo(Settings, deepEqual); +const MemoHistogramBarSeries = React.memo(HistogramBarSeries, deepEqual); +const MemoAxis = React.memo(Axis, deepEqual); + +const SignalsHistogramComponent: React.FC = ({ + chartHeight = DEFAULT_CHART_HEIGHT, + data, + from, + legendPosition = 'right', + loading, + to, + updateDateRange, +}) => { + const theme = useTheme(); + + const chartSize = useMemo(() => ['100%', chartHeight], [chartHeight]); + const xAxisId = useMemo(() => getAxisId('signalsHistogramAxisX'), []); + const yAxisId = useMemo(() => getAxisId('signalsHistogramAxisY'), []); + const id = useMemo(() => getSpecId('signalsHistogram'), []); + const yAccessors = useMemo(() => ['y'], []); + const splitSeriesAccessors = useMemo(() => ['g'], []); + const tickFormat = useMemo(() => histogramDateTimeFormatter([from, to]), [from, to]); + + return ( + <> + {loading && ( + + )} - return ( - <> - {loading && ( - - )} + + - - + - + - + + + + ); +}; - - - - ); - } -); -SignalsHistogram.displayName = 'SignalsHistogram'; +export const SignalsHistogram = React.memo(SignalsHistogramComponent, deepEqual); diff --git a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx index 5cfed4121ba77..fcfdb0e256790 100644 --- a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx @@ -92,46 +92,34 @@ export const HomePage: React.FC = () => ( - } - /> + + + ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - } + render={({ match }) => } /> + + + + + + + + + } /> ( - - )} + render={({ match }) => } /> ( - - )} + render={({ match }) => } /> - } /> + + + )} diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx index 5774feb46240d..bc9810da83272 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx @@ -24,7 +24,7 @@ import { HostAlertsQueryTabBody, } from '../navigation'; -const HostDetailsTabs = React.memo( +export const HostDetailsTabs = React.memo( ({ pageFilters, deleteQuery, @@ -73,37 +73,27 @@ const HostDetailsTabs = React.memo( return ( - } - /> - } - /> - } - /> - ( - - )} - /> - } - /> - } - /> + + + + + + + + + + + + + + + + + + ); } ); HostDetailsTabs.displayName = 'HostDetailsTabs'; - -export { HostDetailsTabs }; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx index b548d91615d19..178b3fec5f2d8 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx @@ -237,9 +237,11 @@ export const makeMapStateToProps = () => { }); }; +const mapDispatchToProps = { + setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, + setHostDetailsTablesActivePageToZero: dispatchHostDetailsTablesActivePageToZero, +}; + export const HostDetails = compose>( - connect(makeMapStateToProps, { - setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, - setHostDetailsTablesActivePageToZero: dispatchHostDetailsTablesActivePageToZero, - }) + connect(makeMapStateToProps, mapDispatchToProps) )(HostDetailsComponent); 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 2e2986fb632b1..cf95a14ec01df 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx @@ -8,7 +8,6 @@ import { EuiSpacer } from '@elastic/eui'; import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; -import { compose } from 'redux'; import { useParams } from 'react-router-dom'; import { FiltersGlobal } from '../../components/filters_global'; @@ -21,7 +20,6 @@ import { KpiHostsComponent } from '../../components/page/hosts'; import { manageQuery } from '../../components/page/manage_query'; import { SiemSearchBar } from '../../components/search_bar'; import { WrapperPage } from '../../components/wrapper_page'; -import { GlobalTimeArgs } from '../../containers/global_time'; import { KpiHostsQuery } from '../../containers/kpi_hosts'; import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source'; import { LastEventIndexKey } from '../../graphql/types'; @@ -168,13 +166,8 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -interface HostsProps extends GlobalTimeArgs { - hostsPagePath: string; -} +const mapDispatchToProps = { + setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, +}; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const Hosts = compose>( - connect(makeMapStateToProps, { - setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker, - }) -)(HostsComponent); +export const Hosts = connect(makeMapStateToProps, mapDispatchToProps)(HostsComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx index 9c13fc4ac386e..80c35e5563c1d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { memo } from 'react'; +import React, { memo, useCallback } from 'react'; import { Route, Switch } from 'react-router-dom'; import { HostsTabsProps } from './types'; @@ -22,7 +22,7 @@ import { } from './navigation'; import { HostAlertsQueryTabBody } from './navigation/alerts_query_tab_body'; -const HostsTabs = memo( +export const HostsTabs = memo( ({ deleteQuery, filterQuery, @@ -44,52 +44,48 @@ const HostsTabs = memo( startDate: from, type, indexPattern, - narrowDateRange: (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - updateDateRange: (min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }, + narrowDateRange: useCallback( + (score: Anomaly, interval: string) => { + const fromTo = scoreIntervalToDateTime(score, interval); + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }); + }, + [setAbsoluteRangeDatePicker] + ), + updateDateRange: useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ), }; return ( - } - /> - } - /> - } - /> - ( - - )} - /> - } - /> - } - /> + + + + + + + + + + + + + + + + + + ); } ); HostsTabs.displayName = 'HostsTabs'; - -export { HostsTabs }; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx index acc5d02299f1f..2bd6b9953c4b3 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx @@ -23,7 +23,7 @@ import { TlsQueryTabBody } from './tls_query_tab_body'; import { Anomaly } from '../../../components/ml/types'; import { NetworkAlertsQueryTabBody } from './alerts_query_tab_body'; -export const NetworkRoutes = ({ +const NetworkRoutesComponent: React.FC = ({ networkPagePath, type, to, @@ -33,7 +33,7 @@ export const NetworkRoutes = ({ indexPattern, setQuery, setAbsoluteRangeDatePicker, -}: NetworkRoutesProps) => { +}) => { const narrowDateRange = useCallback( (score: Anomaly, interval: string) => { const fromTo = scoreIntervalToDateTime(score, interval); @@ -94,62 +94,49 @@ export const NetworkRoutes = ({ return ( - } - /> - ( - <> - - - - + + + + + <> + + + + - - - - - - - - - + + + + + + + + + - - - - - - )} - /> - } - /> - } - /> - ( - - )} - /> - } - /> + + + + + + + + + + + + + + + + + + ); }; -NetworkRoutes.displayName = 'NetworkRoutes'; +export const NetworkRoutes = React.memo(NetworkRoutesComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx index 2009878a51c61..a1e4730ba3420 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx @@ -8,7 +8,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React from 'react'; import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; -import { compose } from 'redux'; import { Query, esFilters } from 'src/plugins/data/public'; import styled from 'styled-components'; @@ -145,6 +144,7 @@ const makeMapStateToProps = () => { const mapDispatchToProps = { setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker }; -export const StatefulOverview = compose>( - connect(makeMapStateToProps, mapDispatchToProps) +export const StatefulOverview = connect( + makeMapStateToProps, + mapDispatchToProps )(React.memo(OverviewComponent)); diff --git a/x-pack/legacy/plugins/siem/public/routes.tsx b/x-pack/legacy/plugins/siem/public/routes.tsx index cbb58a473e8ea..a989fa9873435 100644 --- a/x-pack/legacy/plugins/siem/public/routes.tsx +++ b/x-pack/legacy/plugins/siem/public/routes.tsx @@ -20,8 +20,12 @@ const PageRouterComponent: FC = ({ history }) => ( - } /> - } /> + + + + + + diff --git a/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx b/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx index c88562abef6ae..bb01ebe80bd88 100644 --- a/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx @@ -6,83 +6,81 @@ import * as H from 'history'; import { isEqual } from 'lodash/fp'; -import { memo, useEffect, useState } from 'react'; +import { FC, memo, useEffect, useState } from 'react'; import { withRouter } from 'react-router-dom'; import deepEqual from 'fast-deep-equal'; import { SpyRouteProps } from './types'; import { useRouteSpy } from './use_route_spy'; -export const SpyRouteComponent = memo( - ({ - location: { pathname, search }, - history, - match: { - params: { pageName, detailName, tabName, flowTarget }, - }, - state, - }) => { - const [isInitializing, setIsInitializing] = useState(true); - const [route, dispatch] = useRouteSpy(); +export const SpyRouteComponent: FC = ({ + location: { pathname, search }, + history, + match: { + params: { pageName, detailName, tabName, flowTarget }, + }, + state, +}) => { + const [isInitializing, setIsInitializing] = useState(true); + const [route, dispatch] = useRouteSpy(); - useEffect(() => { - if (isInitializing && search !== '') { + useEffect(() => { + if (isInitializing && search !== '') { + dispatch({ + type: 'updateSearch', + search, + }); + setIsInitializing(false); + } + }, [search]); + useEffect(() => { + if (pageName && !isEqual(route.pathName, pathname)) { + if (isInitializing && detailName == null) { dispatch({ - type: 'updateSearch', - search, + type: 'updateRouteWithOutSearch', + route: { + pageName, + detailName, + tabName, + pathName: pathname, + history, + flowTarget, + }, }); setIsInitializing(false); - } - }, [search]); - useEffect(() => { - if (pageName && !isEqual(route.pathName, pathname)) { - if (isInitializing && detailName == null) { - dispatch({ - type: 'updateRouteWithOutSearch', - route: { - pageName, - detailName, - tabName, - pathName: pathname, - history, - flowTarget, - }, - }); - setIsInitializing(false); - } else { - dispatch({ - type: 'updateRoute', - route: { - pageName, - detailName, - tabName, - search, - pathName: pathname, - history, - flowTarget, - }, - }); - } } else { - if (pageName && !deepEqual(state, route.state)) { - dispatch({ - type: 'updateRoute', - route: { - pageName, - detailName, - tabName, - search, - pathName: pathname, - history, - flowTarget, - state, - }, - }); - } + dispatch({ + type: 'updateRoute', + route: { + pageName, + detailName, + tabName, + search, + pathName: pathname, + history, + flowTarget, + }, + }); + } + } else { + if (pageName && !deepEqual(state, route.state)) { + dispatch({ + type: 'updateRoute', + route: { + pageName, + detailName, + tabName, + search, + pathName: pathname, + history, + flowTarget, + state, + }, + }); } - }, [pathname, search, pageName, detailName, tabName, flowTarget, state]); - return null; - } -); + } + }, [pathname, search, pageName, detailName, tabName, flowTarget, state]); + return null; +}; -export const SpyRoute = withRouter(SpyRouteComponent); +export const SpyRoute = withRouter(memo(SpyRouteComponent, deepEqual)); From 112a64bd4f00c6fc5cfdf775c00e4594d427dead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Sun, 2 Feb 2020 16:08:09 +0100 Subject: [PATCH 02/12] add why-did-you-render --- x-pack/legacy/plugins/siem/package.json | 3 ++- x-pack/legacy/plugins/siem/public/routes.tsx | 10 ++++++++++ yarn.lock | 9 ++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/siem/package.json b/x-pack/legacy/plugins/siem/package.json index 558ac013e5963..9977acc8ab54a 100644 --- a/x-pack/legacy/plugins/siem/package.json +++ b/x-pack/legacy/plugins/siem/package.json @@ -13,7 +13,8 @@ "devDependencies": { "@types/lodash": "^4.14.110", "@types/js-yaml": "^3.12.1", - "@types/react-beautiful-dnd": "^11.0.4" + "@types/react-beautiful-dnd": "^11.0.4", + "@welldone-software/why-did-you-render": "^4.0.0" }, "dependencies": { "lodash": "^4.17.15", diff --git a/x-pack/legacy/plugins/siem/public/routes.tsx b/x-pack/legacy/plugins/siem/public/routes.tsx index a989fa9873435..d81a0160dc21a 100644 --- a/x-pack/legacy/plugins/siem/public/routes.tsx +++ b/x-pack/legacy/plugins/siem/public/routes.tsx @@ -12,6 +12,16 @@ import { NotFoundPage } from './pages/404'; import { HomePage } from './pages/home'; import { ManageRoutesSpy } from './utils/route/manage_spy_routes'; +/* Uncomment only during debugging */ +// const whyDidYouRender = require('@welldone-software/why-did-you-render'); // eslint-disable-line +// whyDidYouRender(React, { +// exclude: [/^ColumnHeaders/, /^Connect/, /^BarValuesComponent/, /^BarGeometries/], +// trackAllPureComponents: true, +// trackHooks: false, +// collapseGroups: true, +// // logOnDifferentValues: true, +// }); + interface RouterProps { history: History; } diff --git a/yarn.lock b/yarn.lock index a3acc2ae216c5..c01184c1b1597 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5580,6 +5580,13 @@ text-table "^0.2.0" webpack-log "^1.1.2" +"@welldone-software/why-did-you-render@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@welldone-software/why-did-you-render/-/why-did-you-render-4.0.0.tgz#cc98c996f5a06ea55bd07dc99ba4b4d68af93332" + integrity sha512-PjqriZ8Ak9biP2+kOcIrg+NwsFwWVhGV03Hm+ns84YBCArn+hWBKM9rMBEU6e62I1qyrYF2/G9yktNpEmfWfJA== + dependencies: + lodash "^4" + "@wry/context@^0.4.0": version "0.4.1" resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.4.1.tgz#b3e23ca036035cbad0bd9711269352dd03a6fe3c" @@ -19631,7 +19638,7 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= -lodash@4.17.11, lodash@4.17.15, lodash@>4.17.4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: +lodash@4.17.11, lodash@4.17.15, lodash@>4.17.4, lodash@^4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== From fbcf91bcf04a99720f0dd8548cca33481bc000e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Sun, 2 Feb 2020 16:26:55 +0100 Subject: [PATCH 03/12] cleanup --- .../public/components/search_bar/index.tsx | 378 +++++++++--------- .../signals_histogram.tsx | 106 ++--- .../network/navigation/network_routes.tsx | 219 +++++----- .../siem/public/utils/route/spy_routes.tsx | 133 +++--- 4 files changed, 423 insertions(+), 413 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx index 28557a3c9463e..f51e932aa6002 100644 --- a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx @@ -5,7 +5,7 @@ */ import { getOr, isEqual, set } from 'lodash/fp'; -import React, { FC, memo, useEffect, useCallback, useMemo } from 'react'; +import React, { memo, useEffect, useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; import { Subscription } from 'rxjs'; @@ -76,206 +76,209 @@ const SearchBarContainer = styled.div` } `; -const SearchBarComponent: FC = ({ - end, - filterQuery, - fromStr, - id, - indexPattern, - isLoading = false, - queries, - savedQuery, - setSavedQuery, - setSearchBarFilter, - start, - toStr, - updateSearch, - dataTestSubj, -}) => { - const { timefilter } = npStart.plugins.data.query.timefilter; - if (fromStr != null && toStr != null) { - timefilter.setTime({ from: fromStr, to: toStr }); - } else if (start != null && end != null) { - timefilter.setTime({ - from: new Date(start).toISOString(), - to: new Date(end).toISOString(), - }); - } - - const onQuerySubmit = useCallback( - (payload: { dateRange: TimeRange; query?: Query }) => { - const isQuickSelection = - payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now'); - let updateSearchBar: UpdateReduxSearchBar = { - id, - end: toStr != null ? toStr : new Date(end).toISOString(), - start: fromStr != null ? fromStr : new Date(start).toISOString(), - isInvalid: false, - isQuickSelection, - updateTime: false, - }; - let isStateUpdated = false; - - if ( - (isQuickSelection && - (fromStr !== payload.dateRange.from || toStr !== payload.dateRange.to)) || - (!isQuickSelection && - (start !== formatDate(payload.dateRange.from) || - end !== formatDate(payload.dateRange.to))) - ) { - isStateUpdated = true; - updateSearchBar.updateTime = true; - updateSearchBar.end = payload.dateRange.to; - updateSearchBar.start = payload.dateRange.from; - } - - if (payload.query != null && !isEqual(payload.query, filterQuery)) { - isStateUpdated = true; - updateSearchBar = set('query', payload.query, updateSearchBar); - } +const SearchBarComponent = memo( + ({ + end, + filterQuery, + fromStr, + id, + indexPattern, + isLoading = false, + queries, + savedQuery, + setSavedQuery, + setSearchBarFilter, + start, + toStr, + updateSearch, + dataTestSubj, + }) => { + const { timefilter } = npStart.plugins.data.query.timefilter; + if (fromStr != null && toStr != null) { + timefilter.setTime({ from: fromStr, to: toStr }); + } else if (start != null && end != null) { + timefilter.setTime({ + from: new Date(start).toISOString(), + to: new Date(end).toISOString(), + }); + } - if (!isStateUpdated) { - // That mean we are doing a refresh! - if (isQuickSelection) { + const onQuerySubmit = useCallback( + (payload: { dateRange: TimeRange; query?: Query }) => { + const isQuickSelection = + payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now'); + let updateSearchBar: UpdateReduxSearchBar = { + id, + end: toStr != null ? toStr : new Date(end).toISOString(), + start: fromStr != null ? fromStr : new Date(start).toISOString(), + isInvalid: false, + isQuickSelection, + updateTime: false, + }; + let isStateUpdated = false; + + if ( + (isQuickSelection && + (fromStr !== payload.dateRange.from || toStr !== payload.dateRange.to)) || + (!isQuickSelection && + (start !== formatDate(payload.dateRange.from) || + end !== formatDate(payload.dateRange.to))) + ) { + isStateUpdated = true; updateSearchBar.updateTime = true; updateSearchBar.end = payload.dateRange.to; updateSearchBar.start = payload.dateRange.from; + } + + if (payload.query != null && !isEqual(payload.query, filterQuery)) { + isStateUpdated = true; + updateSearchBar = set('query', payload.query, updateSearchBar); + } + + if (!isStateUpdated) { + // That mean we are doing a refresh! + if (isQuickSelection) { + updateSearchBar.updateTime = true; + updateSearchBar.end = payload.dateRange.to; + updateSearchBar.start = payload.dateRange.from; + } else { + queries.forEach(q => q.refetch && (q.refetch as inputsModel.Refetch)()); + } + } + + window.setTimeout(() => updateSearch(updateSearchBar), 0); + }, + [id, end, filterQuery, fromStr, queries, start, toStr] + ); + + const onRefresh = useCallback( + (payload: { dateRange: TimeRange }) => { + if (payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now')) { + updateSearch({ + id, + end: payload.dateRange.to, + start: payload.dateRange.from, + isInvalid: false, + isQuickSelection: true, + updateTime: true, + }); } else { queries.forEach(q => q.refetch && (q.refetch as inputsModel.Refetch)()); } - } + }, + [id, queries] + ); - window.setTimeout(() => updateSearch(updateSearchBar), 0); - }, - [id, end, filterQuery, fromStr, queries, start, toStr] - ); + const onSaved = useCallback( + (newSavedQuery: SavedQuery) => { + setSavedQuery({ id, savedQuery: newSavedQuery }); + }, + [id] + ); - const onRefresh = useCallback( - (payload: { dateRange: TimeRange }) => { - if (payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now')) { - updateSearch({ + const onSavedQueryUpdated = useCallback( + (savedQueryUpdated: SavedQuery) => { + const isQuickSelection = savedQueryUpdated.attributes.timefilter + ? savedQueryUpdated.attributes.timefilter.from.includes('now') || + savedQueryUpdated.attributes.timefilter.to.includes('now') + : false; + + let updateSearchBar: UpdateReduxSearchBar = { id, - end: payload.dateRange.to, - start: payload.dateRange.from, + filters: savedQueryUpdated.attributes.filters || [], + end: toStr != null ? toStr : new Date(end).toISOString(), + start: fromStr != null ? fromStr : new Date(start).toISOString(), isInvalid: false, - isQuickSelection: true, - updateTime: true, - }); - } else { - queries.forEach(q => q.refetch && (q.refetch as inputsModel.Refetch)()); - } - }, - [id, queries] - ); - - const onSaved = useCallback( - (newSavedQuery: SavedQuery) => { - setSavedQuery({ id, savedQuery: newSavedQuery }); - }, - [id] - ); - - const onSavedQueryUpdated = useCallback( - (savedQueryUpdated: SavedQuery) => { - const isQuickSelection = savedQueryUpdated.attributes.timefilter - ? savedQueryUpdated.attributes.timefilter.from.includes('now') || - savedQueryUpdated.attributes.timefilter.to.includes('now') - : false; - - let updateSearchBar: UpdateReduxSearchBar = { - id, - filters: savedQueryUpdated.attributes.filters || [], - end: toStr != null ? toStr : new Date(end).toISOString(), - start: fromStr != null ? fromStr : new Date(start).toISOString(), - isInvalid: false, - isQuickSelection, - updateTime: false, - }; + isQuickSelection, + updateTime: false, + }; + + if (savedQueryUpdated.attributes.timefilter) { + updateSearchBar.end = savedQueryUpdated.attributes.timefilter + ? savedQueryUpdated.attributes.timefilter.to + : updateSearchBar.end; + updateSearchBar.start = savedQueryUpdated.attributes.timefilter + ? savedQueryUpdated.attributes.timefilter.from + : updateSearchBar.start; + updateSearchBar.updateTime = true; + } - if (savedQueryUpdated.attributes.timefilter) { - updateSearchBar.end = savedQueryUpdated.attributes.timefilter - ? savedQueryUpdated.attributes.timefilter.to - : updateSearchBar.end; - updateSearchBar.start = savedQueryUpdated.attributes.timefilter - ? savedQueryUpdated.attributes.timefilter.from - : updateSearchBar.start; - updateSearchBar.updateTime = true; - } + updateSearchBar = set('query', savedQueryUpdated.attributes.query, updateSearchBar); + updateSearchBar = set('savedQuery', savedQueryUpdated, updateSearchBar); - updateSearchBar = set('query', savedQueryUpdated.attributes.query, updateSearchBar); - updateSearchBar = set('savedQuery', savedQueryUpdated, updateSearchBar); + updateSearch(updateSearchBar); + }, + [id, end, fromStr, start, toStr] + ); - updateSearch(updateSearchBar); - }, - [id, end, fromStr, start, toStr] - ); + const onClearSavedQuery = useCallback(() => { + if (savedQuery != null) { + updateSearch({ + id, + filters: [], + end: toStr != null ? toStr : new Date(end).toISOString(), + start: fromStr != null ? fromStr : new Date(start).toISOString(), + isInvalid: false, + isQuickSelection: false, + updateTime: false, + query: { + query: '', + language: savedQuery.attributes.query.language, + }, + resetSavedQuery: true, + savedQuery: undefined, + }); + } + }, [id, end, fromStr, start, toStr, savedQuery]); + + useEffect(() => { + let isSubscribed = true; + const subscriptions = new Subscription(); + + subscriptions.add( + siemFilterManager.getUpdates$().subscribe({ + next: () => { + if (isSubscribed) { + setSearchBarFilter({ + id, + filters: siemFilterManager.getFilters(), + }); + } + }, + }) + ); - const onClearSavedQuery = useCallback(() => { - if (savedQuery != null) { - updateSearch({ - id, - filters: [], - end: toStr != null ? toStr : new Date(end).toISOString(), - start: fromStr != null ? fromStr : new Date(start).toISOString(), - isInvalid: false, - isQuickSelection: false, - updateTime: false, - query: { - query: '', - language: savedQuery.attributes.query.language, - }, - resetSavedQuery: true, - savedQuery: undefined, - }); - } - }, [id, end, fromStr, start, toStr, savedQuery]); - - useEffect(() => { - let isSubscribed = true; - const subscriptions = new Subscription(); - - subscriptions.add( - siemFilterManager.getUpdates$().subscribe({ - next: () => { - if (isSubscribed) { - setSearchBarFilter({ - id, - filters: siemFilterManager.getFilters(), - }); - } - }, - }) + return () => { + isSubscribed = false; + subscriptions.unsubscribe(); + }; + }, []); + const indexPatterns = useMemo(() => [indexPattern], [indexPattern]); + return ( + + + ); - - return () => { - isSubscribed = false; - subscriptions.unsubscribe(); - }; - }, []); - const indexPatterns = useMemo(() => [indexPattern], [indexPattern]); - return ( - - - - ); -}; + }, + deepEqual +); const makeMapStateToProps = () => { const getEndSelector = endSelector(); @@ -395,7 +398,4 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ dispatch(inputsActions.setSearchBarFilter({ id, filters })), }); -export const SiemSearchBar = connect( - makeMapStateToProps, - mapDispatchToProps -)(memo(SearchBarComponent, deepEqual)); +export const SiemSearchBar = connect(makeMapStateToProps, mapDispatchToProps)(SearchBarComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx index 413e22be73024..cc475b58a5581 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx @@ -12,11 +12,11 @@ import { HistogramBarSeries, Position, Settings, + ChartSizeArray, } from '@elastic/charts'; import React, { useMemo } from 'react'; import { EuiProgress } from '@elastic/eui'; import deepEqual from 'fast-deep-equal/react'; -import memoizeOne from 'memoize-one'; import { useTheme } from '../../../../components/charts/common'; import { histogramDateTimeFormatter } from '../../../../components/utils'; @@ -34,65 +34,67 @@ interface HistogramSignalsProps { updateDateRange: (min: number, max: number) => void; } -const MemoChart = React.memo(Chart, deepEqual); const MemoSettings = React.memo(Settings, deepEqual); const MemoHistogramBarSeries = React.memo(HistogramBarSeries, deepEqual); const MemoAxis = React.memo(Axis, deepEqual); -const SignalsHistogramComponent: React.FC = ({ - chartHeight = DEFAULT_CHART_HEIGHT, - data, - from, - legendPosition = 'right', - loading, - to, - updateDateRange, -}) => { - const theme = useTheme(); +export const SignalsHistogram = React.memo( + ({ + chartHeight = DEFAULT_CHART_HEIGHT, + data, + from, + legendPosition = 'right', + loading, + to, + updateDateRange, + }) => { + const theme = useTheme(); - const chartSize = useMemo(() => ['100%', chartHeight], [chartHeight]); - const xAxisId = useMemo(() => getAxisId('signalsHistogramAxisX'), []); - const yAxisId = useMemo(() => getAxisId('signalsHistogramAxisY'), []); - const id = useMemo(() => getSpecId('signalsHistogram'), []); - const yAccessors = useMemo(() => ['y'], []); - const splitSeriesAccessors = useMemo(() => ['g'], []); - const tickFormat = useMemo(() => histogramDateTimeFormatter([from, to]), [from, to]); + const chartSize: ChartSizeArray = useMemo(() => ['100%', chartHeight], [chartHeight]); + const xAxisId = useMemo(() => getAxisId('signalsHistogramAxisX'), []); + const yAxisId = useMemo(() => getAxisId('signalsHistogramAxisY'), []); + const id = useMemo(() => getSpecId('signalsHistogram'), []); + const yAccessors = useMemo(() => ['y'], []); + const splitSeriesAccessors = useMemo(() => ['g'], []); + const tickFormat = useMemo(() => histogramDateTimeFormatter([from, to]), [from, to]); - return ( - <> - {loading && ( - - )} + return ( + <> + {loading && ( + + )} - - + + - + - + - - - - ); -}; + + + + ); + }, + deepEqual +); -export const SignalsHistogram = React.memo(SignalsHistogramComponent, deepEqual); +SignalsHistogram.displayName = 'SignalsHistogram'; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx index 2bd6b9953c4b3..b6b54b68ac06a 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx @@ -23,120 +23,125 @@ import { TlsQueryTabBody } from './tls_query_tab_body'; import { Anomaly } from '../../../components/ml/types'; import { NetworkAlertsQueryTabBody } from './alerts_query_tab_body'; -const NetworkRoutesComponent: React.FC = ({ - networkPagePath, - type, - to, - filterQuery, - isInitializing, - from, - indexPattern, - setQuery, - setAbsoluteRangeDatePicker, -}) => { - const narrowDateRange = useCallback( - (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - [setAbsoluteRangeDatePicker] - ); - const updateDateRange = useCallback( - (min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }, - [setAbsoluteRangeDatePicker] - ); +export const NetworkRoutes = React.memo( + ({ + networkPagePath, + type, + to, + filterQuery, + isInitializing, + from, + indexPattern, + setQuery, + setAbsoluteRangeDatePicker, + }) => { + const narrowDateRange = useCallback( + (score: Anomaly, interval: string) => { + const fromTo = scoreIntervalToDateTime(score, interval); + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }); + }, + [setAbsoluteRangeDatePicker] + ); + const updateDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); - const networkAnomaliesFilterQuery = { - bool: { - should: [ - { - exists: { - field: 'source.ip', + const networkAnomaliesFilterQuery = { + bool: { + should: [ + { + exists: { + field: 'source.ip', + }, }, - }, - { - exists: { - field: 'destination.ip', + { + exists: { + field: 'destination.ip', + }, }, - }, - ], - minimum_should_match: 1, - }, - }; + ], + minimum_should_match: 1, + }, + }; - const commonProps = { - startDate: from, - endDate: to, - skip: isInitializing, - type, - narrowDateRange, - setQuery, - filterQuery, - }; + const commonProps = { + startDate: from, + endDate: to, + skip: isInitializing, + type, + narrowDateRange, + setQuery, + filterQuery, + }; - const tabProps = { - ...commonProps, - indexPattern, - updateDateRange, - }; + const tabProps = { + ...commonProps, + indexPattern, + updateDateRange, + }; - const anomaliesProps = { - ...commonProps, - anomaliesFilterQuery: networkAnomaliesFilterQuery, - AnomaliesTableComponent: AnomaliesNetworkTable, - }; + const anomaliesProps = { + ...commonProps, + anomaliesFilterQuery: networkAnomaliesFilterQuery, + AnomaliesTableComponent: AnomaliesNetworkTable, + }; - return ( - - - - - - <> - - - - + return ( + + + + + + <> + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - ); -}; + + + + + + + + + + + + + + + + + + + + ); + } +); -export const NetworkRoutes = React.memo(NetworkRoutesComponent); +NetworkRoutes.displayName = 'NetworkRoutes'; diff --git a/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx b/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx index bb01ebe80bd88..f10a99d407cba 100644 --- a/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx @@ -6,81 +6,84 @@ import * as H from 'history'; import { isEqual } from 'lodash/fp'; -import { FC, memo, useEffect, useState } from 'react'; +import { memo, useEffect, useState } from 'react'; import { withRouter } from 'react-router-dom'; import deepEqual from 'fast-deep-equal'; import { SpyRouteProps } from './types'; import { useRouteSpy } from './use_route_spy'; -export const SpyRouteComponent: FC = ({ - location: { pathname, search }, - history, - match: { - params: { pageName, detailName, tabName, flowTarget }, - }, - state, -}) => { - const [isInitializing, setIsInitializing] = useState(true); - const [route, dispatch] = useRouteSpy(); +export const SpyRouteComponent = memo( + ({ + location: { pathname, search }, + history, + match: { + params: { pageName, detailName, tabName, flowTarget }, + }, + state, + }) => { + const [isInitializing, setIsInitializing] = useState(true); + const [route, dispatch] = useRouteSpy(); - useEffect(() => { - if (isInitializing && search !== '') { - dispatch({ - type: 'updateSearch', - search, - }); - setIsInitializing(false); - } - }, [search]); - useEffect(() => { - if (pageName && !isEqual(route.pathName, pathname)) { - if (isInitializing && detailName == null) { + useEffect(() => { + if (isInitializing && search !== '') { dispatch({ - type: 'updateRouteWithOutSearch', - route: { - pageName, - detailName, - tabName, - pathName: pathname, - history, - flowTarget, - }, + type: 'updateSearch', + search, }); setIsInitializing(false); - } else { - dispatch({ - type: 'updateRoute', - route: { - pageName, - detailName, - tabName, - search, - pathName: pathname, - history, - flowTarget, - }, - }); } - } else { - if (pageName && !deepEqual(state, route.state)) { - dispatch({ - type: 'updateRoute', - route: { - pageName, - detailName, - tabName, - search, - pathName: pathname, - history, - flowTarget, - state, - }, - }); + }, [search]); + useEffect(() => { + if (pageName && !isEqual(route.pathName, pathname)) { + if (isInitializing && detailName == null) { + dispatch({ + type: 'updateRouteWithOutSearch', + route: { + pageName, + detailName, + tabName, + pathName: pathname, + history, + flowTarget, + }, + }); + setIsInitializing(false); + } else { + dispatch({ + type: 'updateRoute', + route: { + pageName, + detailName, + tabName, + search, + pathName: pathname, + history, + flowTarget, + }, + }); + } + } else { + if (pageName && !deepEqual(state, route.state)) { + dispatch({ + type: 'updateRoute', + route: { + pageName, + detailName, + tabName, + search, + pathName: pathname, + history, + flowTarget, + state, + }, + }); + } } - } - }, [pathname, search, pageName, detailName, tabName, flowTarget, state]); - return null; -}; + }, [pathname, search, pageName, detailName, tabName, flowTarget, state]); + return null; + }, + deepEqual +); -export const SpyRoute = withRouter(memo(SpyRouteComponent, deepEqual)); +export const SpyRoute = withRouter(SpyRouteComponent); From 1b40bf4363a3cb6f2547b7d92a1effea1c8895c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Mon, 3 Feb 2020 10:13:24 +0100 Subject: [PATCH 04/12] cleanup --- .../components/page/hosts/authentications_table/index.tsx | 2 +- .../components/page/network/network_dns_table/columns.tsx | 1 - 2 files changed, 1 insertion(+), 2 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 0a51a7662f5bc..c1d5f5fe26e6c 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 @@ -126,7 +126,7 @@ const AuthenticationTableComponent = React.memo( return ( Date: Mon, 3 Feb 2020 15:38:40 +0100 Subject: [PATCH 05/12] fix typings --- tsconfig.json | 3 ++- typings/fast_deep_equal.d.ts | 21 +++++++++++++++++++ .../page/network/network_http_table/index.tsx | 7 ++++++- .../network_top_countries_table/index.tsx | 7 ++++++- .../network_top_n_flow_table/index.tsx | 9 ++++++-- .../page/network/tls_table/index.tsx | 5 ++++- .../siem/public/containers/source/index.tsx | 6 +++--- .../plugins/siem/public/pages/home/index.tsx | 14 +++++++------ x-pack/tsconfig.json | 3 ++- 9 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 typings/fast_deep_equal.d.ts diff --git a/tsconfig.json b/tsconfig.json index 811b05abeb648..7e9df1972c8b8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,8 @@ "test_utils/*": [ "src/test_utils/public/*" ], - "fixtures/*": ["src/fixtures/*"] + "fixtures/*": ["src/fixtures/*"], + "fast-deep-equal/*": ["typings/fast_deep_equal.d.ts"] }, // Support .tsx files and transform JSX into calls to React.createElement "jsx": "react", diff --git a/typings/fast_deep_equal.d.ts b/typings/fast_deep_equal.d.ts new file mode 100644 index 0000000000000..01649d31d69bf --- /dev/null +++ b/typings/fast_deep_equal.d.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +declare const equal: (a: any, b: any) => boolean; +export = equal; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx index c5aacecfce51a..5a7163566c8ad 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx @@ -160,7 +160,12 @@ const mapDispatchToProps = { updateNetworkTable: networkActions.updateNetworkTable, }; -export const NetworkHttpTable = connect( +export const NetworkHttpTable = connect< + NetworkHttpTableReduxProps, + NetworkHttpTableDispatchProps, + OwnProps, + State +>( makeMapStateToProps, mapDispatchToProps )(NetworkHttpTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx index 6427ac74df759..cafcedaa5068b 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx @@ -202,7 +202,12 @@ const mapDispatchToProps = { updateNetworkTable: networkActions.updateNetworkTable, }; -export const NetworkTopCountriesTable = connect( +export const NetworkTopCountriesTable = connect< + NetworkTopCountriesTableReduxProps, + NetworkTopCountriesTableDispatchProps, + OwnProps, + State +>( makeMapStateToProps, mapDispatchToProps )(NetworkTopCountriesTableComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx index 976d1dc5d5988..e71e36f3fbea3 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx @@ -45,7 +45,7 @@ interface NetworkTopNFlowTableReduxProps { interface NetworkTopNFlowTableDispatchProps { updateNetworkTable: ActionCreator<{ networkType: networkModel.NetworkType; - tableType: networkModel.TopNTableType; + tableType: networkModel.NetworkTableType | networkModel.IpDetailsTableType; updates: networkModel.TableUpdates; }>; } @@ -184,7 +184,12 @@ const mapDispatchToProps = { updateNetworkTable: networkActions.updateNetworkTable, }; -export const NetworkTopNFlowTable = connect( +export const NetworkTopNFlowTable = connect< + NetworkTopNFlowTableReduxProps, + NetworkTopNFlowTableDispatchProps, + OwnProps, + State +>( makeMapStateToProps, mapDispatchToProps )(React.memo(NetworkTopNFlowTableComponent, deepEqual)); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx index 7cef983a0e1fc..debb63a37309b 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx @@ -157,7 +157,10 @@ const mapDispatchToProps = { updateNetworkTable: networkActions.updateNetworkTable, }; -export const TlsTable = connect(makeMapStateToProps, mapDispatchToProps)(TlsTableComponent); +export const TlsTable = connect( + makeMapStateToProps, + mapDispatchToProps +)(TlsTableComponent); const getSortField = (sortField: TlsSortField): SortingBasicTable => ({ field: `node.${sortField.field}`, diff --git a/x-pack/legacy/plugins/siem/public/containers/source/index.tsx b/x-pack/legacy/plugins/siem/public/containers/source/index.tsx index ba36ce1a4de24..0c640b3187e90 100644 --- a/x-pack/legacy/plugins/siem/public/containers/source/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/source/index.tsx @@ -84,7 +84,7 @@ export const getBrowserFields = memoizeOne( : {} ); -const WithSourceComponent: React.FC = ({ children, indexToAdd, sourceId }) => { +export const WithSource = React.memo(({ children, indexToAdd, sourceId }) => { const [configIndex] = useUiSetting$(DEFAULT_INDEX_KEY); const defaultIndex = useMemo(() => { if (indexToAdd != null && !isEmpty(indexToAdd)) { @@ -115,9 +115,9 @@ const WithSourceComponent: React.FC = ({ children, indexToAdd, } ); -}; +}, deepEqual); -export const WithSource = React.memo(WithSourceComponent, deepEqual); +WithSource.displayName = 'WithSource'; export const indicesExistOrDataTemporarilyUnavailable = (indicesExist: boolean | undefined) => indicesExist || isUndefined(indicesExist); diff --git a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx index fcfdb0e256790..4f089ca662231 100644 --- a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx @@ -99,12 +99,14 @@ export const HomePage: React.FC = () => ( path={`/:pageName(${SiemPageName.hosts})`} render={({ match }) => } /> - - - - - - + } + /> + } + /> diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 7d2933f9d9238..b622183083f02 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -39,7 +39,8 @@ "x-pack/monitoring/common/*" ], "plugins/*": ["src/legacy/core_plugins/*/public/"], - "fixtures/*": ["src/fixtures/*"] + "fixtures/*": ["src/fixtures/*"], + "fast-deep-equal/*": ["typings/fast_deep_equal.d.ts"] }, "types": [ "node", From cadabd6e06ecd9f3109abb32b2748dec8f8788f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Mon, 3 Feb 2020 17:30:58 +0100 Subject: [PATCH 06/12] update tests --- typings/fast_deep_equal.d.ts | 5 ++++ x-pack/legacy/plugins/siem/package.json | 3 +-- .../components/charts/barchart.test.tsx | 24 +++++++++---------- .../public/components/charts/barchart.tsx | 4 ++++ .../siem/public/components/flyout/index.tsx | 2 ++ .../__snapshots__/index.test.tsx.snap | 15 +++++------- x-pack/package.json | 1 + 7 files changed, 31 insertions(+), 23 deletions(-) diff --git a/typings/fast_deep_equal.d.ts b/typings/fast_deep_equal.d.ts index 01649d31d69bf..21e5465fe4c9d 100644 --- a/typings/fast_deep_equal.d.ts +++ b/typings/fast_deep_equal.d.ts @@ -17,5 +17,10 @@ * under the License. */ +/* + TODO: Remove after https://github.com/epoberezkin/fast-deep-equal/pull/48 + is merged and fast-deep-equal version is bumped +*/ + declare const equal: (a: any, b: any) => boolean; export = equal; diff --git a/x-pack/legacy/plugins/siem/package.json b/x-pack/legacy/plugins/siem/package.json index 9977acc8ab54a..558ac013e5963 100644 --- a/x-pack/legacy/plugins/siem/package.json +++ b/x-pack/legacy/plugins/siem/package.json @@ -13,8 +13,7 @@ "devDependencies": { "@types/lodash": "^4.14.110", "@types/js-yaml": "^3.12.1", - "@types/react-beautiful-dnd": "^11.0.4", - "@welldone-software/why-did-you-render": "^4.0.0" + "@types/react-beautiful-dnd": "^11.0.4" }, "dependencies": { "lodash": "^4.17.15", diff --git a/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx b/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx index d8e5079dd72a6..4396be63425ad 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { BarChartBaseComponent, BarChartComponent } from './barchart'; import { ChartSeriesData } from './common'; -import { BarSeries, ScaleType, Axis } from '@elastic/charts'; +import { ScaleType } from '@elastic/charts'; jest.mock('../../lib/kibana'); @@ -139,7 +139,7 @@ describe('BarChartBaseComponent', () => { }); it('should render two bar series', () => { - expect(shallowWrapper.find('Chart')).toHaveLength(1); + expect(shallowWrapper.find('MemoChart')).toHaveLength(1); }); }); @@ -168,13 +168,13 @@ describe('BarChartBaseComponent', () => { it(`should ${mockBarChartData.length} render BarSeries`, () => { expect(shallow).toMatchSnapshot(); - expect(shallowWrapper.find(BarSeries)).toHaveLength(mockBarChartData.length); + expect(shallowWrapper.find('MemoBarSeries')).toHaveLength(mockBarChartData.length); }); it('should render BarSeries with given xScaleType', () => { expect( shallowWrapper - .find(BarSeries) + .find('MemoBarSeries') .first() .prop('xScaleType') ).toEqual(configs.series.xScaleType); @@ -183,7 +183,7 @@ describe('BarChartBaseComponent', () => { it('should render BarSeries with given yScaleType', () => { expect( shallowWrapper - .find(BarSeries) + .find('MemoBarSeries') .first() .prop('yScaleType') ).toEqual(configs.series.yScaleType); @@ -192,7 +192,7 @@ describe('BarChartBaseComponent', () => { it('should render xAxis with given tick formatter', () => { expect( shallowWrapper - .find(Axis) + .find('MemoAxis') .first() .prop('tickFormat') ).toBeUndefined(); @@ -201,7 +201,7 @@ describe('BarChartBaseComponent', () => { it('should render yAxis with given tick formatter', () => { expect( shallowWrapper - .find(Axis) + .find('MemoAxis') .last() .prop('tickFormat') ).toEqual(mockNumberFormatter); @@ -217,13 +217,13 @@ describe('BarChartBaseComponent', () => { it(`should ${mockBarChartData.length} render BarSeries`, () => { expect(shallow).toMatchSnapshot(); - expect(shallowWrapper.find(BarSeries)).toHaveLength(mockBarChartData.length); + expect(shallowWrapper.find('MemoBarSeries')).toHaveLength(mockBarChartData.length); }); it('should render BarSeries with default xScaleType: Linear', () => { expect( shallowWrapper - .find(BarSeries) + .find('MemoBarSeries') .first() .prop('xScaleType') ).toEqual(ScaleType.Linear); @@ -232,7 +232,7 @@ describe('BarChartBaseComponent', () => { it('should render BarSeries with default yScaleType: Linear', () => { expect( shallowWrapper - .find(BarSeries) + .find('MemoBarSeries') .first() .prop('yScaleType') ).toEqual(ScaleType.Linear); @@ -241,7 +241,7 @@ describe('BarChartBaseComponent', () => { it('should not format xTicks value', () => { expect( shallowWrapper - .find(Axis) + .find('MemoAxis') .last() .prop('tickFormat') ).toBeUndefined(); @@ -250,7 +250,7 @@ describe('BarChartBaseComponent', () => { it('should not format yTicks value', () => { expect( shallowWrapper - .find(Axis) + .find('MemoAxis') .last() .prop('tickFormat') ).toBeUndefined(); diff --git a/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx b/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx index b9c50f9054c36..e6c7c1505706b 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx @@ -25,9 +25,13 @@ import { } from './common'; const MemoChart = React.memo(Chart, deepEqual); +MemoChart.displayName = 'MemoChart'; const MemoSettings = React.memo(Settings, deepEqual); +MemoSettings.displayName = 'MemoSettings'; const MemoBarSeries = React.memo(BarSeries, deepEqual); +MemoBarSeries.displayName = 'MemoBarSeries'; const MemoAxis = React.memo(Axis, deepEqual); +MemoAxis.displayName = 'MemoAxis'; const checkIfAllTheDataInTheSeriesAreValid = (series: ChartSeriesData): series is ChartSeriesData => series != null && diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx index 3dcdf697c23d0..0e73ab55b0e77 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx @@ -135,3 +135,5 @@ const mapDispatchToProps = { }; export const Flyout = connect(mapStateToProps, mapDispatchToProps)(FlyoutComponent); + +Flyout.displayName = 'Flyout'; diff --git a/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap index 69596ba8f3325..cb595ee379e4e 100644 --- a/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap @@ -87,14 +87,13 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] = queryId="statItems" title="KPI HOSTS" > - - + @@ -321,14 +320,13 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] = queryId="statItems" title="KPI HOSTS" > - - + @@ -625,14 +623,13 @@ exports[`Stat Items Component rendering kpis with charts it renders the default queryId="statItems" title="KPI UNIQUE_PRIVATE_IPS" > - - + diff --git a/x-pack/package.json b/x-pack/package.json index ad0be351483f6..c324707bb76a5 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -105,6 +105,7 @@ "@types/uuid": "^3.4.4", "@types/xml-crypto": "^1.4.0", "@types/xml2js": "^0.4.5", + "@welldone-software/why-did-you-render": "^4.0.0", "abab": "^1.0.4", "axios": "^0.19.0", "babel-jest": "^24.9.0", From abe7967dbc09b2a858581cdf3a66a76e7e3f96c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Thu, 6 Feb 2020 01:29:22 +0100 Subject: [PATCH 07/12] cleanup --- .../siem/public/components/flyout/button/index.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/button/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/button/index.tsx index 926059f64e28b..6ec5912872467 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/button/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/button/index.tsx @@ -142,15 +142,10 @@ export const FlyoutButton = React.memo( /> ) : null, - (prevProps, nextProps) => { - console.error('duoa'); - - return ( - prevProps.show === nextProps.show && - prevProps.dataProviders === nextProps.dataProviders && - prevProps.timelineId === nextProps.timelineId - ); - } + (prevProps, nextProps) => + prevProps.show === nextProps.show && + prevProps.dataProviders === nextProps.dataProviders && + prevProps.timelineId === nextProps.timelineId ); FlyoutButton.displayName = 'FlyoutButton'; From a681c58f7b85e6e2233ecf4d536009045da1c57c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Thu, 6 Feb 2020 01:31:09 +0100 Subject: [PATCH 08/12] cleanup --- .../public/components/page/network/network_dns_table/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx index 204f5e313084c..92e531e708548 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx @@ -163,8 +163,7 @@ export const NetworkDnsTableComponent = React.memo( updateLimitPagination={updateLimitPagination} /> ); - }, - deepEqual + } ); NetworkDnsTableComponent.displayName = 'NetworkDnsTableComponent'; From 839f6090244c4f57677ed56f9fff8833ad691109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Thu, 6 Feb 2020 02:11:43 +0100 Subject: [PATCH 09/12] bump charts --- package.json | 2 +- packages/kbn-ui-shared-deps/package.json | 2 +- .../siem/public/components/charts/barchart.tsx | 2 +- .../page/network/kpi_network/index.tsx | 2 +- .../public/components/timeline/timeline.tsx | 3 +-- .../signals_histogram_panel/helpers.tsx | 2 +- yarn.lock | 18 ++++++++++++------ 7 files changed, 18 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 305aeba900503..819a9cc20d5f1 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "@babel/core": "^7.5.5", "@babel/register": "^7.7.0", "@elastic/apm-rum": "^4.6.0", - "@elastic/charts": "^16.1.0", + "@elastic/charts": "^16.1.1", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "7.6.0", "@elastic/eui": "18.3.0", diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index 8c8b8b8a21488..c23523307dd27 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -11,7 +11,7 @@ "devDependencies": { "abort-controller": "^3.0.0", "@elastic/eui": "18.3.0", - "@elastic/charts": "^16.1.0", + "@elastic/charts": "^16.1.1", "@kbn/dev-utils": "1.0.0", "@kbn/i18n": "1.0.0", "@yarnpkg/lockfile": "^1.1.0", diff --git a/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx b/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx index 6f3722f3bcbd9..797344064a515 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx @@ -113,7 +113,7 @@ export const BarChartComponent = ({ {({ measureRef, content: { height, width } }) => ( - ( ); - }, + } ); KpiNetworkComponent.displayName = 'KpiNetworkComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx index efa293348e2d2..844634d03eed8 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx @@ -8,7 +8,6 @@ import { EuiFlexGroup } from '@elastic/eui'; import { getOr, isEmpty } from 'lodash/fp'; import React from 'react'; import styled from 'styled-components'; -import deepEqual from 'fast-deep-equal//react'; import { BrowserFields } from '../../containers/source'; import { TimelineQuery } from '../../containers/timeline'; @@ -231,4 +230,4 @@ export const TimelineComponent = ({ ); }; -export const Timeline = React.memo(TimelineComponent, deepEqual); +export const Timeline = React.memo(TimelineComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/helpers.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/helpers.tsx index a7f3b08b957d3..27ee552146092 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/helpers.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/helpers.tsx @@ -89,4 +89,4 @@ export const showInitialLoadingSpinner = ({ }: { isInitialLoading: boolean; isLoadingSignals: boolean; -}): boolean => isInitialLoading && isLoadingSignals; \ No newline at end of file +}): boolean => isInitialLoading && isLoadingSignals; diff --git a/yarn.lock b/yarn.lock index a25e7301fed36..e663f98afceff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1880,15 +1880,16 @@ dependencies: "@elastic/apm-rum-core" "^4.7.0" -"@elastic/charts@^16.1.0": - version "16.1.0" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-16.1.0.tgz#67cf11625dcd7e1c2cf16ef53349e6a68a73f5b1" - integrity sha512-0jZ7thhGmYC0ZdEVkxfg6M66epCD7k7BfYIi12FnrmIK+mUD2IPhR8b2TJXvaojPryN4YTNreGRncQ9R58fOoQ== +"@elastic/charts@^16.1.1": + version "16.2.1" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-16.2.1.tgz#8cc87321a062526353cb3a41d51e10aac91da447" + integrity sha512-fxBsTgraK0Hs5odW9ScRnHxpGMxiXQ4rmU/fcSPJJyGiVlwyj6SXK7IltuFa+cA7XKzI4v8MXdg5Nvlrescr+g== dependencies: "@types/d3-shape" "^1.3.1" classnames "^2.2.6" d3-array "^1.2.4" d3-collection "^1.0.7" + d3-color "^1.4.0" d3-scale "^1.0.7" d3-shape "^1.3.4" konva "^4.0.18" @@ -1902,7 +1903,7 @@ reselect "^4.0.0" resize-observer-polyfill "^1.5.1" ts-debounce "^1.0.0" - utility-types "^3.9.0" + utility-types "^3.10.0" uuid "^3.3.2" "@elastic/elasticsearch@^7.4.0": @@ -10590,6 +10591,11 @@ d3-color@^1.0.3: resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.3.tgz#bc7643fca8e53a8347e2fbdaffa236796b58509b" integrity sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs= +d3-color@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.0.tgz#89c45a995ed773b13314f06460df26d60ba0ecaf" + integrity sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg== + d3-contour@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-1.1.2.tgz#21f5456fcf57645922d69a27a58e782c91f842b3" @@ -30297,7 +30303,7 @@ utila@^0.4.0, utila@~0.4: resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= -utility-types@^3.10.0, utility-types@^3.9.0: +utility-types@^3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== From 3ee3dd8dabb2e982aab96156c8a474a5313d37c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Thu, 6 Feb 2020 10:35:02 +0100 Subject: [PATCH 10/12] update tests --- .../__snapshots__/barchart.test.tsx.snap | 2 -- .../components/charts/barchart.test.tsx | 27 +++++++++---------- .../__snapshots__/index.test.tsx.snap | 12 ++++----- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/charts/__snapshots__/barchart.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/charts/__snapshots__/barchart.test.tsx.snap index 12b9afb661da1..c330676e9219e 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/__snapshots__/barchart.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/charts/__snapshots__/barchart.test.tsx.snap @@ -1,5 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`BarChartBaseComponent render with customized configs should 2 render BarSeries 1`] = `[Function]`; - exports[`BarChartBaseComponent render with default configs if no customized configs given should 2 render BarSeries 1`] = `[Function]`; diff --git a/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx b/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx index 4396be63425ad..4ce1291e8c776 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { BarChartBaseComponent, BarChartComponent } from './barchart'; import { ChartSeriesData } from './common'; -import { ScaleType } from '@elastic/charts'; +import { Chart, BarSeries, Axis, ScaleType } from '@elastic/charts'; jest.mock('../../lib/kibana'); @@ -139,7 +139,7 @@ describe('BarChartBaseComponent', () => { }); it('should render two bar series', () => { - expect(shallowWrapper.find('MemoChart')).toHaveLength(1); + expect(shallowWrapper.find(Chart)).toHaveLength(1); }); }); @@ -167,14 +167,13 @@ describe('BarChartBaseComponent', () => { }); it(`should ${mockBarChartData.length} render BarSeries`, () => { - expect(shallow).toMatchSnapshot(); - expect(shallowWrapper.find('MemoBarSeries')).toHaveLength(mockBarChartData.length); + expect(shallowWrapper.find(BarSeries)).toHaveLength(mockBarChartData.length); }); it('should render BarSeries with given xScaleType', () => { expect( shallowWrapper - .find('MemoBarSeries') + .find(BarSeries) .first() .prop('xScaleType') ).toEqual(configs.series.xScaleType); @@ -183,7 +182,7 @@ describe('BarChartBaseComponent', () => { it('should render BarSeries with given yScaleType', () => { expect( shallowWrapper - .find('MemoBarSeries') + .find(BarSeries) .first() .prop('yScaleType') ).toEqual(configs.series.yScaleType); @@ -192,7 +191,7 @@ describe('BarChartBaseComponent', () => { it('should render xAxis with given tick formatter', () => { expect( shallowWrapper - .find('MemoAxis') + .find(Axis) .first() .prop('tickFormat') ).toBeUndefined(); @@ -201,7 +200,7 @@ describe('BarChartBaseComponent', () => { it('should render yAxis with given tick formatter', () => { expect( shallowWrapper - .find('MemoAxis') + .find(Axis) .last() .prop('tickFormat') ).toEqual(mockNumberFormatter); @@ -217,13 +216,13 @@ describe('BarChartBaseComponent', () => { it(`should ${mockBarChartData.length} render BarSeries`, () => { expect(shallow).toMatchSnapshot(); - expect(shallowWrapper.find('MemoBarSeries')).toHaveLength(mockBarChartData.length); + expect(shallowWrapper.find(BarSeries)).toHaveLength(mockBarChartData.length); }); it('should render BarSeries with default xScaleType: Linear', () => { expect( shallowWrapper - .find('MemoBarSeries') + .find(BarSeries) .first() .prop('xScaleType') ).toEqual(ScaleType.Linear); @@ -232,7 +231,7 @@ describe('BarChartBaseComponent', () => { it('should render BarSeries with default yScaleType: Linear', () => { expect( shallowWrapper - .find('MemoBarSeries') + .find(BarSeries) .first() .prop('yScaleType') ).toEqual(ScaleType.Linear); @@ -241,7 +240,7 @@ describe('BarChartBaseComponent', () => { it('should not format xTicks value', () => { expect( shallowWrapper - .find('MemoAxis') + .find(Axis) .last() .prop('tickFormat') ).toBeUndefined(); @@ -250,7 +249,7 @@ describe('BarChartBaseComponent', () => { it('should not format yTicks value', () => { expect( shallowWrapper - .find('MemoAxis') + .find(Axis) .last() .prop('tickFormat') ).toBeUndefined(); @@ -265,7 +264,7 @@ describe('BarChartBaseComponent', () => { }); it('should not render without height and width', () => { - expect(shallowWrapper.find('Chart')).toHaveLength(0); + expect(shallowWrapper.find(Chart)).toHaveLength(0); }); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap index cb595ee379e4e..ef077ece19f92 100644 --- a/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap @@ -87,7 +87,7 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] = queryId="statItems" title="KPI HOSTS" > - - + @@ -320,7 +320,7 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] = queryId="statItems" title="KPI HOSTS" > - - + @@ -623,7 +623,7 @@ exports[`Stat Items Component rendering kpis with charts it renders the default queryId="statItems" title="KPI UNIQUE_PRIVATE_IPS" > - - + From 92f292e67e78faa2f830924339b6341cca438418 Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Tue, 25 Feb 2020 10:36:45 +0100 Subject: [PATCH 11/12] Update tsconfig.json --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 62cee1ff5c4d0..811b05abeb648 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "test_utils/*": [ "src/test_utils/public/*" ], - "fixtures/*": ["src/fixtures/*"], + "fixtures/*": ["src/fixtures/*"] }, // Support .tsx files and transform JSX into calls to React.createElement "jsx": "react", From 90ab4ddd70c5673caba336a57e12fc03342643e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Tue, 25 Feb 2020 11:51:16 +0100 Subject: [PATCH 12/12] fix tests --- .../plugins/siem/public/components/charts/areachart.test.tsx | 4 ++-- .../plugins/siem/public/components/charts/barchart.test.tsx | 4 ++-- .../components/timeline/__snapshots__/timeline.test.tsx.snap | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/charts/areachart.test.tsx b/x-pack/legacy/plugins/siem/public/components/charts/areachart.test.tsx index 27f0222b96b77..3c2de28ae423c 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/areachart.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/areachart.test.tsx @@ -331,7 +331,7 @@ describe('AreaChart', () => { }); it(`should render area chart`, () => { - expect(shallowWrapper.find('WrappedByAutoSizer')).toHaveLength(1); + expect(shallowWrapper.find('AreaChartBase')).toHaveLength(1); expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(0); }); }); @@ -344,7 +344,7 @@ describe('AreaChart', () => { }); it(`should render a chart place holder`, () => { - expect(shallowWrapper.find('WrappedByAutoSizer')).toHaveLength(0); + expect(shallowWrapper.find('AreaChartBase')).toHaveLength(0); expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(1); }); } diff --git a/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx b/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx index c4ea125026766..272c41833f368 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx @@ -277,7 +277,7 @@ describe.each(chartDataSets)('BarChart with valid data [%o]', data => { }); it(`should render chart`, () => { - expect(shallowWrapper.find('WrappedByAutoSizer')).toHaveLength(1); + expect(shallowWrapper.find('BarChartBase')).toHaveLength(1); expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(0); }); }); @@ -290,7 +290,7 @@ describe.each(chartHolderDataSets)('BarChart with invalid data [%o]', data => { }); it(`should render a ChartPlaceHolder`, () => { - expect(shallowWrapper.find('WrappedByAutoSizer')).toHaveLength(0); + expect(shallowWrapper.find('BarChartBase')).toHaveLength(0); expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(1); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/__snapshots__/timeline.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/timeline/__snapshots__/timeline.test.tsx.snap index 3fcd258b79147..372930ee3167d 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/__snapshots__/timeline.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/timeline/__snapshots__/timeline.test.tsx.snap @@ -8,7 +8,7 @@ exports[`Timeline rendering renders correctly against snapshot 1`] = ` justifyContent="flexStart" > -