diff --git a/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts b/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts index ff0dca3887ff2..41bc2aa258807 100644 --- a/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts +++ b/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts @@ -3,22 +3,3 @@ * 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 { ChromeBreadcrumb } from 'src/core/public'; - -const makeOverviewBreadcrumb = (search?: string): ChromeBreadcrumb => ({ - text: i18n.translate('xpack.uptime.breadcrumbs.overviewBreadcrumbText', { - defaultMessage: 'Uptime', - }), - href: `#/${search ? search : ''}`, -}); - -export const getOverviewPageBreadcrumbs = (search?: string): ChromeBreadcrumb[] => [ - makeOverviewBreadcrumb(search), -]; - -export const getMonitorPageBreadcrumb = (name: string, search?: string): ChromeBreadcrumb[] => [ - makeOverviewBreadcrumb(search), - { text: name }, -]; diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/pages/page_header_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/pages/page_header_container.tsx deleted file mode 100644 index 9429b87061ff7..0000000000000 --- a/x-pack/legacy/plugins/uptime/public/components/connected/pages/page_header_container.tsx +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 { connect } from 'react-redux'; -import { selectSelectedMonitor } from '../../../state/selectors'; -import { AppState } from '../../../state'; -import { PageHeaderComponent } from '../../../pages/page_header'; - -const mapStateToProps = (state: AppState) => ({ - monitorStatus: selectSelectedMonitor(state), -}); - -export const PageHeader = connect(mapStateToProps, null)(PageHeaderComponent); diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/monitor.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/monitor.test.tsx.snap index 6064caa868bf8..f637af397bbeb 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/monitor.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/monitor.test.tsx.snap @@ -51,6 +51,6 @@ exports[`MonitorPage shallow renders expected elements for valid props 1`] = ` } } > - + `; diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap index 2563b15eed5d5..58d98af5d6b14 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap @@ -1,836 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PageHeaderComponent mount expected page title for valid monitor route 1`] = ` - - - - -
- -
- -

- https://www.elastic.co -

-
-
-
- -
- - - -
- -
- - } - > -
- - - - - } - closePopover={[Function]} - display="inlineBlock" - hasArrow={true} - id="QuickSelectPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - -
-
- - - -
-
-
-
-
-
- } - iconType={false} - isCustom={true} - startDateControl={
} - > -
- -
- - -
-
- -
- - -
- - - - - - - - - -
-
-
- - - -
- -
- - -
- - - - -`; - -exports[`PageHeaderComponent renders expected elements for valid props 1`] = ` -Array [ -
-
-

- Overview -

-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
- - - -
-
-
-
, -
, -] -`; - -exports[`PageHeaderComponent renders expected title for valid monitor route 1`] = ` +exports[`PageHeader shallow renders with breadcrumbs and the date picker: page_header_with_date_picker 1`] = ` Array [
- https://www.elastic.co + TestingHeading
- Overview + TestingHeading
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
- - - -
-
-
,
, ] `; - -exports[`PageHeaderComponent shallow renders expected elements for valid props 1`] = ` - - - -`; diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/page_header.test.tsx b/x-pack/legacy/plugins/uptime/public/pages/__tests__/page_header.test.tsx index 38d074cdb5dba..c1149834b4f59 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/__tests__/page_header.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/__tests__/page_header.test.tsx @@ -6,141 +6,74 @@ import React from 'react'; import { Route } from 'react-router-dom'; -import { PageHeaderComponent } from '../page_header'; -import { mountWithRouter, renderWithRouter, shallowWithRouter } from '../../lib'; -import { MONITOR_ROUTE, OVERVIEW_ROUTE } from '../../../common/constants'; -import { Ping } from '../../../common/graphql/types'; -import { createMemoryHistory } from 'history'; +import { PageHeader, makeBaseBreadcrumb } from '../page_header'; +import { mountWithRouter, renderWithRouter } from '../../lib'; +import { OVERVIEW_ROUTE } from '../../../common/constants'; import { ChromeBreadcrumb } from 'kibana/public'; +import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; +import { UptimeUrlParams, getSupportedUrlParams } from '../../lib/helper'; -describe('PageHeaderComponent', () => { - const monitorStatus: Ping = { - id: 'elastic-co', - tcp: { rtt: { connect: { us: 174982 } } }, - http: { - response: { - body: { - bytes: 2092041, - hash: '5d970606a6be810ae5d37115c4807fdd07ba4c3e407924ee5297e172d2efb3dc', - }, - status_code: 200, - }, - rtt: { - response_header: { us: 340175 }, - write_request: { us: 38 }, - validate: { us: 1797839 }, - content: { us: 1457663 }, - total: { us: 2030012 }, - }, - }, - monitor: { - ip: '2a04:4e42:3::729', - status: 'up', - duration: { us: 2030035 }, - type: 'http', - id: 'elastic-co', - name: 'elastic', - check_group: '2a017afa-4736-11ea-b3d0-acde48001122', - }, - resolve: { ip: '2a04:4e42:3::729', rtt: { us: 2102 } }, - url: { port: 443, full: 'https://www.elastic.co', scheme: 'https', domain: 'www.elastic.co' }, - ecs: { version: '1.4.0' }, - tls: { - certificate_not_valid_after: '2020-07-16T03:15:39.000Z', - rtt: { handshake: { us: 57115 } }, - certificate_not_valid_before: '2019-08-16T01:40:25.000Z', - }, - observer: { - geo: { name: 'US-West', location: '37.422994, -122.083666' }, - }, - timestamp: '2020-02-04T10:07:42.142Z', - }; - - it('shallow renders expected elements for valid props', () => { - const component = shallowWithRouter(); - expect(component).toMatchSnapshot(); - }); - - it('renders expected elements for valid props', () => { - const component = renderWithRouter(); - expect(component).toMatchSnapshot(); - }); +describe('PageHeader', () => { + const simpleBreadcrumbs: ChromeBreadcrumb[] = [ + { text: 'TestCrumb1', href: '#testHref1' }, + { text: 'TestCrumb2', href: '#testHref2' }, + ]; - it('renders expected title for valid overview route', () => { + it('shallow renders with breadcrumbs and the date picker', () => { const component = renderWithRouter( - - - + ); - expect(component).toMatchSnapshot(); - - const titleComponent = component.find('.euiTitle'); - expect(titleComponent.text()).toBe('Overview'); + expect(component).toMatchSnapshot('page_header_with_date_picker'); }); - it('renders expected title for valid monitor route', () => { - const history = createMemoryHistory({ initialEntries: ['/monitor/ZWxhc3RpYy1jbw=='] }); - + it('shallow renders with breadcrumbs without the date picker', () => { const component = renderWithRouter( - - - , - history + ); - expect(component).toMatchSnapshot(); - - const titleComponent = component.find('.euiTitle'); - expect(titleComponent.text()).toBe('https://www.elastic.co'); + expect(component).toMatchSnapshot('page_header_no_date_picker'); }); - it('mount expected page title for valid monitor route', () => { - const history = createMemoryHistory({ initialEntries: ['/monitor/ZWxhc3RpYy1jbw=='] }); - - const component = mountWithRouter( - - - , - history - ); - expect(component).toMatchSnapshot(); - - const titleComponent = component.find('.euiTitle'); - expect(titleComponent.text()).toBe('https://www.elastic.co'); - expect(document.title).toBe('Uptime | elastic - Kibana'); - }); - - it('mount and set expected breadcrumb for monitor route', () => { - const history = createMemoryHistory({ initialEntries: ['/monitor/ZWxhc3RpYy1jbw=='] }); - let breadcrumbObj: ChromeBreadcrumb[] = []; - const setBreadcrumb = (breadcrumbs: ChromeBreadcrumb[]) => { - breadcrumbObj = breadcrumbs; - }; - + it('sets the given breadcrumbs', () => { + const [getBreadcrumbs, core] = mockCore(); mountWithRouter( - - - , - history + + + + + ); - expect(breadcrumbObj).toStrictEqual([ - { href: '#/?', text: 'Uptime' }, - { text: 'https://www.elastic.co' }, - ]); - }); - - it('mount and set expected breadcrumb for overview route', () => { - let breadcrumbObj: ChromeBreadcrumb[] = []; - const setBreadcrumb = (breadcrumbs: ChromeBreadcrumb[]) => { - breadcrumbObj = breadcrumbs; - }; - - mountWithRouter( - - - + const urlParams: UptimeUrlParams = getSupportedUrlParams({}); + expect(getBreadcrumbs()).toStrictEqual( + [makeBaseBreadcrumb(urlParams)].concat(simpleBreadcrumbs) ); - - expect(breadcrumbObj).toStrictEqual([{ href: '#/', text: 'Uptime' }]); }); }); + +const mockCore: () => [() => ChromeBreadcrumb[], any] = () => { + let breadcrumbObj: ChromeBreadcrumb[] = []; + const get = () => { + return breadcrumbObj; + }; + const core = { + chrome: { + setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => { + breadcrumbObj = newBreadcrumbs; + }, + }, + }; + + return [get, core]; +}; diff --git a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx b/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx index 380cc041ae87e..8c608f57a9592 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx @@ -5,19 +5,45 @@ */ import { EuiSpacer } from '@elastic/eui'; -import React, { useContext, useState } from 'react'; +import React, { useContext, useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; +import { ChromeBreadcrumb } from 'kibana/public'; +import { connect, MapDispatchToPropsFunction, MapStateToPropsParam } from 'react-redux'; import { MonitorCharts, PingList } from '../components/functional'; import { UptimeRefreshContext, UptimeThemeContext } from '../contexts'; import { useUptimeTelemetry, useUrlParams, UptimePage } from '../hooks'; import { useTrackPageview } from '../../../../../plugins/observability/public'; import { MonitorStatusDetails } from '../components/connected'; +import { Ping } from '../../common/graphql/types'; +import { AppState } from '../state'; +import { selectSelectedMonitor } from '../state/selectors'; +import { getSelectedMonitor } from '../state/actions'; +import { PageHeader } from './page_header'; -export const MonitorPage = () => { +interface StateProps { + selectedMonitor: Ping | null; +} + +interface DispatchProps { + dispatchGetMonitorStatus: (monitorId: string) => void; +} + +type Props = StateProps & DispatchProps; + +export const MonitorPageComponent: React.FC = ({ + selectedMonitor, + dispatchGetMonitorStatus, +}: Props) => { // decode 64 base string, it was decoded to make it a valid url, since monitor id can be a url let { monitorId } = useParams(); monitorId = atob(monitorId || ''); + useEffect(() => { + if (monitorId) { + dispatchGetMonitorStatus(monitorId); + } + }, [dispatchGetMonitorStatus, monitorId]); + const [pingListPageCount, setPingListPageCount] = useState(10); const { colors } = useContext(UptimeThemeContext); const { refreshApp } = useContext(UptimeRefreshContext); @@ -39,8 +65,11 @@ export const MonitorPage = () => { useTrackPageview({ app: 'uptime', path: 'monitor' }); useTrackPageview({ app: 'uptime', path: 'monitor', delay: 15000 }); + const nameOrId = selectedMonitor?.monitor?.name || selectedMonitor?.monitor?.id || ''; + const breadcrumbs: ChromeBreadcrumb[] = [{ text: nameOrId }]; return ( <> + @@ -65,3 +94,21 @@ export const MonitorPage = () => { ); }; + +const mapStateToProps: MapStateToPropsParam = state => ({ + selectedMonitor: selectSelectedMonitor(state), +}); + +const mapDispatchToProps: MapDispatchToPropsFunction = (dispatch, own) => { + return { + dispatchGetMonitorStatus: (monitorId: string) => { + dispatch( + getSelectedMonitor({ + monitorId, + }) + ); + }, + }; +}; + +export const MonitorPage = connect(mapStateToProps, mapDispatchToProps)(MonitorPageComponent); diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx index cf3631eda042a..15e31d5e44629 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx @@ -7,6 +7,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React, { useContext, useEffect } from 'react'; import styled from 'styled-components'; +import { i18n } from '@kbn/i18n'; import { EmptyState, MonitorList, @@ -20,6 +21,7 @@ import { DataPublicPluginSetup, IIndexPattern } from '../../../../../../src/plug import { UptimeThemeContext } from '../contexts'; import { FilterGroup, KueryBar } from '../components/connected'; import { useUpdateKueryString } from '../hooks'; +import { PageHeader } from './page_header'; interface OverviewPageProps { autocomplete: DataPublicPluginSetup['autocomplete']; @@ -71,8 +73,14 @@ export const OverviewPageComponent = ({ autocomplete, indexPattern, setEsKueryFi const linkParameters = stringifyUrlParams(params, true); + const heading = i18n.translate('xpack.uptime.overviewPage.headerText', { + defaultMessage: 'Overview', + description: `The text that will be displayed in the app's heading when the Overview page loads.`, + }); + return ( <> + diff --git a/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx b/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx index 5c051c491c6f5..b0fb2d0ed7869 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx @@ -4,75 +4,63 @@ * you may not use this file except in compliance with the Elastic License. */ +import React, { useEffect } from 'react'; +import { ChromeBreadcrumb } from 'kibana/public'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useEffect, useState } from 'react'; -import { useRouteMatch } from 'react-router-dom'; -import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { UptimeDatePicker } from '../components/functional/uptime_date_picker'; -import { getMonitorPageBreadcrumb, getOverviewPageBreadcrumbs } from '../breadcrumbs'; +import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { stringifyUrlParams } from '../lib/helper/stringify_url_params'; -import { getTitle } from '../lib/helper/get_title'; -import { UMUpdateBreadcrumbs } from '../lib/lib'; import { useUrlParams } from '../hooks'; -import { MONITOR_ROUTE } from '../../common/constants'; -import { Ping } from '../../common/graphql/types'; +import { UptimeUrlParams } from '../lib/helper'; interface PageHeaderProps { - monitorStatus?: Ping; - setBreadcrumbs: UMUpdateBreadcrumbs; + headingText: string; + breadcrumbs: ChromeBreadcrumb[]; + datePicker: boolean; } -export const PageHeaderComponent = ({ monitorStatus, setBreadcrumbs }: PageHeaderProps) => { - const monitorPage = useRouteMatch({ - path: MONITOR_ROUTE, - }); - - const [getUrlParams] = useUrlParams(); - const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = getUrlParams(); - - const headingText = !monitorPage - ? i18n.translate('xpack.uptime.overviewPage.headerText', { - defaultMessage: 'Overview', - description: `The text that will be displayed in the app's heading when the Overview page loads.`, - }) - : monitorStatus?.url?.full; +export const makeBaseBreadcrumb = (params?: UptimeUrlParams): ChromeBreadcrumb => { + let href = '#/'; + if (params) { + const crumbParams: Partial = { ...params }; + // We don't want to encode this values because they are often set to Date.now(), the relative + // values in dateRangeStart are better for a URL. + delete crumbParams.absoluteDateRangeStart; + delete crumbParams.absoluteDateRangeEnd; + href += stringifyUrlParams(crumbParams, true); + } + return { + text: i18n.translate('xpack.uptime.breadcrumbs.overviewBreadcrumbText', { + defaultMessage: 'Uptime', + }), + href, + }; +}; - const [headerText, setHeaderText] = useState(headingText); +export const PageHeader = ({ headingText, breadcrumbs, datePicker = true }: PageHeaderProps) => { + const setBreadcrumbs = useKibana().services.chrome?.setBreadcrumbs!; + const params = useUrlParams()[0](); useEffect(() => { - if (monitorPage) { - setHeaderText(monitorStatus?.url?.full ?? ''); - if (monitorStatus?.monitor) { - const { name, id } = monitorStatus.monitor; - document.title = getTitle((name || id) ?? ''); - } - } else { - setHeaderText(headingText); - document.title = getTitle(); - } - }, [monitorStatus, monitorPage, setHeaderText, headingText]); + setBreadcrumbs([makeBaseBreadcrumb(params)].concat(breadcrumbs)); + }, [breadcrumbs, params, setBreadcrumbs]); - useEffect(() => { - if (monitorPage) { - if (headerText) { - setBreadcrumbs(getMonitorPageBreadcrumb(headerText, stringifyUrlParams(params, true))); - } - } else { - setBreadcrumbs(getOverviewPageBreadcrumbs()); - } - }, [headerText, setBreadcrumbs, params, monitorPage]); + const datePickerComponent = datePicker ? ( + + + + ) : null; return ( <> -

{headerText}

+

{headingText}

- - - + {datePickerComponent}
diff --git a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx b/x-pack/legacy/plugins/uptime/public/uptime_app.tsx index 66ff5ba7a58ee..427870797a206 100644 --- a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/legacy/plugins/uptime/public/uptime_app.tsx @@ -13,7 +13,7 @@ import { BrowserRouter as Router } from 'react-router-dom'; import { I18nStart, ChromeBreadcrumb, CoreStart } from 'src/core/public'; import { PluginsSetup } from 'ui/new_platform/new_platform'; import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; -import { UMGraphQLClient, UMUpdateBreadcrumbs, UMUpdateBadge } from './lib/lib'; +import { UMGraphQLClient, UMUpdateBadge } from './lib/lib'; import { UptimeRefreshContextProvider, UptimeSettingsContextProvider, @@ -23,7 +23,6 @@ import { CommonlyUsedRange } from './components/functional/uptime_date_picker'; import { store } from './state'; import { setBasePath } from './state/actions'; import { PageRouter } from './routes'; -import { PageHeader } from './components/connected/pages/page_header_container'; export interface UptimeAppColors { danger: string; @@ -47,10 +46,10 @@ export interface UptimeAppProps { kibanaBreadcrumbs: ChromeBreadcrumb[]; plugins: PluginsSetup; routerBasename: string; - setBreadcrumbs: UMUpdateBreadcrumbs; setBadge: UMUpdateBadge; renderGlobalHelpControls(): void; commonlyUsedRanges: CommonlyUsedRange[]; + setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; } const Application = (props: UptimeAppProps) => { @@ -64,7 +63,6 @@ const Application = (props: UptimeAppProps) => { plugins, renderGlobalHelpControls, routerBasename, - setBreadcrumbs, setBadge, } = props; @@ -100,7 +98,6 @@ const Application = (props: UptimeAppProps) => {
-