mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
parent
b1e14ce246
commit
e48317fc82
17 changed files with 264 additions and 95 deletions
|
@ -89,7 +89,8 @@
|
|||
"**/react": "^16.12.0",
|
||||
"**/react-test-renderer": "^16.12.0",
|
||||
"**/deepmerge": "^4.2.2",
|
||||
"**/serialize-javascript": "^2.1.1"
|
||||
"**/serialize-javascript": "^2.1.1",
|
||||
"**/fast-deep-equal": "^3.1.1"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
|
|
|
@ -52,11 +52,15 @@ export const RedirectToEditRulePage = ({ location: { search } }: DetectionEngine
|
|||
);
|
||||
};
|
||||
|
||||
export const getDetectionEngineUrl = () => `#/link-to/${DETECTION_ENGINE_PAGE_NAME}`;
|
||||
const baseDetectionEngineUrl = `#/link-to/${DETECTION_ENGINE_PAGE_NAME}`;
|
||||
|
||||
export const getDetectionEngineUrl = () => `${baseDetectionEngineUrl}`;
|
||||
export const getDetectionEngineAlertUrl = () =>
|
||||
`#/link-to/${DETECTION_ENGINE_PAGE_NAME}/${DetectionEngineTab.alerts}`;
|
||||
export const getRulesUrl = () => `#/link-to/${DETECTION_ENGINE_PAGE_NAME}/rules`;
|
||||
export const getCreateRuleUrl = () => `#/link-to/${DETECTION_ENGINE_PAGE_NAME}/rules/create-rule`;
|
||||
export const getRuleDetailsUrl = () => `#/link-to/${DETECTION_ENGINE_PAGE_NAME}/rules/rule-details`;
|
||||
export const getEditRuleUrl = () =>
|
||||
`#/link-to/${DETECTION_ENGINE_PAGE_NAME}/rules/rule-details/edit-rule`;
|
||||
`${baseDetectionEngineUrl}/${DetectionEngineTab.alerts}`;
|
||||
export const getDetectionEngineTabUrl = (tabPath: string) => `${baseDetectionEngineUrl}/${tabPath}`;
|
||||
export const getRulesUrl = () => `${baseDetectionEngineUrl}/rules`;
|
||||
export const getCreateRuleUrl = () => `${baseDetectionEngineUrl}/rules/create`;
|
||||
export const getRuleDetailsUrl = (detailName: string) =>
|
||||
`${baseDetectionEngineUrl}/rules/id/${detailName}`;
|
||||
export const getEditRuleUrl = (detailName: string) =>
|
||||
`${baseDetectionEngineUrl}/rules/id/${detailName}/edit`;
|
||||
|
|
|
@ -10,6 +10,7 @@ import { getOr, omit } from 'lodash/fp';
|
|||
import { APP_NAME } from '../../../../common/constants';
|
||||
import { getBreadcrumbs as getHostDetailsBreadcrumbs } from '../../../pages/hosts/details/utils';
|
||||
import { getBreadcrumbs as getIPDetailsBreadcrumbs } from '../../../pages/network/ip_details';
|
||||
import { getBreadcrumbs as getDetectionRulesBreadcrumbs } from '../../../pages/detection_engine/rules/utils';
|
||||
import { SiemPageName } from '../../../pages/home/types';
|
||||
import { RouteSpyState, HostRouteSpyState, NetworkRouteSpyState } from '../../../utils/route/types';
|
||||
import { getOverviewUrl } from '../../link_to';
|
||||
|
@ -38,6 +39,9 @@ const isNetworkRoutes = (spyState: RouteSpyState): spyState is NetworkRouteSpySt
|
|||
const isHostsRoutes = (spyState: RouteSpyState): spyState is HostRouteSpyState =>
|
||||
spyState != null && spyState.pageName === SiemPageName.hosts;
|
||||
|
||||
const isDetectionsRoutes = (spyState: RouteSpyState) =>
|
||||
spyState != null && spyState.pageName === SiemPageName.detections;
|
||||
|
||||
export const getBreadcrumbsForRoute = (
|
||||
object: RouteSpyState & TabNavigationProps
|
||||
): Breadcrumb[] | null => {
|
||||
|
@ -76,6 +80,24 @@ export const getBreadcrumbsForRoute = (
|
|||
),
|
||||
];
|
||||
}
|
||||
if (isDetectionsRoutes(spyState) && object.navTabs) {
|
||||
const tempNav: SearchNavTab = { urlKey: 'detections', isDetailPage: false };
|
||||
let urlStateKeys = [getOr(tempNav, spyState.pageName, object.navTabs)];
|
||||
if (spyState.tabName != null) {
|
||||
urlStateKeys = [...urlStateKeys, getOr(tempNav, spyState.tabName, object.navTabs)];
|
||||
}
|
||||
|
||||
return [
|
||||
...siemRootBreadcrumb,
|
||||
...getDetectionRulesBreadcrumbs(
|
||||
spyState,
|
||||
urlStateKeys.reduce(
|
||||
(acc: string[], item: SearchNavTab) => [...acc, getSearch(item, object)],
|
||||
[]
|
||||
)
|
||||
),
|
||||
];
|
||||
}
|
||||
if (
|
||||
spyState != null &&
|
||||
object.navTabs &&
|
||||
|
|
|
@ -187,6 +187,7 @@ describe('SIEM Navigation', () => {
|
|||
query: { language: 'kuery', query: '' },
|
||||
savedQuery: undefined,
|
||||
search: '',
|
||||
state: undefined,
|
||||
tabName: 'authentications',
|
||||
timeline: { id: '', isOpen: false },
|
||||
timerange: {
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { isEqual } from 'lodash/fp';
|
||||
import isEqual from 'lodash/fp/isEqual';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import React, { useEffect } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { compose } from 'redux';
|
||||
|
@ -16,67 +17,78 @@ import { setBreadcrumbs } from './breadcrumbs';
|
|||
import { TabNavigation } from './tab_navigation';
|
||||
import { SiemNavigationProps, SiemNavigationComponentProps } from './types';
|
||||
|
||||
export const SiemNavigationComponent = React.memo<
|
||||
SiemNavigationComponentProps & SiemNavigationProps & RouteSpyState
|
||||
>(
|
||||
({ detailName, display, navTabs, pageName, pathName, search, tabName, urlState, flowTarget }) => {
|
||||
useEffect(() => {
|
||||
if (pathName) {
|
||||
setBreadcrumbs({
|
||||
query: urlState.query,
|
||||
detailName,
|
||||
filters: urlState.filters,
|
||||
navTabs,
|
||||
pageName,
|
||||
pathName,
|
||||
savedQuery: urlState.savedQuery,
|
||||
search,
|
||||
tabName,
|
||||
flowTarget,
|
||||
timerange: urlState.timerange,
|
||||
timeline: urlState.timeline,
|
||||
});
|
||||
}
|
||||
}, [pathName, search, navTabs, urlState]);
|
||||
export const SiemNavigationComponent: React.FC<SiemNavigationComponentProps &
|
||||
SiemNavigationProps &
|
||||
RouteSpyState> = ({
|
||||
detailName,
|
||||
display,
|
||||
navTabs,
|
||||
pageName,
|
||||
pathName,
|
||||
search,
|
||||
tabName,
|
||||
urlState,
|
||||
flowTarget,
|
||||
state,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
if (pathName) {
|
||||
setBreadcrumbs({
|
||||
query: urlState.query,
|
||||
detailName,
|
||||
filters: urlState.filters,
|
||||
navTabs,
|
||||
pageName,
|
||||
pathName,
|
||||
savedQuery: urlState.savedQuery,
|
||||
search,
|
||||
tabName,
|
||||
flowTarget,
|
||||
timerange: urlState.timerange,
|
||||
timeline: urlState.timeline,
|
||||
state,
|
||||
});
|
||||
}
|
||||
}, [pathName, search, navTabs, urlState, state]);
|
||||
|
||||
return (
|
||||
<TabNavigation
|
||||
query={urlState.query}
|
||||
display={display}
|
||||
filters={urlState.filters}
|
||||
navTabs={navTabs}
|
||||
pageName={pageName}
|
||||
pathName={pathName}
|
||||
savedQuery={urlState.savedQuery}
|
||||
tabName={tabName}
|
||||
timeline={urlState.timeline}
|
||||
timerange={urlState.timerange}
|
||||
/>
|
||||
);
|
||||
},
|
||||
(prevProps, nextProps) => {
|
||||
return (
|
||||
prevProps.pathName === nextProps.pathName &&
|
||||
prevProps.search === nextProps.search &&
|
||||
isEqual(prevProps.navTabs, nextProps.navTabs) &&
|
||||
isEqual(prevProps.urlState, nextProps.urlState)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
SiemNavigationComponent.displayName = 'SiemNavigationComponent';
|
||||
return (
|
||||
<TabNavigation
|
||||
query={urlState.query}
|
||||
display={display}
|
||||
filters={urlState.filters}
|
||||
navTabs={navTabs}
|
||||
pageName={pageName}
|
||||
pathName={pathName}
|
||||
savedQuery={urlState.savedQuery}
|
||||
tabName={tabName}
|
||||
timeline={urlState.timeline}
|
||||
timerange={urlState.timerange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const SiemNavigationRedux = compose<
|
||||
React.ComponentClass<SiemNavigationProps & RouteSpyState>
|
||||
>(connect(makeMapStateToProps))(SiemNavigationComponent);
|
||||
>(connect(makeMapStateToProps))(
|
||||
React.memo(
|
||||
SiemNavigationComponent,
|
||||
(prevProps, nextProps) =>
|
||||
prevProps.pathName === nextProps.pathName &&
|
||||
prevProps.search === nextProps.search &&
|
||||
isEqual(prevProps.navTabs, nextProps.navTabs) &&
|
||||
isEqual(prevProps.urlState, nextProps.urlState) &&
|
||||
deepEqual(prevProps.state, nextProps.state)
|
||||
)
|
||||
);
|
||||
|
||||
export const SiemNavigation = React.memo<SiemNavigationProps>(props => {
|
||||
const SiemNavigationContainer: React.FC<SiemNavigationProps> = props => {
|
||||
const [routeProps] = useRouteSpy();
|
||||
const stateNavReduxProps: RouteSpyState & SiemNavigationProps = {
|
||||
...routeProps,
|
||||
...props,
|
||||
};
|
||||
return <SiemNavigationRedux {...stateNavReduxProps} />;
|
||||
});
|
||||
|
||||
SiemNavigation.displayName = 'SiemNavigation';
|
||||
return <SiemNavigationRedux {...stateNavReduxProps} />;
|
||||
};
|
||||
|
||||
export const SiemNavigation = SiemNavigationContainer;
|
||||
|
|
|
@ -230,8 +230,13 @@ const makeMapStateToProps = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const DetectionEngine = connect(makeMapStateToProps, {
|
||||
const mapDispatchToProps = {
|
||||
setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker,
|
||||
})(DetectionEngineComponent);
|
||||
};
|
||||
|
||||
export const DetectionEngine = connect(
|
||||
makeMapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(DetectionEngineComponent);
|
||||
|
||||
DetectionEngine.displayName = 'DetectionEngine';
|
||||
|
|
|
@ -19,7 +19,7 @@ const detectionEnginePath = `/:pageName(detections)`;
|
|||
|
||||
type Props = Partial<RouteComponentProps<{}>> & { url: string };
|
||||
|
||||
export const DetectionEngineContainer = React.memo<Props>(() => (
|
||||
const DetectionEngineContainerComponent: React.FC<Props> = () => (
|
||||
<ManageUserInfo>
|
||||
<Switch>
|
||||
<Route
|
||||
|
@ -35,10 +35,10 @@ export const DetectionEngineContainer = React.memo<Props>(() => (
|
|||
<Route exact path={`${detectionEnginePath}/rules/create`}>
|
||||
<CreateRuleComponent />
|
||||
</Route>
|
||||
<Route exact path={`${detectionEnginePath}/rules/id/:ruleId/`}>
|
||||
<Route exact path={`${detectionEnginePath}/rules/id/:detailName`}>
|
||||
<RuleDetails />
|
||||
</Route>
|
||||
<Route exact path={`${detectionEnginePath}/rules/id/:ruleId/edit`}>
|
||||
<Route exact path={`${detectionEnginePath}/rules/id/:detailName/edit`}>
|
||||
<EditRuleComponent />
|
||||
</Route>
|
||||
<Route
|
||||
|
@ -49,5 +49,6 @@ export const DetectionEngineContainer = React.memo<Props>(() => (
|
|||
/>
|
||||
</Switch>
|
||||
</ManageUserInfo>
|
||||
));
|
||||
DetectionEngineContainer.displayName = 'DetectionEngineContainer';
|
||||
);
|
||||
|
||||
export const DetectionEngineContainer = React.memo(DetectionEngineContainerComponent);
|
||||
|
|
|
@ -109,7 +109,7 @@ const RuleDetailsComponent = memo<RuleDetailsComponentProps>(
|
|||
hasIndexWrite,
|
||||
signalIndexName,
|
||||
} = useUserInfo();
|
||||
const { ruleId } = useParams();
|
||||
const { detailName: ruleId } = useParams();
|
||||
const [isLoading, rule] = useRule(ruleId);
|
||||
// This is used to re-trigger api rule status when user de/activate rule
|
||||
const [ruleEnabled, setRuleEnabled] = useState<boolean | null>(null);
|
||||
|
@ -381,7 +381,7 @@ const RuleDetailsComponent = memo<RuleDetailsComponentProps>(
|
|||
}}
|
||||
</WithSource>
|
||||
|
||||
<SpyRoute />
|
||||
<SpyRoute state={{ ruleName: rule?.name }} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -402,8 +402,10 @@ const makeMapStateToProps = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const RuleDetails = connect(makeMapStateToProps, {
|
||||
const mapDispatchToProps = {
|
||||
setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker,
|
||||
})(RuleDetailsComponent);
|
||||
};
|
||||
|
||||
export const RuleDetails = connect(makeMapStateToProps, mapDispatchToProps)(RuleDetailsComponent);
|
||||
|
||||
RuleDetails.displayName = 'RuleDetails';
|
||||
|
|
|
@ -57,7 +57,7 @@ export const EditRuleComponent = memo(() => {
|
|||
canUserCRUD,
|
||||
hasManageApiKey,
|
||||
} = useUserInfo();
|
||||
const { ruleId } = useParams();
|
||||
const { detailName: ruleId } = useParams();
|
||||
const [loading, rule] = useRule(ruleId);
|
||||
|
||||
const userHasNoPermissions =
|
||||
|
@ -347,7 +347,7 @@ export const EditRuleComponent = memo(() => {
|
|||
</EuiFlexGroup>
|
||||
</WrapperPage>
|
||||
|
||||
<SpyRoute />
|
||||
<SpyRoute state={{ ruleName: rule?.name }} />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -25,6 +25,14 @@ export const PAGE_TITLE = i18n.translate('xpack.siem.detectionEngine.rules.pageT
|
|||
defaultMessage: 'Signal detection rules',
|
||||
});
|
||||
|
||||
export const ADD_PAGE_TITLE = i18n.translate('xpack.siem.detectionEngine.rules.addPageTitle', {
|
||||
defaultMessage: 'Create',
|
||||
});
|
||||
|
||||
export const EDIT_PAGE_TITLE = i18n.translate('xpack.siem.detectionEngine.rules.editPageTitle', {
|
||||
defaultMessage: 'Edit',
|
||||
});
|
||||
|
||||
export const REFRESH = i18n.translate('xpack.siem.detectionEngine.rules.allRules.refreshTitle', {
|
||||
defaultMessage: 'Refresh',
|
||||
});
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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 { Breadcrumb } from 'ui/chrome';
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
|
||||
import {
|
||||
getDetectionEngineUrl,
|
||||
getDetectionEngineTabUrl,
|
||||
getRulesUrl,
|
||||
getRuleDetailsUrl,
|
||||
getCreateRuleUrl,
|
||||
getEditRuleUrl,
|
||||
} from '../../../components/link_to/redirect_to_detection_engine';
|
||||
import * as i18nDetections from '../translations';
|
||||
import * as i18nRules from './translations';
|
||||
import { RouteSpyState } from '../../../utils/route/types';
|
||||
|
||||
const getTabBreadcrumb = (pathname: string, search: string[]) => {
|
||||
const tabPath = pathname.split('/')[2];
|
||||
|
||||
if (tabPath === 'alerts') {
|
||||
return {
|
||||
text: i18nDetections.ALERT,
|
||||
href: `${getDetectionEngineTabUrl(tabPath)}${!isEmpty(search[0]) ? search[0] : ''}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (tabPath === 'signals') {
|
||||
return {
|
||||
text: i18nDetections.SIGNAL,
|
||||
href: `${getDetectionEngineTabUrl(tabPath)}${!isEmpty(search[0]) ? search[0] : ''}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (tabPath === 'rules') {
|
||||
return {
|
||||
text: i18nRules.PAGE_TITLE,
|
||||
href: `${getRulesUrl()}${!isEmpty(search[0]) ? search[0] : ''}`,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const isRuleCreatePage = (pathname: string) =>
|
||||
pathname.includes('/rules') && pathname.includes('/create');
|
||||
|
||||
const isRuleEditPage = (pathname: string) =>
|
||||
pathname.includes('/rules') && pathname.includes('/edit');
|
||||
|
||||
export const getBreadcrumbs = (params: RouteSpyState, search: string[]): Breadcrumb[] => {
|
||||
let breadcrumb = [
|
||||
{
|
||||
text: i18nDetections.PAGE_TITLE,
|
||||
href: `${getDetectionEngineUrl()}${!isEmpty(search[0]) ? search[0] : ''}`,
|
||||
},
|
||||
];
|
||||
|
||||
const tabBreadcrumb = getTabBreadcrumb(params.pathName, search);
|
||||
|
||||
if (tabBreadcrumb) {
|
||||
breadcrumb = [...breadcrumb, tabBreadcrumb];
|
||||
}
|
||||
|
||||
if (params.detailName && params.state?.ruleName) {
|
||||
breadcrumb = [
|
||||
...breadcrumb,
|
||||
{
|
||||
text: params.state.ruleName,
|
||||
href: `${getRuleDetailsUrl(params.detailName)}${!isEmpty(search[1]) ? search[1] : ''}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (isRuleCreatePage(params.pathName)) {
|
||||
breadcrumb = [
|
||||
...breadcrumb,
|
||||
{
|
||||
text: i18nRules.ADD_PAGE_TITLE,
|
||||
href: `${getCreateRuleUrl()}${!isEmpty(search[1]) ? search[1] : ''}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (isRuleEditPage(params.pathName) && params.detailName && params.state?.ruleName) {
|
||||
breadcrumb = [
|
||||
...breadcrumb,
|
||||
{
|
||||
text: i18nRules.EDIT_PAGE_TITLE,
|
||||
href: `${getEditRuleUrl(params.detailName)}${!isEmpty(search[1]) ? search[1] : ''}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return breadcrumb;
|
||||
};
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
import { Breadcrumb } from 'ui/chrome';
|
||||
import { get, isEmpty } from 'lodash/fp';
|
||||
|
||||
import { get } from 'lodash/fp';
|
||||
import { hostsModel } from '../../../store';
|
||||
import { HostsTableType } from '../../../store/hosts/model';
|
||||
import { getHostsUrl, getHostDetailsUrl } from '../../../components/link_to/redirect_to_hosts';
|
||||
|
@ -29,7 +29,7 @@ export const getBreadcrumbs = (params: HostRouteSpyState, search: string[]): Bre
|
|||
let breadcrumb = [
|
||||
{
|
||||
text: i18n.PAGE_TITLE,
|
||||
href: `${getHostsUrl()}${search && search[0] ? search[0] : ''}`,
|
||||
href: `${getHostsUrl()}${!isEmpty(search[0]) ? search[0] : ''}`,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -38,7 +38,7 @@ export const getBreadcrumbs = (params: HostRouteSpyState, search: string[]): Bre
|
|||
...breadcrumb,
|
||||
{
|
||||
text: params.detailName,
|
||||
href: `${getHostDetailsUrl(params.detailName)}${search && search[1] ? search[1] : ''}`,
|
||||
href: `${getHostDetailsUrl(params.detailName)}${!isEmpty(search[1]) ? search[1] : ''}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
import { Breadcrumb } from 'ui/chrome';
|
||||
import { get, isEmpty } from 'lodash/fp';
|
||||
|
||||
import { get } from 'lodash/fp';
|
||||
import { decodeIpv6 } from '../../../lib/helpers';
|
||||
import { getNetworkUrl, getIPDetailsUrl } from '../../../components/link_to/redirect_to_network';
|
||||
import { networkModel } from '../../../store/network';
|
||||
|
@ -28,7 +28,7 @@ export const getBreadcrumbs = (params: NetworkRouteSpyState, search: string[]):
|
|||
let breadcrumb = [
|
||||
{
|
||||
text: i18n.PAGE_TITLE,
|
||||
href: `${getNetworkUrl()}${search && search[0] ? search[0] : ''}`,
|
||||
href: `${getNetworkUrl()}${!isEmpty(search[0]) ? search[0] : ''}`,
|
||||
},
|
||||
];
|
||||
if (params.detailName != null) {
|
||||
|
@ -37,7 +37,7 @@ export const getBreadcrumbs = (params: NetworkRouteSpyState, search: string[]):
|
|||
{
|
||||
text: decodeIpv6(params.detailName),
|
||||
href: `${getIPDetailsUrl(params.detailName, params.flowTarget)}${
|
||||
search && search[1] ? search[1] : ''
|
||||
!isEmpty(search[1]) ? search[1] : ''
|
||||
}`,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -15,6 +15,7 @@ export const initRouteSpy: RouteSpyState = {
|
|||
tabName: undefined,
|
||||
search: '',
|
||||
pathName: '/',
|
||||
state: undefined,
|
||||
};
|
||||
|
||||
export const RouterSpyStateContext = createContext<[RouteSpyState, Dispatch<RouteSpyAction>]>([
|
||||
|
|
|
@ -8,6 +8,7 @@ import * as H from 'history';
|
|||
import { isEqual } from 'lodash/fp';
|
||||
import { memo, useEffect, useState } from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
|
||||
import { SpyRouteProps } from './types';
|
||||
import { useRouteSpy } from './use_route_spy';
|
||||
|
@ -19,6 +20,7 @@ export const SpyRouteComponent = memo<SpyRouteProps & { location: H.Location }>(
|
|||
match: {
|
||||
params: { pageName, detailName, tabName, flowTarget },
|
||||
},
|
||||
state,
|
||||
}) => {
|
||||
const [isInitializing, setIsInitializing] = useState(true);
|
||||
const [route, dispatch] = useRouteSpy();
|
||||
|
@ -61,8 +63,24 @@ export const SpyRouteComponent = memo<SpyRouteProps & { location: H.Location }>(
|
|||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (pageName && !deepEqual(state, route.state)) {
|
||||
dispatch({
|
||||
type: 'updateRoute',
|
||||
route: {
|
||||
pageName,
|
||||
detailName,
|
||||
tabName,
|
||||
search,
|
||||
pathName: pathname,
|
||||
history,
|
||||
flowTarget,
|
||||
state,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [pathname, search, pageName, detailName, tabName, flowTarget]);
|
||||
}, [pathname, search, pageName, detailName, tabName, flowTarget, state]);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -21,6 +21,7 @@ export interface RouteSpyState {
|
|||
pathName: string;
|
||||
history?: H.History;
|
||||
flowTarget?: FlowTarget;
|
||||
state?: Record<string, string | undefined>;
|
||||
}
|
||||
|
||||
export interface HostRouteSpyState extends RouteSpyState {
|
||||
|
@ -38,7 +39,10 @@ export type RouteSpyAction =
|
|||
}
|
||||
| {
|
||||
type: 'updateRouteWithOutSearch';
|
||||
route: Pick<RouteSpyState, 'pageName' & 'detailName' & 'tabName' & 'pathName' & 'history'>;
|
||||
route: Pick<
|
||||
RouteSpyState,
|
||||
'pageName' & 'detailName' & 'tabName' & 'pathName' & 'history' & 'state'
|
||||
>;
|
||||
}
|
||||
| {
|
||||
type: 'updateRoute';
|
||||
|
@ -55,4 +59,6 @@ export type SpyRouteProps = RouteComponentProps<{
|
|||
tabName: HostsTableType | undefined;
|
||||
search: string;
|
||||
flowTarget: FlowTarget | undefined;
|
||||
}>;
|
||||
}> & {
|
||||
state?: Record<string, string | undefined>;
|
||||
};
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -12827,17 +12827,7 @@ fancy-log@^1.3.2:
|
|||
color-support "^1.1.3"
|
||||
time-stamp "^1.0.0"
|
||||
|
||||
fast-deep-equal@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
|
||||
integrity sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=
|
||||
|
||||
fast-deep-equal@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
fast-deep-equal@^1.0.0, fast-deep-equal@^2.0.1, fast-deep-equal@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
|
||||
integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue