From e1a53e6b8b5a2778f55c63a5d6e476d84d0416e8 Mon Sep 17 00:00:00 2001 From: oatkiller Date: Thu, 27 Aug 2020 13:25:30 -0400 Subject: [PATCH] [Resolver] Fix useSelector usage In some cases we have selectors returning thunks. The thunks need to be called inside `useSelector` in order for a rerender to be reliably triggered. --- .../resolver/view/panels/process_details.tsx | 6 ++++-- .../view/panels/related_event_detail.tsx | 7 +++---- .../public/resolver/view/process_event_dot.tsx | 18 +++++++++++------- .../view/resolver_without_providers.tsx | 11 +++++++---- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/security_solution/public/resolver/view/panels/process_details.tsx b/x-pack/plugins/security_solution/public/resolver/view/panels/process_details.tsx index 15711909c4c9b..c5b5dc66907f7 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/panels/process_details.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/panels/process_details.tsx @@ -31,7 +31,7 @@ import { import { CubeForProcess } from './cube_for_process'; import { ResolverEvent } from '../../../../common/endpoint/types'; import { useResolverTheme } from '../assets'; -import { CrumbInfo } from '../../types'; +import { CrumbInfo, ResolverState } from '../../types'; const StyledDescriptionList = styled(EuiDescriptionList)` &.euiDescriptionList.euiDescriptionList--column dt.euiDescriptionList__title.desc-title { @@ -52,7 +52,9 @@ export const ProcessDetails = memo(function ProcessDetails({ }) { const processName = event.eventName(processEvent); const entityId = event.entityId(processEvent); - const isProcessTerminated = useSelector(selectors.isProcessTerminated)(entityId); + const isProcessTerminated = useSelector((state: ResolverState) => + selectors.isProcessTerminated(state)(entityId) + ); const processInfoEntry: EuiDescriptionListProps['listItems'] = useMemo(() => { const eventTime = event.eventTimestamp(processEvent); const dateTime = eventTime === undefined ? null : formatDate(eventTime); diff --git a/x-pack/plugins/security_solution/public/resolver/view/panels/related_event_detail.tsx b/x-pack/plugins/security_solution/public/resolver/view/panels/related_event_detail.tsx index da4cd3c9dacad..da820dd64d61f 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/panels/related_event_detail.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/panels/related_event_detail.tsx @@ -16,7 +16,7 @@ import { ResolverEvent } from '../../../../common/endpoint/types'; import * as selectors from '../../store/selectors'; import { useResolverDispatch } from '../use_resolver_dispatch'; import { PanelContentError } from './panel_content_error'; -import { CrumbInfo } from '../../types'; +import { CrumbInfo, ResolverState } from '../../types'; // Adding some styles to prevent horizontal scrollbars, per request from UX review const StyledDescriptionList = memo(styled(EuiDescriptionList)` @@ -154,9 +154,8 @@ export const RelatedEventDetail = memo(function RelatedEventDetail({ relatedEventCategory = naString, sections, formattedDate, - ] = useSelector(selectors.relatedEventDisplayInfoByEntityAndSelfId)( - processEntityId, - relatedEventId + ] = useSelector((state: ResolverState) => + selectors.relatedEventDisplayInfoByEntityAndSelfId(state)(processEntityId, relatedEventId) ); const waitCrumbs = useMemo(() => { diff --git a/x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx b/x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx index 2bb104801866f..baa8ce1fcdd86 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx @@ -12,7 +12,7 @@ import { htmlIdGenerator, EuiButton, EuiI18nNumber, EuiFlexGroup, EuiFlexItem } import { useSelector } from 'react-redux'; import { NodeSubMenu, subMenuAssets } from './submenu'; import { applyMatrix3 } from '../models/vector2'; -import { Vector2, Matrix3 } from '../types'; +import { Vector2, Matrix3, ResolverState } from '../types'; import { SymbolIds, useResolverTheme, calculateResolverFontSize } from './assets'; import { ResolverEvent, SafeResolverEvent } from '../../../common/endpoint/types'; import { useResolverDispatch } from './use_resolver_dispatch'; @@ -118,7 +118,9 @@ const UnstyledProcessEventDot = React.memo( // NB: this component should be taking nodeID as a `string` instead of handling this logic here throw new Error('Tried to render a node with no ID'); } - const relatedEventStats = useSelector(selectors.relatedEventsStats)(nodeID); + const relatedEventStats = useSelector((state: ResolverState) => + selectors.relatedEventsStats(state)(nodeID) + ); // define a standard way of giving HTML IDs to nodes based on their entity_id/nodeID. // this is used to link nodes via aria attributes @@ -126,11 +128,13 @@ const UnstyledProcessEventDot = React.memo( htmlIDPrefix, ]); - const ariaLevel: number | null = useSelector(selectors.ariaLevel)(nodeID); + const ariaLevel: number | null = useSelector((state: ResolverState) => + selectors.ariaLevel(state)(nodeID) + ); // the node ID to 'flowto' - const ariaFlowtoNodeID: string | null = useSelector(selectors.ariaFlowtoNodeID)(timeAtRender)( - nodeID + const ariaFlowtoNodeID: string | null = useSelector((state: ResolverState) => + selectors.ariaFlowtoNodeID(state)(timeAtRender)(nodeID) ); const isShowingEventActions = xScale > 0.8; @@ -290,8 +294,8 @@ const UnstyledProcessEventDot = React.memo( ? subMenuAssets.initialMenuStatus : relatedEventOptions; - const grandTotal: number | null = useSelector(selectors.relatedEventTotalForProcess)( - event as ResolverEvent + const grandTotal: number | null = useSelector((state: ResolverState) => + selectors.relatedEventTotalForProcess(state)(event as ResolverEvent) ); /* eslint-disable jsx-a11y/click-events-have-key-events */ diff --git a/x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx b/x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx index 32faeec043f2d..aa845e7283ebe 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx @@ -21,7 +21,7 @@ import { useStateSyncingActions } from './use_state_syncing_actions'; import { StyledMapContainer, StyledPanel, GraphContainer } from './styles'; import { entityIDSafeVersion } from '../../../common/endpoint/models/event'; import { SideEffectContext } from './side_effect_context'; -import { ResolverProps } from '../types'; +import { ResolverProps, ResolverState } from '../types'; /** * The highest level connected Resolver component. Needs a `Provider` in its ancestry to work. @@ -46,9 +46,12 @@ export const ResolverWithoutProviders = React.memo( // use this for the entire render in order to keep things in sync const timeAtRender = timestamp(); - const { processNodePositions, connectingEdgeLineSegments } = useSelector( - selectors.visibleNodesAndEdgeLines - )(timeAtRender); + const { + processNodePositions, + connectingEdgeLineSegments, + } = useSelector((state: ResolverState) => + selectors.visibleNodesAndEdgeLines(state)(timeAtRender) + ); const terminatedProcesses = useSelector(selectors.terminatedProcesses); const { projectionMatrix, ref: cameraRef, onMouseDown } = useCamera();