[SIEM] Fix unnecessary re-renders on the Overview page (#56587)

This commit is contained in:
patrykkopycinski 2020-02-25 15:00:50 +01:00 committed by GitHub
parent db05fb6738
commit 418c44a47e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 376 additions and 332 deletions

View file

@ -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]`;

View file

@ -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);
});
}

View file

@ -146,8 +146,4 @@ export const AreaChartComponent: React.FC<AreaChartComponentProps> = ({ areaChar
);
};
AreaChartComponent.displayName = 'AreaChartComponent';
export const AreaChart = React.memo(AreaChartComponent);
AreaChart.displayName = 'AreaChart';

View file

@ -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 { 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('Chart')).toHaveLength(1);
expect(shallowWrapper.find(Chart)).toHaveLength(1);
});
});
@ -167,7 +167,6 @@ describe('BarChartBaseComponent', () => {
});
it(`should ${mockBarChartData.length} render BarSeries`, () => {
expect(shallow).toMatchSnapshot();
expect(shallowWrapper.find(BarSeries)).toHaveLength(mockBarChartData.length);
});
@ -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);
});
});
});
@ -278,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);
});
});
@ -291,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);
});
});

View file

@ -16,7 +16,9 @@ import {
TickFormatter,
Position,
} from '@elastic/charts';
import React, { useMemo } from 'react';
import styled from 'styled-components';
import { useUiSetting } from '../../lib/kibana';
import { DEFAULT_DARK_MODE } from '../../../common/constants';
@ -54,7 +56,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 +68,9 @@ export const WrappedByAutoSizer = styled.div<{ height?: string }>`
}
`;
WrappedByAutoSizer.displayName = 'WrappedByAutoSizer';
WrappedByAutoSizerComponent.displayName = 'WrappedByAutoSizer';
export const WrappedByAutoSizer = React.memo(WrappedByAutoSizerComponent);
export enum SeriesType {
BAR = 'bar',
@ -96,8 +100,9 @@ const theme: PartialTheme = {
export const useTheme = () => {
const isDarkMode = useUiSetting<boolean>(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 = {

View file

@ -4,7 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import React, { createContext, useContext, useEffect } from 'react';
import {
Draggable,
@ -14,6 +13,7 @@ import {
} from 'react-beautiful-dnd';
import { connect, ConnectedProps } from 'react-redux';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
import { EuiPortal } from '@elastic/eui';
import { dragAndDropActions } from '../../store/drag_and_drop';
@ -122,7 +122,7 @@ const DraggableWrapperComponent = React.memo<Props>(
},
(prevProps, nextProps) => {
return (
isEqual(prevProps.dataProvider, nextProps.dataProvider) &&
deepEqual(prevProps.dataProvider, nextProps.dataProvider) &&
prevProps.render !== nextProps.render &&
prevProps.truncate === nextProps.truncate
);

View file

@ -5,10 +5,10 @@
*/
import { EuiPanel } from '@elastic/eui';
import deepEqual from 'fast-deep-equal';
import { getOr, isEmpty, isEqual, union } from 'lodash/fp';
import { getOr, isEmpty, union } from 'lodash/fp';
import React, { useMemo } from 'react';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
import useResizeObserver from 'use-resize-observer/polyfilled';
import { BrowserFields } from '../../containers/source';
@ -228,7 +228,7 @@ const EventsViewerComponent: React.FC<Props> = ({
export const EventsViewer = React.memo(
EventsViewerComponent,
(prevProps, nextProps) =>
isEqual(prevProps.browserFields, nextProps.browserFields) &&
deepEqual(prevProps.browserFields, nextProps.browserFields) &&
prevProps.columns === nextProps.columns &&
prevProps.dataProviders === nextProps.dataProviders &&
prevProps.deletedEventIds === nextProps.deletedEventIds &&
@ -241,9 +241,9 @@ export const EventsViewer = React.memo(
prevProps.itemsPerPage === nextProps.itemsPerPage &&
prevProps.itemsPerPageOptions === nextProps.itemsPerPageOptions &&
prevProps.kqlMode === nextProps.kqlMode &&
isEqual(prevProps.query, nextProps.query) &&
deepEqual(prevProps.query, nextProps.query) &&
prevProps.start === nextProps.start &&
prevProps.sort === nextProps.sort &&
isEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) &&
deepEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) &&
prevProps.utilityBar === nextProps.utilityBar
);

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import React, { useCallback, useMemo, useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { inputsModel, inputsSelectors, State, timelineSelectors } from '../../store';
import { inputsActions, timelineActions } from '../../store/actions';
@ -197,23 +197,23 @@ export const StatefulEventsViewer = connector(
StatefulEventsViewerComponent,
(prevProps, nextProps) =>
prevProps.id === nextProps.id &&
isEqual(prevProps.columns, nextProps.columns) &&
isEqual(prevProps.dataProviders, nextProps.dataProviders) &&
deepEqual(prevProps.columns, nextProps.columns) &&
deepEqual(prevProps.dataProviders, nextProps.dataProviders) &&
prevProps.deletedEventIds === nextProps.deletedEventIds &&
prevProps.end === nextProps.end &&
isEqual(prevProps.filters, nextProps.filters) &&
deepEqual(prevProps.filters, nextProps.filters) &&
prevProps.isLive === nextProps.isLive &&
prevProps.itemsPerPage === nextProps.itemsPerPage &&
isEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) &&
deepEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) &&
prevProps.kqlMode === nextProps.kqlMode &&
isEqual(prevProps.query, nextProps.query) &&
isEqual(prevProps.sort, nextProps.sort) &&
deepEqual(prevProps.query, nextProps.query) &&
deepEqual(prevProps.sort, nextProps.sort) &&
prevProps.start === nextProps.start &&
isEqual(prevProps.pageFilters, nextProps.pageFilters) &&
deepEqual(prevProps.pageFilters, nextProps.pageFilters) &&
prevProps.showCheckboxes === nextProps.showCheckboxes &&
prevProps.showRowRenderers === nextProps.showRowRenderers &&
prevProps.start === nextProps.start &&
isEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) &&
deepEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) &&
prevProps.utilityBar === nextProps.utilityBar
)
);

View file

@ -6,7 +6,7 @@
import { EuiBadge } from '@elastic/eui';
import { defaultTo, getOr } from 'lodash/fp';
import React from 'react';
import React, { useCallback } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import styled from 'styled-components';
@ -58,28 +58,39 @@ export const FlyoutComponent = React.memo<Props>(
timelineId,
usersViewing,
width,
}) => (
<>
<Visible show={show}>
<Pane
flyoutHeight={flyoutHeight}
headerHeight={headerHeight}
onClose={() => 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 (
<>
<Visible show={show}>
<Pane
flyoutHeight={flyoutHeight}
headerHeight={headerHeight}
onClose={handleClose}
timelineId={timelineId}
usersViewing={usersViewing}
width={width}
>
{children}
</Pane>
</Visible>
<FlyoutButton
dataProviders={dataProviders!}
show={!show}
timelineId={timelineId}
usersViewing={usersViewing}
width={width}
>
{children}
</Pane>
</Visible>
<FlyoutButton
dataProviders={dataProviders!}
show={!show}
timelineId={timelineId}
onOpen={() => showTimeline({ id: timelineId, show: true })}
/>
</>
)
onOpen={handleOpen}
/>
</>
);
}
);
FlyoutComponent.displayName = 'FlyoutComponent';

View file

@ -5,7 +5,7 @@
*/
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';
@ -162,7 +162,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;
};

View file

@ -4,11 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import isEqual from 'lodash/fp/isEqual';
import deepEqual from 'fast-deep-equal';
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
import deepEqual from 'fast-deep-equal';
import { useKibana } from '../../lib/kibana';
import { RouteSpyState } from '../../utils/route/types';
@ -81,8 +80,8 @@ export const SiemNavigationRedux = compose<
(prevProps, nextProps) =>
prevProps.pathName === nextProps.pathName &&
prevProps.search === nextProps.search &&
isEqual(prevProps.navTabs, nextProps.navTabs) &&
isEqual(prevProps.urlState, nextProps.urlState) &&
deepEqual(prevProps.navTabs, nextProps.navTabs) &&
deepEqual(prevProps.urlState, nextProps.urlState) &&
deepEqual(prevProps.state, nextProps.state)
)
);

View file

@ -7,7 +7,7 @@
/* eslint-disable react/display-name */
import { has } from 'lodash/fp';
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { hostsActions } from '../../../../store/hosts';
@ -100,10 +100,12 @@ const AuthenticationTableComponent = React.memo<AuthenticationTableProps>(
[type, updateTableActivePage]
);
const columns = useMemo(() => getAuthenticationColumnsCurated(type), [type]);
return (
<PaginatedTable
activePage={activePage}
columns={getAuthenticationColumnsCurated(type)}
columns={columns}
dataTestSubj={`table-${tableType}`}
headerCount={totalCount}
headerTitle={i18n.AUTHENTICATIONS}

View file

@ -7,6 +7,7 @@
import React, { useMemo, useCallback } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { IIndexPattern } from 'src/plugins/data/public';
import { hostsActions } from '../../../../store/actions';
import {
Direction,

View file

@ -7,6 +7,7 @@
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { KpiHostsData, KpiHostDetailsData } from '../../../../graphql/types';
import { StatItemsComponent, StatItemsProps, useKpiMatrixStatus } from '../../../stat_items';
import { kpiHostsMapping } from './kpi_hosts_mapping';

View file

@ -6,7 +6,7 @@
/* eslint-disable react/display-name */
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { hostsActions } from '../../../../store/actions';
@ -98,10 +98,12 @@ const UncommonProcessTableComponent = React.memo<UncommonProcessTableProps>(
[type, updateTableActivePage]
);
const columns = useMemo(() => getUncommonColumnsCurated(type), [type]);
return (
<PaginatedTable
activePage={activePage}
columns={getUncommonColumnsCurated(type)}
columns={columns}
dataTestSubj={`table-${tableType}`}
headerCount={totalCount}
headerTitle={i18n.UNCOMMON_PROCESSES}

View file

@ -15,6 +15,7 @@ import {
} from '@elastic/eui';
import styled from 'styled-components';
import { chunk as _chunk } from 'lodash/fp';
import {
StatItemsComponent,
StatItemsProps,

View file

@ -8,7 +8,6 @@ import numeral from '@elastic/numeral';
import React from 'react';
import { NetworkDnsFields, NetworkDnsItem } from '../../../../graphql/types';
import { networkModel } from '../../../../store';
import { DragEffects, DraggableWrapper } from '../../../drag_and_drop/draggable_wrapper';
import { escapeDataProviderId } from '../../../drag_and_drop/helpers';
import { defaultToEmptyTag, getEmptyTagValue } from '../../../empty_value';
@ -26,7 +25,7 @@ export type NetworkDnsColumns = [
Columns<NetworkDnsItem['dnsBytesOut']>
];
export const getNetworkDnsColumns = (type: networkModel.NetworkType): NetworkDnsColumns => [
export const getNetworkDnsColumns = (): NetworkDnsColumns => [
{
field: `node.${NetworkDnsFields.dnsName}`,
name: i18n.REGISTERED_DOMAIN,

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { networkActions } from '../../../../store/actions';
import {
@ -93,7 +93,7 @@ export const NetworkDnsTableComponent = React.memo<NetworkDnsTableProps>(
field: criteria.sort.field.split('.')[1] as NetworkDnsFields,
direction: criteria.sort.direction as Direction,
};
if (!isEqual(newDnsSortField, sort)) {
if (!deepEqual(newDnsSortField, sort)) {
updateNetworkTable({
networkType: type,
tableType,
@ -115,10 +115,12 @@ export const NetworkDnsTableComponent = React.memo<NetworkDnsTableProps>(
[type, updateNetworkTable, isPtrIncluded]
);
const columns = useMemo(() => getNetworkDnsColumns(), []);
return (
<PaginatedTable
activePage={activePage}
columns={getNetworkDnsColumns(type)}
columns={columns}
dataTestSubj={`table-${tableType}`}
headerCount={totalCount}
headerSupplement={

View file

@ -4,7 +4,7 @@
* 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, ConnectedProps } from 'react-redux';
import { networkActions } from '../../../../store/actions';
@ -99,10 +99,12 @@ const NetworkHttpTableComponent: React.FC<NetworkHttpTableProps> = ({
const sorting = { field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction };
const columns = useMemo(() => getNetworkHttpColumns(tableType), [tableType]);
return (
<PaginatedTable
activePage={activePage}
columns={getNetworkHttpColumns(tableType)}
columns={columns}
dataTestSubj={`table-${tableType}`}
headerCount={totalCount}
headerTitle={i18n.HTTP_REQUESTS}

View file

@ -4,9 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual, last } from 'lodash/fp';
import { last } from 'lodash/fp';
import React, { useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { IIndexPattern } from 'src/plugins/data/public';
import { networkActions } from '../../../../store/actions';
@ -125,7 +126,7 @@ const NetworkTopCountriesTableComponent = React.memo<NetworkTopCountriesTablePro
field: lastField as NetworkTopTablesFields,
direction: newSortDirection as Direction,
};
if (!isEqual(newTopCountriesSort, sort)) {
if (!deepEqual(newTopCountriesSort, sort)) {
updateNetworkTable({
networkType: type,
tableType,

View file

@ -3,9 +3,10 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual, last } from 'lodash/fp';
import { last } from 'lodash/fp';
import React, { useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { networkActions } from '../../../../store/actions';
import {
@ -96,7 +97,7 @@ const NetworkTopNFlowTableComponent: React.FC<NetworkTopNFlowTableProps> = ({
field: field as NetworkTopTablesFields,
direction: newSortDirection as Direction,
};
if (!isEqual(newTopNFlowSort, sort)) {
if (!deepEqual(newTopNFlowSort, sort)) {
updateNetworkTable({
networkType: type,
tableType,

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { networkActions } from '../../../../store/network';
import { TlsEdges, TlsSortField, TlsFields, Direction } from '../../../../graphql/types';
@ -91,7 +91,7 @@ const TlsTableComponent = React.memo<TlsTableProps>(
field: getSortFromString(splitField[splitField.length - 1]),
direction: criteria.sort.direction as Direction,
};
if (!isEqual(newTlsSort, sort)) {
if (!deepEqual(newTlsSort, sort)) {
updateNetworkTable({
networkType: type,
tableType,
@ -103,10 +103,12 @@ const TlsTableComponent = React.memo<TlsTableProps>(
[sort, type, tableType, updateNetworkTable]
);
const columns = useMemo(() => getTlsColumns(tlsTableId), [tlsTableId]);
return (
<PaginatedTable
activePage={activePage}
columns={getTlsColumns(tlsTableId)}
columns={columns}
dataTestSubj={`table-${tableType}`}
showMorePagesIndicator={showMorePagesIndicator}
headerCount={totalCount}

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { networkActions } from '../../../../store/network';
import {
@ -97,7 +97,7 @@ const UsersTableComponent = React.memo<UsersTableProps>(
field: getSortFromString(splitField[splitField.length - 1]),
direction: criteria.sort.direction as Direction,
};
if (!isEqual(newUsersSort, sort)) {
if (!deepEqual(newUsersSort, sort)) {
updateNetworkTable({
networkType: type,
tableType,
@ -109,10 +109,15 @@ const UsersTableComponent = React.memo<UsersTableProps>(
[sort, type, updateNetworkTable]
);
const columns = useMemo(() => getUsersColumns(flowTarget, usersTableId), [
flowTarget,
usersTableId,
]);
return (
<PaginatedTable
activePage={activePage}
columns={getUsersColumns(flowTarget, usersTableId)}
columns={columns}
dataTestSubj={`table-${tableType}`}
showMorePagesIndicator={showMorePagesIndicator}
headerCount={totalCount}

View file

@ -266,6 +266,4 @@ const OverviewHostStatsComponent: React.FC<OverviewHostProps> = ({ data, loading
);
};
OverviewHostStatsComponent.displayName = 'OverviewHostStatsComponent';
export const OverviewHostStats = React.memo(OverviewHostStatsComponent);

View file

@ -130,7 +130,7 @@ const AccordionContent = styled.div`
margin-top: 8px;
`;
export const OverviewNetworkStats = React.memo<OverviewNetworkProps>(({ data, loading }) => {
const OverviewNetworkStatsComponent: React.FC<OverviewNetworkProps> = ({ data, loading }) => {
const allNetworkStats = getOverviewNetworkStats(data);
const allNetworkStatsCount = allNetworkStats.reduce((total, stat) => total + stat.count, 0);
@ -190,6 +190,6 @@ export const OverviewNetworkStats = React.memo<OverviewNetworkProps>(({ data, lo
})}
</NetworkStatsContainer>
);
});
};
OverviewNetworkStats.displayName = 'OverviewNetworkStats';
export const OverviewNetworkStats = React.memo(OverviewNetworkStatsComponent);

View file

@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import React, { memo, useState, useEffect, useMemo, useCallback } from 'react';
import deepEqual from 'fast-deep-equal';
import {
Filter,
@ -64,7 +64,7 @@ export const QueryBar = memo<QueryBarComponentProps>(
const onQuerySubmit = useCallback(
(payload: { dateRange: TimeRange; query?: Query }) => {
if (payload.query != null && !isEqual(payload.query, filterQuery)) {
if (payload.query != null && !deepEqual(payload.query, filterQuery)) {
onSubmitQuery(payload.query);
}
},
@ -73,7 +73,7 @@ export const QueryBar = memo<QueryBarComponentProps>(
const onQueryChange = useCallback(
(payload: { dateRange: TimeRange; query?: Query }) => {
if (payload.query != null && !isEqual(payload.query, draftQuery)) {
if (payload.query != null && !deepEqual(payload.query, draftQuery)) {
setDraftQuery(payload.query);
onChangedQuery(payload.query);
}

View file

@ -4,12 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { getOr, isEqual, set } from 'lodash/fp';
import { getOr, set } from 'lodash/fp';
import React, { memo, useEffect, useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { Dispatch } from 'redux';
import { Subscription } from 'rxjs';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
import { FilterManager, IIndexPattern, TimeRange, Query, Filter } from 'src/plugins/data/public';
import { SavedQuery } from 'src/legacy/core_plugins/data/public';
@ -60,7 +61,6 @@ const SearchBarComponent = memo<SiemSearchBarProps & PropsFromRedux>(
setSavedQuery,
setSearchBarFilter,
start,
timelineId,
toStr,
updateSearch,
dataTestSubj,
@ -108,7 +108,7 @@ const SearchBarComponent = memo<SiemSearchBarProps & PropsFromRedux>(
updateSearchBar.start = payload.dateRange.from;
}
if (payload.query != null && !isEqual(payload.query, filterQuery)) {
if (payload.query != null && !deepEqual(payload.query, filterQuery)) {
isStateUpdated = true;
updateSearchBar = set('query', payload.query, updateSearchBar);
}

View file

@ -5,8 +5,9 @@
*/
import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { isEmpty, isEqual, uniqWith } from 'lodash/fp';
import { isEmpty, uniqWith } from 'lodash/fp';
import React from 'react';
import deepEqual from 'fast-deep-equal';
import { DESTINATION_IP_FIELD_NAME, SOURCE_IP_FIELD_NAME } from '../ip';
import { DESTINATION_PORT_FIELD_NAME, SOURCE_PORT_FIELD_NAME, Port } from '../port';
@ -115,7 +116,7 @@ const IpAdressesWithPorts = React.memo<{
return (
<EuiFlexGroup gutterSize="none">
{uniqWith(isEqual, ipPortPairs).map(
{uniqWith(deepEqual, ipPortPairs).map(
ipPortPair =>
ipPortPair.ip != null && (
<EuiFlexItem grow={false} key={ipPortPair.ip}>

View file

@ -94,7 +94,6 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] =
isInspected={false}
loading={false}
queryId="statItems"
refetch={null}
selectedInspectIndex={0}
setIsInspected={[Function]}
title="KPI HOSTS"
@ -328,7 +327,6 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] =
isInspected={false}
loading={false}
queryId="statItems"
refetch={null}
selectedInspectIndex={0}
setIsInspected={[Function]}
title="KPI HOSTS"
@ -632,7 +630,6 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
isInspected={false}
loading={false}
queryId="statItems"
refetch={null}
selectedInspectIndex={0}
setIsInspected={[Function]}
title="KPI UNIQUE_PRIVATE_IPS"

View file

@ -8,7 +8,7 @@ exports[`Timeline rendering renders correctly against snapshot 1`] = `
justifyContent="flexStart"
>
<WrappedByAutoSizer>
<TimelineHeader
<Memo(TimelineHeaderComponent)
browserFields={
Object {
"agent": Object {

View file

@ -47,7 +47,7 @@ const TimelineHeaderContainer = styled.div`
TimelineHeaderContainer.displayName = 'TimelineHeaderContainer';
export const TimelineHeaderComponent = ({
export const TimelineHeaderComponent: React.FC<Props> = ({
browserFields,
id,
indexPattern,
@ -60,7 +60,7 @@ export const TimelineHeaderComponent = ({
onToggleDataProviderExcluded,
show,
showCallOutUnauthorizedMsg,
}: Props) => (
}) => (
<TimelineHeaderContainer data-test-subj="timelineHeader">
{showCallOutUnauthorizedMsg && (
<EuiCallOut
@ -91,8 +91,4 @@ export const TimelineHeaderComponent = ({
</TimelineHeaderContainer>
);
TimelineHeaderComponent.displayName = 'TimelineHeaderComponent';
export const TimelineHeader = React.memo(TimelineHeaderComponent);
TimelineHeader.displayName = 'TimelineHeader';

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import React, { useEffect, useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { WithSource } from '../../containers/source';
import { useSignalIndex } from '../../containers/detection_engine/signals/use_signal_index';
@ -215,11 +215,11 @@ const StatefulTimelineComponent = React.memo<Props>(
prevProps.show === nextProps.show &&
prevProps.showCallOutUnauthorizedMsg === nextProps.showCallOutUnauthorizedMsg &&
prevProps.start === nextProps.start &&
isEqual(prevProps.columns, nextProps.columns) &&
isEqual(prevProps.dataProviders, nextProps.dataProviders) &&
isEqual(prevProps.filters, nextProps.filters) &&
isEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) &&
isEqual(prevProps.sort, nextProps.sort)
deepEqual(prevProps.columns, nextProps.columns) &&
deepEqual(prevProps.dataProviders, nextProps.dataProviders) &&
deepEqual(prevProps.filters, nextProps.filters) &&
deepEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) &&
deepEqual(prevProps.sort, nextProps.sort)
);
}
);

View file

@ -4,9 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual, isEmpty } from 'lodash/fp';
import { isEmpty } from 'lodash/fp';
import React, { memo, useCallback, useState, useEffect } from 'react';
import { Subscription } from 'rxjs';
import deepEqual from 'fast-deep-equal';
import {
IIndexPattern,
@ -127,7 +128,7 @@ export const QueryBarTimeline = memo<QueryBarTimelineComponentProps>(
const filterWithoutDropArea = filterManager
.getFilters()
.filter((f: Filter) => f.meta.controlledBy !== timelineFilterDropArea);
if (!isEqual(filters, filterWithoutDropArea)) {
if (!deepEqual(filters, filterWithoutDropArea)) {
filterManager.setFilters(filters);
}
}, [filters]);

View file

@ -4,10 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { getOr, isEqual } from 'lodash/fp';
import { getOr } from 'lodash/fp';
import React, { useCallback } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { Dispatch } from 'redux';
import deepEqual from 'fast-deep-equal';
import { Filter, IIndexPattern } from '../../../../../../../../src/plugins/data/public';
import { BrowserFields } from '../../../containers/source';
@ -152,15 +153,15 @@ const StatefulSearchOrFilterComponent = React.memo<Props>(
prevProps.isRefreshPaused === nextProps.isRefreshPaused &&
prevProps.refreshInterval === nextProps.refreshInterval &&
prevProps.timelineId === nextProps.timelineId &&
isEqual(prevProps.browserFields, nextProps.browserFields) &&
isEqual(prevProps.dataProviders, nextProps.dataProviders) &&
isEqual(prevProps.filters, nextProps.filters) &&
isEqual(prevProps.filterQuery, nextProps.filterQuery) &&
isEqual(prevProps.filterQueryDraft, nextProps.filterQueryDraft) &&
isEqual(prevProps.indexPattern, nextProps.indexPattern) &&
isEqual(prevProps.kqlMode, nextProps.kqlMode) &&
isEqual(prevProps.savedQueryId, nextProps.savedQueryId) &&
isEqual(prevProps.timelineId, nextProps.timelineId)
deepEqual(prevProps.browserFields, nextProps.browserFields) &&
deepEqual(prevProps.dataProviders, nextProps.dataProviders) &&
deepEqual(prevProps.filters, nextProps.filters) &&
deepEqual(prevProps.filterQuery, nextProps.filterQuery) &&
deepEqual(prevProps.filterQueryDraft, nextProps.filterQueryDraft) &&
deepEqual(prevProps.indexPattern, nextProps.indexPattern) &&
deepEqual(prevProps.kqlMode, nextProps.kqlMode) &&
deepEqual(prevProps.savedQueryId, nextProps.savedQueryId) &&
deepEqual(prevProps.timelineId, nextProps.timelineId)
);
}
);

View file

@ -229,8 +229,4 @@ export const TimelineComponent: React.FC<Props> = ({
);
};
TimelineComponent.displayName = 'TimelineComponent';
export const Timeline = React.memo(TimelineComponent);
Timeline.displayName = 'Timeline';

View file

@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import React from 'react';
import { compose, Dispatch } from 'redux';
import { connect } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { timelineActions } from '../../store/actions';
import { RouteSpyState } from '../../utils/route/types';
@ -39,7 +39,7 @@ export const UrlStateRedux = compose<React.ComponentClass<UrlStateProps & RouteS
React.memo(
UrlStateContainer,
(prevProps, nextProps) =>
prevProps.pathName === nextProps.pathName && isEqual(prevProps.urlState, nextProps.urlState)
prevProps.pathName === nextProps.pathName && deepEqual(prevProps.urlState, nextProps.urlState)
)
);

View file

@ -4,8 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual, difference, isEmpty } from 'lodash/fp';
import { difference, isEmpty } from 'lodash/fp';
import { useEffect, useRef, useState } from 'react';
import deepEqual from 'fast-deep-equal';
import { useKibana } from '../../lib/kibana';
import { useApolloClient } from '../../utils/apollo_context';
@ -77,7 +78,7 @@ export const useUrlStateHooks = ({
const updatedUrlStateString =
getParamFromQueryString(getQueryStringFromLocation(mySearch), urlKey) ??
newUrlStateString;
if (isInitializing || !isEqual(updatedUrlStateString, newUrlStateString)) {
if (isInitializing || !deepEqual(updatedUrlStateString, newUrlStateString)) {
urlStateToUpdate = [
...urlStateToUpdate,
{
@ -157,7 +158,7 @@ export const useUrlStateHooks = ({
if (isInitializing && pageName != null && pageName !== '') {
handleInitialize(type);
setIsInitializing(false);
} else if (!isEqual(urlState, prevProps.urlState) && !isInitializing) {
} else if (!deepEqual(urlState, prevProps.urlState) && !isInitializing) {
let mySearch = search;
URL_STATE_KEYS[type].forEach((urlKey: KeyUrlState) => {
if (

View file

@ -4,8 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEmpty, isEqual, get } from 'lodash/fp';
import { isEmpty, get } from 'lodash/fp';
import { useEffect, useState, Dispatch, SetStateAction } from 'react';
import deepEqual from 'fast-deep-equal';
import { IIndexPattern } from '../../../../../../../../src/plugins/data/public';
import {
@ -41,7 +42,7 @@ export const useFetchIndexPatterns = (defaultIndices: string[] = []): Return =>
const [, dispatchToaster] = useStateToaster();
useEffect(() => {
if (!isEqual(defaultIndices, indices)) {
if (!deepEqual(defaultIndices, indices)) {
setIndices(defaultIndices);
}
}, [defaultIndices, indices]);

View file

@ -4,7 +4,7 @@
* 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, ConnectedProps } from 'react-redux';
import { inputsModel, inputsSelectors, State } from '../../store';
@ -41,6 +41,17 @@ export const GlobalTimeComponent: React.FC<GlobalTimeProps> = ({
}) => {
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);
@ -56,9 +67,8 @@ export const GlobalTimeComponent: React.FC<GlobalTimeProps> = ({
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,
})}
</>
);

View file

@ -5,10 +5,10 @@
*/
import { ApolloQueryResult, NetworkStatus } from 'apollo-client';
import { isEqual } from 'lodash/fp';
import memoizeOne from 'memoize-one';
import React from 'react';
import { FetchMoreOptions, FetchMoreQueryOptions, OperationVariables } from 'react-apollo';
import deepEqual from 'fast-deep-equal';
import { ESQuery } from '../../common/typed_json';
import { inputsModel } from '../store/model';
@ -85,7 +85,7 @@ export class QueryTemplatePaginated<
public isItAValidLoading(loading: boolean, variables: TVariables, networkStatus: NetworkStatus) {
if (
!this.myLoading &&
(!isEqual(variables, this.queryVariables) || networkStatus === NetworkStatus.refetch) &&
(!deepEqual(variables, this.queryVariables) || networkStatus === NetworkStatus.refetch) &&
loading
) {
this.myLoading = true;

View file

@ -10,6 +10,7 @@ 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 { useUiSetting$ } from '../../lib/kibana';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';

View file

@ -12,9 +12,11 @@ import {
HistogramBarSeries,
Position,
Settings,
ChartSizeArray,
} from '@elastic/charts';
import React from 'react';
import React, { useMemo } from 'react';
import { EuiProgress } from '@elastic/eui';
import { useTheme } from '../../../../components/charts/common';
import { histogramDateTimeFormatter } from '../../../../components/utils';
import { HistogramData } from './types';
@ -43,6 +45,14 @@ export const SignalsHistogram = React.memo<HistogramSignalsProps>(
}) => {
const theme = useTheme();
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 && (
@ -54,7 +64,7 @@ export const SignalsHistogram = React.memo<HistogramSignalsProps>(
/>
)}
<Chart size={['100%', chartHeight]}>
<Chart size={chartSize}>
<Settings
legendPosition={legendPosition}
onBrushEnd={updateDateRange}
@ -62,21 +72,17 @@ export const SignalsHistogram = React.memo<HistogramSignalsProps>(
theme={theme}
/>
<Axis
id={getAxisId('signalsHistogramAxisX')}
position="bottom"
tickFormat={histogramDateTimeFormatter([from, to])}
/>
<Axis id={xAxisId} position="bottom" tickFormat={tickFormat} />
<Axis id={getAxisId('signalsHistogramAxisY')} position="left" />
<Axis id={yAxisId} position="left" />
<HistogramBarSeries
id={getSpecId('signalsHistogram')}
id={id}
xScaleType="time"
yScaleType="linear"
xAccessor="x"
yAccessors={['y']}
splitSeriesAccessors={['g']}
yAccessors={yAccessors}
splitSeriesAccessors={splitSeriesAccessors}
data={data}
/>
</Chart>
@ -84,4 +90,5 @@ export const SignalsHistogram = React.memo<HistogramSignalsProps>(
);
}
);
SignalsHistogram.displayName = 'SignalsHistogram';

View file

@ -5,10 +5,10 @@
*/
import { EuiFormRow, EuiMutationObserver } from '@elastic/eui';
import { isEqual } from 'lodash/fp';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Subscription } from 'rxjs';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
import {
Filter,
@ -99,7 +99,7 @@ export const QueryBarDefineRule = ({
const newFilters = filterManager.getFilters();
const { filters } = field.value as FieldValueQueryBar;
if (!isEqual(filters, newFilters)) {
if (!deepEqual(filters, newFilters)) {
field.setValue({ ...(field.value as FieldValueQueryBar), filters: newFilters });
}
}
@ -117,10 +117,10 @@ export const QueryBarDefineRule = ({
let isSubscribed = true;
async function updateFilterQueryFromValue() {
const { filters, query, saved_id: savedId } = field.value as FieldValueQueryBar;
if (!isEqual(query, queryDraft)) {
if (!deepEqual(query, queryDraft)) {
setQueryDraft(query);
}
if (!isEqual(filters, filterManager.getFilters())) {
if (!deepEqual(filters, filterManager.getFilters())) {
filterManager.setFilters(filters);
}
if (
@ -148,7 +148,7 @@ export const QueryBarDefineRule = ({
const onSubmitQuery = useCallback(
(newQuery: Query, timefilter?: SavedQueryTimeFilter) => {
const { query } = field.value as FieldValueQueryBar;
if (!isEqual(query, newQuery)) {
if (!deepEqual(query, newQuery)) {
field.setValue({ ...(field.value as FieldValueQueryBar), query: newQuery });
}
},
@ -158,7 +158,7 @@ export const QueryBarDefineRule = ({
const onChangedQuery = useCallback(
(newQuery: Query) => {
const { query } = field.value as FieldValueQueryBar;
if (!isEqual(query, newQuery)) {
if (!deepEqual(query, newQuery)) {
field.setValue({ ...(field.value as FieldValueQueryBar), query: newQuery });
}
},

View file

@ -12,8 +12,8 @@ import {
EuiLoadingSpinner,
EuiText,
} from '@elastic/eui';
import { isEqual } from 'lodash/fp';
import React, { memo, useCallback, useEffect, useState } from 'react';
import deepEqual from 'fast-deep-equal';
import { useRuleStatus, RuleInfoStatus } from '../../../../../containers/detection_engine/rules';
import { FormattedDate } from '../../../../../components/formatted_date';
@ -43,7 +43,7 @@ const RuleStatusComponent: React.FC<RuleStatusProps> = ({ ruleId, ruleEnabled })
}, [fetchRuleStatus, myRuleEnabled, ruleId, ruleEnabled, setMyRuleEnabled]);
useEffect(() => {
if (!isEqual(currentStatus, ruleStatus?.current_status)) {
if (!deepEqual(currentStatus, ruleStatus?.current_status)) {
setCurrentStatus(ruleStatus?.current_status ?? null);
}
}, [currentStatus, ruleStatus, setCurrentStatus]);

View file

@ -13,9 +13,9 @@ import {
EuiSpacer,
EuiButtonEmpty,
} from '@elastic/eui';
import { isEqual } from 'lodash/fp';
import React, { FC, memo, useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
import { setFieldValue } from '../../helpers';
import { RuleStepProps, RuleStep, AboutStepRule } from '../../types';
@ -103,7 +103,7 @@ const StepAboutRuleComponent: FC<StepAboutRuleProps> = ({
useEffect(() => {
const { isNew, ...initDefaultValue } = myStepData;
if (defaultValues != null && !isEqual(initDefaultValue, defaultValues)) {
if (defaultValues != null && !deepEqual(initDefaultValue, defaultValues)) {
const myDefaultValues = {
...defaultValues,
isNew: false,

View file

@ -11,9 +11,10 @@ import {
EuiFlexItem,
EuiButton,
} from '@elastic/eui';
import { isEmpty, isEqual } from 'lodash/fp';
import { isEmpty } from 'lodash/fp';
import React, { FC, memo, useCallback, useState, useEffect } from 'react';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
import { IIndexPattern } from '../../../../../../../../../../src/plugins/data/public';
import { useFetchIndexPatterns } from '../../../../../containers/detection_engine/rules';
@ -126,9 +127,9 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
useEffect(() => {
if (indicesConfig != null && defaultValues != null) {
const myDefaultValues = getStepDefaultValue(indicesConfig, defaultValues);
if (!isEqual(myDefaultValues, myStepData)) {
if (!deepEqual(myDefaultValues, myStepData)) {
setMyStepData(myDefaultValues);
setLocalUseIndicesConfig(isEqual(myDefaultValues.index, indicesConfig));
setLocalUseIndicesConfig(deepEqual(myDefaultValues.index, indicesConfig));
setFieldValue(form, schema, myDefaultValues);
}
}
@ -212,13 +213,13 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
<FormDataProvider pathsToWatch="index">
{({ index }) => {
if (index != null) {
if (isEqual(index, indicesConfig) && !localUseIndicesConfig) {
if (deepEqual(index, indicesConfig) && !localUseIndicesConfig) {
setLocalUseIndicesConfig(true);
}
if (!isEqual(index, indicesConfig) && localUseIndicesConfig) {
if (!deepEqual(index, indicesConfig) && localUseIndicesConfig) {
setLocalUseIndicesConfig(false);
}
if (index != null && !isEmpty(index) && !isEqual(index, mylocalIndicesConfig)) {
if (index != null && !isEmpty(index) && !deepEqual(index, mylocalIndicesConfig)) {
setMyLocalIndicesConfig(index);
}
}

View file

@ -5,8 +5,8 @@
*/
import { EuiHorizontalRule, EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui';
import { isEqual } from 'lodash/fp';
import React, { FC, memo, useCallback, useEffect, useState } from 'react';
import deepEqual from 'fast-deep-equal';
import { setFieldValue } from '../../helpers';
import { RuleStep, RuleStepProps, ScheduleStepRule } from '../../types';
@ -62,7 +62,7 @@ const StepScheduleRuleComponent: FC<StepScheduleRuleProps> = ({
useEffect(() => {
const { isNew, ...initDefaultValue } = myStepData;
if (defaultValues != null && !isEqual(initDefaultValue, defaultValues)) {
if (defaultValues != null && !deepEqual(initDefaultValue, defaultValues)) {
const myDefaultValues = {
...defaultValues,
isNew: false,

View file

@ -73,32 +73,25 @@ export const HostDetailsTabs = React.memo<HostDetailsTabsProps>(
return (
<Switch>
<Route
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.authentications})`}
render={() => <AuthenticationsQueryTabBody {...tabProps} />}
/>
<Route
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.hosts})`}
render={() => <HostsQueryTabBody {...tabProps} />}
/>
<Route
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.uncommonProcesses})`}
render={() => <UncommonProcessQueryTabBody {...tabProps} />}
/>
<Route
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.anomalies})`}
render={() => (
<AnomaliesQueryTabBody {...tabProps} AnomaliesTableComponent={AnomaliesHostTable} />
)}
/>
<Route
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.events})`}
render={() => <EventsQueryTabBody {...tabProps} pageFilters={pageFilters} />}
/>
<Route
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.alerts})`}
render={() => <HostAlertsQueryTabBody {...tabProps} pageFilters={pageFilters} />}
/>
<Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.authentications})`}>
<AuthenticationsQueryTabBody {...tabProps} />
</Route>
<Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.hosts})`}>
<HostsQueryTabBody {...tabProps} />
</Route>
<Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.uncommonProcesses})`}>
<UncommonProcessQueryTabBody {...tabProps} />
</Route>
<Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.anomalies})`}>
<AnomaliesQueryTabBody {...tabProps} AnomaliesTableComponent={AnomaliesHostTable} />
</Route>
<Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.events})`}>
<EventsQueryTabBody {...tabProps} pageFilters={pageFilters} />
</Route>
<Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.alerts})`}>
<HostAlertsQueryTabBody {...tabProps} pageFilters={pageFilters} />
</Route>
</Switch>
);
}

View file

@ -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<HostsTabsProps>(
export const HostsTabs = memo<HostsTabsProps>(
({
deleteQuery,
filterQuery,
@ -44,49 +44,48 @@ const HostsTabs = memo<HostsTabsProps>(
startDate: from,
type,
indexPattern,
narrowDateRange: (score: Anomaly, interval: string) => {
const fromTo = scoreIntervalToDateTime(score, interval);
setAbsoluteRangeDatePicker({
id: 'global',
from: fromTo.from,
to: fromTo.to,
});
},
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 (
<Switch>
<Route
path={`${hostsPagePath}/:tabName(${HostsTableType.hosts})`}
render={() => <HostsQueryTabBody {...tabProps} />}
/>
<Route
path={`${hostsPagePath}/:tabName(${HostsTableType.authentications})`}
render={() => <AuthenticationsQueryTabBody {...tabProps} />}
/>
<Route
path={`${hostsPagePath}/:tabName(${HostsTableType.uncommonProcesses})`}
render={() => <UncommonProcessQueryTabBody {...tabProps} />}
/>
<Route
path={`${hostsPagePath}/:tabName(${HostsTableType.anomalies})`}
render={() => (
<AnomaliesQueryTabBody {...tabProps} AnomaliesTableComponent={AnomaliesHostTable} />
)}
/>
<Route
path={`${hostsPagePath}/:tabName(${HostsTableType.events})`}
render={() => <EventsQueryTabBody {...tabProps} />}
/>
<Route
path={`${hostsPagePath}/:tabName(${HostsTableType.alerts})`}
render={() => <HostAlertsQueryTabBody {...tabProps} />}
/>
<Route path={`${hostsPagePath}/:tabName(${HostsTableType.hosts})`}>
<HostsQueryTabBody {...tabProps} />
</Route>
<Route path={`${hostsPagePath}/:tabName(${HostsTableType.authentications})`}>
<AuthenticationsQueryTabBody {...tabProps} />
</Route>
<Route path={`${hostsPagePath}/:tabName(${HostsTableType.uncommonProcesses})`}>
<UncommonProcessQueryTabBody {...tabProps} />
</Route>
<Route path={`${hostsPagePath}/:tabName(${HostsTableType.anomalies})`}>
<AnomaliesQueryTabBody {...tabProps} AnomaliesTableComponent={AnomaliesHostTable} />
</Route>
<Route path={`${hostsPagePath}/:tabName(${HostsTableType.events})`}>
<EventsQueryTabBody {...tabProps} />
</Route>
<Route path={`${hostsPagePath}/:tabName(${HostsTableType.alerts})`}>
<HostAlertsQueryTabBody {...tabProps} />
</Route>
</Switch>
);
}
);
HostsTabs.displayName = 'HostsTabs';
export { HostsTabs };

View file

@ -23,77 +23,82 @@ import { TlsQueryTabBody } from './tls_query_tab_body';
import { Anomaly } from '../../../components/ml/types';
import { NetworkAlertsQueryTabBody } from './alerts_query_tab_body';
export const NetworkRoutes = ({
networkPagePath,
type,
to,
filterQuery,
isInitializing,
from,
indexPattern,
setQuery,
setAbsoluteRangeDatePicker,
}: NetworkRoutesProps) => {
const narrowDateRange = useCallback(
(score: Anomaly, interval: string) => {
const fromTo = scoreIntervalToDateTime(score, interval);
setAbsoluteRangeDatePicker({
id: 'global',
from: fromTo.from,
to: fromTo.to,
});
},
[setAbsoluteRangeDatePicker]
);
const networkAnomaliesFilterQuery = {
bool: {
should: [
{
exists: {
field: 'source.ip',
},
},
{
exists: {
field: 'destination.ip',
},
},
],
minimum_should_match: 1,
},
};
const commonProps = {
startDate: from,
endDate: to,
skip: isInitializing,
export const NetworkRoutes = React.memo<NetworkRoutesProps>(
({
networkPagePath,
type,
narrowDateRange,
setQuery,
to,
filterQuery,
};
const tabProps = {
...commonProps,
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 anomaliesProps = {
...commonProps,
anomaliesFilterQuery: networkAnomaliesFilterQuery,
AnomaliesTableComponent: AnomaliesNetworkTable,
};
const networkAnomaliesFilterQuery = {
bool: {
should: [
{
exists: {
field: 'source.ip',
},
},
{
exists: {
field: 'destination.ip',
},
},
],
minimum_should_match: 1,
},
};
return (
<Switch>
<Route
path={`${networkPagePath}/:tabName(${NetworkRouteType.dns})`}
render={() => <DnsQueryTabBody {...tabProps} />}
/>
<Route
path={`${networkPagePath}/:tabName(${NetworkRouteType.flows})`}
render={() => (
const commonProps = {
startDate: from,
endDate: to,
skip: isInitializing,
type,
narrowDateRange,
setQuery,
filterQuery,
};
const tabProps = {
...commonProps,
indexPattern,
updateDateRange,
};
const anomaliesProps = {
...commonProps,
anomaliesFilterQuery: networkAnomaliesFilterQuery,
AnomaliesTableComponent: AnomaliesNetworkTable,
};
return (
<Switch>
<Route path={`${networkPagePath}/:tabName(${NetworkRouteType.dns})`}>
<DnsQueryTabBody {...tabProps} />
</Route>
<Route path={`${networkPagePath}/:tabName(${NetworkRouteType.flows})`}>
<>
<ConditionalFlexGroup direction="column">
<EuiFlexItem>
@ -118,31 +123,25 @@ export const NetworkRoutes = ({
</EuiFlexItem>
</ConditionalFlexGroup>
</>
)}
/>
<Route
path={`${networkPagePath}/:tabName(${NetworkRouteType.http})`}
render={() => <HttpQueryTabBody {...tabProps} />}
/>
<Route
path={`${networkPagePath}/:tabName(${NetworkRouteType.tls})`}
render={() => <TlsQueryTabBody {...tabProps} flowTarget={FlowTargetSourceDest.source} />}
/>
<Route
path={`${networkPagePath}/:tabName(${NetworkRouteType.anomalies})`}
render={() => (
</Route>
<Route path={`${networkPagePath}/:tabName(${NetworkRouteType.http})`}>
<HttpQueryTabBody {...tabProps} />
</Route>
<Route path={`${networkPagePath}/:tabName(${NetworkRouteType.tls})`}>
<TlsQueryTabBody {...tabProps} flowTarget={FlowTargetSourceDest.source} />
</Route>
<Route path={`${networkPagePath}/:tabName(${NetworkRouteType.anomalies})`}>
<AnomaliesQueryTabBody
{...anomaliesProps}
AnomaliesTableComponent={AnomaliesNetworkTable}
/>
)}
/>
<Route
path={`${networkPagePath}/:tabName(${NetworkRouteType.alerts})`}
render={() => <NetworkAlertsQueryTabBody {...tabProps} />}
/>
</Switch>
);
};
</Route>
<Route path={`${networkPagePath}/:tabName(${NetworkRouteType.alerts})`}>
<NetworkAlertsQueryTabBody {...tabProps} />
</Route>
</Switch>
);
}
);
NetworkRoutes.displayName = 'NetworkRoutes';

View file

@ -20,8 +20,12 @@ const PageRouterComponent: FC<RouterProps> = ({ history }) => (
<ManageRoutesSpy>
<Router history={history}>
<Switch>
<Route path="/" render={() => <HomePage />} />
<Route render={() => <NotFoundPage />} />
<Route path="/">
<HomePage />
</Route>
<Route>
<NotFoundPage />
</Route>
</Switch>
</Router>
</ManageRoutesSpy>

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isEqual } from 'lodash/fp';
import { Dispatch } from 'redux';
import { IIndexPattern } from 'src/plugins/data/public';
import deepEqual from 'fast-deep-equal';
import { KueryFilterQuery } from '../../store';
import { applyKqlFilterQuery as dispatchApplyTimelineFilterQuery } from '../../store/timeline/actions';
@ -29,7 +29,7 @@ export const useUpdateKql = ({
timelineId,
}: UseUpdateKqlProps): RefetchKql => {
const updateKql: RefetchKql = (dispatch: Dispatch) => {
if (kueryFilterQueryDraft != null && !isEqual(kueryFilterQuery, kueryFilterQueryDraft)) {
if (kueryFilterQueryDraft != null && !deepEqual(kueryFilterQuery, kueryFilterQueryDraft)) {
if (storeType === 'timelineType' && timelineId != null) {
dispatch(
dispatchApplyTimelineFilterQuery({

View file

@ -5,7 +5,6 @@
*/
import * as H from 'history';
import { isEqual } from 'lodash/fp';
import { memo, useEffect, useState } from 'react';
import { withRouter } from 'react-router-dom';
import deepEqual from 'fast-deep-equal';
@ -35,7 +34,7 @@ export const SpyRouteComponent = memo<SpyRouteProps & { location: H.Location }>(
}
}, [search]);
useEffect(() => {
if (pageName && !isEqual(route.pathName, pathname)) {
if (pageName && !deepEqual(route.pathName, pathname)) {
if (isInitializing && detailName == null) {
dispatch({
type: 'updateRouteWithOutSearch',

View file

@ -106,6 +106,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",

View file

@ -36,7 +36,7 @@
"x-pack/test_utils/*"
],
"plugins/*": ["src/legacy/core_plugins/*/public/"],
"fixtures/*": ["src/fixtures/*"]
"fixtures/*": ["src/fixtures/*"],
},
"types": [
"node",

View file

@ -5684,6 +5684,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"
@ -19767,7 +19774,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==