diff --git a/docs/development/core/public/kibana-plugin-public.app.md b/docs/development/core/public/kibana-plugin-public.app.md
index c500c080a5feb..edab4f88497f6 100644
--- a/docs/development/core/public/kibana-plugin-public.app.md
+++ b/docs/development/core/public/kibana-plugin-public.app.md
@@ -17,5 +17,5 @@ export interface App extends AppBase
| Property | Type | Description |
| --- | --- | --- |
| [chromeless](./kibana-plugin-public.app.chromeless.md) | boolean
| Hide the UI chrome when the application is mounted. Defaults to false
. Takes precedence over chrome service visibility settings. |
-| [mount](./kibana-plugin-public.app.mount.md) | (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise<AppUnmount>
| A mount function called when the user navigates to this app's route. |
+| [mount](./kibana-plugin-public.app.mount.md) | AppMount | AppMountDeprecated
| A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md). |
diff --git a/docs/development/core/public/kibana-plugin-public.app.mount.md b/docs/development/core/public/kibana-plugin-public.app.mount.md
index dda06b035db4a..151fb7baeb138 100644
--- a/docs/development/core/public/kibana-plugin-public.app.mount.md
+++ b/docs/development/core/public/kibana-plugin-public.app.mount.md
@@ -4,10 +4,15 @@
## App.mount property
-A mount function called when the user navigates to this app's route.
+A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md).
Signature:
```typescript
-mount: (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise;
+mount: AppMount | AppMountDeprecated;
```
+
+## Remarks
+
+When function has two arguments, it will be called with a [context](./kibana-plugin-public.appmountcontext.md) as the first argument. This behavior is \*\*deprecated\*\*, and consumers should instead use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md).
+
diff --git a/docs/development/core/public/kibana-plugin-public.applicationsetup.md b/docs/development/core/public/kibana-plugin-public.applicationsetup.md
index b53873bc0fb8a..a63de399c2ecb 100644
--- a/docs/development/core/public/kibana-plugin-public.applicationsetup.md
+++ b/docs/development/core/public/kibana-plugin-public.applicationsetup.md
@@ -16,5 +16,5 @@ export interface ApplicationSetup
| Method | Description |
| --- | --- |
| [register(app)](./kibana-plugin-public.applicationsetup.register.md) | Register an mountable application to the system. |
-| [registerMountContext(contextName, provider)](./kibana-plugin-public.applicationsetup.registermountcontext.md) | Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. |
+| [registerMountContext(contextName, provider)](./kibana-plugin-public.applicationsetup.registermountcontext.md) | Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). |
diff --git a/docs/development/core/public/kibana-plugin-public.applicationsetup.registermountcontext.md b/docs/development/core/public/kibana-plugin-public.applicationsetup.registermountcontext.md
index f264ba500ed6e..275ba431bc7e7 100644
--- a/docs/development/core/public/kibana-plugin-public.applicationsetup.registermountcontext.md
+++ b/docs/development/core/public/kibana-plugin-public.applicationsetup.registermountcontext.md
@@ -4,12 +4,16 @@
## ApplicationSetup.registerMountContext() method
-Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context.
+> Warning: This API is now obsolete.
+>
+>
+
+Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md).
Signature:
```typescript
-registerMountContext(contextName: T, provider: IContextProvider): void;
+registerMountContext(contextName: T, provider: IContextProvider): void;
```
## Parameters
@@ -17,7 +21,7 @@ registerMountContext(contextName: T, provider:
| Parameter | Type | Description |
| --- | --- | --- |
| contextName | T
| The key of [AppMountContext](./kibana-plugin-public.appmountcontext.md) this provider's return value should be attached to. |
-| provider | IContextProvider<App['mount'], T>
| A [IContextProvider](./kibana-plugin-public.icontextprovider.md) function |
+| provider | IContextProvider<AppMountDeprecated, T>
| A [IContextProvider](./kibana-plugin-public.icontextprovider.md) function |
Returns:
diff --git a/docs/development/core/public/kibana-plugin-public.applicationstart.md b/docs/development/core/public/kibana-plugin-public.applicationstart.md
index 2a60ff449e44e..4baa4565ff7b0 100644
--- a/docs/development/core/public/kibana-plugin-public.applicationstart.md
+++ b/docs/development/core/public/kibana-plugin-public.applicationstart.md
@@ -23,5 +23,5 @@ export interface ApplicationStart
| --- | --- |
| [getUrlForApp(appId, options)](./kibana-plugin-public.applicationstart.geturlforapp.md) | Returns a relative URL to a given app, including the global base path. |
| [navigateToApp(appId, options)](./kibana-plugin-public.applicationstart.navigatetoapp.md) | Navigiate to a given app |
-| [registerMountContext(contextName, provider)](./kibana-plugin-public.applicationstart.registermountcontext.md) | Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. |
+| [registerMountContext(contextName, provider)](./kibana-plugin-public.applicationstart.registermountcontext.md) | Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). |
diff --git a/docs/development/core/public/kibana-plugin-public.applicationstart.registermountcontext.md b/docs/development/core/public/kibana-plugin-public.applicationstart.registermountcontext.md
index 62821fcbb92ba..c15a23fe82b21 100644
--- a/docs/development/core/public/kibana-plugin-public.applicationstart.registermountcontext.md
+++ b/docs/development/core/public/kibana-plugin-public.applicationstart.registermountcontext.md
@@ -4,12 +4,16 @@
## ApplicationStart.registerMountContext() method
-Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context.
+> Warning: This API is now obsolete.
+>
+>
+
+Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md).
Signature:
```typescript
-registerMountContext(contextName: T, provider: IContextProvider): void;
+registerMountContext(contextName: T, provider: IContextProvider): void;
```
## Parameters
@@ -17,7 +21,7 @@ registerMountContext(contextName: T, provider:
| Parameter | Type | Description |
| --- | --- | --- |
| contextName | T
| The key of [AppMountContext](./kibana-plugin-public.appmountcontext.md) this provider's return value should be attached to. |
-| provider | IContextProvider<App['mount'], T>
| A [IContextProvider](./kibana-plugin-public.icontextprovider.md) function |
+| provider | IContextProvider<AppMountDeprecated, T>
| A [IContextProvider](./kibana-plugin-public.icontextprovider.md) function |
Returns:
diff --git a/docs/development/core/public/kibana-plugin-public.appmount.md b/docs/development/core/public/kibana-plugin-public.appmount.md
new file mode 100644
index 0000000000000..25faa7be30b68
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.appmount.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [AppMount](./kibana-plugin-public.appmount.md)
+
+## AppMount type
+
+A mount function called when the user navigates to this app's route.
+
+Signature:
+
+```typescript
+export declare type AppMount = (params: AppMountParameters) => AppUnmount | Promise;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.appmountcontext.md b/docs/development/core/public/kibana-plugin-public.appmountcontext.md
index 68a1c27b11836..2f8c0553d0b38 100644
--- a/docs/development/core/public/kibana-plugin-public.appmountcontext.md
+++ b/docs/development/core/public/kibana-plugin-public.appmountcontext.md
@@ -4,7 +4,11 @@
## AppMountContext interface
-The context object received when applications are mounted to the DOM.
+> Warning: This API is now obsolete.
+>
+>
+
+The context object received when applications are mounted to the DOM. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md).
Signature:
diff --git a/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md b/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md
new file mode 100644
index 0000000000000..936642abcc97a
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md)
+
+## AppMountDeprecated type
+
+> Warning: This API is now obsolete.
+>
+>
+
+A mount function called when the user navigates to this app's route.
+
+Signature:
+
+```typescript
+export declare type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise;
+```
+
+## Remarks
+
+When function has two arguments, it will be called with a [context](./kibana-plugin-public.appmountcontext.md) as the first argument. This behavior is \*\*deprecated\*\*, and consumers should instead use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md).
+
diff --git a/docs/development/core/public/kibana-plugin-public.coresetup.context.md b/docs/development/core/public/kibana-plugin-public.coresetup.context.md
index e56ecb92074c4..f2a891c6c674e 100644
--- a/docs/development/core/public/kibana-plugin-public.coresetup.context.md
+++ b/docs/development/core/public/kibana-plugin-public.coresetup.context.md
@@ -4,6 +4,10 @@
## CoreSetup.context property
+> Warning: This API is now obsolete.
+>
+>
+
[ContextSetup](./kibana-plugin-public.contextsetup.md)
Signature:
diff --git a/docs/development/core/public/kibana-plugin-public.coresetup.getstartservices.md b/docs/development/core/public/kibana-plugin-public.coresetup.getstartservices.md
new file mode 100644
index 0000000000000..b89d98b0a9ed5
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.coresetup.getstartservices.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreSetup](./kibana-plugin-public.coresetup.md) > [getStartServices](./kibana-plugin-public.coresetup.getstartservices.md)
+
+## CoreSetup.getStartServices() method
+
+Allows plugins to get access to APIs available in start inside async handlers, such as [App.mount](./kibana-plugin-public.app.mount.md). Promise will not resolve until Core and plugin dependencies have completed `start`.
+
+Signature:
+
+```typescript
+getStartServices(): Promise<[CoreStart, TPluginsStart]>;
+```
+Returns:
+
+`Promise<[CoreStart, TPluginsStart]>`
+
diff --git a/docs/development/core/public/kibana-plugin-public.coresetup.md b/docs/development/core/public/kibana-plugin-public.coresetup.md
index 8314bde7b95f0..7d75782df2e32 100644
--- a/docs/development/core/public/kibana-plugin-public.coresetup.md
+++ b/docs/development/core/public/kibana-plugin-public.coresetup.md
@@ -9,7 +9,7 @@ Core services exposed to the `Plugin` setup lifecycle
Signature:
```typescript
-export interface CoreSetup
+export interface CoreSetup
```
## Properties
@@ -24,3 +24,9 @@ export interface CoreSetup
| [notifications](./kibana-plugin-public.coresetup.notifications.md) | NotificationsSetup
| [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) |
| [uiSettings](./kibana-plugin-public.coresetup.uisettings.md) | IUiSettingsClient
| [IUiSettingsClient](./kibana-plugin-public.iuisettingsclient.md) |
+## Methods
+
+| Method | Description |
+| --- | --- |
+| [getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md) | Allows plugins to get access to APIs available in start inside async handlers, such as [App.mount](./kibana-plugin-public.app.mount.md). Promise will not resolve until Core and plugin dependencies have completed start
. |
+
diff --git a/docs/development/core/public/kibana-plugin-public.legacycoresetup.md b/docs/development/core/public/kibana-plugin-public.legacycoresetup.md
index f704bc65d12a5..a753300437c1c 100644
--- a/docs/development/core/public/kibana-plugin-public.legacycoresetup.md
+++ b/docs/development/core/public/kibana-plugin-public.legacycoresetup.md
@@ -13,7 +13,7 @@ Setup interface exposed to the legacy platform via the `ui/new_platform` module.
Signature:
```typescript
-export interface LegacyCoreSetup extends CoreSetup
+export interface LegacyCoreSetup extends CoreSetup
```
## Properties
diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md
index 22b6f7faf2daa..c599e1eaa14fe 100644
--- a/docs/development/core/public/kibana-plugin-public.md
+++ b/docs/development/core/public/kibana-plugin-public.md
@@ -26,7 +26,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [AppBase](./kibana-plugin-public.appbase.md) | |
| [ApplicationSetup](./kibana-plugin-public.applicationsetup.md) | |
| [ApplicationStart](./kibana-plugin-public.applicationstart.md) | |
-| [AppMountContext](./kibana-plugin-public.appmountcontext.md) | The context object received when applications are mounted to the DOM. |
+| [AppMountContext](./kibana-plugin-public.appmountcontext.md) | The context object received when applications are mounted to the DOM. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). |
| [AppMountParameters](./kibana-plugin-public.appmountparameters.md) | |
| [Capabilities](./kibana-plugin-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. |
| [ChromeBadge](./kibana-plugin-public.chromebadge.md) | |
@@ -98,6 +98,8 @@ The plugin integrates with the core system via lifecycle events: `setup`
| Type Alias | Description |
| --- | --- |
+| [AppMount](./kibana-plugin-public.appmount.md) | A mount function called when the user navigates to this app's route. |
+| [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md) | A mount function called when the user navigates to this app's route. |
| [AppUnmount](./kibana-plugin-public.appunmount.md) | A function called when an application should be unmounted from the page. This function should be synchronous. |
| [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) | |
| [ChromeHelpExtensionMenuCustomLink](./kibana-plugin-public.chromehelpextensionmenucustomlink.md) | |
diff --git a/docs/development/core/public/kibana-plugin-public.plugin.setup.md b/docs/development/core/public/kibana-plugin-public.plugin.setup.md
index 56855b02cfbad..f058bc8d86fbc 100644
--- a/docs/development/core/public/kibana-plugin-public.plugin.setup.md
+++ b/docs/development/core/public/kibana-plugin-public.plugin.setup.md
@@ -7,14 +7,14 @@
Signature:
```typescript
-setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
+setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| core | CoreSetup
| |
+| core | CoreSetup<TPluginsStart>
| |
| plugins | TPluginsSetup
| |
Returns:
diff --git a/src/core/public/application/application_service.test.tsx b/src/core/public/application/application_service.test.tsx
index 19a208aeefb37..32634572466a6 100644
--- a/src/core/public/application/application_service.test.tsx
+++ b/src/core/public/application/application_service.test.tsx
@@ -32,9 +32,9 @@ describe('#setup()', () => {
const service = new ApplicationService();
const context = contextServiceMock.createSetupContract();
const setup = service.setup({ context });
- setup.register(Symbol(), { id: 'app1' } as any);
+ setup.register(Symbol(), { id: 'app1', mount: jest.fn() } as any);
expect(() =>
- setup.register(Symbol(), { id: 'app1' } as any)
+ setup.register(Symbol(), { id: 'app1', mount: jest.fn() } as any)
).toThrowErrorMatchingInlineSnapshot(
`"An application is already registered with the id \\"app1\\""`
);
@@ -51,6 +51,18 @@ describe('#setup()', () => {
setup.register(Symbol(), { id: 'app1' } as any)
).toThrowErrorMatchingInlineSnapshot(`"Applications cannot be registered after \\"setup\\""`);
});
+
+ it('logs a warning when registering a deprecated app mount', async () => {
+ const consoleWarnSpy = jest.spyOn(console, 'warn');
+ const service = new ApplicationService();
+ const context = contextServiceMock.createSetupContract();
+ const setup = service.setup({ context });
+ setup.register(Symbol(), { id: 'app1', mount: (ctx: any, params: any) => {} } as any);
+ expect(consoleWarnSpy).toHaveBeenCalledWith(
+ `App [app1] is using deprecated mount context. Use core.getStartServices() instead.`
+ );
+ consoleWarnSpy.mockRestore();
+ });
});
describe('registerLegacyApp', () => {
@@ -100,7 +112,7 @@ describe('#start()', () => {
const service = new ApplicationService();
const context = contextServiceMock.createSetupContract();
const setup = service.setup({ context });
- setup.register(Symbol(), { id: 'app1' } as any);
+ setup.register(Symbol(), { id: 'app1', mount: jest.fn() } as any);
setup.registerLegacyApp({ id: 'app2' } as any);
const http = httpServiceMock.createStartContract();
@@ -108,12 +120,13 @@ describe('#start()', () => {
const startContract = await service.start({ http, injectedMetadata });
expect(startContract.availableApps).toMatchInlineSnapshot(`
- Map {
- "app1" => Object {
- "id": "app1",
- },
- }
- `);
+ Map {
+ "app1" => Object {
+ "id": "app1",
+ "mount": [MockFunction],
+ },
+ }
+ `);
expect(startContract.availableLegacyApps).toMatchInlineSnapshot(`
Map {
"app2" => Object {
@@ -127,14 +140,15 @@ describe('#start()', () => {
const service = new ApplicationService();
const context = contextServiceMock.createSetupContract();
const setup = service.setup({ context });
- setup.register(Symbol(), { id: 'app1' } as any);
+ const app1 = { id: 'app1', mount: jest.fn() };
+ setup.register(Symbol(), app1 as any);
const http = httpServiceMock.createStartContract();
const injectedMetadata = injectedMetadataServiceMock.createStartContract();
await service.start({ http, injectedMetadata });
expect(MockCapabilitiesService.start).toHaveBeenCalledWith({
- apps: new Map([['app1', { id: 'app1' }]]),
+ apps: new Map([['app1', app1]]),
legacyApps: new Map(),
http,
});
diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx
index 45ca7f3fe7f7b..df00c84028e6f 100644
--- a/src/core/public/application/application_service.tsx
+++ b/src/core/public/application/application_service.tsx
@@ -29,7 +29,8 @@ import { ContextSetup, IContextContainer } from '../context';
import {
App,
LegacyApp,
- AppMounter,
+ AppMount,
+ AppMountDeprecated,
InternalApplicationSetup,
InternalApplicationStart,
} from './types';
@@ -50,7 +51,7 @@ interface StartDeps {
interface AppBox {
app: App;
- mount: AppMounter;
+ mount: AppMount;
}
/**
@@ -61,7 +62,7 @@ export class ApplicationService {
private readonly apps$ = new BehaviorSubject>(new Map());
private readonly legacyApps$ = new BehaviorSubject>(new Map());
private readonly capabilities = new CapabilitiesService();
- private mountContext?: IContextContainer;
+ private mountContext?: IContextContainer;
public setup({ context }: SetupDeps): InternalApplicationSetup {
this.mountContext = context.createContextContainer();
@@ -75,10 +76,21 @@ export class ApplicationService {
throw new Error(`Applications cannot be registered after "setup"`);
}
- const appBox: AppBox = {
- app,
- mount: this.mountContext!.createHandler(plugin, app.mount),
- };
+ let appBox: AppBox;
+ if (isAppMountDeprecated(app.mount)) {
+ // eslint-disable-next-line no-console
+ console.warn(
+ `App [${app.id}] is using deprecated mount context. Use core.getStartServices() instead.`
+ );
+
+ appBox = {
+ app,
+ mount: this.mountContext!.createHandler(plugin, app.mount),
+ };
+ } else {
+ appBox = { app, mount: app.mount };
+ }
+
this.apps$.next(new Map([...this.apps$.value.entries(), [app.id, appBox]]));
},
registerLegacyApp: (app: LegacyApp) => {
@@ -146,7 +158,7 @@ export class ApplicationService {
}
// Filter only available apps and map to just the mount function.
- const appMounters = new Map(
+ const appMounts = new Map(
[...this.apps$.value]
.filter(([id]) => availableApps.has(id))
.map(([id, { mount }]) => [id, mount])
@@ -154,7 +166,7 @@ export class ApplicationService {
return (
path
? `/app/${appId}/${path.replace(/^\//, '')}` // Remove preceding slash from path if present
: `/app/${appId}`;
+
+function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated {
+ // Mount functions with two arguments are assumed to expect deprecated `context` object.
+ return mount.length === 2;
+}
diff --git a/src/core/public/application/index.ts b/src/core/public/application/index.ts
index ae25b54cf07a8..9c4427c772a5e 100644
--- a/src/core/public/application/index.ts
+++ b/src/core/public/application/index.ts
@@ -22,6 +22,8 @@ export { Capabilities } from './capabilities';
export {
App,
AppBase,
+ AppMount,
+ AppMountDeprecated,
AppUnmount,
AppMountContext,
AppMountParameters,
diff --git a/src/core/public/application/integration_tests/router.test.tsx b/src/core/public/application/integration_tests/router.test.tsx
index 593858851d387..81aef5204c7e2 100644
--- a/src/core/public/application/integration_tests/router.test.tsx
+++ b/src/core/public/application/integration_tests/router.test.tsx
@@ -24,7 +24,7 @@ import { BehaviorSubject } from 'rxjs';
import { I18nProvider } from '@kbn/i18n/react';
-import { AppMounter, LegacyApp, AppMountParameters } from '../types';
+import { AppMount, LegacyApp, AppMountParameters } from '../types';
import { httpServiceMock } from '../../http/http_service.mock';
import { AppRouter, AppNotFound } from '../ui';
@@ -35,7 +35,7 @@ const createMountHandler = (htmlString: string) =>
});
describe('AppContainer', () => {
- let apps: Map, Parameters>>;
+ let apps: Map, Parameters>>;
let legacyApps: Map;
let history: History;
let router: ReactWrapper;
diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts
index a031ab6070413..72460b07900da 100644
--- a/src/core/public/application/types.ts
+++ b/src/core/public/application/types.ts
@@ -75,12 +75,14 @@ export interface AppBase {
*/
export interface App extends AppBase {
/**
- * A mount function called when the user navigates to this app's route.
- * @param context The mount context for this app.
- * @param targetDomElement An HTMLElement to mount the application onto.
- * @returns An unmounting function that will be called to unmount the application.
+ * A mount function called when the user navigates to this app's route. May have signature of {@link AppMount} or
+ * {@link AppMountDeprecated}.
+ *
+ * @remarks
+ * When function has two arguments, it will be called with a {@link AppMountContext | context} as the first argument.
+ * This behavior is **deprecated**, and consumers should instead use {@link CoreSetup.getStartServices}.
*/
- mount: (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise;
+ mount: AppMount | AppMountDeprecated;
/**
* Hide the UI chrome when the application is mounted. Defaults to `false`.
@@ -97,7 +99,39 @@ export interface LegacyApp extends AppBase {
}
/**
- * The context object received when applications are mounted to the DOM.
+ * A mount function called when the user navigates to this app's route.
+ *
+ * @param params {@link AppMountParameters}
+ * @returns An unmounting function that will be called to unmount the application. See {@link AppUnmount}.
+ *
+ * @public
+ */
+export type AppMount = (params: AppMountParameters) => AppUnmount | Promise;
+
+/**
+ * A mount function called when the user navigates to this app's route.
+ *
+ * @remarks
+ * When function has two arguments, it will be called with a {@link AppMountContext | context} as the first argument.
+ * This behavior is **deprecated**, and consumers should instead use {@link CoreSetup.getStartServices}.
+ *
+ * @param context The mount context for this app. Deprecated, use {@link CoreSetup.getStartServices}.
+ * @param params {@link AppMountParameters}
+ * @returns An unmounting function that will be called to unmount the application. See {@link AppUnmount}.
+ *
+ * @deprecated
+ * @public
+ */
+export type AppMountDeprecated = (
+ context: AppMountContext,
+ params: AppMountParameters
+) => AppUnmount | Promise;
+
+/**
+ * The context object received when applications are mounted to the DOM. Deprecated, use
+ * {@link CoreSetup.getStartServices}.
+ *
+ * @deprecated
* @public
*/
export interface AppMountContext {
@@ -192,9 +226,6 @@ export interface AppMountParameters {
*/
export type AppUnmount = () => void;
-/** @internal */
-export type AppMounter = (params: AppMountParameters) => Promise;
-
/** @public */
export interface ApplicationSetup {
/**
@@ -205,14 +236,15 @@ export interface ApplicationSetup {
/**
* Register a context provider for application mounting. Will only be available to applications that depend on the
- * plugin that registered this context.
+ * plugin that registered this context. Deprecated, use {@link CoreSetup.getStartServices}.
*
+ * @deprecated
* @param contextName - The key of {@link AppMountContext} this provider's return value should be attached to.
* @param provider - A {@link IContextProvider} function
*/
registerMountContext(
contextName: T,
- provider: IContextProvider
+ provider: IContextProvider
): void;
}
@@ -234,8 +266,9 @@ export interface InternalApplicationSetup {
/**
* Register a context provider for application mounting. Will only be available to applications that depend on the
- * plugin that registered this context.
+ * plugin that registered this context. Deprecated, use {@link CoreSetup.getStartServices}.
*
+ * @deprecated
* @param pluginOpaqueId - The opaque ID of the plugin that is registering the context.
* @param contextName - The key of {@link AppMountContext} this provider's return value should be attached to.
* @param provider - A {@link IContextProvider} function
@@ -243,7 +276,7 @@ export interface InternalApplicationSetup {
registerMountContext(
pluginOpaqueId: PluginOpaqueId,
contextName: T,
- provider: IContextProvider
+ provider: IContextProvider
): void;
}
@@ -272,15 +305,16 @@ export interface ApplicationStart {
/**
* Register a context provider for application mounting. Will only be available to applications that depend on the
- * plugin that registered this context.
+ * plugin that registered this context. Deprecated, use {@link CoreSetup.getStartServices}.
*
+ * @deprecated
* @param pluginOpaqueId - The opaque ID of the plugin that is registering the context.
* @param contextName - The key of {@link AppMountContext} this provider's return value should be attached to.
* @param provider - A {@link IContextProvider} function
*/
registerMountContext(
contextName: T,
- provider: IContextProvider
+ provider: IContextProvider
): void;
}
@@ -301,8 +335,9 @@ export interface InternalApplicationStart
/**
* Register a context provider for application mounting. Will only be available to applications that depend on the
- * plugin that registered this context.
+ * plugin that registered this context. Deprecated, use {@link CoreSetup.getStartServices}.
*
+ * @deprecated
* @param pluginOpaqueId - The opaque ID of the plugin that is registering the context.
* @param contextName - The key of {@link AppMountContext} this provider's return value should be attached to.
* @param provider - A {@link IContextProvider} function
@@ -310,7 +345,7 @@ export interface InternalApplicationStart
registerMountContext(
pluginOpaqueId: PluginOpaqueId,
contextName: T,
- provider: IContextProvider
+ provider: IContextProvider
): void;
// Internal APIs
diff --git a/src/core/public/application/ui/app_container.tsx b/src/core/public/application/ui/app_container.tsx
index 876cd3aa3a3d3..9c2bb30e79503 100644
--- a/src/core/public/application/ui/app_container.tsx
+++ b/src/core/public/application/ui/app_container.tsx
@@ -21,12 +21,12 @@ import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { Subject } from 'rxjs';
-import { LegacyApp, AppMounter, AppUnmount } from '../types';
+import { LegacyApp, AppMount, AppUnmount } from '../types';
import { HttpStart } from '../../http';
import { AppNotFound } from './app_not_found_screen';
interface Props extends RouteComponentProps<{ appId: string }> {
- apps: ReadonlyMap;
+ apps: ReadonlyMap;
legacyApps: ReadonlyMap;
basePath: HttpStart['basePath'];
currentAppId$: Subject;
diff --git a/src/core/public/application/ui/app_router.tsx b/src/core/public/application/ui/app_router.tsx
index b574bf16278e2..67701a33dabf4 100644
--- a/src/core/public/application/ui/app_router.tsx
+++ b/src/core/public/application/ui/app_router.tsx
@@ -22,12 +22,12 @@ import React from 'react';
import { Router, Route } from 'react-router-dom';
import { Subject } from 'rxjs';
-import { LegacyApp, AppMounter } from '../types';
+import { LegacyApp, AppMount } from '../types';
import { AppContainer } from './app_container';
import { HttpStart } from '../../http';
interface Props {
- apps: ReadonlyMap;
+ apps: ReadonlyMap;
legacyApps: ReadonlyMap;
basePath: HttpStart['basePath'];
currentAppId$: Subject;
diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts
index 4818484b00819..abc4c144356e8 100644
--- a/src/core/public/core_system.ts
+++ b/src/core/public/core_system.ts
@@ -64,7 +64,7 @@ export interface CoreContext {
}
/** @internal */
-export interface InternalCoreSetup extends Omit {
+export interface InternalCoreSetup extends Omit {
application: InternalApplicationSetup;
injectedMetadata: InjectedMetadataSetup;
}
@@ -253,11 +253,11 @@ export class CoreSystem {
docLinks,
http,
i18n,
+ injectedMetadata: pick(injectedMetadata, ['getInjectedVar']),
notifications,
overlays,
savedObjects,
uiSettings,
- injectedMetadata: pick(injectedMetadata, ['getInjectedVar']),
}));
const core: InternalCoreStart = {
diff --git a/src/core/public/index.ts b/src/core/public/index.ts
index 035cbcca86ac7..f53bf44bcdcfd 100644
--- a/src/core/public/index.ts
+++ b/src/core/public/index.ts
@@ -79,7 +79,17 @@ import {
export { CoreContext, CoreSystem } from './core_system';
export { RecursiveReadonly } from '../utils';
-export { App, AppBase, AppUnmount, AppMountContext, AppMountParameters } from './application';
+export {
+ ApplicationSetup,
+ ApplicationStart,
+ App,
+ AppBase,
+ AppMount,
+ AppMountDeprecated,
+ AppUnmount,
+ AppMountContext,
+ AppMountParameters,
+} from './application';
export {
SavedObjectsBatchResponse,
@@ -145,10 +155,13 @@ export { MountPoint, UnmountCallback } from './types';
* navigation in the generated docs until there's a fix for
* https://github.com/Microsoft/web-build-tools/issues/1237
*/
-export interface CoreSetup {
+export interface CoreSetup {
/** {@link ApplicationSetup} */
application: ApplicationSetup;
- /** {@link ContextSetup} */
+ /**
+ * {@link ContextSetup}
+ * @deprecated
+ */
context: ContextSetup;
/** {@link FatalErrorsSetup} */
fatalErrors: FatalErrorsSetup;
@@ -167,6 +180,13 @@ export interface CoreSetup {
injectedMetadata: {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
};
+
+ /**
+ * Allows plugins to get access to APIs available in start inside async
+ * handlers, such as {@link App.mount}. Promise will not resolve until Core
+ * and plugin dependencies have completed `start`.
+ */
+ getStartServices(): Promise<[CoreStart, TPluginsStart]>;
}
/**
@@ -218,7 +238,7 @@ export interface CoreStart {
* @public
* @deprecated
*/
-export interface LegacyCoreSetup extends CoreSetup {
+export interface LegacyCoreSetup extends CoreSetup {
/** @deprecated */
injectedMetadata: InjectedMetadataSetup;
}
@@ -239,8 +259,6 @@ export interface LegacyCoreStart extends CoreStart {
}
export {
- ApplicationSetup,
- ApplicationStart,
Capabilities,
ChromeBadge,
ChromeBrand,
diff --git a/src/core/public/legacy/legacy_service.test.ts b/src/core/public/legacy/legacy_service.test.ts
index 37e07af0a7da5..9dd24f9e4a7a3 100644
--- a/src/core/public/legacy/legacy_service.test.ts
+++ b/src/core/public/legacy/legacy_service.test.ts
@@ -169,6 +169,20 @@ describe('#start()', () => {
expect(mockUiNewPlatformStart).toHaveBeenCalledWith(expect.any(Object), {});
});
+ it('resolves getStartServices with core and plugin APIs', async () => {
+ const legacyPlatform = new LegacyPlatformService({
+ ...defaultParams,
+ });
+
+ legacyPlatform.setup(defaultSetupDeps);
+ legacyPlatform.start(defaultStartDeps);
+
+ const { getStartServices } = mockUiNewPlatformSetup.mock.calls[0][0];
+ const [coreStart, pluginsStart] = await getStartServices();
+ expect(coreStart).toEqual(expect.any(Object));
+ expect(pluginsStart).toBe(defaultStartDeps.plugins);
+ });
+
describe('useLegacyTestHarness = false', () => {
it('passes the targetDomElement to ui/chrome', () => {
const legacyPlatform = new LegacyPlatformService({
diff --git a/src/core/public/legacy/legacy_service.ts b/src/core/public/legacy/legacy_service.ts
index 22e315f9e1b03..a4fdd86de5311 100644
--- a/src/core/public/legacy/legacy_service.ts
+++ b/src/core/public/legacy/legacy_service.ts
@@ -18,6 +18,8 @@
*/
import angular from 'angular';
+import { first } from 'rxjs/operators';
+import { Subject } from 'rxjs';
import { InternalCoreSetup, InternalCoreStart } from '../core_system';
import { LegacyCoreSetup, LegacyCoreStart, MountPoint } from '../';
@@ -55,6 +57,8 @@ export class LegacyPlatformService {
public readonly legacyId = Symbol();
private bootstrapModule?: BootstrapModule;
private targetDomElement?: HTMLElement;
+ private readonly startDependencies$ = new Subject<[LegacyCoreStart, object]>();
+ private readonly startDependencies = this.startDependencies$.pipe(first()).toPromise();
constructor(private readonly params: LegacyPlatformParams) {}
@@ -75,6 +79,7 @@ export class LegacyPlatformService {
const legacyCore: LegacyCoreSetup = {
...core,
+ getStartServices: () => this.startDependencies,
application: {
register: notSupported(`core.application.register()`),
registerMountContext: notSupported(`core.application.registerMountContext()`),
@@ -120,6 +125,8 @@ export class LegacyPlatformService {
},
};
+ this.startDependencies$.next([legacyCore, plugins]);
+
// Inject parts of the new platform into parts of the legacy platform
// so that legacy APIs/modules can mimic their new platform counterparts
require('ui/new_platform').__start__(legacyCore, plugins);
diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts
index 644df259b8e24..43c8aa6f1d6b9 100644
--- a/src/core/public/mocks.ts
+++ b/src/core/public/mocks.ts
@@ -46,6 +46,9 @@ function createCoreSetupMock({ basePath = '' } = {}) {
application: applicationServiceMock.createSetupContract(),
context: contextServiceMock.createSetupContract(),
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
+ getStartServices: jest.fn, object]>, []>(() =>
+ Promise.resolve([createCoreStartMock({ basePath }), {}])
+ ),
http: httpServiceMock.createSetupContract({ basePath }),
notifications: notificationServiceMock.createSetupContract(),
uiSettings: uiSettingsServiceMock.createSetupContract(),
@@ -75,6 +78,7 @@ function createCoreStartMock({ basePath = '' } = {}) {
return mock;
}
+
function pluginInitializerContextMock() {
const mock: PluginInitializerContext = {
opaqueId: Symbol(),
diff --git a/src/core/public/plugins/plugin.test.ts b/src/core/public/plugins/plugin.test.ts
index 85de5c6620cc1..111ee93dd699b 100644
--- a/src/core/public/plugins/plugin.test.ts
+++ b/src/core/public/plugins/plugin.test.ts
@@ -106,6 +106,33 @@ describe('PluginWrapper', () => {
expect(mockPlugin.start).toHaveBeenCalledWith(context, deps);
});
+ test("`start` resolves `startDependencies` Promise after plugin's start", async () => {
+ expect.assertions(2);
+
+ let startDependenciesResolved = false;
+ mockPluginLoader.mockResolvedValueOnce(() => ({
+ setup: jest.fn(),
+ start: async () => {
+ // Add small delay to ensure startDependencies is not resolved until after the plugin instance's start resolves.
+ await new Promise(resolve => setTimeout(resolve, 10));
+ expect(startDependenciesResolved).toBe(false);
+ },
+ }));
+ await plugin.load(addBasePath);
+ await plugin.setup({} as any, {} as any);
+ const context = { any: 'thing' } as any;
+ const deps = { otherDep: 'value' };
+
+ // Add promise callback prior to calling `start` to ensure calls in `setup` will not resolve before `start` is
+ // called.
+ const startDependenciesCheck = plugin.startDependencies.then(res => {
+ startDependenciesResolved = true;
+ expect(res).toEqual([context, deps]);
+ });
+ await plugin.start(context, deps);
+ await startDependenciesCheck;
+ });
+
test('`stop` fails if plugin is not setup up', async () => {
expect(() => plugin.stop()).toThrowErrorMatchingInlineSnapshot(
`"Plugin \\"plugin-a\\" can't be stopped since it isn't set up."`
diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts
index 05268bbfcdd05..e880627e352c8 100644
--- a/src/core/public/plugins/plugin.ts
+++ b/src/core/public/plugins/plugin.ts
@@ -17,6 +17,8 @@
* under the License.
*/
+import { Subject } from 'rxjs';
+import { first } from 'rxjs/operators';
import { DiscoveredPlugin, PluginOpaqueId } from '../../server';
import { PluginInitializerContext } from './plugin_context';
import { loadPluginBundle } from './plugin_loader';
@@ -33,7 +35,7 @@ export interface Plugin<
TPluginsSetup extends object = object,
TPluginsStart extends object = object
> {
- setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
+ setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise;
stop?(): void;
}
@@ -70,6 +72,9 @@ export class PluginWrapper<
private initializer?: PluginInitializer;
private instance?: Plugin;
+ private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart]>();
+ public readonly startDependencies = this.startDependencies$.pipe(first()).toPromise();
+
constructor(
public readonly discoveredPlugin: DiscoveredPlugin,
public readonly opaqueId: PluginOpaqueId,
@@ -100,7 +105,7 @@ export class PluginWrapper<
* @param plugins The dictionary where the key is the dependency name and the value
* is the contract returned by the dependency's `setup` function.
*/
- public async setup(setupContext: CoreSetup, plugins: TPluginsSetup) {
+ public async setup(setupContext: CoreSetup, plugins: TPluginsSetup) {
this.instance = await this.createPluginInstance();
return await this.instance.setup(setupContext, plugins);
@@ -118,7 +123,11 @@ export class PluginWrapper<
throw new Error(`Plugin "${this.name}" can't be started since it isn't set up.`);
}
- return await this.instance.start(startContext, plugins);
+ const startContract = await this.instance.start(startContext, plugins);
+
+ this.startDependencies$.next([startContext, plugins]);
+
+ return startContract;
}
/**
diff --git a/src/core/public/plugins/plugin_context.ts b/src/core/public/plugins/plugin_context.ts
index f77ddd8f2f696..848f46605d4de 100644
--- a/src/core/public/plugins/plugin_context.ts
+++ b/src/core/public/plugins/plugin_context.ts
@@ -107,6 +107,7 @@ export function createPluginSetupContext<
injectedMetadata: {
getInjectedVar: deps.injectedMetadata.getInjectedVar,
},
+ getStartServices: () => plugin.startDependencies,
};
}
diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts
index 2983d7583cb49..281778f9420dd 100644
--- a/src/core/public/plugins/plugins_service.test.ts
+++ b/src/core/public/plugins/plugins_service.test.ts
@@ -98,6 +98,7 @@ describe('PluginsService', () => {
mockSetupContext = {
...mockSetupDeps,
application: expect.any(Object),
+ getStartServices: expect.any(Function),
};
mockStartDeps = {
application: applicationServiceMock.createInternalStartContract(),
diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md
index 157f0bab466b0..b745c23d52212 100644
--- a/src/core/public/public.api.md
+++ b/src/core/public/public.api.md
@@ -19,7 +19,7 @@ import { UserProvidedValues as UserProvidedValues_2 } from 'src/core/server/type
// @public
export interface App extends AppBase {
chromeless?: boolean;
- mount: (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise;
+ mount: AppMount | AppMountDeprecated;
}
// @public (undocumented)
@@ -37,7 +37,8 @@ export interface AppBase {
// @public (undocumented)
export interface ApplicationSetup {
register(app: App): void;
- registerMountContext(contextName: T, provider: IContextProvider): void;
+ // @deprecated
+ registerMountContext(contextName: T, provider: IContextProvider): void;
}
// @public (undocumented)
@@ -50,10 +51,14 @@ export interface ApplicationStart {
path?: string;
state?: any;
}): void;
- registerMountContext(contextName: T, provider: IContextProvider): void;
+ // @deprecated
+ registerMountContext(contextName: T, provider: IContextProvider): void;
}
// @public
+export type AppMount = (params: AppMountParameters) => AppUnmount | Promise;
+
+// @public @deprecated
export interface AppMountContext {
core: {
application: Pick;
@@ -71,6 +76,9 @@ export interface AppMountContext {
};
}
+// @public @deprecated
+export type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise;
+
// @public (undocumented)
export interface AppMountParameters {
appBasePath: string;
@@ -275,13 +283,14 @@ export interface CoreContext {
}
// @public
-export interface CoreSetup {
+export interface CoreSetup {
// (undocumented)
application: ApplicationSetup;
- // (undocumented)
+ // @deprecated (undocumented)
context: ContextSetup;
// (undocumented)
fatalErrors: FatalErrorsSetup;
+ getStartServices(): Promise<[CoreStart, TPluginsStart]>;
// (undocumented)
http: HttpSetup;
// @deprecated
@@ -653,7 +662,7 @@ export interface IUiSettingsClient {
}
// @public @deprecated
-export interface LegacyCoreSetup extends CoreSetup {
+export interface LegacyCoreSetup extends CoreSetup {
// Warning: (ae-forgotten-export) The symbol "InjectedMetadataSetup" needs to be exported by the entry point index.d.ts
//
// @deprecated (undocumented)
@@ -749,7 +758,7 @@ export interface PackageInfo {
// @public
export interface Plugin {
// (undocumented)
- setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
+ setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
// (undocumented)
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise;
// (undocumented)
diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
index e5bfd88ea7637..cd3e0d2fd9f89 100644
--- a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
+++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { App, AppUnmount } from 'kibana/public';
+import { App, AppUnmount, AppMountDeprecated } from 'kibana/public';
import { UIRoutes } from 'ui/routes';
import { ILocationService, IScope } from 'angular';
import { npStart } from 'ui/new_platform';
@@ -68,7 +68,10 @@ export class LocalApplicationService {
isUnmounted = true;
});
(async () => {
- unmountHandler = await app.mount({ core: npStart.core }, { element, appBasePath: '' });
+ const params = { element, appBasePath: '' };
+ unmountHandler = isAppMountDeprecated(app.mount)
+ ? await app.mount({ core: npStart.core }, params)
+ : await app.mount(params);
// immediately unmount app if scope got destroyed in the meantime
if (isUnmounted) {
unmountHandler();
@@ -90,3 +93,8 @@ export class LocalApplicationService {
}
export const localApplicationService = new LocalApplicationService();
+
+function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated {
+ // Mount functions with two arguments are assumed to expect deprecated `context` object.
+ return mount.length === 2;
+}
diff --git a/src/legacy/ui/public/new_platform/new_platform.test.ts b/src/legacy/ui/public/new_platform/new_platform.test.ts
index e5d5cd0a87776..cd1af311d4eff 100644
--- a/src/legacy/ui/public/new_platform/new_platform.test.ts
+++ b/src/legacy/ui/public/new_platform/new_platform.test.ts
@@ -58,6 +58,26 @@ describe('ui/new_platform', () => {
const scopeMock = { $on: jest.fn() };
const elementMock = [document.createElement('div')];
+ controller(scopeMock, elementMock);
+ expect(mountMock).toHaveBeenCalledWith({
+ element: elementMock[0],
+ appBasePath: '/test/base/path/app/test',
+ });
+ });
+
+ test('controller calls deprecated context app.mount when invoked', () => {
+ const unmountMock = jest.fn();
+ // Two arguments changes how this is called.
+ const mountMock = jest.fn((context, params) => unmountMock);
+ legacyAppRegister({
+ id: 'test',
+ title: 'Test',
+ mount: mountMock,
+ });
+ const controller = setRootControllerMock.mock.calls[0][1];
+ const scopeMock = { $on: jest.fn() };
+ const elementMock = [document.createElement('div')];
+
controller(scopeMock, elementMock);
expect(mountMock).toHaveBeenCalledWith(expect.any(Object), {
element: elementMock[0],
diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts
index c0b2d6d913257..d80d11e1b1bdd 100644
--- a/src/legacy/ui/public/new_platform/new_platform.ts
+++ b/src/legacy/ui/public/new_platform/new_platform.ts
@@ -20,7 +20,7 @@ import { IScope } from 'angular';
import { IUiActionsStart, IUiActionsSetup } from 'src/plugins/ui_actions/public';
import { IEmbeddableStart, IEmbeddableSetup } from 'src/plugins/embeddable/public';
-import { LegacyCoreSetup, LegacyCoreStart, App } from '../../../../core/public';
+import { LegacyCoreSetup, LegacyCoreStart, App, AppMountDeprecated } from '../../../../core/public';
import { Plugin as DataPlugin } from '../../../../plugins/data/public';
import { Plugin as ExpressionsPlugin } from '../../../../plugins/expressions/public';
import {
@@ -111,13 +111,18 @@ export const legacyAppRegister = (app: App) => {
// Root controller cannot return a Promise so use an internal async function and call it immediately
(async () => {
- const unmount = await app.mount(
- { core: npStart.core },
- { element, appBasePath: npSetup.core.http.basePath.prepend(`/app/${app.id}`) }
- );
+ const params = { element, appBasePath: npSetup.core.http.basePath.prepend(`/app/${app.id}`) };
+ const unmount = isAppMountDeprecated(app.mount)
+ ? await app.mount({ core: npStart.core }, params)
+ : await app.mount(params);
$scope.$on('$destroy', () => {
unmount();
});
})();
});
};
+
+function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated {
+ // Mount functions with two arguments are assumed to expect deprecated `context` object.
+ return mount.length === 2;
+}
diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx
index b3c6bb592f378..be142f2cc74e6 100644
--- a/src/plugins/dev_tools/public/application.tsx
+++ b/src/plugins/dev_tools/public/application.tsx
@@ -25,7 +25,7 @@ import * as React from 'react';
import ReactDOM from 'react-dom';
import { useEffect, useRef } from 'react';
-import { AppMountContext } from 'kibana/public';
+import { AppMountContext, AppMountDeprecated } from 'kibana/public';
import { DevTool } from './plugin';
interface DevToolsWrapperProps {
@@ -91,10 +91,10 @@ function DevToolsWrapper({
if (mountedTool.current) {
mountedTool.current.unmountHandler();
}
- const unmountHandler = await activeDevTool.mount(appMountContext, {
- element,
- appBasePath: '',
- });
+ const params = { element, appBasePath: '' };
+ const unmountHandler = isAppMountDeprecated(activeDevTool.mount)
+ ? await activeDevTool.mount(appMountContext, params)
+ : await activeDevTool.mount(params);
mountedTool.current = {
devTool: activeDevTool,
mountpoint: element,
@@ -182,3 +182,8 @@ export function renderApp(
return () => ReactDOM.unmountComponentAtNode(element);
}
+
+function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated {
+ // Mount functions with two arguments are assumed to expect deprecated `context` object.
+ return mount.length === 2;
+}
diff --git a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx
index 56cc1cb4ab425..5c8e1d03d5a4a 100644
--- a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx
+++ b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx
@@ -24,6 +24,7 @@ declare global {
interface Window {
corePluginB?: string;
hasAccessToInjectedMetadata?: boolean;
+ receivedStartServices?: boolean;
env?: PluginInitializerContext['env'];
}
}
@@ -40,6 +41,9 @@ export class CorePluginBPlugin
public setup(core: CoreSetup, deps: CorePluginBDeps) {
window.corePluginB = `Plugin A said: ${deps.core_plugin_a.getGreeting()}`;
window.hasAccessToInjectedMetadata = 'getInjectedVar' in core.injectedMetadata;
+ core.getStartServices().then(([coreStart, plugins]) => {
+ window.receivedStartServices = 'overlays' in coreStart;
+ });
core.application.register({
id: 'bar',
diff --git a/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts b/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts
index 6988ed82f34a7..51b5d2aaf3587 100644
--- a/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts
+++ b/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts
@@ -22,8 +22,8 @@ import { npSetup } from 'ui/new_platform';
npSetup.core.application.register({
id: 'core_legacy_compat',
title: 'Core Legacy Compat',
- async mount(...args) {
+ async mount(context, params) {
const { renderApp } = await import('./application');
- return renderApp(...args);
+ return renderApp(context, params);
},
});
diff --git a/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts b/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts
index a971921ad3ed8..ff53583546487 100644
--- a/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts
+++ b/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts
@@ -36,28 +36,41 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider
expect(corePluginB).to.equal(`Plugin A said: Hello from Plugin A!`);
});
});
+
describe('have injectedMetadata service provided', function describeIndexTests() {
before(async () => {
await PageObjects.common.navigateToApp('bar');
});
- it('should attach string to window.corePluginB', async () => {
+ it('should attach boolean to window.hasAccessToInjectedMetadata', async () => {
const hasAccessToInjectedMetadata = await browser.execute(
'return window.hasAccessToInjectedMetadata'
);
expect(hasAccessToInjectedMetadata).to.equal(true);
});
});
+
describe('have env data provided', function describeIndexTests() {
before(async () => {
await PageObjects.common.navigateToApp('bar');
});
- it('should attach pluginContext to window.corePluginB', async () => {
+ it('should attach pluginContext to window.env', async () => {
const envData: any = await browser.execute('return window.env');
expect(envData.mode.dev).to.be(true);
expect(envData.packageInfo.version).to.be.a('string');
});
});
+
+ describe('have access to start services via coreSetup.getStartServices', function describeIndexTests() {
+ before(async () => {
+ await PageObjects.common.navigateToApp('bar');
+ });
+
+ it('should attach boolean to window.receivedStartServices', async () => {
+ const receivedStartServices = await browser.execute('return window.receivedStartServices');
+ expect(receivedStartServices).to.equal(true);
+ });
+ });
});
}