Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Resolver] model location.search in redux #76140

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file will have the logic for getting values out of (and constructing new) URLSearchParams

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,
};
}
28 changes: 28 additions & 0 deletions x-pack/plugins/security_solution/public/resolver/store/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.
Expand Down Expand Up @@ -68,7 +68,13 @@ describe('data state', () => {
actions = [
{
type: 'appReceivedNewExternalProperties',
payload: { databaseDocumentID, resolverComponentInstanceID },
payload: {
databaseDocumentID,
resolverComponentInstanceID,

// `locationSearch` doesn't matter for this test
locationSearch: '',
},
},
];
});
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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
Expand All @@ -195,6 +209,8 @@ describe('data state', () => {
payload: {
databaseDocumentID: secondDatabaseDocumentID,
resolverComponentInstanceID: resolverComponentInstanceID2,
// `locationSearch` doesn't matter for this test
locationSearch: '',
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,15 @@ export const ariaFlowtoNodeID: (
}
);

/**
* The legacy `crumbEvent` and `crumbId` parameters.
* @deprecated
*/
export const breadcrumbParameters = composeSelectors(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use this to get the query string parameters used by the panel

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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
I'm guessing this is another line-endings thing.

(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(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function was added. the rest of the changes (except for import statements) are white space.

(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);
}
);
20 changes: 18 additions & 2 deletions x-pack/plugins/security_solution/public/resolver/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 {
Expand Down Expand Up @@ -62,6 +60,7 @@ export const EventCountsForProcess = memo(function EventCountsForProcess({
defaultMessage: 'Events',
}
);
const pushToQueryParams = useReplaceBreadcrumbParameters();
const crumbs = useMemo(() => {
return [
{
Expand Down
Loading