Skip to content

Commit

Permalink
[7.x] Add ContextService (#41251) (#42278)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshdover committed Jul 30, 2019
1 parent 9be59c0 commit 1898510
Show file tree
Hide file tree
Showing 35 changed files with 1,353 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-public](./kibana-plugin-public.md) &gt; [ContextSetup](./kibana-plugin-public.contextsetup.md) &gt; [createContextContainer](./kibana-plugin-public.contextsetup.createcontextcontainer.md)

## ContextSetup.createContextContainer() method

Creates a new [IContextContainer](./kibana-plugin-public.icontextcontainer.md) for a service owner.

<b>Signature:</b>

```typescript
createContextContainer<TContext extends {}, THandlerReturn, THandlerParmaters extends any[] = []>(): IContextContainer<TContext, THandlerReturn, THandlerParmaters>;
```
<b>Returns:</b>
`IContextContainer<TContext, THandlerReturn, THandlerParmaters>`
137 changes: 137 additions & 0 deletions docs/development/core/public/kibana-plugin-public.contextsetup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-public](./kibana-plugin-public.md) &gt; [ContextSetup](./kibana-plugin-public.contextsetup.md)

## ContextSetup interface

An object that handles registration of context providers and configuring handlers with context.

<b>Signature:</b>

```typescript
export interface ContextSetup
```

## Methods

| Method | Description |
| --- | --- |
| [createContextContainer()](./kibana-plugin-public.contextsetup.createcontextcontainer.md) | Creates a new [IContextContainer](./kibana-plugin-public.icontextcontainer.md) for a service owner. |

## Remarks

A [IContextContainer](./kibana-plugin-public.icontextcontainer.md) can be used by any Core service or plugin (known as the "service owner") which wishes to expose APIs in a handler function. The container object will manage registering context providers and configuring a handler with all of the contexts that should be exposed to the handler's plugin. This is dependent on the dependencies that the handler's plugin declares.

Contexts providers are executed in the order they were registered. Each provider gets access to context values provided by any plugins that it depends on.

In order to configure a handler with context, you must call the [IContextContainer.createHandler()](./kibana-plugin-public.icontextcontainer.createhandler.md) function and use the returned handler which will automatically build a context object when called.

When registering context or creating handlers, the \_calling plugin's opaque id\_ must be provided. This id is passed in via the plugin's initializer and can be accessed from the [PluginInitializerContext.opaqueId](./kibana-plugin-public.plugininitializercontext.opaqueid.md) Note this should NOT be the context service owner's id, but the plugin that is actually registering the context or handler.

```ts
// Correct
class MyPlugin {
private readonly handlers = new Map();

setup(core) {
this.contextContainer = core.context.createContextContainer();
return {
registerContext(pluginOpaqueId, contextName, provider) {
this.contextContainer.registerContext(pluginOpaqueId, contextName, provider);
},
registerRoute(pluginOpaqueId, path, handler) {
this.handlers.set(
path,
this.contextContainer.createHandler(pluginOpaqueId, handler)
);
}
}
}
}

// Incorrect
class MyPlugin {
private readonly handlers = new Map();

constructor(private readonly initContext: PluginInitializerContext) {}

setup(core) {
this.contextContainer = core.context.createContextContainer();
return {
registerContext(contextName, provider) {
// BUG!
// This would leak this context to all handlers rather that only plugins that depend on the calling plugin.
this.contextContainer.registerContext(this.initContext.opaqueId, contextName, provider);
},
registerRoute(path, handler) {
this.handlers.set(
path,
// BUG!
// This handler will not receive any contexts provided by other dependencies of the calling plugin.
this.contextContainer.createHandler(this.initContext.opaqueId, handler)
);
}
}
}
}

```

## Example

Say we're creating a plugin for rendering visualizations that allows new rendering methods to be registered. If we want to offer context to these rendering methods, we can leverage the ContextService to manage these contexts.

```ts
export interface VizRenderContext {
core: {
i18n: I18nStart;
uiSettings: UISettingsClientContract;
}
[contextName: string]: unknown;
}

export type VizRenderer = (context: VizRenderContext, domElement: HTMLElement) => () => void;

class VizRenderingPlugin {
private readonly vizRenderers = new Map<string, ((domElement: HTMLElement) => () => void)>();

setup(core) {
this.contextContainer = core.createContextContainer<
VizRenderContext,
ReturnType<VizRenderer>,
[HTMLElement]
>();

return {
registerContext: this.contextContainer.registerContext,
registerVizRenderer: (plugin: PluginOpaqueId, renderMethod: string, renderer: VizTypeRenderer) =>
this.vizRenderers.set(renderMethod, this.contextContainer.createHandler(plugin, renderer)),
};
}

start(core) {
// Register the core context available to all renderers. Use the VizRendererContext's pluginId as the first arg.
this.contextContainer.registerContext('viz_rendering', 'core', () => ({
i18n: core.i18n,
uiSettings: core.uiSettings
}));

return {
registerContext: this.contextContainer.registerContext,

renderVizualization: (renderMethod: string, domElement: HTMLElement) => {
if (!this.vizRenderer.has(renderMethod)) {
throw new Error(`Render method '${renderMethod}' has not been registered`);
}

// The handler can now be called directly with only an `HTMLElement` and will automatically
// have a new `context` object created and populated by the context container.
const handler = this.vizRenderers.get(renderMethod)
return handler(domElement);
}
};
}
}

```

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-public](./kibana-plugin-public.md) &gt; [CoreSetup](./kibana-plugin-public.coresetup.md) &gt; [context](./kibana-plugin-public.coresetup.context.md)

## CoreSetup.context property

[ContextSetup](./kibana-plugin-public.contextsetup.md)

<b>Signature:</b>

```typescript
context: ContextSetup;
```
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface CoreSetup

| Property | Type | Description |
| --- | --- | --- |
| [context](./kibana-plugin-public.coresetup.context.md) | <code>ContextSetup</code> | [ContextSetup](./kibana-plugin-public.contextsetup.md) |
| [fatalErrors](./kibana-plugin-public.coresetup.fatalerrors.md) | <code>FatalErrorsSetup</code> | [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) |
| [http](./kibana-plugin-public.coresetup.http.md) | <code>HttpSetup</code> | [HttpSetup](./kibana-plugin-public.httpsetup.md) |
| [notifications](./kibana-plugin-public.coresetup.notifications.md) | <code>NotificationsSetup</code> | [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-public](./kibana-plugin-public.md) &gt; [IContextContainer](./kibana-plugin-public.icontextcontainer.md) &gt; [createHandler](./kibana-plugin-public.icontextcontainer.createhandler.md)

## IContextContainer.createHandler() method

Create a new handler function pre-wired to context for the plugin.

<b>Signature:</b>

```typescript
createHandler(pluginOpaqueId: PluginOpaqueId, handler: IContextHandler<TContext, THandlerReturn, THandlerParameters>): (...rest: THandlerParameters) => Promisify<THandlerReturn>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| pluginOpaqueId | <code>PluginOpaqueId</code> | The plugin opaque ID for the plugin that registers this handler. |
| handler | <code>IContextHandler&lt;TContext, THandlerReturn, THandlerParameters&gt;</code> | Handler function to pass context object to. |

<b>Returns:</b>

`(...rest: THandlerParameters) => Promisify<THandlerReturn>`

A function that takes `THandlerParameters`<!-- -->, calls `handler` with a new context, and returns a Promise of the `handler` return value.

Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-public](./kibana-plugin-public.md) &gt; [IContextContainer](./kibana-plugin-public.icontextcontainer.md)

## IContextContainer interface

An object that handles registration of context providers and configuring handlers with context.

<b>Signature:</b>

```typescript
export interface IContextContainer<TContext extends {}, THandlerReturn, THandlerParameters extends any[] = []>
```

## Methods

| Method | Description |
| --- | --- |
| [createHandler(pluginOpaqueId, handler)](./kibana-plugin-public.icontextcontainer.createhandler.md) | Create a new handler function pre-wired to context for the plugin. |
| [registerContext(pluginOpaqueId, contextName, provider)](./kibana-plugin-public.icontextcontainer.registercontext.md) | Register a new context provider. |

## Remarks

A [IContextContainer](./kibana-plugin-public.icontextcontainer.md) can be used by any Core service or plugin (known as the "service owner") which wishes to expose APIs in a handler function. The container object will manage registering context providers and configuring a handler with all of the contexts that should be exposed to the handler's plugin. This is dependent on the dependencies that the handler's plugin declares.

Contexts providers are executed in the order they were registered. Each provider gets access to context values provided by any plugins that it depends on.

In order to configure a handler with context, you must call the [IContextContainer.createHandler()](./kibana-plugin-public.icontextcontainer.createhandler.md) function and use the returned handler which will automatically build a context object when called.

When registering context or creating handlers, the \_calling plugin's opaque id\_ must be provided. This id is passed in via the plugin's initializer and can be accessed from the [PluginInitializerContext.opaqueId](./kibana-plugin-public.plugininitializercontext.opaqueid.md) Note this should NOT be the context service owner's id, but the plugin that is actually registering the context or handler.

```ts
// Correct
class MyPlugin {
private readonly handlers = new Map();

setup(core) {
this.contextContainer = core.context.createContextContainer();
return {
registerContext(pluginOpaqueId, contextName, provider) {
this.contextContainer.registerContext(pluginOpaqueId, contextName, provider);
},
registerRoute(pluginOpaqueId, path, handler) {
this.handlers.set(
path,
this.contextContainer.createHandler(pluginOpaqueId, handler)
);
}
}
}
}

// Incorrect
class MyPlugin {
private readonly handlers = new Map();

constructor(private readonly initContext: PluginInitializerContext) {}

setup(core) {
this.contextContainer = core.context.createContextContainer();
return {
registerContext(contextName, provider) {
// BUG!
// This would leak this context to all handlers rather that only plugins that depend on the calling plugin.
this.contextContainer.registerContext(this.initContext.opaqueId, contextName, provider);
},
registerRoute(path, handler) {
this.handlers.set(
path,
// BUG!
// This handler will not receive any contexts provided by other dependencies of the calling plugin.
this.contextContainer.createHandler(this.initContext.opaqueId, handler)
);
}
}
}
}

```

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-public](./kibana-plugin-public.md) &gt; [IContextContainer](./kibana-plugin-public.icontextcontainer.md) &gt; [registerContext](./kibana-plugin-public.icontextcontainer.registercontext.md)

## IContextContainer.registerContext() method

Register a new context provider.

<b>Signature:</b>

```typescript
registerContext<TContextName extends keyof TContext>(pluginOpaqueId: PluginOpaqueId, contextName: TContextName, provider: IContextProvider<TContext, TContextName, THandlerParameters>): this;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| pluginOpaqueId | <code>PluginOpaqueId</code> | The plugin opaque ID for the plugin that registers this context. |
| contextName | <code>TContextName</code> | The key of the <code>TContext</code> object this provider supplies the value for. |
| provider | <code>IContextProvider&lt;TContext, TContextName, THandlerParameters&gt;</code> | A [IContextProvider](./kibana-plugin-public.icontextprovider.md) to be called each time a new context is created. |
<b>Returns:</b>
`this`
The [IContextContainer](./kibana-plugin-public.icontextcontainer.md) for method chaining.
## Remarks
The value (or resolved Promise value) returned by the `provider` function will be attached to the context object on the key specified by `contextName`<!-- -->.
Throws an exception if more than one provider is registered for the same `contextName`<!-- -->.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-public](./kibana-plugin-public.md) &gt; [IContextHandler](./kibana-plugin-public.icontexthandler.md)

## IContextHandler type

A function registered by a plugin to perform some action.

<b>Signature:</b>

```typescript
export declare type IContextHandler<TContext extends {}, TReturn, THandlerParameters extends any[] = []> = (context: TContext, ...rest: THandlerParameters) => TReturn;
```

## Remarks

A new `TContext` will be built for each handler before invoking.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-public](./kibana-plugin-public.md) &gt; [IContextProvider](./kibana-plugin-public.icontextprovider.md)

## IContextProvider type

A function that returns a context value for a specific key of given context type.

<b>Signature:</b>

```typescript
export declare type IContextProvider<TContext extends Record<string, any>, TContextName extends keyof TContext, TProviderParameters extends any[] = []> = (context: Partial<TContext>, ...rest: TProviderParameters) => Promise<TContext[TContextName]> | TContext[TContextName];
```

## Remarks

This function will be called each time a new context is built for a handler invocation.

4 changes: 4 additions & 0 deletions docs/development/core/public/kibana-plugin-public.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [ChromeRecentlyAccessed](./kibana-plugin-public.chromerecentlyaccessed.md) | [APIs](./kibana-plugin-public.chromerecentlyaccessed.md) for recently accessed history. |
| [ChromeRecentlyAccessedHistoryItem](./kibana-plugin-public.chromerecentlyaccessedhistoryitem.md) | |
| [ChromeStart](./kibana-plugin-public.chromestart.md) | ChromeStart allows plugins to customize the global chrome header UI and enrich the UX with additional information about the current location of the browser. |
| [ContextSetup](./kibana-plugin-public.contextsetup.md) | An object that handles registration of context providers and configuring handlers with context. |
| [CoreSetup](./kibana-plugin-public.coresetup.md) | Core services exposed to the <code>Plugin</code> setup lifecycle |
| [CoreStart](./kibana-plugin-public.corestart.md) | Core services exposed to the <code>Plugin</code> start lifecycle |
| [DocLinksStart](./kibana-plugin-public.doclinksstart.md) | |
Expand All @@ -50,6 +51,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [HttpResponse](./kibana-plugin-public.httpresponse.md) | |
| [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | |
| [I18nStart](./kibana-plugin-public.i18nstart.md) | I18nStart.Context is required by any localizable React component from @<!-- -->kbn/i18n and @<!-- -->elastic/eui packages and is supposed to be used as the topmost component for any i18n-compatible React tree. |
| [IContextContainer](./kibana-plugin-public.icontextcontainer.md) | An object that handles registration of context providers and configuring handlers with context. |
| [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) | |
| [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) | |
| [NotificationsStart](./kibana-plugin-public.notificationsstart.md) | |
Expand All @@ -69,6 +71,8 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [HttpHandler](./kibana-plugin-public.httphandler.md) | |
| [HttpSetup](./kibana-plugin-public.httpsetup.md) | |
| [HttpStart](./kibana-plugin-public.httpstart.md) | |
| [IContextHandler](./kibana-plugin-public.icontexthandler.md) | A function registered by a plugin to perform some action. |
| [IContextProvider](./kibana-plugin-public.icontextprovider.md) | A function that returns a context value for a specific key of given context type. |
| [PluginInitializer](./kibana-plugin-public.plugininitializer.md) | The <code>plugin</code> export at the root of a plugin's <code>public</code> directory should conform to this interface. |
| [RecursiveReadonly](./kibana-plugin-public.recursivereadonly.md) | |
| [ToastInput](./kibana-plugin-public.toastinput.md) | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ The available core services passed to a `PluginInitializer`
```typescript
export interface PluginInitializerContext
```

## Properties

| Property | Type | Description |
| --- | --- | --- |
| [opaqueId](./kibana-plugin-public.plugininitializercontext.opaqueid.md) | <code>PluginOpaqueId</code> | A symbol used to identify this plugin in the system. Needed when registering handlers or context providers. |

Loading

0 comments on commit 1898510

Please sign in to comment.