Skip to content

Commit

Permalink
Move resolver query param logic into shared hook
Browse files Browse the repository at this point in the history
  • Loading branch information
kqualters-elastic committed Jul 13, 2020
1 parent 4b99029 commit 1206284
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 80 deletions.
12 changes: 11 additions & 1 deletion x-pack/plugins/security_solution/public/resolver/view/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
export const Resolver = React.memo(function ({
className,
databaseDocumentID,
documentLocation,
}: {
/**
* Used by `styled-components`.
Expand All @@ -28,6 +29,11 @@ export const Resolver = React.memo(function ({
* Used as the origin of the Resolver graph.
*/
databaseDocumentID?: string;
/**
* A string literal describing where in the app resolver is located,
* used to prevent collisions in things like query params
*/
documentLocation: string;
}) {
const context = useKibana<StartServices>();
const store = useMemo(() => {
Expand All @@ -40,7 +46,11 @@ export const Resolver = React.memo(function ({
*/
return (
<Provider store={store}>
<ResolverMap className={className} databaseDocumentID={databaseDocumentID} />
<ResolverMap
className={className}
databaseDocumentID={databaseDocumentID}
documentLocation={documentLocation}
/>
</Provider>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { SideEffectContext } from './side_effect_context';
export const ResolverMap = React.memo(function ({
className,
databaseDocumentID,
documentLocation,
}: {
/**
* Used by `styled-components`.
Expand All @@ -39,6 +40,7 @@ export const ResolverMap = React.memo(function ({
* Used as the origin of the Resolver graph.
*/
databaseDocumentID?: string;
documentLocation: string;
}) {
/**
* This is responsible for dispatching actions that include any external data.
Expand Down Expand Up @@ -111,13 +113,14 @@ export const ResolverMap = React.memo(function ({
relatedEventsStats ? relatedEventsStats.get(entityId(processEvent)) : undefined
}
isProcessTerminated={terminatedProcesses.has(processEntityId)}
documentLocation={documentLocation}
isProcessOrigin={false}
/>
);
})}
</GraphContainer>
)}
<StyledPanel />
<StyledPanel documentLocation={documentLocation} />
<GraphControls />
<SymbolDefinitions />
</StyledMapContainer>
Expand Down
59 changes: 17 additions & 42 deletions x-pack/plugins/security_solution/public/resolver/view/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { memo, useCallback, useMemo, useContext, useLayoutEffect, useState } from 'react';
import React, { memo, useMemo, useContext, useLayoutEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useHistory, useLocation } from 'react-router-dom';
// eslint-disable-next-line import/no-nodejs-modules
import querystring from 'querystring';
import { EuiPanel } from '@elastic/eui';
import { displayNameRecord } from './process_event_dot';
import * as selectors from '../store/selectors';
Expand All @@ -21,7 +18,7 @@ import { EventCountsForProcess } from './panels/panel_content_related_counts';
import { ProcessDetails } from './panels/panel_content_process_detail';
import { ProcessListWithCounts } from './panels/panel_content_process_list';
import { RelatedEventDetail } from './panels/panel_content_related_detail';
import { CrumbInfo } from './panels/panel_content_utilities';
import { useResolverQueryParams } from './use_resolver_query_params';

/**
* The team decided to use this table to determine which breadcrumbs/view to display:
Expand All @@ -38,15 +35,16 @@ import { CrumbInfo } from './panels/panel_content_utilities';
*
* @returns {JSX.Element} The "right" table content to show based on the query params as described above
*/
const PanelContent = memo(function PanelContent() {
const history = useHistory();
const urlSearch = useLocation().search;
const PanelContent = memo(function PanelContent({
documentLocation,
}: {
documentLocation: string;
}) {
const dispatch = useResolverDispatch();

const { timestamp } = useContext(SideEffectContext);
const queryParams: CrumbInfo = useMemo(() => {
return { crumbId: '', crumbEvent: '', ...querystring.parse(urlSearch.slice(1)) };
}, [urlSearch]);

const { pushToQueryParams, queryParams } = useResolverQueryParams(documentLocation);

const graphableProcesses = useSelector(selectors.graphableProcesses);
const graphableProcessEntityIds = useMemo(() => {
Expand Down Expand Up @@ -104,35 +102,6 @@ const PanelContent = memo(function PanelContent() {
}
}, [dispatch, uiSelectedEvent, paramsSelectedEvent, lastUpdatedProcess, timestamp]);

/**
* This updates the breadcrumb nav and the panel view. It's supplied to each
* panel content view to allow them to dispatch transitions to each other.
*/
const pushToQueryParams = useCallback(
(newCrumbs: CrumbInfo) => {
// Construct a new set of params from the current set (minus empty params)
// by assigning the new set of params provided in `newCrumbs`
const crumbsToPass = {
...querystring.parse(urlSearch.slice(1)),
...newCrumbs,
};

// If either was passed in as empty, remove it from the record
if (crumbsToPass.crumbId === '') {
delete crumbsToPass.crumbId;
}
if (crumbsToPass.crumbEvent === '') {
delete crumbsToPass.crumbEvent;
}

const relativeURL = { search: querystring.stringify(crumbsToPass) };
// We probably don't want to nuke the user's history with a huge
// trail of these, thus `.replace` instead of `.push`
return history.replace(relativeURL);
},
[history, urlSearch]
);

const relatedEventStats = useSelector(selectors.relatedEventsStats);
const { crumbId, crumbEvent } = queryParams;
const relatedStatsForIdFromParams: ResolverNodeStats | undefined =
Expand Down Expand Up @@ -269,10 +238,16 @@ const PanelContent = memo(function PanelContent() {
});
PanelContent.displayName = 'PanelContent';

export const Panel = memo(function Event({ className }: { className?: string }) {
export const Panel = memo(function Event({
className,
documentLocation,
}: {
className?: string;
documentLocation: string;
}) {
return (
<EuiPanel className={className}>
<PanelContent />
<PanelContent documentLocation={documentLocation} />
</EuiPanel>
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ const BetaHeader = styled(`header`)`
* The two query parameters we read/write on to control which view the table presents:
*/
export interface CrumbInfo {
readonly crumbId: string;
readonly crumbEvent: string;
readonly [x: string]: string;
}

const ThemedBreadcrumbs = styled(EuiBreadcrumbs)<{ background: string; text: string }>`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import React, { useCallback, useMemo } from 'react';
import styled from 'styled-components';
import { i18n } from '@kbn/i18n';
import { htmlIdGenerator, EuiButton, EuiI18nNumber, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { useHistory } from 'react-router-dom';
// eslint-disable-next-line import/no-nodejs-modules
import querystring from 'querystring';
import { useSelector } from 'react-redux';
import { NodeSubMenu, subMenuAssets } from './submenu';
import { applyMatrix3 } from '../models/vector2';
Expand All @@ -22,7 +19,7 @@ import { ResolverEvent, ResolverNodeStats } from '../../../common/endpoint/types
import { useResolverDispatch } from './use_resolver_dispatch';
import * as eventModel from '../../../common/endpoint/models/event';
import * as selectors from '../store/selectors';
import { CrumbInfo } from './panels/panel_content_utilities';
import { useResolverQueryParams } from './use_resolver_query_params';

/**
* A record of all known event types (in schema format) to translations
Expand Down Expand Up @@ -244,6 +241,7 @@ const UnstyledProcessEventDot = React.memo(
isProcessTerminated,
isProcessOrigin,
relatedEventsStatsForProcess,
documentLocation,
}: {
/**
* A `className` string provided by `styled`
Expand Down Expand Up @@ -279,6 +277,7 @@ const UnstyledProcessEventDot = React.memo(
* Statistics for the number of related events and alerts for this process node
*/
relatedEventsStatsForProcess?: ResolverNodeStats;
documentLocation: string;
}) => {
/**
* Convert the position, which is in 'world' coordinates, to screen coordinates.
Expand Down Expand Up @@ -403,35 +402,7 @@ const UnstyledProcessEventDot = React.memo(
});
}, [dispatch, selfId]);

const history = useHistory();
const urlSearch = history.location.search;

/**
* This updates the breadcrumb nav, the table view
*/
const pushToQueryParams = useCallback(
(newCrumbs: CrumbInfo) => {
// Construct a new set of params from the current set (minus empty params)
// by assigning the new set of params provided in `newCrumbs`
const crumbsToPass = {
...querystring.parse(urlSearch.slice(1)),
...newCrumbs,
};

// If either was passed in as empty, remove it from the record
if (crumbsToPass.crumbId === '') {
delete crumbsToPass.crumbId;
}
if (crumbsToPass.crumbEvent === '') {
delete crumbsToPass.crumbEvent;
}

const relativeURL = { search: querystring.stringify(crumbsToPass) };

return history.replace(relativeURL);
},
[history, urlSearch]
);
const { pushToQueryParams } = useResolverQueryParams(documentLocation);

const handleClick = useCallback(() => {
if (animationTarget.current !== null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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 { useCallback, useMemo } from 'react';
// eslint-disable-next-line import/no-nodejs-modules
import querystring from 'querystring';
import { useHistory, useLocation } from 'react-router-dom';
import { CrumbInfo } from './panels/panel_content_utilities';

export function useResolverQueryParams(documentLocation: string) {
/**
* This updates the breadcrumb nav and the panel view. It's supplied to each
* panel content view to allow them to dispatch transitions to each other.
*/
const history = useHistory();
const urlSearch = useLocation().search;
const uniqueCrumbIdKey = `${documentLocation}CrumbId`;
const uniqueCrumbEventKey = `${documentLocation}CrumbEvent`;
const pushToQueryParams = useCallback(
(newCrumbs: CrumbInfo) => {
// Construct a new set of params from the current set (minus empty params)
// by assigning the new set of params provided in `newCrumbs`
const crumbsToPass = {
...querystring.parse(urlSearch.slice(1)),
[uniqueCrumbIdKey]: newCrumbs.crumbId,
[uniqueCrumbEventKey]: newCrumbs.crumbEvent,
};

// If either was passed in as empty, remove it from the record
if (crumbsToPass.uniqueCrumbIdKey === '') {
delete crumbsToPass.uniqueCrumbIdKey;
}
if (crumbsToPass.uniqueCrumbEventKey === '') {
delete crumbsToPass.uniqueCrumbEventKey;
}

const relativeURL = { search: querystring.stringify(crumbsToPass) };
// We probably don't want to nuke the user's history with a huge
// trail of these, thus `.replace` instead of `.push`
return history.replace(relativeURL);
},
[history, urlSearch, uniqueCrumbIdKey, uniqueCrumbEventKey]
);
const queryParams: CrumbInfo = useMemo(() => {
const newParams = {
[uniqueCrumbIdKey]: '',
[uniqueCrumbEventKey]: '',
...querystring.parse(urlSearch.slice(1)),
};
newParams.crumbId = newParams[uniqueCrumbIdKey];
newParams.crumbEvent = newParams[uniqueCrumbEventKey];
return newParams;
}, [urlSearch, uniqueCrumbIdKey, uniqueCrumbEventKey]);

return {
pushToQueryParams,
queryParams,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const GraphOverlayComponent = ({
</EuiFlexGroup>

<EuiHorizontalRule margin="none" />
<StyledResolver databaseDocumentID={graphEventId} />
<StyledResolver databaseDocumentID={graphEventId} documentLocation={currentTimeline.id} />
<AllCasesModal
onCloseCaseModal={onCloseCaseModal}
showCaseModal={showCaseModal}
Expand Down

0 comments on commit 1206284

Please sign in to comment.