diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/__tests__/use_monitor_breadcrumbs.test.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/__tests__/use_monitor_breadcrumbs.test.tsx new file mode 100644 index 0000000000000..ec95fcd7f8cfb --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/__tests__/use_monitor_breadcrumbs.test.tsx @@ -0,0 +1,82 @@ +/* + * 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 { ChromeBreadcrumb } from 'kibana/public'; +import React from 'react'; +import { Route } from 'react-router-dom'; +import { of } from 'rxjs'; +import { MountWithReduxProvider, mountWithRouter } from '../../../../../lib'; +import { KibanaContextProvider } from '../../../../../../../../../src/plugins/kibana_react/public'; +import { useMonitorBreadcrumb } from '../use_monitor_breadcrumb'; +import { OVERVIEW_ROUTE } from '../../../../../../common/constants'; +import { Ping } from '../../../../../../common/runtime_types/ping'; +import { JourneyState } from '../../../../../state/reducers/journey'; + +describe('useMonitorBreadcrumbs', () => { + it('sets the given breadcrumbs', () => { + const [getBreadcrumbs, core] = mockCore(); + + const Component = () => { + useMonitorBreadcrumb({ + activeStep: { monitor: { id: 'test-monitor' } } as Ping, + journey: { details: { timestamp: '2021-01-04T11:25:19.104Z' } } as JourneyState, + }); + return <>Step Water Fall; + }; + + mountWithRouter( + + + + + + + + ); + + expect(getBreadcrumbs()).toMatchInlineSnapshot(` + Array [ + Object { + "href": "/app/uptime", + "onClick": [Function], + "text": "Uptime", + }, + Object { + "href": "/app/uptime/monitor/dGVzdC1tb25pdG9y", + "onClick": [Function], + "text": "test-monitor", + }, + Object { + "text": "Jan 4, 2021 @ 06:25:19.104", + }, + ] + `); + }); +}); + +const mockCore: () => [() => ChromeBreadcrumb[], any] = () => { + let breadcrumbObj: ChromeBreadcrumb[] = []; + const get = () => { + return breadcrumbObj; + }; + const core = { + application: { + getUrlForApp: () => '/app/uptime', + navigateToUrl: jest.fn(), + }, + chrome: { + setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => { + breadcrumbObj = newBreadcrumbs; + }, + }, + uiSettings: { + get: (key: string) => 'MMM D, YYYY @ HH:mm:ss.SSS', + get$: (key: string) => of('MMM D, YYYY @ HH:mm:ss.SSS'), + }, + }; + + return [get, core]; +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/step_detail_container.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/step_detail_container.tsx index 58cf8d6e492da..bdc6dbf3f6de2 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/step_detail_container.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/step_detail_container.tsx @@ -9,12 +9,11 @@ import { i18n } from '@kbn/i18n'; import React, { useEffect, useCallback, useMemo } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useHistory } from 'react-router-dom'; -import moment from 'moment'; -import { useBreadcrumbs } from '../../../../hooks/use_breadcrumbs'; import { getJourneySteps } from '../../../../state/actions/journey'; import { journeySelector } from '../../../../state/selectors'; import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public'; import { StepDetail } from './step_detail'; +import { useMonitorBreadcrumb } from './use_monitor_breadcrumb'; export const NO_STEP_DATA = i18n.translate('xpack.uptime.synthetics.stepDetail.noData', { defaultMessage: 'No data could be found for this step', @@ -48,12 +47,7 @@ export const StepDetailContainer: React.FC = ({ checkGroup, stepIndex }) }; }, [stepIndex, journey]); - useBreadcrumbs([ - ...(activeStep?.monitor?.name ? [{ text: activeStep?.monitor?.name }] : []), - ...(journey?.details?.timestamp - ? [{ text: moment(journey?.details?.timestamp).format(dateFormat) }] - : []), - ]); + useMonitorBreadcrumb({ journey, activeStep }); const handleNextStep = useCallback(() => { history.push(`/journey/${checkGroup}/step/${stepIndex + 1}`); diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/use_monitor_breadcrumb.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/use_monitor_breadcrumb.tsx new file mode 100644 index 0000000000000..8e228da615ef9 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/use_monitor_breadcrumb.tsx @@ -0,0 +1,38 @@ +/* + * 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 moment from 'moment'; +import { useBreadcrumbs } from '../../../../hooks/use_breadcrumbs'; +import { useKibana, useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public'; +import { JourneyState } from '../../../../state/reducers/journey'; +import { Ping } from '../../../../../common/runtime_types/ping'; +import { PLUGIN } from '../../../../../common/constants/plugin'; + +interface Props { + journey: JourneyState; + activeStep?: Ping; +} + +export const useMonitorBreadcrumb = ({ journey, activeStep }: Props) => { + const [dateFormat] = useUiSetting$('dateFormat'); + + const kibana = useKibana(); + const appPath = kibana.services.application?.getUrlForApp(PLUGIN.ID) ?? ''; + + useBreadcrumbs([ + ...(activeStep?.monitor + ? [ + { + text: activeStep?.monitor?.name || activeStep?.monitor.id, + href: `${appPath}/monitor/${btoa(activeStep?.monitor.id)}`, + }, + ] + : []), + ...(journey?.details?.timestamp + ? [{ text: moment(journey?.details?.timestamp).format(dateFormat) }] + : []), + ]); +}; diff --git a/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx b/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx index 9b9af20285304..5b7032f796fc6 100644 --- a/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx @@ -45,9 +45,7 @@ describe('useBreadcrumbs', () => { const urlParams: UptimeUrlParams = getSupportedUrlParams({}); expect(JSON.stringify(getBreadcrumbs())).toEqual( - JSON.stringify( - [makeBaseBreadcrumb('/app/uptime', jest.fn(), urlParams)].concat(expectedCrumbs) - ) + JSON.stringify([makeBaseBreadcrumb('/app/uptime', urlParams)].concat(expectedCrumbs)) ); }); }); diff --git a/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts b/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts index d7b111f6fadf3..2c2fc88ffa480 100644 --- a/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts +++ b/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts @@ -6,7 +6,7 @@ import { ChromeBreadcrumb } from 'kibana/public'; import { i18n } from '@kbn/i18n'; -import { useEffect } from 'react'; +import { MouseEvent, useEffect } from 'react'; import { EuiBreadcrumb } from '@elastic/eui'; import { UptimeUrlParams } from '../lib/helper'; import { stringifyUrlParams } from '../lib/helper/stringify_url_params'; @@ -16,11 +16,26 @@ import { PLUGIN } from '../../common/constants/plugin'; const EMPTY_QUERY = '?'; -export const makeBaseBreadcrumb = ( - href: string, - navigateToHref?: (url: string) => Promise, - params?: UptimeUrlParams -): EuiBreadcrumb => { +function handleBreadcrumbClick( + breadcrumbs: ChromeBreadcrumb[], + navigateToHref?: (url: string) => Promise +) { + return breadcrumbs.map((bc) => ({ + ...bc, + ...(bc.href + ? { + onClick: (event: MouseEvent) => { + if (navigateToHref && bc.href) { + event.preventDefault(); + navigateToHref(bc.href); + } + }, + } + : {}), + })); +} + +export const makeBaseBreadcrumb = (href: string, params?: UptimeUrlParams): EuiBreadcrumb => { if (params) { const crumbParams: Partial = { ...params }; // We don't want to encode this values because they are often set to Date.now(), the relative @@ -36,12 +51,6 @@ export const makeBaseBreadcrumb = ( defaultMessage: 'Uptime', }), href, - onClick: (event) => { - if (href && navigateToHref) { - event.preventDefault(); - navigateToHref(href); - } - }, }; }; @@ -51,9 +60,12 @@ export const useBreadcrumbs = (extraCrumbs: ChromeBreadcrumb[]) => { const setBreadcrumbs = kibana.services.chrome?.setBreadcrumbs; const appPath = kibana.services.application?.getUrlForApp(PLUGIN.ID) ?? ''; const navigate = kibana.services.application?.navigateToUrl; + useEffect(() => { if (setBreadcrumbs) { - setBreadcrumbs([makeBaseBreadcrumb(appPath, navigate, params)].concat(extraCrumbs)); + setBreadcrumbs( + handleBreadcrumbClick([makeBaseBreadcrumb(appPath, params)].concat(extraCrumbs), navigate) + ); } }, [appPath, extraCrumbs, navigate, params, setBreadcrumbs]); };