From 965643027b30721cd75b5082baeadaa3523be329 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Wed, 24 Jul 2019 01:15:05 -0700 Subject: [PATCH 1/2] [APM] Remove dependency on ui/chrome in favor of newer core APIs --- .../app/GlobalHelpExtension/index.tsx | 6 ++- .../components/app/Main/UpdateBreadcrumbs.tsx | 8 +++- .../Main/__test__/UpdateBreadcrumbs.test.js | 39 ++++++------------- .../app/Main/useUpdateBadgeEffect.ts | 5 ++- .../ServiceIntegrations/WatcherFlyout.tsx | 22 +++++++---- .../__test__/createErrorGroupWatch.test.ts | 5 +-- .../createErrorGroupWatch.ts | 6 +-- .../ServiceIntegrations/index.tsx | 8 +++- .../components/app/ServiceOverview/index.tsx | 5 ++- .../components/shared/KueryBar/index.tsx | 7 +++- .../Links/DiscoverLinks/DiscoverLink.tsx | 5 ++- .../shared/Links/InfraLink.test.tsx | 15 +++++-- .../components/shared/Links/InfraLink.tsx | 5 ++- .../shared/Links/KibanaLink.test.tsx | 32 ++++++++++----- .../components/shared/Links/KibanaLink.tsx | 5 ++- .../MachineLearningLinks/MLLink.test.tsx | 15 +++++-- .../Links/MachineLearningLinks/MLLink.tsx | 5 ++- .../TransactionActionMenu.tsx | 6 ++- .../apm/public/context/CoreContext.tsx | 16 ++++++++ .../InvalidLicenseNotification.tsx | 11 ++++-- .../public/hacks/toggle_app_link_in_nav.ts | 8 ++-- .../plugins/apm/public/hooks/useCore.tsx | 12 ++++++ x-pack/legacy/plugins/apm/public/index.tsx | 22 ++++++----- .../apm/public/new-platform/plugin.tsx | 21 +++++----- .../plugins/apm/public/register_feature.js | 7 +++- .../plugins/apm/public/services/rest/ml.ts | 8 +++- 26 files changed, 193 insertions(+), 111 deletions(-) create mode 100644 x-pack/legacy/plugins/apm/public/context/CoreContext.tsx create mode 100644 x-pack/legacy/plugins/apm/public/hooks/useCore.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/GlobalHelpExtension/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/GlobalHelpExtension/index.tsx index def6608eaf7f1..fb10a65d975bf 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/GlobalHelpExtension/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/GlobalHelpExtension/index.tsx @@ -8,15 +8,17 @@ import { EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { Fragment } from 'react'; import styled from 'styled-components'; -import chrome from 'ui/chrome'; import url from 'url'; import { px, units } from '../../../style/variables'; +import { useCore } from '../../../hooks/useCore'; const Container = styled.div` margin: ${px(units.minus)} 0; `; export const GlobalHelpExtension: React.SFC = () => { + const core = useCore(); + return ( @@ -33,7 +35,7 @@ export const GlobalHelpExtension: React.SFC = () => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx index 30aeb5fe31733..5b7cc34b1530c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx @@ -7,7 +7,8 @@ import { Location } from 'history'; import { last } from 'lodash'; import React from 'react'; -import chrome from 'ui/chrome'; +import { InternalCoreStart } from 'src/core/public'; +import { useCore } from '../../../hooks/useCore'; import { getAPMHref } from '../../shared/Links/APMLink'; import { Breadcrumb, ProvideBreadcrumbs } from './ProvideBreadcrumbs'; import { routes } from './route_config'; @@ -15,6 +16,7 @@ import { routes } from './route_config'; interface Props { location: Location; breadcrumbs: Breadcrumb[]; + core: InternalCoreStart; } class UpdateBreadcrumbsComponent extends React.Component { @@ -26,7 +28,7 @@ class UpdateBreadcrumbsComponent extends React.Component { const current = last(breadcrumbs) || { text: '' }; document.title = current.text; - chrome.breadcrumbs.set(breadcrumbs); + this.props.core.chrome.setBreadcrumbs(breadcrumbs); } public componentDidMount() { @@ -43,6 +45,7 @@ class UpdateBreadcrumbsComponent extends React.Component { } export function UpdateBreadcrumbs() { + const core = useCore(); return ( )} /> diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/UpdateBreadcrumbs.test.js b/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/UpdateBreadcrumbs.test.js index dd4fbdbb24492..60540b0b8b4f4 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/UpdateBreadcrumbs.test.js +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/UpdateBreadcrumbs.test.js @@ -7,35 +7,18 @@ import { mount } from 'enzyme'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; -import chrome from 'ui/chrome'; import { UpdateBreadcrumbs } from '../UpdateBreadcrumbs'; +import * as hooks from '../../../../hooks/useCore'; jest.mock('ui/kfetch'); -jest.mock( - 'ui/chrome', - () => ({ - breadcrumbs: { - set: jest.fn() - }, - getBasePath: () => `/some/base/path`, - getUiSettingsClient: () => { - return { - get: key => { - switch (key) { - case 'timepicker:timeDefaults': - return { from: 'now-15m', to: 'now', mode: 'quick' }; - case 'timepicker:refreshIntervalDefaults': - return { pause: false, value: 0 }; - default: - throw new Error(`Unexpected config key: ${key}`); - } - } - }; - } - }), - { virtual: true } -); +const coreMock = { + chrome: { + setBreadcrumbs: jest.fn() + } +}; + +jest.spyOn(hooks, 'useCore').mockReturnValue(coreMock); function expectBreadcrumbToMatchSnapshot(route) { mount( @@ -43,8 +26,8 @@ function expectBreadcrumbToMatchSnapshot(route) { ); - expect(chrome.breadcrumbs.set).toHaveBeenCalledTimes(1); - expect(chrome.breadcrumbs.set.mock.calls[0][0]).toMatchSnapshot(); + expect(coreMock.chrome.setBreadcrumbs).toHaveBeenCalledTimes(1); + expect(coreMock.chrome.setBreadcrumbs.mock.calls[0][0]).toMatchSnapshot(); } describe('Breadcrumbs', () => { @@ -55,7 +38,7 @@ describe('Breadcrumbs', () => { global.document = { title: 'Kibana' }; - chrome.breadcrumbs.set.mockReset(); + coreMock.chrome.setBreadcrumbs.mockReset(); }); afterEach(() => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/useUpdateBadgeEffect.ts b/x-pack/legacy/plugins/apm/public/components/app/Main/useUpdateBadgeEffect.ts index 47c95a5da5a70..807655450b4a5 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/useUpdateBadgeEffect.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/useUpdateBadgeEffect.ts @@ -7,12 +7,13 @@ import { i18n } from '@kbn/i18n'; import { useEffect } from 'react'; import { capabilities } from 'ui/capabilities'; -import chrome from 'ui/chrome'; +import { useCore } from '../../../hooks/useCore'; export const useUpdateBadgeEffect = () => { + const { chrome } = useCore(); useEffect(() => { const uiCapabilities = capabilities.get(); - chrome.badge.set( + chrome.setBadge( !uiCapabilities.apm.save ? { text: i18n.translate('xpack.apm.header.badge.readOnly.text', { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx index 45701f414b010..134934ff8425e 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx @@ -30,20 +30,20 @@ import { memoize, padLeft, range } from 'lodash'; import moment from 'moment-timezone'; import React, { Component } from 'react'; import styled from 'styled-components'; -import chrome from 'ui/chrome'; import { toastNotifications } from 'ui/notify'; +import { InternalCoreStart } from 'src/core/public'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { KibanaLink } from '../../../shared/Links/KibanaLink'; import { createErrorGroupWatch, Schedule } from './createErrorGroupWatch'; import { ElasticDocsLink } from '../../../shared/Links/ElasticDocsLink'; +import { CoreContext } from '../../../../context/CoreContext'; type ScheduleKey = keyof Schedule; -const getUserTimezone = memoize(() => { - const uiSettings = chrome.getUiSettingsClient(); - return uiSettings.get('dateFormat:tz') === 'Browser' +const getUserTimezone = memoize((core: InternalCoreStart): string => { + return core.uiSettings.get('dateFormat:tz') === 'Browser' ? moment.tz.guess() - : uiSettings.get('dateFormat:tz'); + : core.uiSettings.get('dateFormat:tz'); }); const SmallInput = styled.div` @@ -83,6 +83,7 @@ export class WatcherFlyout extends Component< WatcherFlyoutProps, WatcherFlyoutState > { + static contextType = CoreContext; public state: WatcherFlyoutState = { schedule: 'daily', threshold: 10, @@ -155,6 +156,7 @@ export class WatcherFlyout extends Component< }; public createWatch = () => { + const core: InternalCoreStart = this.context; const { serviceName } = this.props.urlParams; if (!serviceName) { @@ -190,13 +192,18 @@ export class WatcherFlyout extends Component< unit: 'h' }; + const apmIndexPatternTitle = core.injectedMetadata.getInjectedVar( + 'apmIndexPatternTitle' + ) as string; + return createErrorGroupWatch({ emails, schedule, serviceName, slackUrl, threshold: this.state.threshold, - timeRange + timeRange, + apmIndexPatternTitle }) .then((id: string) => { this.props.onClose(); @@ -271,7 +278,8 @@ export class WatcherFlyout extends Component< return null; } - const userTimezoneSetting = getUserTimezone(); + const core: InternalCoreStart = this.context; + const userTimezoneSetting = getUserTimezone(core); const dailyTime = this.state.daily; const inputTime = `${dailyTime}Z`; // Add tz to make into UTC const inputFormat = 'HH:mmZ'; // Parse as 24 hour w. tz diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts index c952ce7f7ced2..1bc2c8e2a84ea 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts @@ -6,7 +6,6 @@ import { isArray, isObject, isString } from 'lodash'; import mustache from 'mustache'; -import chrome from 'ui/chrome'; import uuid from 'uuid'; import { StringMap } from '../../../../../../typings/common'; // @ts-ignore @@ -23,7 +22,6 @@ describe('createErrorGroupWatch', () => { let createWatchResponse: string; let tmpl: any; beforeEach(async () => { - chrome.getInjected = jest.fn().mockReturnValue('myIndexPattern'); jest.spyOn(uuid, 'v4').mockReturnValue(new Buffer('mocked-uuid')); jest.spyOn(rest, 'createWatch').mockReturnValue(undefined); @@ -37,7 +35,8 @@ describe('createErrorGroupWatch', () => { serviceName: 'opbeans-node', slackUrl: 'https://hooks.slack.com/services/slackid1/slackid2/slackid3', threshold: 10, - timeRange: { value: 24, unit: 'h' } + timeRange: { value: 24, unit: 'h' }, + apmIndexPatternTitle: 'myIndexPattern' }); const watchBody = rest.createWatch.mock.calls[0][1]; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts index 81ec61fc1bb5d..2617fef6de1d2 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts @@ -6,7 +6,6 @@ import { i18n } from '@kbn/i18n'; import { isEmpty } from 'lodash'; -import chrome from 'ui/chrome'; import url from 'url'; import uuid from 'uuid'; import { @@ -46,6 +45,7 @@ interface Arguments { value: number; unit: string; }; + apmIndexPatternTitle: string; } interface Actions { @@ -60,10 +60,10 @@ export async function createErrorGroupWatch({ serviceName, slackUrl, threshold, - timeRange + timeRange, + apmIndexPatternTitle }: Arguments) { const id = `apm-${uuid.v4()}`; - const apmIndexPatternTitle = chrome.getInjected('apmIndexPatternTitle'); const slackUrlPath = getSlackPathUrl(slackUrl); const emailTemplate = i18n.translate( diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx index 9835c01fa1018..6e83015b69a26 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx @@ -13,11 +13,12 @@ import { import { i18n } from '@kbn/i18n'; import { memoize } from 'lodash'; import React, { Fragment } from 'react'; -import chrome from 'ui/chrome'; +import { InternalCoreStart } from 'src/core/public'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { LicenseContext } from '../../../../context/LicenseContext'; import { MachineLearningFlyout } from './MachineLearningFlyout'; import { WatcherFlyout } from './WatcherFlyout'; +import { CoreContext } from '../../../../context/CoreContext'; interface Props { transactionTypes: string[]; @@ -30,6 +31,7 @@ interface State { type FlyoutName = null | 'ML' | 'Watcher'; export class ServiceIntegrations extends React.Component { + static contextType = CoreContext; public state: State = { isPopoverOpen: false, activeFlyout: null }; public getPanelItems = memoize((mlAvailable: boolean) => { @@ -65,6 +67,8 @@ export class ServiceIntegrations extends React.Component { }; public getWatcherPanelItems = () => { + const core: InternalCoreStart = this.context; + return [ { name: i18n.translate( @@ -87,7 +91,7 @@ export class ServiceIntegrations extends React.Component { } ), icon: 'watchesApp', - href: chrome.addBasePath( + href: core.http.basePath.prepend( '/app/kibana#/management/elasticsearch/watcher' ), target: '_blank', diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx index 4d3aaf820cb8d..2b81e9f7f0a78 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx @@ -8,7 +8,6 @@ import { EuiPanel } from '@elastic/eui'; import { EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useEffect } from 'react'; -import chrome from 'ui/chrome'; import { toastNotifications } from 'ui/notify'; import url from 'url'; import { useFetcher } from '../../../hooks/useFetcher'; @@ -17,6 +16,7 @@ import { NoServicesMessage } from './NoServicesMessage'; import { ServiceList } from './ServiceList'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { useTrackPageview } from '../../../../../infra/public'; +import { useCore } from '../../../hooks/useCore'; const initalData = { items: [], @@ -27,6 +27,7 @@ const initalData = { let hasDisplayedToast = false; export function ServiceOverview() { + const core = useCore(); const { urlParams: { start, end }, uiFilters @@ -54,7 +55,7 @@ export function ServiceOverview() { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index 0bef2e49a77e8..8eaa399381606 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -7,7 +7,6 @@ import React, { useState, useEffect } from 'react'; import { uniqueId, startsWith } from 'lodash'; import { EuiCallOut } from '@elastic/eui'; -import chrome from 'ui/chrome'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; @@ -29,6 +28,7 @@ import { useUrlParams } from '../../../hooks/useUrlParams'; import { history } from '../../../utils/history'; import { useMatchedRoutes } from '../../../hooks/useMatchedRoutes'; import { RouteName } from '../../app/Main/route_config/route_names'; +import { useCore } from '../../../hooks/useCore'; const Container = styled.div` margin-bottom: 10px; @@ -42,6 +42,7 @@ interface State { } export function KueryBar() { + const core = useCore(); const [state, setState] = useState({ indexPattern: null, suggestions: [], @@ -52,7 +53,9 @@ export function KueryBar() { const location = useLocation(); const matchedRoutes = useMatchedRoutes(); - const apmIndexPatternTitle = chrome.getInjected('apmIndexPatternTitle'); + const apmIndexPatternTitle = core.injectedMetadata.getInjectedVar( + 'apmIndexPatternTitle' + ); const indexPatternMissing = !state.isLoadingIndexPattern && !state.indexPattern; let currentRequestCheck; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx index d5633611f09e8..0673ab5e75cc6 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx @@ -6,12 +6,12 @@ import { EuiLink } from '@elastic/eui'; import React from 'react'; -import chrome from 'ui/chrome'; import url from 'url'; import rison, { RisonValue } from 'rison-node'; import { useAPMIndexPattern } from '../../../../hooks/useAPMIndexPattern'; import { useLocation } from '../../../../hooks/useLocation'; import { getTimepickerRisonData } from '../rison_helpers'; +import { useCore } from '../../../../hooks/useCore'; interface Props { query: { @@ -31,6 +31,7 @@ interface Props { } export function DiscoverLink({ query = {}, ...rest }: Props) { + const core = useCore(); const apmIndexPattern = useAPMIndexPattern(); const location = useLocation(); @@ -47,7 +48,7 @@ export function DiscoverLink({ query = {}, ...rest }: Props) { }; const href = url.format({ - pathname: chrome.addBasePath('/app/kibana'), + pathname: core.http.basePath.prepend('/app/kibana'), hash: `/discover?_g=${rison.encode(risonQuery._g)}&_a=${rison.encode( risonQuery._a as RisonValue )}` diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx index 832cb13f3ba27..9925d87a159ca 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx @@ -8,11 +8,18 @@ import { Location } from 'history'; import React from 'react'; import { getRenderedHref } from '../../../utils/testHelpers'; import { InfraLink } from './InfraLink'; -import chrome from 'ui/chrome'; +import * as hooks from '../../../hooks/useCore'; +import { InternalCoreStart } from 'src/core/public'; -jest - .spyOn(chrome, 'addBasePath') - .mockImplementation(path => `/basepath${path}`); +const coreMock = ({ + http: { + basePath: { + prepend: (path: string) => `/basepath${path}` + } + } +} as unknown) as InternalCoreStart; + +jest.spyOn(hooks, 'useCore').mockReturnValue(coreMock); test('InfraLink produces the correct URL', async () => { const href = await getRenderedHref( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx index 6bc2f0c355a23..eda64b4bbedb2 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx @@ -7,9 +7,9 @@ import { EuiLink, EuiLinkAnchorProps } from '@elastic/eui'; import { compact } from 'lodash'; import React from 'react'; -import chrome from 'ui/chrome'; import url from 'url'; import { fromQuery } from './url_helpers'; +import { useCore } from '../../../hooks/useCore'; interface InfraQueryParams { time?: number; @@ -24,9 +24,10 @@ interface Props extends EuiLinkAnchorProps { } export function InfraLink({ path, query = {}, ...rest }: Props) { + const core = useCore(); const nextSearch = fromQuery(query); const href = url.format({ - pathname: chrome.addBasePath('/app/infra'), + pathname: core.http.basePath.prepend('/app/infra'), hash: compact([path, nextSearch]).join('?') }); return ; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx index e1cf2f5f4d562..24637f971bf3c 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx @@ -8,16 +8,30 @@ import { Location } from 'history'; import React from 'react'; import { getRenderedHref } from '../../../utils/testHelpers'; import { KibanaLink } from './KibanaLink'; -import chrome from 'ui/chrome'; +import * as hooks from '../../../hooks/useCore'; +import { InternalCoreStart } from 'src/core/public'; -jest - .spyOn(chrome, 'addBasePath') - .mockImplementation(path => `/basepath${path}`); +describe('KibanaLink', () => { + beforeEach(() => { + const coreMock = ({ + http: { + basePath: { + prepend: (path: string) => `/basepath${path}` + } + } + } as unknown) as InternalCoreStart; -test('KibanaLink produces the correct URL', async () => { - const href = await getRenderedHref(() => , { - search: '?rangeFrom=now-5h&rangeTo=now-2h' - } as Location); + jest.spyOn(hooks, 'useCore').mockReturnValue(coreMock); + }); - expect(href).toMatchInlineSnapshot(`"/basepath/app/kibana#/some/path"`); + afterEach(() => { + jest.resetAllMocks(); + }); + + it('produces the correct URL', async () => { + const href = await getRenderedHref(() => , { + search: '?rangeFrom=now-5h&rangeTo=now-2h' + } as Location); + expect(href).toMatchInlineSnapshot(`"/basepath/app/kibana#/some/path"`); + }); }); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx index cc558a35bf609..53fe9da734644 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx @@ -6,8 +6,8 @@ import { EuiLink, EuiLinkAnchorProps } from '@elastic/eui'; import React from 'react'; -import chrome from 'ui/chrome'; import url from 'url'; +import { useCore } from '../../../hooks/useCore'; interface Props extends EuiLinkAnchorProps { path?: string; @@ -15,8 +15,9 @@ interface Props extends EuiLinkAnchorProps { } export function KibanaLink({ path, ...rest }: Props) { + const core = useCore(); const href = url.format({ - pathname: chrome.addBasePath('/app/kibana'), + pathname: core.http.basePath.prepend('/app/kibana'), hash: path }); return ; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx index ac31ac55952bf..2bb4da88236ca 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx @@ -8,14 +8,21 @@ import { Location } from 'history'; import React from 'react'; import { getRenderedHref } from '../../../../utils/testHelpers'; import { MLLink } from './MLLink'; -import chrome from 'ui/chrome'; import * as savedObjects from '../../../../services/rest/savedObjects'; +import * as hooks from '../../../../hooks/useCore'; +import { InternalCoreStart } from 'src/core/public'; jest.mock('ui/kfetch'); -jest - .spyOn(chrome, 'addBasePath') - .mockImplementation(path => `/basepath${path}`); +const coreMock = ({ + http: { + basePath: { + prepend: (path: string) => `/basepath${path}` + } + } +} as unknown) as InternalCoreStart; + +jest.spyOn(hooks, 'useCore').mockReturnValue(coreMock); jest .spyOn(savedObjects, 'getAPMIndexPattern') diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx index 949c64a2171dc..e0b9331d28496 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx @@ -6,11 +6,11 @@ import { EuiLink } from '@elastic/eui'; import React from 'react'; -import chrome from 'ui/chrome'; import url from 'url'; import rison, { RisonValue } from 'rison-node'; import { useLocation } from '../../../../hooks/useLocation'; import { getTimepickerRisonData, TimepickerRisonData } from '../rison_helpers'; +import { useCore } from '../../../../hooks/useCore'; interface MlRisonData { ml?: { @@ -25,6 +25,7 @@ interface Props { } export function MLLink({ children, path = '', query = {} }: Props) { + const core = useCore(); const location = useLocation(); const risonQuery: MlRisonData & TimepickerRisonData = getTimepickerRisonData( @@ -36,7 +37,7 @@ export function MLLink({ children, path = '', query = {} }: Props) { } const href = url.format({ - pathname: chrome.addBasePath('/app/ml'), + pathname: core.http.basePath.prepend('/app/ml'), hash: `${path}?_g=${rison.encode(risonQuery as RisonValue)}` }); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx index e0b8b40e3dcf4..2e3382f71b204 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx @@ -14,7 +14,6 @@ import { EuiPopover, EuiLink } from '@elastic/eui'; -import chrome from 'ui/chrome'; import url from 'url'; import { i18n } from '@kbn/i18n'; import React, { useState, FunctionComponent } from 'react'; @@ -25,6 +24,7 @@ import { DiscoverTransactionLink } from '../Links/DiscoverLinks/DiscoverTransact import { InfraLink } from '../Links/InfraLink'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { fromQuery } from '../Links/url_helpers'; +import { useCore } from '../../../hooks/useCore'; function getInfraMetricsQuery(transaction: Transaction) { const plus5 = new Date(transaction['@timestamp']); @@ -66,6 +66,8 @@ export const TransactionActionMenu: FunctionComponent = ( ) => { const { transaction } = props; + const core = useCore(); + const [isOpen, setIsOpen] = useState(false); const { urlParams } = useUrlParams(); @@ -164,7 +166,7 @@ export const TransactionActionMenu: FunctionComponent = ( ); const uptimeLink = url.format({ - pathname: chrome.addBasePath('/app/uptime'), + pathname: core.http.basePath.prepend('/app/uptime'), hash: `/?${fromQuery( pick( { diff --git a/x-pack/legacy/plugins/apm/public/context/CoreContext.tsx b/x-pack/legacy/plugins/apm/public/context/CoreContext.tsx new file mode 100644 index 0000000000000..0bf39e4d9dadb --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/context/CoreContext.tsx @@ -0,0 +1,16 @@ +/* + * 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 React, { createContext } from 'react'; +import { InternalCoreStart } from 'src/core/public'; + +const CoreContext = createContext({} as InternalCoreStart); +const CoreProvider: React.SFC<{ core: InternalCoreStart }> = props => { + const { core, ...restProps } = props; + return ; +}; + +export { CoreContext, CoreProvider }; diff --git a/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx b/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx index 40d8f59cd9249..ffd85412be0f4 100644 --- a/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx +++ b/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx @@ -6,11 +6,14 @@ import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import chrome from 'ui/chrome'; - -const MANAGE_LICENSE_URL = `${chrome.getBasePath()}/app/kibana#/management/elasticsearch/license_management`; +import { useCore } from '../../hooks/useCore'; export function InvalidLicenseNotification() { + const core = useCore(); + const manageLicenseURL = core.http.basePath.prepend( + '/app/kibana#/management/elasticsearch/license_management' + ); + return ( } actions={[ - + {i18n.translate('xpack.apm.invalidLicense.licenseManagementLink', { defaultMessage: 'Manage your license' })} diff --git a/x-pack/legacy/plugins/apm/public/hacks/toggle_app_link_in_nav.ts b/x-pack/legacy/plugins/apm/public/hacks/toggle_app_link_in_nav.ts index 628c334863bc9..295b101777541 100644 --- a/x-pack/legacy/plugins/apm/public/hacks/toggle_app_link_in_nav.ts +++ b/x-pack/legacy/plugins/apm/public/hacks/toggle_app_link_in_nav.ts @@ -6,9 +6,9 @@ import { npStart } from 'ui/new_platform'; -const apmUiEnabled = npStart.core.injectedMetadata.getInjectedVar( - 'apmUiEnabled' -); +const { core } = npStart; +const apmUiEnabled = core.injectedMetadata.getInjectedVar('apmUiEnabled'); + if (apmUiEnabled === false) { - npStart.core.chrome.navLinks.update('apm', { hidden: true }); + core.chrome.navLinks.update('apm', { hidden: true }); } diff --git a/x-pack/legacy/plugins/apm/public/hooks/useCore.tsx b/x-pack/legacy/plugins/apm/public/hooks/useCore.tsx new file mode 100644 index 0000000000000..06942019d6530 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/hooks/useCore.tsx @@ -0,0 +1,12 @@ +/* + * 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 { useContext } from 'react'; +import { CoreContext } from '../context/CoreContext'; + +export function useCore() { + return useContext(CoreContext); +} diff --git a/x-pack/legacy/plugins/apm/public/index.tsx b/x-pack/legacy/plugins/apm/public/index.tsx index 86b9a5f69a8ad..f9fd08a06f6b2 100644 --- a/x-pack/legacy/plugins/apm/public/index.tsx +++ b/x-pack/legacy/plugins/apm/public/index.tsx @@ -6,12 +6,11 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { npStart } from 'ui/new_platform'; import 'react-vis/dist/style.css'; -import { CoreStart } from 'src/core/public'; import 'ui/autoload/all'; import 'ui/autoload/styles'; import chrome from 'ui/chrome'; -import { I18nContext } from 'ui/i18n'; // @ts-ignore import { uiModules } from 'ui/modules'; import 'uiExports/autocompleteProviders'; @@ -20,10 +19,19 @@ import { plugin } from './new-platform'; import { REACT_APP_ROOT_ID } from './new-platform/plugin'; import './style/global_overrides.css'; import template from './templates/index.html'; +import { CoreProvider } from './context/CoreContext'; + +const { core } = npStart; +// console.log(npStart); // render APM feedback link in global help menu -chrome.helpExtension.set(domElement => { - ReactDOM.render(, domElement); +core.chrome.setHelpExtension(domElement => { + ReactDOM.render( + + + , + domElement + ); return () => { ReactDOM.unmountComponentAtNode(domElement); }; @@ -42,12 +50,6 @@ const checkForRoot = () => { } }); }; - checkForRoot().then(() => { - const core = { - i18n: { - Context: I18nContext - } - } as CoreStart; plugin().start(core); }); diff --git a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx index 64f240f3dc4f7..abd793245cbb6 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx @@ -8,8 +8,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, Switch } from 'react-router-dom'; import styled from 'styled-components'; -import { CoreStart } from 'src/core/public'; +import { InternalCoreStart } from 'src/core/public'; import { history } from '../utils/history'; +import { CoreProvider } from '../context/CoreContext'; import { LocationProvider } from '../context/LocationContext'; import { UrlParamsProvider } from '../context/UrlParamsContext'; import { px, unit, units } from '../style/variables'; @@ -53,16 +54,18 @@ const App = () => { }; export class Plugin { - public start(core: CoreStart) { + public start(core: InternalCoreStart) { const { i18n } = core; ReactDOM.render( - - - - - - - , + + + + + + + + + , document.getElementById(REACT_APP_ROOT_ID) ); } diff --git a/x-pack/legacy/plugins/apm/public/register_feature.js b/x-pack/legacy/plugins/apm/public/register_feature.js index 0e27d1427f691..8994fac17e914 100644 --- a/x-pack/legacy/plugins/apm/public/register_feature.js +++ b/x-pack/legacy/plugins/apm/public/register_feature.js @@ -4,14 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; +import { npStart } from 'ui/new_platform'; import { i18n } from '@kbn/i18n'; import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue'; -if (chrome.getInjected('apmUiEnabled')) { +const { core } = npStart; +const apmUiEnabled = core.injectedMetadata.getInjectedVar('apmUiEnabled'); + +if (apmUiEnabled) { FeatureCatalogueRegistryProvider.register(() => { return { id: 'apm', diff --git a/x-pack/legacy/plugins/apm/public/services/rest/ml.ts b/x-pack/legacy/plugins/apm/public/services/rest/ml.ts index 6ce6ee36fdda1..c327a3bb0e5c0 100644 --- a/x-pack/legacy/plugins/apm/public/services/rest/ml.ts +++ b/x-pack/legacy/plugins/apm/public/services/rest/ml.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { npStart } from 'ui/new_platform'; import { ESFilter } from 'elasticsearch'; -import chrome from 'ui/chrome'; import { PROCESSOR_EVENT, SERVICE_NAME, @@ -31,6 +31,8 @@ interface StartedMLJobApiResponse { jobs: MlResponseItem[]; } +const { core } = npStart; + export async function startMLJob({ serviceName, transactionType @@ -38,7 +40,9 @@ export async function startMLJob({ serviceName: string; transactionType: string; }) { - const indexPatternName = chrome.getInjected('apmIndexPatternTitle'); + const indexPatternName = core.injectedMetadata.getInjectedVar( + 'apmIndexPatternTitle' + ); const groups = ['apm', serviceName.toLowerCase()]; const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, From dccb5cf6cc4bf1e5c177cc84d8cb977cf9677859 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Wed, 24 Jul 2019 11:12:54 -0700 Subject: [PATCH 2/2] [APM] fix broken tests by mocking useCore hook --- .../__test__/ServiceOverview.test.tsx | 15 ++++++++++++-- .../ServiceOverview.test.tsx.snap | 4 ++-- .../DiscoverLinks.integration.test.tsx | 20 +++++++++++++++---- .../MachineLearningLinks/MLJobLink.test.tsx | 19 +++++++++++++++++- .../__test__/TransactionActionMenu.test.tsx | 15 ++++++++++++-- x-pack/legacy/plugins/apm/public/index.tsx | 1 - 6 files changed, 62 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx index b616111d7b71b..013d803e6411d 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx @@ -10,7 +10,9 @@ import 'react-testing-library/cleanup-after-each'; import { toastNotifications } from 'ui/notify'; import * as apmRestServices from '../../../../services/rest/apm/services'; import { ServiceOverview } from '..'; -import * as hooks from '../../../../hooks/useUrlParams'; +import * as urlParamsHooks from '../../../../hooks/useUrlParams'; +import * as coreHooks from '../../../../hooks/useCore'; +import { InternalCoreStart } from 'src/core/public'; jest.mock('ui/kfetch'); @@ -20,13 +22,22 @@ function renderServiceOverview() { describe('Service Overview -> View', () => { beforeEach(() => { + const coreMock = ({ + http: { + basePath: { + prepend: (path: string) => `/basepath${path}` + } + } + } as unknown) as InternalCoreStart; + // mock urlParams - spyOn(hooks, 'useUrlParams').and.returnValue({ + spyOn(urlParamsHooks, 'useUrlParams').and.returnValue({ urlParams: { start: 'myStart', end: 'myEnd' } }); + spyOn(coreHooks, 'useCore').and.returnValue(coreMock); }); afterEach(() => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap index 4d3f9f9ee8ee5..ee930c1218600 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap @@ -79,7 +79,7 @@ NodeList [ Learn more by visiting the Kibana Upgrade Assistant @@ -96,7 +96,7 @@ NodeList [ />