diff --git a/x-pack/legacy/plugins/siem/public/components/flow_controls/flow_target_select.tsx b/x-pack/legacy/plugins/siem/public/components/flow_controls/flow_target_select.tsx index b1c463fdc32f40..f5dd4650159cd3 100644 --- a/x-pack/legacy/plugins/siem/public/components/flow_controls/flow_target_select.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flow_controls/flow_target_select.tsx @@ -5,7 +5,7 @@ */ import { EuiSuperSelect } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback } from 'react'; import { ActionCreator } from 'typescript-fsa'; import { FlowDirection, FlowTarget } from '../../graphql/types'; @@ -65,22 +65,27 @@ export const FlowTargetSelect = React.memo( selectedTarget, displayTextOverride = [], updateFlowTargetAction, - }) => ( - - option.directions.includes(selectedDirection) - ) - : toggleTargetOptions(id, displayTextOverride) - } - valueOfSelected={selectedTarget} - onChange={(newFlowTarget: FlowTarget) => - onChangeTarget(newFlowTarget, updateFlowTargetAction) - } - isLoading={isLoading} - /> - ) + }) => { + const handleChange = useCallback( + (newFlowTarget: FlowTarget) => onChangeTarget(newFlowTarget, updateFlowTargetAction), + [updateFlowTargetAction] + ); + + return ( + + option.directions.includes(selectedDirection) + ) + : toggleTargetOptions(id, displayTextOverride) + } + valueOfSelected={selectedTarget} + onChange={handleChange} + isLoading={isLoading} + /> + ); + } ); FlowTargetSelect.displayName = 'FlowTargetSelect'; 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 6908aba542e4ca..04d6d94d6624d6 100644 --- a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx @@ -6,7 +6,7 @@ import { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; import { getOr } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; import styled from 'styled-components'; @@ -72,72 +72,71 @@ const InspectButtonComponent = React.memo( setIsInspected, show, title = '', - }: InspectButtonProps) => ( - - {inputId === 'timeline' && !compact && ( - { - setIsInspected({ - id: queryId, - inputId, - isInspected: true, - selectedInspectIndex: inspectIndex, - }); - }} - > - {i18n.INSPECT} - - )} - {(inputId === 'global' || compact) && ( - { - setIsInspected({ - id: queryId, - inputId, - isInspected: true, - selectedInspectIndex: inspectIndex, - }); - }} - /> - )} - { - if (onCloseInspect != null) { - onCloseInspect(); + }: InspectButtonProps) => { + const handleClick = useCallback(() => { + setIsInspected({ + id: queryId, + inputId, + isInspected: true, + selectedInspectIndex: inspectIndex, + }); + }, [setIsInspected, queryId, inputId, inspectIndex]); + + const handleCloseModal = useCallback(() => { + if (onCloseInspect != null) { + onCloseInspect(); + } + setIsInspected({ + id: queryId, + inputId, + isInspected: false, + selectedInspectIndex: inspectIndex, + }); + }, [onCloseInspect, setIsInspected, queryId, inputId, inspectIndex]); + + return ( + + {inputId === 'timeline' && !compact && ( + + {i18n.INSPECT} + + )} + {(inputId === 'global' || compact) && ( + + )} + 0 ? inspect.dsl[inspectIndex] : null} + response={ + inspect != null && inspect.response.length > 0 ? inspect.response[inspectIndex] : null } - setIsInspected({ - id: queryId, - inputId, - isInspected: false, - selectedInspectIndex: inspectIndex, - }); - }} - isShowing={!loading && selectedInspectIndex === inspectIndex && isInspected} - request={inspect != null && inspect.dsl.length > 0 ? inspect.dsl[inspectIndex] : null} - response={ - inspect != null && inspect.response.length > 0 ? inspect.response[inspectIndex] : null - } - title={title} - data-test-subj="inspect-modal" - /> - - ) + title={title} + data-test-subj="inspect-modal" + /> + + ); + } ); InspectButtonComponent.displayName = 'InspectButtonComponent'; 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 f79c61a29c26b4..25af0a03f4aba9 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 @@ -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, { useState, useEffect, useCallback } from 'react'; import { ScaleType } from '@elastic/charts'; import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; @@ -56,12 +56,15 @@ export const MatrixHistogram = ({ } }, [loading]); + const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); + const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); + return ( setShowInspect(true)} - onMouseLeave={() => setShowInspect(false)} + onMouseEnter={handleOnMouseEnter} + onMouseLeave={handleOnMouseLeave} > ( - - snapshot.isDragging ? ( - - - - ) : ( - <> - {index !== 0 && ( - <> - {','} - - - )} - {getScoreString(score.severity)} - - ) - } - /> -); +}): JSX.Element => { + const scoreString = getScoreString(score.severity); + + return ( + + snapshot.isDragging ? ( + + + + ) : ( + <> + {index !== 0 && ( + <> + {','} + + + )} + {scoreString} + + ) + } + /> + ); +}; DraggableScoreComponent.displayName = 'DraggableScoreComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx b/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx index 74e61f27fb2d19..be2c824564c950 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import React, { Dispatch, SetStateAction, useEffect, useState, useCallback } from 'react'; import { EuiFilterButton, @@ -42,6 +42,21 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab onFilterChanged({ filterQuery, showCustomJobs, showElasticJobs, selectedGroups }); }, [filterQuery, selectedGroups.sort().join(), showCustomJobs, showElasticJobs]); + const handleChange = useCallback( + (query: EuiSearchBarQuery) => setFilterQuery(query.queryText.trim()), + [setFilterQuery] + ); + + const handleElasticJobsClick = useCallback(() => { + setShowElasticJobs(!showElasticJobs); + setShowCustomJobs(false); + }, [setShowElasticJobs, showElasticJobs, setShowCustomJobs]); + + const handleCustomJobsClick = useCallback(() => { + setShowCustomJobs(!showCustomJobs); + setShowElasticJobs(false); + }, [setShowElasticJobs, showCustomJobs, setShowCustomJobs]); + return ( @@ -51,7 +66,7 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab placeholder: i18n.FILTER_PLACEHOLDER, incremental: true, }} - onChange={(query: EuiSearchBarQuery) => setFilterQuery(query.queryText.trim())} + onChange={handleChange} /> @@ -65,10 +80,7 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab { - setShowElasticJobs(!showElasticJobs); - setShowCustomJobs(false); - }} + onClick={handleElasticJobsClick} data-test-subj="show-elastic-jobs-filter-button" withNext > @@ -76,10 +88,7 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab { - setShowCustomJobs(!showCustomJobs); - setShowElasticJobs(false); - }} + onClick={handleCustomJobsClick} data-test-subj="show-custom-jobs-filter-button" > {i18n.SHOW_CUSTOM_JOBS} diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/job_switch.tsx b/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/job_switch.tsx index c915bf04126ec4..0d503e2db3d9d1 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/job_switch.tsx +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/job_switch.tsx @@ -5,7 +5,7 @@ */ import styled from 'styled-components'; -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSwitch } from '@elastic/eui'; import { SiemJob } from '../types'; @@ -47,6 +47,13 @@ export const JobSwitchComponent = ({ onJobStateChange, }: JobSwitchProps) => { const [isLoading, setIsLoading] = useState(false); + const handleChange = useCallback( + e => { + setIsLoading(true); + onJobStateChange(job, job.latestTimestampMs || 0, e.target.checked); + }, + [job, setIsLoading, onJobStateChange] + ); return ( @@ -58,10 +65,7 @@ export const JobSwitchComponent = ({ data-test-subj="job-switch" disabled={isFailure(job.jobState, job.datafeedState)} checked={isChecked(job.jobState, job.datafeedState)} - onChange={e => { - setIsLoading(true); - onJobStateChange(job, job.latestTimestampMs || 0, e.target.checked); - }} + onChange={handleChange} showLabel={false} label="" /> diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx index d405ec404b1112..421b4c8bef4e3b 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx @@ -5,11 +5,39 @@ */ import { EuiTab, EuiTabs } from '@elastic/eui'; import { getOr } from 'lodash/fp'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useCallback, useMemo } from 'react'; import { trackUiAction as track, METRIC_TYPE, TELEMETRY_EVENT } from '../../../lib/track_usage'; import { getSearch } from '../helpers'; -import { TabNavigationProps } from './types'; +import { TabNavigationProps, TabNavigationItemProps } from './types'; + +const TabNavigationItemComponent = ({ + href, + hrefWithSearch, + id, + disabled, + name, + isSelected, +}: TabNavigationItemProps) => { + const handleClick = useCallback(() => { + track(METRIC_TYPE.CLICK, `${TELEMETRY_EVENT.TAB_CLICKED}${id}`); + }, [id]); + + return ( + + {name} + + ); +}; + +const TabNavigationItem = React.memo(TabNavigationItemComponent); export const TabNavigationComponent = (props: TabNavigationProps) => { const { display, navTabs, pageName, tabName } = props; @@ -33,24 +61,28 @@ export const TabNavigationComponent = (props: TabNavigationProps) => { // we do need navTabs in case the selectedTabId appears after initial load (ex. checking permissions for anomalies) }, [pageName, tabName, navTabs]); - const renderTabs = (): JSX.Element[] => - Object.values(navTabs).map(tab => ( - { - track(METRIC_TYPE.CLICK, `${TELEMETRY_EVENT.TAB_CLICKED}${tab.id}`); - }} - > - {tab.name} - - )); - - return {renderTabs()}; + const renderTabs = useMemo( + () => + Object.values(navTabs).map(tab => { + const isSelected = selectedTabId === tab.id; + const hrefWithSearch = tab.href + getSearch(tab, props); + + return ( + + ); + }), + [navTabs] + ); + + return {renderTabs}; }; TabNavigationComponent.displayName = 'TabNavigationComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts index 1283691e658065..3fac783b550479 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts +++ b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts @@ -22,3 +22,12 @@ export interface TabNavigationProps extends SiemNavigationProps { [CONSTANTS.timerange]: UrlInputsModel; [CONSTANTS.timeline]: Timeline; } + +export interface TabNavigationItemProps { + href: string; + hrefWithSearch: string; + id: string; + disabled: boolean; + name: string; + isSelected: boolean; +} diff --git a/x-pack/legacy/plugins/siem/public/components/notes/add_note/index.tsx b/x-pack/legacy/plugins/siem/public/components/notes/add_note/index.tsx index 6e13538cf9beab..28cab2b46755f8 100644 --- a/x-pack/legacy/plugins/siem/public/components/notes/add_note/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/notes/add_note/index.tsx @@ -5,7 +5,7 @@ */ import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import * as React from 'react'; +import React, { useCallback } from 'react'; import styled from 'styled-components'; import { MarkdownHint } from '../../markdown/markdown_hint'; @@ -49,38 +49,44 @@ export const AddNote = React.memo<{ onCancelAddNote?: () => void; updateNewNote: UpdateInternalNewNote; updateNote: UpdateNote; -}>(({ associateNote, getNewNoteId, newNote, onCancelAddNote, updateNewNote, updateNote }) => ( - - - - 0} /> - - - {onCancelAddNote != null ? ( +}>(({ associateNote, getNewNoteId, newNote, onCancelAddNote, updateNewNote, updateNote }) => { + const handleClick = useCallback( + () => + updateAndAssociateNode({ + associateNote, + getNewNoteId, + newNote, + updateNewNote, + updateNote, + }), + [associateNote, getNewNoteId, newNote, updateNewNote, updateNote] + ); + + return ( + + + + 0} /> + + + {onCancelAddNote != null ? ( + + + + ) : null} - + + {i18n.ADD_NOTE} + - ) : null} - - - updateAndAssociateNode({ - associateNote, - getNewNoteId, - newNote, - updateNewNote, - updateNote, - }) - } - > - {i18n.ADD_NOTE} - - - - -)); + + + ); +}); AddNote.displayName = 'AddNote'; 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 7efcde5b89c675..d49d7784bb1ee9 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 @@ -5,7 +5,7 @@ */ import { has } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; @@ -98,39 +98,49 @@ const AuthenticationTableComponent = React.memo( type, updateTableActivePage, updateTableLimit, - }) => ( - loadPage(newActivePage)} - pageOfItems={data} - showMorePagesIndicator={showMorePagesIndicator} - totalCount={fakeTotalCount} - updateLimitPagination={newLimit => + }) => { + const updateLimitPagination = useCallback( + newLimit => updateTableLimit({ hostsType: type, limit: newLimit, tableType, - }) - } - updateActivePage={newPage => + }), + [type] + ); + + const updateActivePage = useCallback( + newPage => updateTableActivePage({ activePage: newPage, hostsType: type, tableType, - }) - } - /> - ) + }), + [type] + ); + + return ( + + ); + } ); AuthenticationTableComponent.displayName = 'AuthenticationTableComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/host_overview/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/host_overview/index.tsx index ba953d8e74b29d..437d14edeb5c8d 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/host_overview/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/host_overview/index.tsx @@ -8,7 +8,7 @@ import { EuiFlexItem } from '@elastic/eui'; import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; import { getOr } from 'lodash/fp'; -import React, { useContext, useState } from 'react'; +import React, { useContext, useState, useCallback } from 'react'; import { DEFAULT_DARK_MODE } from '../../../../../common/constants'; import { DescriptionList } from '../../../../../common/utility_types'; @@ -165,11 +165,11 @@ export const HostOverview = React.memo( ], ]; + const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); + const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); + return ( - setShowInspect(true)} - onMouseLeave={() => setShowInspect(false)} - > + ( updateTableActivePage, updateTableLimit, }) => { + const updateLimitPagination = useCallback( + newLimit => + updateTableLimit({ + hostsType: type, + limit: newLimit, + tableType, + }), + [type] + ); + + const updateActivePage = useCallback( + newPage => + updateTableActivePage({ + activePage: newPage, + hostsType: type, + tableType, + }), + [type] + ); + const onChange = useCallback( (criteria: Criteria) => { if (criteria.sort != null) { @@ -153,26 +173,14 @@ const HostsTableComponent = React.memo( itemsPerRow={rowItems} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} sorting={sorting} totalCount={fakeTotalCount} - updateLimitPagination={newLimit => - updateTableLimit({ - hostsType: type, - limit: newLimit, - tableType, - }) - } - updateActivePage={newPage => - updateTableActivePage({ - activePage: newPage, - hostsType: type, - tableType, - }) - } + updateLimitPagination={updateLimitPagination} + updateActivePage={updateActivePage} /> ); } 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 a4fd4d636b35e9..645b4d1add34cb 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 @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; @@ -96,39 +96,49 @@ const UncommonProcessTableComponent = React.memo( updateTableActivePage, updateTableLimit, type, - }) => ( - loadPage(newActivePage)} - pageOfItems={data} - showMorePagesIndicator={showMorePagesIndicator} - totalCount={fakeTotalCount} - updateLimitPagination={newLimit => + }) => { + const updateLimitPagination = useCallback( + newLimit => updateTableLimit({ hostsType: type, limit: newLimit, tableType, - }) - } - updateActivePage={newPage => + }), + [type] + ); + + const updateActivePage = useCallback( + newPage => updateTableActivePage({ activePage: newPage, hostsType: type, tableType, - }) - } - /> - ) + }), + [type] + ); + + return ( + + ); + } ); UncommonProcessTableComponent.displayName = 'UncommonProcessTableComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/ip_overview/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/ip_overview/index.tsx index 70b4d033624389..8cb55f0d0fb589 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/ip_overview/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/ip_overview/index.tsx @@ -7,7 +7,7 @@ import { EuiFlexItem } from '@elastic/eui'; import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; -import React, { useContext, useState } from 'react'; +import React, { useContext, useState, useCallback } from 'react'; import { DEFAULT_DARK_MODE } from '../../../../../common/constants'; import { DescriptionList } from '../../../../../common/utility_types'; @@ -139,11 +139,12 @@ export const IpOverview = React.memo( { title: i18n.REPUTATION, description: reputationRenderer(ip) }, ], ]; + + const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); + const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); + return ( - setShowInspect(true)} - onMouseLeave={() => setShowInspect(false)} - > + ( type, updateNetworkTable, }) => { + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type] + ); + const onChange = useCallback( (criteria: Criteria) => { if (criteria.sort != null) { @@ -93,7 +113,7 @@ export const NetworkDnsTableComponent = React.memo( } } }, - [sort, type] + [sort, type, tableType] ); const onChangePtrIncluded = useCallback( @@ -123,7 +143,7 @@ export const NetworkDnsTableComponent = React.memo( isInspect={isInspect} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} @@ -132,20 +152,8 @@ export const NetworkDnsTableComponent = React.memo( direction: sort.direction, }} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } 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 e5ad39b814caac..f818dc07c788c2 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,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; @@ -76,23 +76,50 @@ const NetworkHttpTableComponent = React.memo( type, updateNetworkTable, }) => { - const onChange = (criteria: Criteria, tableType: networkModel.HttpTableType) => { - if (criteria.sort != null && criteria.sort.direction !== sort.direction) { + const updateLimitPagination = useCallback( + newLimit => updateNetworkTable({ networkType: type, tableType, - updates: { - sort: { - direction: criteria.sort.direction, - }, - }, - }); - } - }; + updates: { limit: newLimit }, + }), + [type] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type] + ); + const tableType = type === networkModel.NetworkType.page ? networkModel.NetworkTableType.http : networkModel.IpDetailsTableType.http; + + const onChange = useCallback( + (criteria: Criteria) => { + if (criteria.sort != null && criteria.sort.direction !== sort.direction) { + updateNetworkTable({ + networkType: type, + tableType, + updates: { + sort: { + direction: criteria.sort.direction, + }, + }, + }); + } + }, + [tableType, sort.direction, type, updateNetworkTable] + ); + + const sorting = { field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }; + return ( ( isInspect={isInspect} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} - onChange={criteria => onChange(criteria, tableType)} + loadPage={loadPage} + onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} - sorting={{ field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }} + sorting={sorting} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } 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 81a48ca162e156..c6b3106a4ec872 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 @@ -5,7 +5,7 @@ */ import { isEqual, last } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; @@ -88,26 +88,25 @@ const NetworkTopCountriesTableComponent = React.memo { - const onChange = (criteria: Criteria, tableType: networkModel.TopCountriesTableType) => { - if (criteria.sort != null) { - const splitField = criteria.sort.field.split('.'); - const field = last(splitField); - const newSortDirection = field !== sort.field ? Direction.desc : criteria.sort.direction; // sort by desc on init click - const newTopCountriesSort: NetworkTopTablesSortField = { - field: field as NetworkTopTablesFields, - direction: newSortDirection, - }; - if (!isEqual(newTopCountriesSort, sort)) { - updateNetworkTable({ - networkType: type, - tableType, - updates: { - sort: newTopCountriesSort, - }, - }); - } - } - }; + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type] + ); let tableType: networkModel.TopCountriesTableType; const headerTitle: string = @@ -133,15 +132,41 @@ const NetworkTopCountriesTableComponent = React.memo { + if (criteria.sort != null) { + const splitField = criteria.sort.field.split('.'); + const lastField = last(splitField); + const newSortDirection = + lastField !== sort.field ? Direction.desc : criteria.sort.direction; // sort by desc on init click + const newTopCountriesSort: NetworkTopTablesSortField = { + field: lastField as NetworkTopTablesFields, + direction: newSortDirection, + }; + if (!isEqual(newTopCountriesSort, sort)) { + updateNetworkTable({ + networkType: type, + tableType, + updates: { + sort: newTopCountriesSort, + }, + }); + } + } + }, + [type, sort.field, sort.direction] + ); + + const columns = useMemo( + () => + getCountriesColumnsCurated(indexPattern, flowTargeted, type, NetworkTopCountriesTableId), + [indexPattern, flowTargeted, type] + ); + return ( loadPage(newActivePage)} - onChange={criteria => onChange(criteria, tableType)} + loadPage={loadPage} + onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} sorting={{ field, direction: sort.direction }} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } 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 12b87a517b4f77..527f05a1dba3fb 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 @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { isEqual, last } 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'; @@ -87,8 +87,29 @@ const NetworkTopNFlowTableComponent = React.memo( type, updateNetworkTable, }) => { + const columns = useMemo( + () => getNFlowColumnsCurated(indexPattern, flowTargeted, type, NetworkTopNFlowTableId), + [indexPattern, flowTargeted, type] + ); + + let tableType: networkModel.TopNTableType; + const headerTitle: string = + flowTargeted === FlowTargetSourceDest.source ? i18n.SOURCE_IP : i18n.DESTINATION_IP; + + if (type === networkModel.NetworkType.page) { + tableType = + flowTargeted === FlowTargetSourceDest.source + ? networkModel.NetworkTableType.topNFlowSource + : networkModel.NetworkTableType.topNFlowDestination; + } else { + tableType = + flowTargeted === FlowTargetSourceDest.source + ? networkModel.IpDetailsTableType.topNFlowSource + : networkModel.IpDetailsTableType.topNFlowDestination; + } + const onChange = useCallback( - (criteria: Criteria, tableType: networkModel.TopNTableType) => { + (criteria: Criteria) => { if (criteria.sort != null) { const splitField = criteria.sort.field.split('.'); const field = last(splitField); @@ -108,35 +129,35 @@ const NetworkTopNFlowTableComponent = React.memo( } } }, - [sort, type] + [sort, type, tableType] ); - let tableType: networkModel.TopNTableType; - const headerTitle: string = - flowTargeted === FlowTargetSourceDest.source ? i18n.SOURCE_IP : i18n.DESTINATION_IP; - - if (type === networkModel.NetworkType.page) { - tableType = - flowTargeted === FlowTargetSourceDest.source - ? networkModel.NetworkTableType.topNFlowSource - : networkModel.NetworkTableType.topNFlowDestination; - } else { - tableType = - flowTargeted === FlowTargetSourceDest.source - ? networkModel.IpDetailsTableType.topNFlowSource - : networkModel.IpDetailsTableType.topNFlowDestination; - } - const field = sort.field === NetworkTopTablesFields.bytes_out || sort.field === NetworkTopTablesFields.bytes_in ? `node.network.${sort.field}` : `node.${flowTargeted}.${sort.field}`; + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [updateNetworkTable, type, tableType] + ); + + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ networkType: type, tableType, updates: { limit: newLimit } }), + [updateNetworkTable, type, tableType] + ); + return ( ( itemsPerRow={rowItems} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} - onChange={criteria => onChange(criteria, tableType)} + loadPage={loadPage} + onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} sorting={{ field, direction: sort.direction }} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ networkType: type, tableType, updates: { limit: newLimit } }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } 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 7dd9ca0273c5b8..6d17c1bdad9333 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 @@ -74,6 +74,26 @@ const TlsTableComponent = React.memo( type, updateNetworkTable, }) => { + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type] + ); + const tableType: networkModel.TopTlsTableType = type === networkModel.NetworkType.page ? networkModel.NetworkTableType.tls @@ -96,7 +116,7 @@ const TlsTableComponent = React.memo( } } }, - [sort, type] + [sort, type, tableType] ); return ( ( itemsPerRow={rowItems} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} onChange={onChange} pageOfItems={data} sorting={getSortField(sort)} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } 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 8da41fca8f3841..6d01a853eb3df4 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 @@ -78,6 +78,26 @@ const UsersTableComponent = React.memo( updateNetworkTable, sort, }) => { + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type] + ); + const onChange = useCallback( (criteria: Criteria) => { if (criteria.sort != null) { @@ -112,25 +132,13 @@ const UsersTableComponent = React.memo( itemsPerRow={rowItems} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} onChange={onChange} pageOfItems={data} sorting={getSortField(sort)} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx index 077a2d9aebe527..302917c3de93e3 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx @@ -6,7 +6,7 @@ import { EuiButton, EuiFlexItem, EuiPanel } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { HeaderSection } from '../../../header_section'; import { manageQuery } from '../../../page/manage_query'; @@ -38,9 +38,12 @@ const OverviewHostStatsManage = manageQuery(OverviewHostStats); type OverviewHostProps = OwnProps; export const OverviewHost = React.memo(({ endDate, startDate, setQuery }) => { const [isHover, setIsHover] = useState(false); + const handleMouseEnter = useCallback(() => setIsHover(true), [setIsHover]); + const handleMouseLeave = useCallback(() => setIsHover(false), [setIsHover]); + return ( - setIsHover(true)} onMouseLeave={() => setIsHover(false)}> + (({ endDate, startDate, setQuery }) => { const [isHover, setIsHover] = useState(false); + const handleMouseEnter = useCallback(() => setIsHover(true), [setIsHover]); + const handleMouseLeave = useCallback(() => setIsHover(false), [setIsHover]); + return ( - setIsHover(true)} onMouseLeave={() => setIsHover(false)}> + { itemsPerRow={rowItems} limit={1} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -75,11 +75,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={true} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={[]} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -104,11 +104,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={true} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -131,7 +131,7 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} @@ -168,11 +168,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={2} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -199,11 +199,11 @@ describe('Paginated Table Component', () => { itemsPerRow={[]} limit={2} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -233,7 +233,7 @@ describe('Paginated Table Component', () => { showMorePagesIndicator={true} sorting={{ direction: Direction.asc, field: 'node.host.name' }} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -256,11 +256,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={DEFAULT_MAX_TABLE_QUERY_SIZE * 3} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -286,11 +286,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={30} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -312,11 +312,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={1} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -340,11 +340,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -370,11 +370,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={2} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -408,11 +408,11 @@ describe('Paginated Table Component', () => { itemsPerRow: rowItems, limit: 1, loading: false, - loadPage: newActivePage => loadPage(newActivePage), + loadPage, pageOfItems: mockData.Hosts.edges, showMorePagesIndicator: true, totalCount: 10, - updateActivePage: activePage => updateActivePage(activePage), + updateActivePage, updateLimitPagination: limit => updateLimitPagination({ limit }), }; @@ -460,11 +460,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={2} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -503,7 +503,7 @@ describe('Paginated Table Component', () => { showMorePagesIndicator={true} sorting={{ direction: Direction.asc, field: 'node.host.name' }} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> 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 aedec1a340bfde..7a7a8ee5dfa7d2 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 @@ -16,7 +16,7 @@ import { EuiPopover, } from '@elastic/eui'; import { noop } from 'lodash/fp'; -import React, { memo, useState, useEffect } from 'react'; +import React, { memo, useState, useEffect, useCallback } from 'react'; import styled from 'styled-components'; import { Direction } from '../../graphql/types'; @@ -226,13 +226,15 @@ export const PaginatedTable = memo( )); const PaginationWrapper = showMorePagesIndicator ? PaginationEuiFlexItem : EuiFlexItem; + const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); + const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); return ( setShowInspect(true)} - onMouseLeave={() => setShowInspect(false)} + onMouseEnter={handleOnMouseEnter} + onMouseLeave={handleOnMouseLeave} > ( to, }) => { const [isHover, setIsHover] = useState(false); + const handleMouseEnter = useCallback(() => setIsHover(true), [setIsHover]); + const handleMouseLeave = useCallback(() => setIsHover(false), [setIsHover]); const isBarChartDataAvailable = barChart && barChart.length && @@ -218,9 +220,10 @@ export const StatItemsComponent = React.memo( areaChart && areaChart.length && areaChart.every(item => item.value != null && item.value.length > 0); + return ( - setIsHover(true)} onMouseLeave={() => setIsHover(false)}> + diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/activity_monitor/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/activity_monitor/index.tsx index d7306b8630bc2d..2d48d64acaecf7 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/activity_monitor/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/activity_monitor/index.tsx @@ -5,7 +5,7 @@ */ import { EuiBasicTable, EuiPanel, EuiSpacer } from '@elastic/eui'; -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { HeaderSection } from '../../../../components/header_section'; import { UtilityBar, @@ -278,6 +278,14 @@ export const ActivityMonitor = React.memo(() => { // const [selectedState, setSelectedState] = useState([]); const [sortState, setSortState] = useState({ field: 'ran', direction: 'desc' }); + const handleChange = useCallback( + ({ page, sort }: { page: PageTypes; sort: SortTypes }) => { + setPageState(page); + setSortState(sort); + }, + [setPageState, setSortState] + ); + return ( <> @@ -308,10 +316,7 @@ export const ActivityMonitor = React.memo(() => { isSelectable itemId="id" items={sampleTableData} - onChange={({ page, sort }: { page: PageTypes; sort: SortTypes }) => { - setPageState(page); - setSortState(sort); - }} + onChange={handleChange} pagination={{ pageIndex: pageState.index, pageSize: pageState.size, diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all_rules/columns.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all_rules/columns.tsx index cae0fb3eaf9065..9575ee736dea3b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all_rules/columns.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all_rules/columns.tsx @@ -21,7 +21,7 @@ import { Action } from './reducer'; import { TableData } from '../types'; import * as i18n from '../translations'; import { PreferenceFormattedDate } from '../../../../components/formatted_date'; -import { RuleSwitch } from '../components/rule_switch'; +import { RuleSwitch, RuleStateChangeCallback } from '../components/rule_switch'; const getActions = (dispatch: React.Dispatch, kbnVersion: string) => [ { @@ -147,16 +147,20 @@ export const getColumns = (dispatch: React.Dispatch, kbnVersion: string) align: 'center', field: 'activate', name: i18n.COLUMN_ACTIVATE, - render: (value: TableData['activate'], item: TableData) => ( - { - await enableRulesAction([id], enabled, dispatch, kbnVersion); - }} - /> - ), + render: (value: TableData['activate'], item: TableData) => { + const handleRuleStateChange: RuleStateChangeCallback = async (enabled, id) => { + await enableRulesAction([id], enabled, dispatch, kbnVersion); + }; + + return ( + + ); + }, sortable: true, width: '85px', }, diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx index 19523752f4f4a9..6d9b0a36f8548b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx @@ -5,7 +5,7 @@ */ import styled from 'styled-components'; -import React from 'react'; +import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSwitch } from '@elastic/eui'; const StaticSwitch = styled(EuiSwitch)` @@ -17,11 +17,13 @@ const StaticSwitch = styled(EuiSwitch)` StaticSwitch.displayName = 'StaticSwitch'; +export type RuleStateChangeCallback = (isEnabled: boolean, id: string) => void; + export interface RuleSwitchProps { id: string; enabled: boolean; isLoading: boolean; - onRuleStateChange: (isEnabled: boolean, id: string) => void; + onRuleStateChange: RuleStateChangeCallback; } /** @@ -32,26 +34,32 @@ export const RuleSwitchComponent = ({ enabled, isLoading, onRuleStateChange, -}: RuleSwitchProps) => ( - - - {isLoading ? ( - - ) : ( - { - onRuleStateChange(e.target.checked!, id); - }} - /> - )} - - -); +}: RuleSwitchProps) => { + const handleChange = useCallback( + e => { + onRuleStateChange(e.target.checked!, id); + }, + [onRuleStateChange, id] + ); + return ( + + + {isLoading ? ( + + ) : ( + + )} + + + ); +}; export const RuleSwitch = React.memo(RuleSwitchComponent); 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 97f0a21928a8af..137fce679a46d2 100644 --- a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as React from 'react'; +import React from 'react'; import { Redirect, Route, Switch } from 'react-router-dom'; import styled from 'styled-components'; @@ -57,88 +57,89 @@ const calculateFlyoutHeight = ({ export const HomePage: React.FC = () => ( - {({ measureRef, windowMeasurement: { height: windowHeight = 0 } }) => ( - - + {({ measureRef, windowMeasurement: { height: windowHeight = 0 } }) => { + const flyoutHeight = calculateFlyoutHeight({ + globalHeaderSize: globalHeaderHeightPx, + windowHeight, + }); -
- - {({ browserFields, indexPattern }) => ( - - - - - - + return ( + + - - - } - /> - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - } - /> - } /> - ( - - )} - /> - ( - - )} - /> - } /> - - - )} - -
+
+ + {({ browserFields, indexPattern }) => ( + + + + + + - + + + } + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + } + /> + } /> + ( + + )} + /> + ( + + )} + /> + } /> + + + )} + +
- -
- )} + + + + + ); + }}
); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx index a9a0693a254471..65b23c440609e6 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx @@ -62,7 +62,7 @@ describe('body', () => { from={0} isInitializing={false} detailName={'host-1'} - setQuery={() => {}} + setQuery={jest.fn()} to={0} setAbsoluteRangeDatePicker={(jest.fn() as unknown) as SetAbsoluteRangeDatePicker} hostDetailsPagePath={hostDetailsPagePath} 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 1252c7031e8a5f..1f03e2373b5d55 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 @@ -52,7 +52,7 @@ const HostDetailsTabs = React.memo( (min: number, max: number) => { setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); }, - [setAbsoluteRangeDatePicker, scoreIntervalToDateTime] + [setAbsoluteRangeDatePicker] ); const tabProps = { 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 d30665c5a21426..c995cc9730b145 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 @@ -5,7 +5,7 @@ */ import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; -import React, { useContext, useEffect } from 'react'; +import React, { useContext, useEffect, useCallback } from 'react'; import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; import { compose } from 'redux'; @@ -64,6 +64,12 @@ const HostDetailsComponent = React.memo( }, [detailName]); const capabilities = useContext(MlCapabilitiesContext); const core = useKibanaCore(); + const narrowDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); return ( <> @@ -176,9 +182,7 @@ const HostDetailsComponent = React.memo( refetch={refetch} setQuery={setQuery} to={to} - narrowDateRange={(min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }} + narrowDateRange={narrowDateRange} /> )} 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 4ff666464404e2..0c058f25854c01 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx @@ -5,7 +5,7 @@ */ import { EuiSpacer } from '@elastic/eui'; -import * as React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; import { compose } from 'redux'; @@ -52,6 +52,12 @@ const HostsComponent = React.memo( }) => { const capabilities = React.useContext(MlCapabilitiesContext); const core = useKibanaCore(); + const narrowDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); return ( <> @@ -93,9 +99,7 @@ const HostsComponent = React.memo( refetch={refetch} setQuery={setQuery} to={to} - narrowDateRange={(min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }} + narrowDateRange={narrowDateRange} /> )} diff --git a/x-pack/legacy/plugins/siem/public/pages/network/index.tsx b/x-pack/legacy/plugins/siem/public/pages/network/index.tsx index 009a89bb3889f6..1bc3d9a054bb89 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext } from 'react'; +import React, { useContext, useMemo } from 'react'; import { Redirect, Route, Switch, RouteComponentProps } from 'react-router-dom'; import { MlCapabilitiesContext } from '../../components/ml/permissions/ml_capabilities_provider'; @@ -24,6 +24,14 @@ const ipDetailsPagePath = `${networkPagePath}/ip/:detailName`; export const NetworkContainer = React.memo(() => { const capabilities = useContext(MlCapabilitiesContext); + const capabilitiesFetched = capabilities.capabilitiesFetched; + const userHasMlUserPermissions = useMemo(() => hasMlUserPermissions(capabilities), [ + capabilities, + ]); + const networkRoutePath = useMemo( + () => getNetworkRoutePath(networkPagePath, capabilitiesFetched, userHasMlUserPermissions), + [capabilitiesFetched, userHasMlUserPermissions] + ); return ( @@ -31,11 +39,7 @@ export const NetworkContainer = React.memo(() => { ( (() => { deleteQuery={deleteQuery} isInitializing={isInitializing} capabilitiesFetched={capabilities.capabilitiesFetched} - hasMlUserPermissions={hasMlUserPermissions(capabilities)} + hasMlUserPermissions={userHasMlUserPermissions} /> )} /> diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx index 75ca5a5dfe1a68..1700532adbee53 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx @@ -134,14 +134,7 @@ export const IPDetailsComponent = ({ setQuery={setQuery} startDate={from} endDate={to} - narrowDateRange={(score, interval) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }} + narrowDateRange={narrowDateRange} /> )} diff --git a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx index aa7572e5741bda..116664fef6ddcc 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx @@ -5,7 +5,7 @@ */ import { EuiSpacer } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; @@ -49,6 +49,12 @@ const NetworkComponent = React.memo( capabilitiesFetched, }) => { const core = useKibanaCore(); + const narrowDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); return ( <> @@ -101,9 +107,7 @@ const NetworkComponent = React.memo( loading={loading} from={from} to={to} - narrowDateRange={(min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }} + narrowDateRange={narrowDateRange} /> )} diff --git a/x-pack/legacy/plugins/siem/public/pages/timelines/timelines_page.tsx b/x-pack/legacy/plugins/siem/public/pages/timelines/timelines_page.tsx index 93c8397e214317..4dec9278ed6b02 100644 --- a/x-pack/legacy/plugins/siem/public/pages/timelines/timelines_page.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/timelines/timelines_page.tsx @@ -15,7 +15,7 @@ import { SpyRoute } from '../../utils/route/spy_routes'; import * as i18n from './translations'; const TimelinesContainer = styled.div` - width: 100%: + width: 100%; `; TimelinesContainer.displayName = 'TimelinesContainer';