Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ContextService #41251

Merged
merged 5 commits into from
Jul 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it a necessary declaration?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not. I thought it could be useful to help show that the contextName parameter in registerContext corresponds to keys on this object.

}

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