[Resolver] model location.search
in redux (#76140)
Read location.search from the redux store instead of a hook so that the entire view has a single (synchronized) source of truth. Also, no longer pass `pushToQueryParams` function to various components.
This commit is contained in:
parent
712c4bdde7
commit
3fc3f58c62
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The legacy `crumbEvent` and `crumbId` parameters.
|
||||
* @deprecated
|
||||
*/
|
||||
export function breadcrumbParameters(
|
||||
locationSearch: string,
|
||||
resolverComponentInstanceID: string
|
||||
): { crumbEvent: string; crumbId: string } {
|
||||
const urlSearchParams = new URLSearchParams(locationSearch);
|
||||
const { eventKey, idKey } = parameterNames(resolverComponentInstanceID);
|
||||
return {
|
||||
// Use `''` for backwards compatibility with deprecated code.
|
||||
crumbEvent: urlSearchParams.get(eventKey) ?? '',
|
||||
crumbId: urlSearchParams.get(idKey) ?? '',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter names based on the `resolverComponentInstanceID`.
|
||||
*/
|
||||
function parameterNames(
|
||||
resolverComponentInstanceID: string
|
||||
): {
|
||||
idKey: string;
|
||||
eventKey: string;
|
||||
} {
|
||||
const idKey: string = `resolver-${resolverComponentInstanceID}-id`;
|
||||
const eventKey: string = `resolver-${resolverComponentInstanceID}-event`;
|
||||
return {
|
||||
idKey,
|
||||
eventKey,
|
||||
};
|
||||
}
|
|
@ -101,9 +101,37 @@ interface UserSelectedRelatedEventCategory {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `useStateSyncingActions` hook.
|
||||
* This is dispatched when external sources provide new parameters for Resolver.
|
||||
* When the component receives a new 'databaseDocumentID' prop, this is fired.
|
||||
*/
|
||||
interface AppReceivedNewExternalProperties {
|
||||
type: 'appReceivedNewExternalProperties';
|
||||
/**
|
||||
* Defines the externally provided properties that Resolver acknowledges.
|
||||
*/
|
||||
payload: {
|
||||
/**
|
||||
* the `_id` of an ES document. This defines the origin of the Resolver graph.
|
||||
*/
|
||||
databaseDocumentID?: string;
|
||||
/**
|
||||
* An ID that uniquely identifies this Resolver instance from other concurrent Resolvers.
|
||||
*/
|
||||
resolverComponentInstanceID: string;
|
||||
|
||||
/**
|
||||
* The `search` part of the URL of this page.
|
||||
*/
|
||||
locationSearch: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ResolverAction =
|
||||
| CameraAction
|
||||
| DataAction
|
||||
| AppReceivedNewExternalProperties
|
||||
| UserBroughtProcessIntoView
|
||||
| UserFocusedOnResolverNode
|
||||
| UserSelectedResolverNode
|
||||
|
|
|
@ -60,30 +60,10 @@ interface ServerReturnedRelatedEventData {
|
|||
readonly payload: ResolverRelatedEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `useStateSyncingActions` hook.
|
||||
* This is dispatched when external sources provide new parameters for Resolver.
|
||||
* When the component receives a new 'databaseDocumentID' prop, this is fired.
|
||||
*/
|
||||
interface AppReceivedNewExternalProperties {
|
||||
type: 'appReceivedNewExternalProperties';
|
||||
/**
|
||||
* Defines the externally provided properties that Resolver acknowledges.
|
||||
*/
|
||||
payload: {
|
||||
/**
|
||||
* the `_id` of an ES document. This defines the origin of the Resolver graph.
|
||||
*/
|
||||
databaseDocumentID?: string;
|
||||
resolverComponentInstanceID: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type DataAction =
|
||||
| ServerReturnedResolverData
|
||||
| ServerFailedToReturnResolverData
|
||||
| ServerFailedToReturnRelatedEventData
|
||||
| ServerReturnedRelatedEventData
|
||||
| AppReceivedNewExternalProperties
|
||||
| AppRequestedResolverData
|
||||
| AppAbortedResolverDataRequest;
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
import * as selectors from './selectors';
|
||||
import { DataState } from '../../types';
|
||||
import { ResolverAction } from '../actions';
|
||||
import { dataReducer } from './reducer';
|
||||
import { DataAction } from './action';
|
||||
import { createStore } from 'redux';
|
||||
import {
|
||||
mockTreeWithNoAncestorsAnd2Children,
|
||||
|
@ -20,7 +20,7 @@ import { uniquePidForProcess } from '../../models/process_event';
|
|||
import { EndpointEvent } from '../../../../common/endpoint/types';
|
||||
|
||||
describe('data state', () => {
|
||||
let actions: DataAction[] = [];
|
||||
let actions: ResolverAction[] = [];
|
||||
|
||||
/**
|
||||
* Get state, given an ordered collection of actions.
|
||||
|
@ -68,7 +68,13 @@ describe('data state', () => {
|
|||
actions = [
|
||||
{
|
||||
type: 'appReceivedNewExternalProperties',
|
||||
payload: { databaseDocumentID, resolverComponentInstanceID },
|
||||
payload: {
|
||||
databaseDocumentID,
|
||||
resolverComponentInstanceID,
|
||||
|
||||
// `locationSearch` doesn't matter for this test
|
||||
locationSearch: '',
|
||||
},
|
||||
},
|
||||
];
|
||||
});
|
||||
|
@ -120,7 +126,13 @@ describe('data state', () => {
|
|||
actions = [
|
||||
{
|
||||
type: 'appReceivedNewExternalProperties',
|
||||
payload: { databaseDocumentID, resolverComponentInstanceID },
|
||||
payload: {
|
||||
databaseDocumentID,
|
||||
resolverComponentInstanceID,
|
||||
|
||||
// `locationSearch` doesn't matter for this test
|
||||
locationSearch: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'appRequestedResolverData',
|
||||
|
@ -182,6 +194,8 @@ describe('data state', () => {
|
|||
payload: {
|
||||
databaseDocumentID: firstDatabaseDocumentID,
|
||||
resolverComponentInstanceID: resolverComponentInstanceID1,
|
||||
// `locationSearch` doesn't matter for this test
|
||||
locationSearch: '',
|
||||
},
|
||||
},
|
||||
// this happens when the middleware starts the request
|
||||
|
@ -195,6 +209,8 @@ describe('data state', () => {
|
|||
payload: {
|
||||
databaseDocumentID: secondDatabaseDocumentID,
|
||||
resolverComponentInstanceID: resolverComponentInstanceID2,
|
||||
// `locationSearch` doesn't matter for this test
|
||||
locationSearch: '',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -48,6 +48,13 @@ const uiReducer: Reducer<ResolverUIState, ResolverAction> = (
|
|||
selectedNode: nodeID,
|
||||
};
|
||||
return next;
|
||||
} else if (action.type === 'appReceivedNewExternalProperties') {
|
||||
const next: ResolverUIState = {
|
||||
...state,
|
||||
locationSearch: action.payload.locationSearch,
|
||||
resolverComponentInstanceID: action.payload.resolverComponentInstanceID,
|
||||
};
|
||||
return next;
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -301,6 +301,15 @@ export const ariaFlowtoNodeID: (
|
|||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* The legacy `crumbEvent` and `crumbId` parameters.
|
||||
* @deprecated
|
||||
*/
|
||||
export const breadcrumbParameters = composeSelectors(
|
||||
uiStateSelector,
|
||||
uiSelectors.breadcrumbParameters
|
||||
);
|
||||
|
||||
/**
|
||||
* Calls the `secondSelector` with the result of the `selector`. Use this when re-exporting a
|
||||
* concern-specific selector. `selector` should return the concern-specific state.
|
||||
|
|
|
@ -1,30 +1,50 @@
|
|||
/*
|
||||
* 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 { createSelector } from 'reselect';
|
||||
import { ResolverUIState } from '../../types';
|
||||
|
||||
/**
|
||||
* id of the "current" tree node (fake-focused)
|
||||
*/
|
||||
export const ariaActiveDescendant = createSelector(
|
||||
(uiState: ResolverUIState) => uiState,
|
||||
/* eslint-disable no-shadow */
|
||||
({ ariaActiveDescendant }) => {
|
||||
return ariaActiveDescendant;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* id of the currently "selected" tree node
|
||||
*/
|
||||
export const selectedNode = createSelector(
|
||||
(uiState: ResolverUIState) => uiState,
|
||||
/* eslint-disable no-shadow */
|
||||
({ selectedNode }: ResolverUIState) => {
|
||||
return selectedNode;
|
||||
}
|
||||
);
|
||||
/*
|
||||
* 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 { createSelector } from 'reselect';
|
||||
import { ResolverUIState } from '../../types';
|
||||
import * as locationSearchModel from '../../models/location_search';
|
||||
|
||||
/**
|
||||
* id of the "current" tree node (fake-focused)
|
||||
*/
|
||||
export const ariaActiveDescendant = createSelector(
|
||||
(uiState: ResolverUIState) => uiState,
|
||||
/* eslint-disable no-shadow */
|
||||
({ ariaActiveDescendant }) => {
|
||||
return ariaActiveDescendant;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* id of the currently "selected" tree node
|
||||
*/
|
||||
export const selectedNode = createSelector(
|
||||
(uiState: ResolverUIState) => uiState,
|
||||
/* eslint-disable no-shadow */
|
||||
({ selectedNode }: ResolverUIState) => {
|
||||
return selectedNode;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* The legacy `crumbEvent` and `crumbId` parameters.
|
||||
* @deprecated
|
||||
*/
|
||||
export const breadcrumbParameters = createSelector(
|
||||
(state: ResolverUIState) => state.locationSearch,
|
||||
(state: ResolverUIState) => state.resolverComponentInstanceID,
|
||||
(locationSearch, resolverComponentInstanceID) => {
|
||||
if (locationSearch === undefined || resolverComponentInstanceID === undefined) {
|
||||
// Equivalent to `null`
|
||||
return {
|
||||
crumbId: '',
|
||||
crumbEvent: '',
|
||||
};
|
||||
}
|
||||
return locationSearchModel.breadcrumbParameters(locationSearch, resolverComponentInstanceID);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -50,6 +50,16 @@ export interface ResolverUIState {
|
|||
* `nodeID` of the selected node
|
||||
*/
|
||||
readonly selectedNode: string | null;
|
||||
|
||||
/**
|
||||
* The `search` part of the URL.
|
||||
*/
|
||||
readonly locationSearch?: string;
|
||||
|
||||
/**
|
||||
* An ID that is used to differentiate this Resolver instance from others concurrently running on the same page.
|
||||
*/
|
||||
readonly resolverComponentInstanceID?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,7 +208,12 @@ export interface DataState {
|
|||
* The id used for the pending request, if there is one.
|
||||
*/
|
||||
readonly pendingRequestDatabaseDocumentID?: string;
|
||||
readonly resolverComponentInstanceID: string | undefined;
|
||||
|
||||
/**
|
||||
* An ID that is used to differentiate this Resolver instance from others concurrently running on the same page.
|
||||
* Used to prevent collisions in things like query parameters.
|
||||
*/
|
||||
readonly resolverComponentInstanceID?: string;
|
||||
|
||||
/**
|
||||
* The parameters and response from the last successful request.
|
||||
|
@ -510,8 +525,9 @@ export interface ResolverProps {
|
|||
* Used as the origin of the Resolver graph.
|
||||
*/
|
||||
databaseDocumentID?: string;
|
||||
|
||||
/**
|
||||
* A string literal describing where in the application resolver is located.
|
||||
* An ID that is used to differentiate this Resolver instance from others concurrently running on the same page.
|
||||
* Used to prevent collisions in things like query parameters.
|
||||
*/
|
||||
resolverComponentInstanceID: string;
|
||||
|
|
|
@ -12,7 +12,7 @@ import { StyledBreadcrumbs } from './panel_content_utilities';
|
|||
|
||||
import * as event from '../../../../common/endpoint/models/event';
|
||||
import { ResolverEvent, ResolverNodeStats } from '../../../../common/endpoint/types';
|
||||
import { CrumbInfo } from '../../types';
|
||||
import { useReplaceBreadcrumbParameters } from '../use_replace_breadcrumb_parameters';
|
||||
|
||||
/**
|
||||
* This view gives counts for all the related events of a process grouped by related event type.
|
||||
|
@ -27,11 +27,9 @@ import { CrumbInfo } from '../../types';
|
|||
*/
|
||||
export const EventCountsForProcess = memo(function EventCountsForProcess({
|
||||
processEvent,
|
||||
pushToQueryParams,
|
||||
relatedStats,
|
||||
}: {
|
||||
processEvent: ResolverEvent;
|
||||
pushToQueryParams: (queryStringKeyValuePair: CrumbInfo) => unknown;
|
||||
relatedStats: ResolverNodeStats;
|
||||
}) {
|
||||
interface EventCountsTableView {
|
||||
|
@ -62,6 +60,7 @@ export const EventCountsForProcess = memo(function EventCountsForProcess({
|
|||
defaultMessage: 'Events',
|
||||
}
|
||||
);
|
||||
const pushToQueryParams = useReplaceBreadcrumbParameters();
|
||||
const crumbs = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
|
|
|
@ -17,7 +17,6 @@ import { EventCountsForProcess } from './event_counts_for_process';
|
|||
import { ProcessDetails } from './process_details';
|
||||
import { ProcessListWithCounts } from './process_list_with_counts';
|
||||
import { RelatedEventDetail } from './related_event_detail';
|
||||
import { useResolverQueryParams } from '../use_resolver_query_params';
|
||||
|
||||
/**
|
||||
* The team decided to use this table to determine which breadcrumbs/view to display:
|
||||
|
@ -39,7 +38,7 @@ const PanelContent = memo(function PanelContent() {
|
|||
|
||||
const { timestamp } = useContext(SideEffectContext);
|
||||
|
||||
const { pushToQueryParams, queryParams } = useResolverQueryParams();
|
||||
const queryParams = useSelector(selectors.breadcrumbParameters);
|
||||
|
||||
const graphableProcesses = useSelector(selectors.graphableProcesses);
|
||||
const graphableProcessEntityIds = useMemo(() => {
|
||||
|
@ -164,16 +163,13 @@ const PanelContent = memo(function PanelContent() {
|
|||
|
||||
const panelInstance = useMemo(() => {
|
||||
if (panelToShow === 'processDetails') {
|
||||
return (
|
||||
<ProcessDetails processEvent={uiSelectedEvent!} pushToQueryParams={pushToQueryParams} />
|
||||
);
|
||||
return <ProcessDetails processEvent={uiSelectedEvent!} />;
|
||||
}
|
||||
|
||||
if (panelToShow === 'eventCountsForProcess') {
|
||||
return (
|
||||
<EventCountsForProcess
|
||||
processEvent={uiSelectedEvent!}
|
||||
pushToQueryParams={pushToQueryParams}
|
||||
relatedStats={relatedStatsForIdFromParams!}
|
||||
/>
|
||||
);
|
||||
|
@ -183,7 +179,6 @@ const PanelContent = memo(function PanelContent() {
|
|||
return (
|
||||
<ProcessEventList
|
||||
processEvent={uiSelectedEvent!}
|
||||
pushToQueryParams={pushToQueryParams}
|
||||
relatedStats={relatedStatsForIdFromParams!}
|
||||
eventType={crumbEvent}
|
||||
/>
|
||||
|
@ -198,21 +193,13 @@ const PanelContent = memo(function PanelContent() {
|
|||
<RelatedEventDetail
|
||||
relatedEventId={crumbId}
|
||||
parentEvent={uiSelectedEvent!}
|
||||
pushToQueryParams={pushToQueryParams}
|
||||
countForParent={parentCount}
|
||||
/>
|
||||
);
|
||||
}
|
||||
// The default 'Event List' / 'List of all processes' view
|
||||
return <ProcessListWithCounts pushToQueryParams={pushToQueryParams} />;
|
||||
}, [
|
||||
uiSelectedEvent,
|
||||
crumbEvent,
|
||||
crumbId,
|
||||
pushToQueryParams,
|
||||
relatedStatsForIdFromParams,
|
||||
panelToShow,
|
||||
]);
|
||||
return <ProcessListWithCounts />;
|
||||
}, [uiSelectedEvent, crumbEvent, crumbId, relatedStatsForIdFromParams, panelToShow]);
|
||||
|
||||
return <>{panelInstance}</>;
|
||||
});
|
||||
|
|
|
@ -1,62 +1,61 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { EuiSpacer, EuiText, EuiButtonEmpty } from '@elastic/eui';
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import { StyledBreadcrumbs } from './panel_content_utilities';
|
||||
import { CrumbInfo } from '../../types';
|
||||
|
||||
/**
|
||||
* Display an error in the panel when something goes wrong and give the user a way to "retreat" back to a default state.
|
||||
*
|
||||
* @param {function} pushToQueryparams A function to update the hash value in the URL to control panel state
|
||||
* @param {string} translatedErrorMessage The message to display in the panel when something goes wrong
|
||||
*/
|
||||
export const PanelContentError = memo(function ({
|
||||
translatedErrorMessage,
|
||||
pushToQueryParams,
|
||||
}: {
|
||||
translatedErrorMessage: string;
|
||||
pushToQueryParams: (arg0: CrumbInfo) => unknown;
|
||||
}) {
|
||||
const crumbs = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
text: i18n.translate('xpack.securitySolution.endpoint.resolver.panel.error.events', {
|
||||
defaultMessage: 'Events',
|
||||
}),
|
||||
onClick: () => {
|
||||
pushToQueryParams({ crumbId: '', crumbEvent: '' });
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.translate('xpack.securitySolution.endpoint.resolver.panel.error.error', {
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
onClick: () => {},
|
||||
},
|
||||
];
|
||||
}, [pushToQueryParams]);
|
||||
return (
|
||||
<>
|
||||
<StyledBreadcrumbs breadcrumbs={crumbs} />
|
||||
<EuiSpacer size="l" />
|
||||
<EuiText textAlign="center">{translatedErrorMessage}</EuiText>
|
||||
<EuiSpacer size="l" />
|
||||
<EuiButtonEmpty
|
||||
onClick={() => {
|
||||
pushToQueryParams({ crumbId: '', crumbEvent: '' });
|
||||
}}
|
||||
>
|
||||
{i18n.translate('xpack.securitySolution.endpoint.resolver.panel.error.goBack', {
|
||||
defaultMessage: 'Click this link to return to the list of all processes.',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</>
|
||||
);
|
||||
});
|
||||
PanelContentError.displayName = 'TableServiceError';
|
||||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { EuiSpacer, EuiText, EuiButtonEmpty } from '@elastic/eui';
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import { StyledBreadcrumbs } from './panel_content_utilities';
|
||||
import { useReplaceBreadcrumbParameters } from '../use_replace_breadcrumb_parameters';
|
||||
|
||||
/**
|
||||
* Display an error in the panel when something goes wrong and give the user a way to "retreat" back to a default state.
|
||||
*
|
||||
* @param {function} pushToQueryparams A function to update the hash value in the URL to control panel state
|
||||
* @param {string} translatedErrorMessage The message to display in the panel when something goes wrong
|
||||
*/
|
||||
export const PanelContentError = memo(function ({
|
||||
translatedErrorMessage,
|
||||
}: {
|
||||
translatedErrorMessage: string;
|
||||
}) {
|
||||
const pushToQueryParams = useReplaceBreadcrumbParameters();
|
||||
const crumbs = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
text: i18n.translate('xpack.securitySolution.endpoint.resolver.panel.error.events', {
|
||||
defaultMessage: 'Events',
|
||||
}),
|
||||
onClick: () => {
|
||||
pushToQueryParams({ crumbId: '', crumbEvent: '' });
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.translate('xpack.securitySolution.endpoint.resolver.panel.error.error', {
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
onClick: () => {},
|
||||
},
|
||||
];
|
||||
}, [pushToQueryParams]);
|
||||
return (
|
||||
<>
|
||||
<StyledBreadcrumbs breadcrumbs={crumbs} />
|
||||
<EuiSpacer size="l" />
|
||||
<EuiText textAlign="center">{translatedErrorMessage}</EuiText>
|
||||
<EuiSpacer size="l" />
|
||||
<EuiButtonEmpty
|
||||
onClick={() => {
|
||||
pushToQueryParams({ crumbId: '', crumbEvent: '' });
|
||||
}}
|
||||
>
|
||||
{i18n.translate('xpack.securitySolution.endpoint.resolver.panel.error.goBack', {
|
||||
defaultMessage: 'Click this link to return to the list of all processes.',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</>
|
||||
);
|
||||
});
|
||||
PanelContentError.displayName = 'TableServiceError';
|
||||
|
|
|
@ -31,7 +31,8 @@ import {
|
|||
import { CubeForProcess } from './cube_for_process';
|
||||
import { ResolverEvent } from '../../../../common/endpoint/types';
|
||||
import { useResolverTheme } from '../assets';
|
||||
import { CrumbInfo, ResolverState } from '../../types';
|
||||
import { ResolverState } from '../../types';
|
||||
import { useReplaceBreadcrumbParameters } from '../use_replace_breadcrumb_parameters';
|
||||
|
||||
const StyledDescriptionList = styled(EuiDescriptionList)`
|
||||
&.euiDescriptionList.euiDescriptionList--column dt.euiDescriptionList__title.desc-title {
|
||||
|
@ -49,10 +50,8 @@ const StyledTitle = styled('h4')`
|
|||
*/
|
||||
export const ProcessDetails = memo(function ProcessDetails({
|
||||
processEvent,
|
||||
pushToQueryParams,
|
||||
}: {
|
||||
processEvent: ResolverEvent;
|
||||
pushToQueryParams: (queryStringKeyValuePair: CrumbInfo) => unknown;
|
||||
}) {
|
||||
const processName = event.eventName(processEvent);
|
||||
const entityId = event.entityId(processEvent);
|
||||
|
@ -127,6 +126,8 @@ export const ProcessDetails = memo(function ProcessDetails({
|
|||
return processDescriptionListData;
|
||||
}, [processEvent]);
|
||||
|
||||
const pushToQueryParams = useReplaceBreadcrumbParameters();
|
||||
|
||||
const crumbs = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@ import { ResolverEvent, ResolverNodeStats } from '../../../../common/endpoint/ty
|
|||
import * as selectors from '../../store/selectors';
|
||||
import { useResolverDispatch } from '../use_resolver_dispatch';
|
||||
import { RelatedEventLimitWarning } from '../limit_warnings';
|
||||
import { CrumbInfo } from '../../types';
|
||||
import { useReplaceBreadcrumbParameters } from '../use_replace_breadcrumb_parameters';
|
||||
|
||||
/**
|
||||
* This view presents a list of related events of a given type for a given process.
|
||||
|
@ -129,10 +129,8 @@ export const ProcessEventList = memo(function ProcessEventList({
|
|||
processEvent,
|
||||
eventType,
|
||||
relatedStats,
|
||||
pushToQueryParams,
|
||||
}: {
|
||||
processEvent: ResolverEvent;
|
||||
pushToQueryParams: (arg0: CrumbInfo) => unknown;
|
||||
eventType: string;
|
||||
relatedStats: ResolverNodeStats;
|
||||
}) {
|
||||
|
@ -169,6 +167,8 @@ export const ProcessEventList = memo(function ProcessEventList({
|
|||
}
|
||||
}, [relatedsReady, dispatch, processEntityId]);
|
||||
|
||||
const pushToQueryParams = useReplaceBreadcrumbParameters();
|
||||
|
||||
const waitCrumbs = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/* eslint-disable react/display-name */
|
||||
|
||||
import React, { memo, useContext, useCallback, useMemo } from 'react';
|
||||
import {
|
||||
EuiBasicTableColumn,
|
||||
|
@ -22,7 +25,7 @@ import { SideEffectContext } from '../side_effect_context';
|
|||
import { CubeForProcess } from './cube_for_process';
|
||||
import { SafeResolverEvent } from '../../../../common/endpoint/types';
|
||||
import { LimitWarning } from '../limit_warnings';
|
||||
import { CrumbInfo } from '../../types';
|
||||
import { useReplaceBreadcrumbParameters } from '../use_replace_breadcrumb_parameters';
|
||||
|
||||
const StyledLimitWarning = styled(LimitWarning)`
|
||||
flex-flow: row wrap;
|
||||
|
@ -46,14 +49,8 @@ const StyledLimitWarning = styled(LimitWarning)`
|
|||
|
||||
/**
|
||||
* The "default" view for the panel: A list of all the processes currently in the graph.
|
||||
*
|
||||
* @param {function} pushToQueryparams A function to update the hash value in the URL to control panel state
|
||||
*/
|
||||
export const ProcessListWithCounts = memo(function ProcessListWithCounts({
|
||||
pushToQueryParams,
|
||||
}: {
|
||||
pushToQueryParams: (queryStringKeyValuePair: CrumbInfo) => unknown;
|
||||
}) {
|
||||
export const ProcessListWithCounts = memo(() => {
|
||||
interface ProcessTableView {
|
||||
name?: string;
|
||||
timestamp?: Date;
|
||||
|
@ -63,6 +60,7 @@ export const ProcessListWithCounts = memo(function ProcessListWithCounts({
|
|||
const dispatch = useResolverDispatch();
|
||||
const { timestamp } = useContext(SideEffectContext);
|
||||
const isProcessTerminated = useSelector(selectors.isProcessTerminated);
|
||||
const pushToQueryParams = useReplaceBreadcrumbParameters();
|
||||
const handleBringIntoViewClick = useCallback(
|
||||
(processTableViewItem) => {
|
||||
dispatch({
|
||||
|
|
|
@ -16,7 +16,8 @@ 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, ResolverState } from '../../types';
|
||||
import { ResolverState } from '../../types';
|
||||
import { useReplaceBreadcrumbParameters } from '../use_replace_breadcrumb_parameters';
|
||||
|
||||
// Adding some styles to prevent horizontal scrollbars, per request from UX review
|
||||
const StyledDescriptionList = memo(styled(EuiDescriptionList)`
|
||||
|
@ -76,15 +77,13 @@ function entriesForDisplay(entries: Array<{ title: string; description: string }
|
|||
* This view presents a detailed view of all the available data for a related event, split and titled by the "section"
|
||||
* it appears in the underlying ResolverEvent
|
||||
*/
|
||||
export const RelatedEventDetail = memo(function RelatedEventDetail({
|
||||
export const RelatedEventDetail = memo(function ({
|
||||
relatedEventId,
|
||||
parentEvent,
|
||||
pushToQueryParams,
|
||||
countForParent,
|
||||
}: {
|
||||
relatedEventId: string;
|
||||
parentEvent: ResolverEvent;
|
||||
pushToQueryParams: (queryStringKeyValuePair: CrumbInfo) => unknown;
|
||||
countForParent: number | undefined;
|
||||
}) {
|
||||
const processName = (parentEvent && event.eventName(parentEvent)) || '*';
|
||||
|
@ -130,6 +129,8 @@ export const RelatedEventDetail = memo(function RelatedEventDetail({
|
|||
selectors.relatedEventDisplayInfoByEntityAndSelfId(state)(processEntityId, relatedEventId)
|
||||
);
|
||||
|
||||
const pushToQueryParams = useReplaceBreadcrumbParameters();
|
||||
|
||||
const waitCrumbs = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
|
@ -247,9 +248,7 @@ export const RelatedEventDetail = memo(function RelatedEventDetail({
|
|||
defaultMessage: 'Related event not found.',
|
||||
}
|
||||
);
|
||||
return (
|
||||
<PanelContentError translatedErrorMessage={errString} pushToQueryParams={pushToQueryParams} />
|
||||
);
|
||||
return <PanelContentError translatedErrorMessage={errString} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -18,7 +18,7 @@ import { ResolverEvent, SafeResolverEvent } 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 { useResolverQueryParams } from './use_resolver_query_params';
|
||||
import { useReplaceBreadcrumbParameters } from './use_replace_breadcrumb_parameters';
|
||||
|
||||
interface StyledActionsContainer {
|
||||
readonly color: string;
|
||||
|
@ -242,7 +242,7 @@ const UnstyledProcessEventDot = React.memo(
|
|||
});
|
||||
}, [dispatch, nodeID]);
|
||||
|
||||
const { pushToQueryParams } = useResolverQueryParams();
|
||||
const pushToQueryParams = useReplaceBreadcrumbParameters();
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (animationTarget.current?.beginElement) {
|
||||
|
|
|
@ -4,12 +4,17 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { useQueryStringKeys } from './use_query_string_keys';
|
||||
import { CrumbInfo } from '../types';
|
||||
|
||||
export function useResolverQueryParams() {
|
||||
/**
|
||||
* @deprecated
|
||||
* Update the browser's `search` with data from `queryStringState`. The URL search parameter names
|
||||
* will include Resolver's `resolverComponentInstanceID`.
|
||||
*/
|
||||
export function useReplaceBreadcrumbParameters(): (queryStringState: CrumbInfo) => void {
|
||||
/**
|
||||
* 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.
|
||||
|
@ -17,7 +22,7 @@ export function useResolverQueryParams() {
|
|||
const history = useHistory();
|
||||
const urlSearch = useLocation().search;
|
||||
const { idKey, eventKey } = useQueryStringKeys();
|
||||
const pushToQueryParams = useCallback(
|
||||
return useCallback(
|
||||
(queryStringState: CrumbInfo) => {
|
||||
const urlSearchParams = new URLSearchParams(urlSearch);
|
||||
|
||||
|
@ -39,17 +44,4 @@ export function useResolverQueryParams() {
|
|||
},
|
||||
[history, urlSearch, idKey, eventKey]
|
||||
);
|
||||
const queryParams: CrumbInfo = useMemo(() => {
|
||||
const urlSearchParams = new URLSearchParams(urlSearch);
|
||||
return {
|
||||
// Use `''` for backwards compatibility with deprecated code.
|
||||
crumbEvent: urlSearchParams.get(eventKey) ?? '',
|
||||
crumbId: urlSearchParams.get(idKey) ?? '',
|
||||
};
|
||||
}, [urlSearch, idKey, eventKey]);
|
||||
|
||||
return {
|
||||
pushToQueryParams,
|
||||
queryParams,
|
||||
};
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { useLayoutEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useResolverDispatch } from './use_resolver_dispatch';
|
||||
|
||||
/**
|
||||
|
@ -22,10 +23,11 @@ export function useStateSyncingActions({
|
|||
resolverComponentInstanceID: string;
|
||||
}) {
|
||||
const dispatch = useResolverDispatch();
|
||||
const locationSearch = useLocation().search;
|
||||
useLayoutEffect(() => {
|
||||
dispatch({
|
||||
type: 'appReceivedNewExternalProperties',
|
||||
payload: { databaseDocumentID, resolverComponentInstanceID },
|
||||
payload: { databaseDocumentID, resolverComponentInstanceID, locationSearch },
|
||||
});
|
||||
}, [dispatch, databaseDocumentID, resolverComponentInstanceID]);
|
||||
}, [dispatch, databaseDocumentID, resolverComponentInstanceID, locationSearch]);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue