diff --git a/x-pack/legacy/plugins/siem/public/components/link_to/helpers.test.ts b/x-pack/legacy/plugins/siem/public/components/link_to/helpers.test.ts new file mode 100644 index 000000000000000..14b367de674a271 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/link_to/helpers.test.ts @@ -0,0 +1,19 @@ +/* + * 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 { appendSearch } from './helpers'; + +describe('appendSearch', () => { + test('should return empty string if no parameter', () => { + expect(appendSearch()).toEqual(''); + }); + test('should return empty string if parameter is undefined', () => { + expect(appendSearch(undefined)).toEqual(''); + }); + test('should return parameter if parameter is defined', () => { + expect(appendSearch('helloWorld')).toEqual('helloWorld'); + }); +}); diff --git a/x-pack/legacy/plugins/siem/public/components/link_to/helpers.ts b/x-pack/legacy/plugins/siem/public/components/link_to/helpers.ts new file mode 100644 index 000000000000000..9d818ab3b647935 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/link_to/helpers.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +export const appendSearch = (search?: string) => (search != null ? `${search}` : ''); diff --git a/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_detection_engine.tsx b/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_detection_engine.tsx index 3701069389b7264..18111aa93a27a85 100644 --- a/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_detection_engine.tsx +++ b/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_detection_engine.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { DetectionEngineTab } from '../../pages/detection_engine/types'; +import { appendSearch } from './helpers'; import { RedirectWrapper } from './redirect_wrapper'; export type DetectionEngineComponentProps = RouteComponentProps<{ @@ -63,9 +64,10 @@ export const RedirectToEditRulePage = ({ const baseDetectionEngineUrl = `#/link-to/${DETECTION_ENGINE_PAGE_NAME}`; -export const getDetectionEngineUrl = () => `${baseDetectionEngineUrl}`; -export const getDetectionEngineAlertUrl = () => - `${baseDetectionEngineUrl}/${DetectionEngineTab.alerts}`; +export const getDetectionEngineUrl = (search?: string) => + `${baseDetectionEngineUrl}${appendSearch(search)}`; +export const getDetectionEngineAlertUrl = (search?: string) => + `${baseDetectionEngineUrl}/${DetectionEngineTab.alerts}${appendSearch(search)}`; export const getDetectionEngineTabUrl = (tabPath: string) => `${baseDetectionEngineUrl}/${tabPath}`; export const getRulesUrl = () => `${baseDetectionEngineUrl}/rules`; export const getCreateRuleUrl = () => `${baseDetectionEngineUrl}/rules/create`; diff --git a/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_hosts.tsx b/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_hosts.tsx index 05139320b171dff..746a959cc996a1a 100644 --- a/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_hosts.tsx @@ -7,10 +7,12 @@ import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { RedirectWrapper } from './redirect_wrapper'; import { HostsTableType } from '../../store/hosts/model'; import { SiemPageName } from '../../pages/home/types'; +import { appendSearch } from './helpers'; +import { RedirectWrapper } from './redirect_wrapper'; + export type HostComponentProps = RouteComponentProps<{ detailName: string; tabName: HostsTableType; @@ -44,9 +46,10 @@ export const RedirectToHostDetailsPage = ({ const baseHostsUrl = `#/link-to/${SiemPageName.hosts}`; -export const getHostsUrl = () => baseHostsUrl; +export const getHostsUrl = (search?: string) => `${baseHostsUrl}${appendSearch(search)}`; -export const getTabsOnHostsUrl = (tabName: HostsTableType) => `${baseHostsUrl}/${tabName}`; +export const getTabsOnHostsUrl = (tabName: HostsTableType, search?: string) => + `${baseHostsUrl}/${tabName}${appendSearch(search)}`; export const getHostDetailsUrl = (detailName: string) => `${baseHostsUrl}/${detailName}`; diff --git a/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_network.tsx b/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_network.tsx index f206e2f323a742a..71925edd5c0864e 100644 --- a/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_network.tsx +++ b/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_network.tsx @@ -7,10 +7,12 @@ import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { RedirectWrapper } from './redirect_wrapper'; import { SiemPageName } from '../../pages/home/types'; import { FlowTarget, FlowTargetSourceDest } from '../../graphql/types'; +import { appendSearch } from './helpers'; +import { RedirectWrapper } from './redirect_wrapper'; + export type NetworkComponentProps = RouteComponentProps<{ detailName?: string; flowTarget?: string; @@ -33,7 +35,7 @@ export const RedirectToNetworkPage = ({ ); const baseNetworkUrl = `#/link-to/${SiemPageName.network}`; -export const getNetworkUrl = () => baseNetworkUrl; +export const getNetworkUrl = (search?: string) => `${baseNetworkUrl}${appendSearch(search)}`; export const getIPDetailsUrl = ( detailName: string, flowTarget?: FlowTarget | FlowTargetSourceDest diff --git a/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_timelines.tsx b/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_timelines.tsx index 1b71432b3f7299c..27765a4125afcd4 100644 --- a/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_timelines.tsx +++ b/x-pack/legacy/plugins/siem/public/components/link_to/redirect_to_timelines.tsx @@ -6,9 +6,12 @@ import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { RedirectWrapper } from './redirect_wrapper'; + import { SiemPageName } from '../../pages/home/types'; +import { appendSearch } from './helpers'; +import { RedirectWrapper } from './redirect_wrapper'; + export type TimelineComponentProps = RouteComponentProps<{ search: string; }>; @@ -17,4 +20,5 @@ export const RedirectToTimelinesPage = ({ location: { search } }: TimelineCompon ); -export const getTimelinesUrl = () => `#/link-to/${SiemPageName.timelines}`; +export const getTimelinesUrl = (search?: string) => + `#/link-to/${SiemPageName.timelines}${appendSearch(search)}`; diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/helpers.ts b/x-pack/legacy/plugins/siem/public/components/navigation/helpers.ts index 9a95d93a2df7008..899d108fe246d1b 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/components/navigation/helpers.ts @@ -10,7 +10,7 @@ import { Location } from 'history'; import { UrlInputsModel } from '../../store/inputs/model'; import { TimelineUrl } from '../../store/timeline/model'; import { CONSTANTS } from '../url_state/constants'; -import { URL_STATE_KEYS, KeyUrlState } from '../url_state/types'; +import { URL_STATE_KEYS, KeyUrlState, UrlState } from '../url_state/types'; import { replaceQueryStringInLocation, replaceStateKeyInQueryString, @@ -18,10 +18,9 @@ import { } from '../url_state/helpers'; import { Query, Filter } from '../../../../../../../src/plugins/data/public'; -import { TabNavigationProps } from './tab_navigation/types'; import { SearchNavTab } from './types'; -export const getSearch = (tab: SearchNavTab, urlState: TabNavigationProps): string => { +export const getSearch = (tab: SearchNavTab, urlState: UrlState): string => { if (tab && tab.urlKey != null && URL_STATE_KEYS[tab.urlKey] != null) { return URL_STATE_KEYS[tab.urlKey].reduce( (myLocation: Location, urlKey: KeyUrlState) => { @@ -58,7 +57,7 @@ export const getSearch = (tab: SearchNavTab, urlState: TabNavigationProps): stri ); }, { - pathname: urlState.pathName, + pathname: '', hash: '', search: '', state: '', diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx index cebf9b90656ca34..ab4d75a2b116804 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx @@ -66,7 +66,9 @@ export const TabNavigationComponent = (props: TabNavigationProps) => { () => Object.values(navTabs).map(tab => { const isSelected = selectedTabId === tab.id; - const hrefWithSearch = tab.href + getSearch(tab, props); + const { query, filters, savedQuery, timerange, timeline } = props; + const hrefWithSearch = + tab.href + getSearch(tab, { query, filters, savedQuery, timerange, timeline }); return ( { + const mapState = makeMapStateToProps(); + const { urlState } = useSelector(mapState, isEqual); + const urlSearch = useMemo(() => getSearch(tab, urlState), [tab, urlState]); + return urlSearch; +}; diff --git a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx index 3868885fa29ee51..52c142ceff48051 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx @@ -8,7 +8,7 @@ import { isEmpty } from 'lodash/fp'; import { EuiButton, EuiFlexItem, EuiPanel } from '@elastic/eui'; import numeral from '@elastic/numeral'; import { FormattedMessage } from '@kbn/i18n/react'; -import React from 'react'; +import React, { useMemo } from 'react'; import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants'; import { ESQuery } from '../../../../../common/typed_json'; @@ -23,6 +23,8 @@ import { getOverviewHostStats, OverviewHostStats } from '../overview_host_stats' import { manageQuery } from '../../../page/manage_query'; import { inputsModel } from '../../../../store/inputs'; import { InspectButtonContainer } from '../../../inspect'; +import { useGetUrlSearch } from '../../../navigation/use_get_url_search'; +import { navTabs } from '../../../../pages/home/home_navigations'; export interface OwnProps { startDate: number; @@ -51,7 +53,15 @@ const OverviewHostComponent: React.FC = ({ setQuery, }) => { const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); - + const urlSearch = useGetUrlSearch(navTabs.hosts); + const hostPageButton = useMemo( + () => ( + + + + ), + [urlSearch] + ); return ( @@ -95,12 +105,7 @@ const OverviewHostComponent: React.FC = ({ /> } > - - - + {hostPageButton} = ({ setQuery, }) => { const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); - + const urlSearch = useGetUrlSearch(navTabs.network); + const networkPageButton = useMemo( + () => ( + + + + ), + [urlSearch] + ); return ( @@ -96,12 +106,7 @@ const OverviewNetworkComponent: React.FC = ({ /> } > - - - + {networkPageButton} ; @@ -45,6 +48,11 @@ const StatefulRecentTimelinesComponent = React.memo( const noTimelinesMessage = filterBy === 'favorites' ? i18n.NO_FAVORITE_TIMELINES : i18n.NO_TIMELINES; + const urlSearch = useGetUrlSearch(navTabs.timelines); + const linkAllTimelines = useMemo( + () => {i18n.VIEW_ALL_TIMELINES}, + [urlSearch] + ); return ( ( /> )} - - {i18n.VIEW_ALL_TIMELINES} - + {linkAllTimelines} )} diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/helpers.ts b/x-pack/legacy/plugins/siem/public/components/url_state/helpers.ts index d085af91da1f063..b30244e57d0f1a2 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/components/url_state/helpers.ts @@ -19,12 +19,7 @@ import { TimelineUrl } from '../../store/timeline/model'; import { formatDate } from '../super_date_picker'; import { NavTab } from '../navigation/types'; import { CONSTANTS, UrlStateType } from './constants'; -import { - LocationTypes, - UrlStateContainerPropTypes, - ReplaceStateInLocation, - UpdateUrlStateString, -} from './types'; +import { ReplaceStateInLocation, UpdateUrlStateString } from './types'; export const decodeRisonUrlState = (value: string | undefined): T | null => { try { @@ -113,42 +108,13 @@ export const getTitle = ( return navTabs[pageName] != null ? navTabs[pageName].name : ''; }; -export const getCurrentLocation = ( - pageName: string, - detailName: string | undefined -): LocationTypes => { - if (pageName === SiemPageName.overview) { - return CONSTANTS.overviewPage; - } else if (pageName === SiemPageName.hosts) { - if (detailName != null) { - return CONSTANTS.hostsDetails; - } - return CONSTANTS.hostsPage; - } else if (pageName === SiemPageName.network) { - if (detailName != null) { - return CONSTANTS.networkDetails; - } - return CONSTANTS.networkPage; - } else if (pageName === SiemPageName.detections) { - return CONSTANTS.detectionsPage; - } else if (pageName === SiemPageName.timelines) { - return CONSTANTS.timelinePage; - } else if (pageName === SiemPageName.case) { - if (detailName != null) { - return CONSTANTS.caseDetails; - } - return CONSTANTS.casePage; - } - return CONSTANTS.unknown; -}; - export const makeMapStateToProps = () => { const getInputsSelector = inputsSelectors.inputsSelector(); const getGlobalQuerySelector = inputsSelectors.globalQuerySelector(); const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector(); const getGlobalSavedQuerySelector = inputsSelectors.globalSavedQuerySelector(); const getTimelines = timelineSelectors.getTimelines(); - const mapStateToProps = (state: State, { pageName, detailName }: UrlStateContainerPropTypes) => { + const mapStateToProps = (state: State) => { const inputState = getInputsSelector(state); const { linkTo: globalLinkTo, timerange: globalTimerange } = inputState.global; const { linkTo: timelineLinkTo, timerange: timelineTimerange } = inputState.timeline; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx index 079293bd4523143..e25442b31da4e3c 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx @@ -11,19 +11,21 @@ import styled from 'styled-components'; import { isEmpty } from 'lodash/fp'; import { HeaderSection } from '../../../../components/header_section'; -import { SignalsHistogram } from './signals_histogram'; + import { Filter, esQuery, Query } from '../../../../../../../../../src/plugins/data/public'; -import { RegisterQuery, SignalsHistogramOption, SignalsAggregation, SignalsTotal } from './types'; -import { signalsHistogramOptions } from './config'; -import { getDetectionEngineUrl } from '../../../../components/link_to'; import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants'; -import { useKibana, useUiSetting$ } from '../../../../lib/kibana'; -import { InspectButtonContainer } from '../../../../components/inspect'; import { useQuerySignals } from '../../../../containers/detection_engine/signals/use_query'; +import { getDetectionEngineUrl } from '../../../../components/link_to'; +import { InspectButtonContainer } from '../../../../components/inspect'; +import { useGetUrlSearch } from '../../../../components/navigation/use_get_url_search'; import { MatrixLoader } from '../../../../components/matrix_histogram/matrix_loader'; - +import { useKibana, useUiSetting$ } from '../../../../lib/kibana'; +import { navTabs } from '../../../home/home_navigations'; +import { signalsHistogramOptions } from './config'; import { formatSignalsData, getSignalsHistogramQuery, showInitialLoadingSpinner } from './helpers'; +import { SignalsHistogram } from './signals_histogram'; import * as i18n from './translations'; +import { RegisterQuery, SignalsHistogramOption, SignalsAggregation, SignalsTotal } from './types'; const DEFAULT_PANEL_HEIGHT = 300; @@ -101,6 +103,7 @@ export const SignalsHistogramPanel = memo( signalIndexName ); const kibana = useKibana(); + const urlSearch = useGetUrlSearch(navTabs.detections); const totalSignals = useMemo( () => @@ -184,6 +187,16 @@ export const SignalsHistogramPanel = memo( ); }, [selectedStackByOption.value, from, to, query, filters]); + const linkButton = useMemo(() => { + if (showLinkToSignals) { + return ( + + {i18n.VIEW_SIGNALS} + + ); + } + }, [showLinkToSignals, urlSearch]); + return ( @@ -210,11 +223,7 @@ export const SignalsHistogramPanel = memo( /> )} - {showLinkToSignals && ( - - {i18n.VIEW_SIGNALS} - - )} + {linkButton} diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/alerts_by_category/index.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/alerts_by_category/index.tsx index f71d83558ae9d11..e0d383c59e2ee76 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/alerts_by_category/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/alerts_by_category/index.tsx @@ -30,6 +30,8 @@ import { histogramConfigs, } from '../../../components/alerts_viewer/histogram_configs'; import { MatrixHisrogramConfigs } from '../../../components/matrix_histogram/types'; +import { useGetUrlSearch } from '../../../components/navigation/use_get_url_search'; +import { navTabs } from '../../home/home_navigations'; const ID = 'alertsByCategoryOverview'; @@ -73,10 +75,11 @@ const AlertsByCategoryComponent: React.FC = ({ const kibana = useKibana(); const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); + const urlSearch = useGetUrlSearch(navTabs.detections); const alertsCountViewAlertsButton = useMemo( - () => {i18n.VIEW_ALERTS}, - [] + () => {i18n.VIEW_ALERTS}, + [urlSearch] ); const alertsByCategoryHistogramConfigs: MatrixHisrogramConfigs = useMemo( diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/events_by_dataset/index.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/events_by_dataset/index.tsx index 315aac5fcae9efe..cc1f9b1cc5681d4 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/events_by_dataset/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/events_by_dataset/index.tsx @@ -28,6 +28,8 @@ import { DEFAULT_NUMBER_FORMAT } from '../../../../common/constants'; import * as i18n from '../translations'; import { MatrixHisrogramConfigs } from '../../../components/matrix_histogram/types'; +import { useGetUrlSearch } from '../../../components/navigation/use_get_url_search'; +import { navTabs } from '../../home/home_navigations'; const NO_FILTERS: Filter[] = []; const DEFAULT_QUERY: Query = { query: '', language: 'kuery' }; @@ -69,10 +71,15 @@ const EventsByDatasetComponent: React.FC = ({ const kibana = useKibana(); const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); + const urlSearch = useGetUrlSearch(navTabs.hosts); const eventsCountViewEventsButton = useMemo( - () => {i18n.VIEW_EVENTS}, - [] + () => ( + + {i18n.VIEW_EVENTS} + + ), + [urlSearch] ); const filterQuery = useMemo(