diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx index 035015c82a0a..7a23c9f7de84 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx @@ -8,7 +8,6 @@ import { shallow } from 'enzyme'; import React from 'react'; import { Home } from '../Home'; -jest.mock('ui/index_patterns'); jest.mock('ui/new_platform'); describe('Home component', () => { 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 deleted file mode 100644 index bb9f581129c5..000000000000 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/useUpdateBadgeEffect.ts +++ /dev/null @@ -1,31 +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 { i18n } from '@kbn/i18n'; -import { useEffect } from 'react'; -import { capabilities } from 'ui/capabilities'; -import { useKibanaCore } from '../../../../../observability/public'; - -export const useUpdateBadgeEffect = () => { - const { chrome } = useKibanaCore(); - - useEffect(() => { - const uiCapabilities = capabilities.get(); - chrome.setBadge( - !uiCapabilities.apm.save - ? { - text: i18n.translate('xpack.apm.header.badge.readOnly.text', { - defaultMessage: 'Read only' - }), - tooltip: i18n.translate('xpack.apm.header.badge.readOnly.tooltip', { - defaultMessage: 'Unable to save' - }), - iconType: 'glasses' - } - : undefined - ); - }, [chrome]); -}; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx index 881e5975fc81..05094c59712a 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx @@ -18,8 +18,6 @@ import { mount } from 'enzyme'; import { EuiSuperDatePicker } from '@elastic/eui'; import { MemoryRouter } from 'react-router-dom'; -jest.mock('ui/kfetch'); - const mockHistoryPush = jest.spyOn(history, 'push'); const mockRefreshTimeRange = jest.fn(); const MockUrlParamsProvider: React.FC<{ 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 66946e5b447f..24d320505c99 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 } from 'react'; import { uniqueId, startsWith } from 'lodash'; import styled from 'styled-components'; -import { npStart } from 'ui/new_platform'; import { StaticIndexPattern } from 'ui/index_patterns'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; @@ -18,16 +17,17 @@ import { getBoolFilter } from './get_bool_filter'; import { useLocation } from '../../../hooks/useLocation'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { history } from '../../../utils/history'; -import { AutocompleteSuggestion } from '../../../../../../../../src/plugins/data/public'; +import { + AutocompleteSuggestion, + AutocompleteProvider +} from '../../../../../../../../src/plugins/data/public'; import { useDynamicIndexPattern } from '../../../hooks/useDynamicIndexPattern'; +import { usePlugins } from '../../../new-platform/plugin'; const Container = styled.div` margin-bottom: 10px; `; -const getAutocompleteProvider = (language: string) => - npStart.plugins.data.autocomplete.getProvider(language); - interface State { suggestions: AutocompleteSuggestion[]; isLoadingSuggestions: boolean; @@ -45,9 +45,9 @@ function getSuggestions( query: string, selectionStart: number, indexPattern: StaticIndexPattern, - boolFilter: unknown + boolFilter: unknown, + autocompleteProvider?: AutocompleteProvider ) { - const autocompleteProvider = getAutocompleteProvider('kuery'); if (!autocompleteProvider) { return []; } @@ -74,6 +74,8 @@ export function KueryBar() { }); const { urlParams } = useUrlParams(); const location = useLocation(); + const { data } = usePlugins(); + const autocompleteProvider = data.autocomplete.getProvider('kuery'); let currentRequestCheck; @@ -108,7 +110,8 @@ export function KueryBar() { inputValue, selectionStart, indexPattern, - boolFilter + boolFilter, + autocompleteProvider ) ) .filter(suggestion => !startsWith(suggestion.text, 'span.')) diff --git a/x-pack/legacy/plugins/apm/public/index.tsx b/x-pack/legacy/plugins/apm/public/index.tsx index 8fd3cb0893de..db14e1c52002 100644 --- a/x-pack/legacy/plugins/apm/public/index.tsx +++ b/x-pack/legacy/plugins/apm/public/index.tsx @@ -6,43 +6,18 @@ import { npStart } from 'ui/new_platform'; import 'react-vis/dist/style.css'; +import { PluginInitializerContext } from 'kibana/public'; import 'ui/autoload/all'; import chrome from 'ui/chrome'; -import { i18n } from '@kbn/i18n'; -import url from 'url'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; 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'; -const { core } = npStart; - -// render APM feedback link in global help menu -core.chrome.setHelpExtension({ - appName: i18n.translate('xpack.apm.feedbackMenu.appName', { - defaultMessage: 'APM' - }), - links: [ - { - linkType: 'discuss', - href: 'https://discuss.elastic.co/c/apm' - }, - { - linkType: 'custom', - href: url.format({ - pathname: core.http.basePath.prepend('/app/kibana'), - hash: '/management/elasticsearch/upgrade_assistant' - }), - content: i18n.translate('xpack.apm.helpMenu.upgradeAssistantLink', { - defaultMessage: 'Upgrade assistant' - }) - } - ] -}); +const { core, plugins } = npStart; +// This will be moved to core.application.register when the new platform +// migration is complete. // @ts-ignore chrome.setRootTemplate(template); @@ -57,5 +32,5 @@ const checkForRoot = () => { }); }; checkForRoot().then(() => { - plugin().start(core); + plugin({} as PluginInitializerContext).start(core, plugins); }); diff --git a/x-pack/legacy/plugins/apm/public/new-platform/index.tsx b/x-pack/legacy/plugins/apm/public/new-platform/index.tsx index cb4cc2a845a4..9dce4bcdd828 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/index.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/index.tsx @@ -4,8 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Plugin } from './plugin'; +import { PluginInitializer } from '../../../../../../src/core/public'; +import { ApmPlugin, ApmPluginSetup, ApmPluginStart } from './plugin'; -export function plugin() { - return new Plugin(); -} +export const plugin: PluginInitializer< + ApmPluginSetup, + ApmPluginStart +> = _core => new ApmPlugin(); 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 ac4aca4c795b..b5986610d304 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx @@ -4,11 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useContext, createContext } from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, Switch } from 'react-router-dom'; import styled from 'styled-components'; -import { LegacyCoreStart } from 'src/core/public'; +import { + CoreStart, + LegacyCoreStart, + Plugin, + CoreSetup +} from '../../../../../../src/core/public'; +import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; import { KibanaCoreContextProvider } from '../../../observability/public'; import { history } from '../utils/history'; import { LocationProvider } from '../context/LocationContext'; @@ -19,9 +25,10 @@ import { LicenseProvider } from '../context/LicenseContext'; import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; import { routes } from '../components/app/Main/route_config'; import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; -import { useUpdateBadgeEffect } from '../components/app/Main/useUpdateBadgeEffect'; import { MatchedRouteProvider } from '../context/MatchedRouteContext'; import { createStaticIndexPattern } from '../services/rest/index_pattern'; +import { setHelpExtension } from './setHelpExtension'; +import { setReadonlyBadge } from './updateBadge'; export const REACT_APP_ROOT_ID = 'react-apm-root'; @@ -31,41 +38,70 @@ const MainContainer = styled.main` `; const App = () => { - useUpdateBadgeEffect(); - return ( - - - - - - - - - {routes.map((route, i) => ( - - ))} - - - - - - + + + + + {routes.map((route, i) => ( + + ))} + + ); }; -export class Plugin { - public start(core: LegacyCoreStart) { - const { i18n } = core; +export type ApmPluginSetup = void; +export type ApmPluginStart = void; +export type ApmPluginSetupDeps = {}; // eslint-disable-line @typescript-eslint/consistent-type-definitions + +export interface ApmPluginStartDeps { + data: DataPublicPluginStart; +} + +const PluginsContext = createContext({} as ApmPluginStartDeps); + +export function usePlugins() { + return useContext(PluginsContext); +} + +export class ApmPlugin + implements + Plugin< + ApmPluginSetup, + ApmPluginStart, + ApmPluginSetupDeps, + ApmPluginStartDeps + > { + // Take the DOM element as the constructor, so we can mount the app. + public setup(_core: CoreSetup, _plugins: ApmPluginSetupDeps) {} + + public start(core: CoreStart, plugins: ApmPluginStartDeps) { + const i18nCore = core.i18n; + + // render APM feedback link in global help menu + setHelpExtension(core); + setReadonlyBadge(core); + ReactDOM.render( - - - - - - - - + + + + + + + + + + + + + + + + + + , document.getElementById(REACT_APP_ROOT_ID) ); @@ -76,4 +112,6 @@ export class Plugin { console.log('Error fetching static index pattern', e); }); } + + public stop() {} } diff --git a/x-pack/legacy/plugins/apm/public/new-platform/setHelpExtension.ts b/x-pack/legacy/plugins/apm/public/new-platform/setHelpExtension.ts new file mode 100644 index 000000000000..1a3394651b2f --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/new-platform/setHelpExtension.ts @@ -0,0 +1,33 @@ +/* + * 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 url from 'url'; +import { i18n } from '@kbn/i18n'; +import { CoreStart } from 'kibana/public'; + +export function setHelpExtension({ chrome, http }: CoreStart) { + chrome.setHelpExtension({ + appName: i18n.translate('xpack.apm.feedbackMenu.appName', { + defaultMessage: 'APM' + }), + links: [ + { + linkType: 'discuss', + href: 'https://discuss.elastic.co/c/apm' + }, + { + linkType: 'custom', + href: url.format({ + pathname: http.basePath.prepend('/app/kibana'), + hash: '/management/elasticsearch/upgrade_assistant' + }), + content: i18n.translate('xpack.apm.helpMenu.upgradeAssistantLink', { + defaultMessage: 'Upgrade assistant' + }) + } + ] + }); +} diff --git a/x-pack/legacy/plugins/apm/public/new-platform/updateBadge.ts b/x-pack/legacy/plugins/apm/public/new-platform/updateBadge.ts new file mode 100644 index 000000000000..b3e29bb891c2 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/new-platform/updateBadge.ts @@ -0,0 +1,27 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { CoreStart } from 'kibana/public'; + +export function setReadonlyBadge({ application, chrome }: CoreStart) { + const canSave = application.capabilities.apm.save; + const { setBadge } = chrome; + + setBadge( + !canSave + ? { + text: i18n.translate('xpack.apm.header.badge.readOnly.text', { + defaultMessage: 'Read only' + }), + tooltip: i18n.translate('xpack.apm.header.badge.readOnly.tooltip', { + defaultMessage: 'Unable to save' + }), + iconType: 'glasses' + } + : undefined + ); +}