From 7f1f45392911a15909677015868a04b4e7ce2942 Mon Sep 17 00:00:00 2001 From: oatkiller Date: Thu, 13 Aug 2020 14:38:04 -0400 Subject: [PATCH] refactor --- .../view/resolver_without_providers.tsx | 3 + .../resolver/view/use_query_string_keys.ts | 21 +++++++ .../view/use_resolver_query_params.ts | 6 +- .../view/use_resolver_query_params_cleaner.ts | 55 +++++++++++++++++++ 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/resolver/view/use_query_string_keys.ts create mode 100644 x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params_cleaner.ts 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 caa1365044407..59564b08628ee 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 @@ -10,6 +10,7 @@ import React, { useContext, useCallback } from 'react'; import { useSelector } from 'react-redux'; import { EuiLoadingSpinner } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { useResolverQueryParamCleaner } from './use_resolver_query_params_cleaner'; import * as selectors from '../store/selectors'; import { EdgeLine } from './edge_line'; import { GraphControls } from './graph_controls'; @@ -33,6 +34,8 @@ export const ResolverWithoutProviders = React.memo( { className, databaseDocumentID, resolverComponentInstanceID }: ResolverProps, refToForward ) { + // + useResolverQueryParamCleaner(); /** * This is responsible for dispatching actions that include any external data. * `databaseDocumentID` diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_query_string_keys.ts b/x-pack/plugins/security_solution/public/resolver/view/use_query_string_keys.ts new file mode 100644 index 0000000000000..11f1a30db72fc --- /dev/null +++ b/x-pack/plugins/security_solution/public/resolver/view/use_query_string_keys.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useSelector } from 'react-redux'; +import * as selectors from '../store/selectors'; + +/** + * Get the query string keys used by this Resolver instance. + */ +export function useQueryStringKeys(): { idKey: string; eventKey: string } { + const resolverComponentInstanceID = useSelector(selectors.resolverComponentInstanceID); + const idKey: string = `resolver-${resolverComponentInstanceID}-id`; + const eventKey: string = `resolver-${resolverComponentInstanceID}-event`; + return { + idKey, + eventKey, + }; +} diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params.ts b/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params.ts index 6c804c465bf07..3c76b8015aa30 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params.ts +++ b/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params.ts @@ -5,8 +5,8 @@ */ import { useCallback, useMemo, useEffect } from 'react'; -import { useSelector } from 'react-redux'; import { useHistory, useLocation } from 'react-router-dom'; +import { useQueryStringKeys } from './use_query_string_keys'; import * as selectors from '../store/selectors'; import { CrumbInfo } from './panels/panel_content_utilities'; @@ -17,9 +17,7 @@ export function useResolverQueryParams() { */ const history = useHistory(); const urlSearch = useLocation().search; - const resolverComponentInstanceID = useSelector(selectors.resolverComponentInstanceID); - const idKey: string = `resolver-${resolverComponentInstanceID}-id`; - const eventKey: string = `resolver-${resolverComponentInstanceID}-event`; + const { idKey, eventKey } = useQueryStringKeys(); const pushToQueryParams = useCallback( (queryStringState: CrumbInfo) => { const urlSearchParams = new URLSearchParams(urlSearch); diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params_cleaner.ts b/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params_cleaner.ts new file mode 100644 index 0000000000000..f88df7707848a --- /dev/null +++ b/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params_cleaner.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useRef, useEffect } from 'react'; +import { useLocation, useHistory } from 'react-router-dom'; + +import { useQueryStringKeys } from './use_query_string_keys'; +/** + * Cleanup any query string keys that were added by this Resolver instance. + * This works by having a React effect that just has behavior in the 'cleanup' function. + */ +export function useResolverQueryParamCleaner() { + /** + * Keep a reference to the current search value. This is used in the cleanup function. + * This value of useLocation().search isn't used directly since that would change and + * we only want the cleanup to run on unmount or when the resolverComponentInstanceID + * changes. + */ + const searchRef = useRef(); + searchRef.current = useLocation().search; + + const history = useHistory(); + + const { idKey, eventKey } = useQueryStringKeys(); + + useEffect(() => { + /** + * Keep track of the old query string keys so we can remove them. + */ + const oldIdKey = idKey; + const oldEventKey = eventKey; + /** + * When `idKey` or `eventKey` changes (such as when the `resolverComponentInstanceID` has changed) or when the component unmounts, remove any state from the query string. + */ + return () => { + /** + * This effect must not be invalidated when `search` changes. + * Use the current location.search via the `history` object. + * `history` doesn't change so this is effectively like accessing `search` via a ref. + */ + const urlSearchParams = new URLSearchParams(searchRef.current); + + /** + * Remove old keys from the url + */ + urlSearchParams.delete(oldIdKey); + urlSearchParams.delete(oldEventKey); + const relativeURL = { search: urlSearchParams.toString() }; + history.replace(relativeURL); + }; + }, [idKey, eventKey, history]); +}