diff --git a/examples/routing_example/public/app.tsx b/examples/routing_example/public/app.tsx index eb9589919d2ab93..4a2200742c53df8 100644 --- a/examples/routing_example/public/app.tsx +++ b/examples/routing_example/public/app.tsx @@ -16,6 +16,7 @@ import { EuiHorizontalRule, EuiListGroup, } from '@elastic/eui'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { RandomNumberRouteExample } from './random_number_example'; import { RandomNumberBetweenRouteExample } from './random_number_between_example'; import { Services } from './services'; @@ -30,56 +31,59 @@ function RoutingExplorer({ addSuccessToast, postMessage, getMessageById, + startServices, }: Props) { return ( - - - -

Routing examples

-
-
- - + + + - +

Routing examples

- - - - +
+ + + + + + + + + - - + + - - - - -
+ + +
+
+
+ ); } diff --git a/examples/routing_example/public/services.ts b/examples/routing_example/public/services.ts index d98791ff5c24069..75308f5279ddff1 100644 --- a/examples/routing_example/public/services.ts +++ b/examples/routing_example/public/services.ts @@ -6,7 +6,12 @@ * Side Public License, v 1. */ -import type { CoreStart } from '@kbn/core/public'; +import type { + AnalyticsServiceStart, + CoreStart, + I18nStart, + ThemeServiceStart, +} from '@kbn/core/public'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import { RANDOM_NUMBER_ROUTE_PATH, @@ -15,7 +20,14 @@ import { INTERNAL_GET_MESSAGE_BY_ID_ROUTE, } from '../common'; +interface StartServices { + analytics: Pick; + i18n: I18nStart; + theme: Pick; +} + export interface Services { + startServices: StartServices; fetchRandomNumber: () => Promise; fetchRandomNumberBetween: (max: number) => Promise; postMessage: (message: string, id: string) => Promise; @@ -24,7 +36,11 @@ export interface Services { } export function getServices(core: CoreStart): Services { + const { analytics, i18n, theme } = core; + const startServices = { analytics, i18n, theme }; + return { + startServices, addSuccessToast: (message: string) => core.notifications.toasts.addSuccess(message), fetchRandomNumber: async () => { try { diff --git a/examples/routing_example/tsconfig.json b/examples/routing_example/tsconfig.json index bf0c7af2e33c2a9..b35e8dbd34f4a56 100644 --- a/examples/routing_example/tsconfig.json +++ b/examples/routing_example/tsconfig.json @@ -19,5 +19,6 @@ "@kbn/developer-examples-plugin", "@kbn/core-http-browser", "@kbn/config-schema", + "@kbn/react-kibana-context-render", ] } diff --git a/packages/cloud/connection_details/kibana/global.ts b/packages/cloud/connection_details/kibana/global.ts index 0a2ede8e5157ddf..805cc324c98275c 100644 --- a/packages/cloud/connection_details/kibana/global.ts +++ b/packages/cloud/connection_details/kibana/global.ts @@ -13,13 +13,13 @@ import type { SharePluginStart } from '@kbn/share-plugin/public'; export interface ConnectionDetailsGlobalDependencies { start: { core: { + analytics: CoreStart['analytics']; i18n: CoreStart['i18n']; docLinks: CoreStart['docLinks']; theme: CoreStart['theme']; http: CoreStart['http']; application: CoreStart['application']; overlays: CoreStart['overlays']; - analytics?: CoreStart['analytics']; }; plugins: { cloud?: CloudStart; diff --git a/packages/cloud/connection_details/kibana/open_connection_details.tsx b/packages/cloud/connection_details/kibana/open_connection_details.tsx index 52078662c337d27..6e29f6bffec9ebb 100644 --- a/packages/cloud/connection_details/kibana/open_connection_details.tsx +++ b/packages/cloud/connection_details/kibana/open_connection_details.tsx @@ -8,6 +8,7 @@ import * as React from 'react'; import ReactDOM from 'react-dom'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import type { CoreStart } from '@kbn/core-lifecycle-browser'; import * as conn from '..'; @@ -16,6 +17,9 @@ export interface OpenConnectionDetailsParams { start: { core: { overlays: CoreStart['overlays']; + i18n: CoreStart['i18n']; + analytics?: CoreStart['analytics']; + theme: CoreStart['theme']; }; }; } @@ -23,14 +27,16 @@ export interface OpenConnectionDetailsParams { export const openConnectionDetails = async ({ props, start }: OpenConnectionDetailsParams) => { const mount = (element: HTMLElement) => { const reactElement = ( - { - flyoutRef?.close(); - }} - > - - + + { + flyoutRef?.close(); + }} + > + + + ); ReactDOM.render(reactElement, element); diff --git a/packages/cloud/tsconfig.json b/packages/cloud/tsconfig.json index 1eb5dbd01b1e07c..63d6c281f819990 100644 --- a/packages/cloud/tsconfig.json +++ b/packages/cloud/tsconfig.json @@ -22,5 +22,6 @@ "@kbn/cloud-plugin", "@kbn/share-plugin", "@kbn/security-plugin-types-server", + "@kbn/react-kibana-context-render", ] } diff --git a/packages/core/apps/core-apps-browser-internal/src/core_app.ts b/packages/core/apps/core-apps-browser-internal/src/core_app.ts index 6ea7eb8835849ed..85c61ff7f8641bb 100644 --- a/packages/core/apps/core-apps-browser-internal/src/core_app.ts +++ b/packages/core/apps/core-apps-browser-internal/src/core_app.ts @@ -18,12 +18,15 @@ import type { InternalApplicationSetup, InternalApplicationStart, } from '@kbn/core-application-browser-internal'; +import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser'; +import type { I18nStart } from '@kbn/core-i18n-browser'; +import type { ThemeServiceStart } from '@kbn/core-theme-browser'; +import { renderApp as renderStatusApp } from './status'; import { renderApp as renderErrorApp, setupPublicBaseUrlConfigWarning, setupUrlOverflowDetection, } from './errors'; -import { renderApp as renderStatusApp } from './status'; export interface CoreAppsServiceSetupDeps { application: InternalApplicationSetup; @@ -38,6 +41,9 @@ export interface CoreAppsServiceStartDeps { http: InternalHttpStart; notifications: NotificationsStart; uiSettings: IUiSettingsClient; + analytics: AnalyticsServiceStart; + i18n: I18nStart; + theme: ThemeServiceStart; } export class CoreAppsService { @@ -79,6 +85,9 @@ export class CoreAppsService { http, notifications, uiSettings, + analytics, + i18n, + theme, }: CoreAppsServiceStartDeps) { if (!application.history) { return; @@ -91,7 +100,7 @@ export class CoreAppsService { uiSettings, }); - setupPublicBaseUrlConfigWarning({ docLinks, http, notifications }); + setupPublicBaseUrlConfigWarning({ docLinks, http, notifications, analytics, i18n, theme }); } public stop() { diff --git a/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.test.tsx b/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.test.tsx index edcdc18740664cc..fc5c60555d7e49b 100644 --- a/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.test.tsx +++ b/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.test.tsx @@ -6,15 +6,28 @@ * Side Public License, v 1. */ +import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; import { docLinksServiceMock } from '@kbn/core-doc-links-browser-mocks'; import { httpServiceMock } from '@kbn/core-http-browser-mocks'; - +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; +import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; + import { setupPublicBaseUrlConfigWarning } from './public_base_url'; describe('publicBaseUrl warning', () => { const docLinks = docLinksServiceMock.createStartContract(); const notifications = notificationServiceMock.createStartContract(); + const i18nStart = i18nServiceMock.createStartContract(); + const analytics = analyticsServiceMock.createAnalyticsServiceStart(); + const theme = themeServiceMock.createStartContract(); + const startServices = { + notifications, + analytics, + i18n: i18nStart, + theme, + }; + const addWarningToastSpy = jest.spyOn(notifications.toasts, 'addWarning'); beforeEach(() => { jest.resetAllMocks(); @@ -24,38 +37,38 @@ describe('publicBaseUrl warning', () => { const http = httpServiceMock.createStartContract(); setupPublicBaseUrlConfigWarning({ + ...startServices, docLinks, - notifications, http, location: { hostname: 'localhost', } as Location, }); - expect(notifications.toasts.addWarning).not.toHaveBeenCalled(); + expect(addWarningToastSpy).not.toHaveBeenCalled(); }); it('does not show any toast on 127.0.0.1', () => { const http = httpServiceMock.createStartContract(); setupPublicBaseUrlConfigWarning({ + ...startServices, docLinks, - notifications, http, location: { hostname: '127.0.0.1', } as Location, }); - expect(notifications.toasts.addWarning).not.toHaveBeenCalled(); + expect(addWarningToastSpy).not.toHaveBeenCalled(); }); it('does not show toast if configured correctly', () => { const http = httpServiceMock.createStartContract({ publicBaseUrl: 'http://myhost.com' }); setupPublicBaseUrlConfigWarning({ + ...startServices, docLinks, - notifications, http, location: { hostname: 'myhost.com', @@ -65,7 +78,7 @@ describe('publicBaseUrl warning', () => { } as Location, }); - expect(notifications.toasts.addWarning).not.toHaveBeenCalled(); + expect(addWarningToastSpy).not.toHaveBeenCalled(); }); describe('config missing toast', () => { @@ -73,8 +86,8 @@ describe('publicBaseUrl warning', () => { const http = httpServiceMock.createStartContract({ publicBaseUrl: undefined }); setupPublicBaseUrlConfigWarning({ + ...startServices, docLinks, - notifications, http, location: { hostname: 'myhost.com', @@ -84,7 +97,7 @@ describe('publicBaseUrl warning', () => { } as Location, }); - expect(notifications.toasts.addWarning).toHaveBeenCalledWith({ + expect(addWarningToastSpy).toHaveBeenCalledWith({ title: 'Configuration recommended', text: expect.any(Function), }); @@ -94,8 +107,8 @@ describe('publicBaseUrl warning', () => { const http = httpServiceMock.createStartContract({ publicBaseUrl: undefined }); setupPublicBaseUrlConfigWarning({ + ...startServices, docLinks, - notifications, http, location: { hostname: 'myhost.com', @@ -104,11 +117,11 @@ describe('publicBaseUrl warning', () => { }, } as Location, storage: { - getItem: (id: string) => 'true', + getItem: (_id: string) => 'true', } as Storage, }); - expect(notifications.toasts.addWarning).not.toHaveBeenCalled(); + expect(addWarningToastSpy).not.toHaveBeenCalled(); }); }); }); diff --git a/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.tsx b/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.tsx index f125d032398021d..33557bc86de9152 100644 --- a/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.tsx +++ b/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.tsx @@ -12,9 +12,13 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { DocLinksStart } from '@kbn/core-doc-links-browser'; +import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser'; +import type { I18nStart } from '@kbn/core-i18n-browser'; +import type { ThemeServiceStart } from '@kbn/core-theme-browser'; import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import type { NotificationsStart } from '@kbn/core-notifications-browser'; import { mountReactNode } from '@kbn/core-mount-utils-browser-internal'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; /** Only exported for tests */ export const MISSING_CONFIG_STORAGE_KEY = `core.warnings.publicBaseUrlMissingDismissed`; @@ -26,6 +30,10 @@ interface Deps { // Exposed for easier testing storage?: Storage; location?: Location; + // For KibanaRenderContextProvider + analytics: AnalyticsServiceStart; + i18n: I18nStart; + theme: ThemeServiceStart; } export const setupPublicBaseUrlConfigWarning = ({ @@ -34,6 +42,7 @@ export const setupPublicBaseUrlConfigWarning = ({ notifications, storage = window.localStorage, location = window.location, + ...renderContextDeps }: Deps) => { if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') { return; @@ -49,7 +58,7 @@ export const setupPublicBaseUrlConfigWarning = ({ defaultMessage: 'Configuration recommended', }), text: mountReactNode( - <> +

- + ), }); }; diff --git a/packages/core/apps/core-apps-browser-internal/tsconfig.json b/packages/core/apps/core-apps-browser-internal/tsconfig.json index 35e25675fe078f9..a18bb3421a1f433 100644 --- a/packages/core/apps/core-apps-browser-internal/tsconfig.json +++ b/packages/core/apps/core-apps-browser-internal/tsconfig.json @@ -10,7 +10,7 @@ }, "include": [ "**/*.ts", - "**/*.tsx", + "**/*.tsx" ], "kbn_references": [ "@kbn/i18n", @@ -35,8 +35,15 @@ "@kbn/core-doc-links-browser-mocks", "@kbn/test-jest-helpers", "@kbn/react-kibana-context-theme", + "@kbn/core-analytics-browser", + "@kbn/core-i18n-browser", + "@kbn/core-theme-browser", + "@kbn/react-kibana-context-render", + "@kbn/core-analytics-browser-mocks", + "@kbn/core-i18n-browser-mocks", + "@kbn/core-theme-browser-mocks" ], "exclude": [ - "target/**/*", + "target/**/*" ] } diff --git a/packages/core/notifications/core-notifications-browser-internal/src/toasts/__snapshots__/error_toast.test.tsx.snap b/packages/core/notifications/core-notifications-browser-internal/src/toasts/__snapshots__/error_toast.test.tsx.snap index 3f21369a67da1ff..3c7645d3ce33319 100644 --- a/packages/core/notifications/core-notifications-browser-internal/src/toasts/__snapshots__/error_toast.test.tsx.snap +++ b/packages/core/notifications/core-notifications-browser-internal/src/toasts/__snapshots__/error_toast.test.tsx.snap @@ -1,7 +1,35 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders matching snapshot 1`] = ` - +

@@ -23,5 +51,5 @@ exports[`renders matching snapshot 1`] = ` /> - + `; diff --git a/packages/core/notifications/core-notifications-browser-internal/src/toasts/error_toast.tsx b/packages/core/notifications/core-notifications-browser-internal/src/toasts/error_toast.tsx index e494b0294f94826..d47293b8836326a 100644 --- a/packages/core/notifications/core-notifications-browser-internal/src/toasts/error_toast.tsx +++ b/packages/core/notifications/core-notifications-browser-internal/src/toasts/error_toast.tsx @@ -111,7 +111,7 @@ export function ErrorToast({ ...startServices }: ErrorToastProps) { return ( - +

{toastMessage}

- +
); } diff --git a/packages/core/root/core-root-browser-internal/src/core_system.ts b/packages/core/root/core-root-browser-internal/src/core_system.ts index c9dcbf064823aea..f06f1becbf2483b 100644 --- a/packages/core/root/core-root-browser-internal/src/core_system.ts +++ b/packages/core/root/core-root-browser-internal/src/core_system.ts @@ -291,14 +291,14 @@ export class CoreSystem { const analytics = this.analytics.start(); const security = this.security.start(); const userProfile = this.userProfile.start(); - const injectedMetadata = await this.injectedMetadata.start(); - const uiSettings = await this.uiSettings.start(); - const settings = await this.settings.start(); + const injectedMetadata = this.injectedMetadata.start(); + const uiSettings = this.uiSettings.start(); + const settings = this.settings.start(); const docLinks = this.docLinks.start({ injectedMetadata }); - const http = await this.http.start(); + const http = this.http.start(); const savedObjects = await this.savedObjects.start({ http }); - const i18n = await this.i18n.start(); - const fatalErrors = await this.fatalErrors.start(); + const i18n = this.i18n.start(); + const fatalErrors = this.fatalErrors.start(); const theme = this.theme.start(); await this.integrations.start({ uiSettings }); @@ -345,7 +345,16 @@ export class CoreSystem { }); const deprecations = this.deprecations.start({ http }); - this.coreApp.start({ application, docLinks, http, notifications, uiSettings }); + this.coreApp.start({ + application, + docLinks, + http, + notifications, + uiSettings, + analytics, + i18n, + theme, + }); const core: InternalCoreStart = { analytics, diff --git a/test/plugin_functional/plugins/core_app_status/public/application.tsx b/test/plugin_functional/plugins/core_app_status/public/application.tsx index 3ea989dfbf1d298..4ee336ae0aa2fae 100644 --- a/test/plugin_functional/plugins/core_app_status/public/application.tsx +++ b/test/plugin_functional/plugins/core_app_status/public/application.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { EuiPage, EuiPageBody, @@ -17,7 +18,7 @@ import { EuiTitle, } from '@elastic/eui'; -import { AppMountParameters } from '@kbn/core/public'; +import { AppMountParameters, CoreStart } from '@kbn/core/public'; const AppStatusApp = ({ appId }: { appId: string }) => ( @@ -41,8 +42,17 @@ const AppStatusApp = ({ appId }: { appId: string }) => ( ); -export const renderApp = (appId: string, { element }: AppMountParameters) => { - render(, element); +export const renderApp = async ( + appId: string, + { element }: AppMountParameters, + core: CoreStart +) => { + render( + + + , + element + ); return () => unmountComponentAtNode(element); }; diff --git a/test/plugin_functional/plugins/core_app_status/public/plugin.tsx b/test/plugin_functional/plugins/core_app_status/public/plugin.tsx index e5be727bea1741a..d3901e8a446320b 100644 --- a/test/plugin_functional/plugins/core_app_status/public/plugin.tsx +++ b/test/plugin_functional/plugins/core_app_status/public/plugin.tsx @@ -26,7 +26,8 @@ export class CoreAppStatusPlugin implements Plugin<{}, CoreAppStatusPluginStart> id: 'app_status_start', title: 'App Status Start Page', async mount(params: AppMountParameters) { - return renderApp('app_status_start', params); + const [coreStart] = await core.getStartServices(); + return renderApp('app_status_start', params, coreStart); }, }); @@ -36,7 +37,8 @@ export class CoreAppStatusPlugin implements Plugin<{}, CoreAppStatusPluginStart> euiIconType: 'snowflake', updater$: this.appUpdater, async mount(params: AppMountParameters) { - return renderApp('app_status', params); + const [coreStart] = await core.getStartServices(); + return renderApp('app_status', params, coreStart); }, }); diff --git a/test/plugin_functional/plugins/core_app_status/tsconfig.json b/test/plugin_functional/plugins/core_app_status/tsconfig.json index ef3b1a3322e4366..75bcb3f61eba2bc 100644 --- a/test/plugin_functional/plugins/core_app_status/tsconfig.json +++ b/test/plugin_functional/plugins/core_app_status/tsconfig.json @@ -14,5 +14,6 @@ ], "kbn_references": [ "@kbn/core", + "@kbn/react-kibana-context-render", ], } diff --git a/test/plugin_functional/plugins/core_plugin_a/public/application.tsx b/test/plugin_functional/plugins/core_plugin_a/public/application.tsx index 6c1440c10abf222..b0b9f61da09458c 100644 --- a/test/plugin_functional/plugins/core_plugin_a/public/application.tsx +++ b/test/plugin_functional/plugins/core_plugin_a/public/application.tsx @@ -10,6 +10,7 @@ import { History } from 'history'; import React from 'react'; import ReactDOM from 'react-dom'; import { withRouter, RouteComponentProps, Redirect } from 'react-router-dom'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { Router, Route } from '@kbn/shared-ux-router'; import { @@ -100,16 +101,18 @@ const Nav = withRouter(({ history, navigateToApp }: NavProps) => ( )); const FooApp = ({ history, coreStart }: { history: History; coreStart: CoreStart }) => ( - - - -