mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Add plugin start contract to getStartServices return value (#61216)
* add plugin own contract as third element of getStartServices result * adapt plugins code * update tests * revert unknown to use void again * update generated doc * fix UT * update mock to allow non-object `pluginStartContract` * add @typeParam documentation
This commit is contained in:
parent
9d0d3f7a53
commit
468de51153
47 changed files with 178 additions and 93 deletions
|
@ -9,5 +9,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getStartServices: StartServicesAccessor<TPluginsStart>;
|
||||
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@ Core services exposed to the `Plugin` setup lifecycle
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface CoreSetup<TPluginsStart extends object = object>
|
||||
export interface CoreSetup<TPluginsStart extends object = object, TStart = unknown>
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
@ -19,7 +19,7 @@ export interface CoreSetup<TPluginsStart extends object = object>
|
|||
| [application](./kibana-plugin-core-public.coresetup.application.md) | <code>ApplicationSetup</code> | [ApplicationSetup](./kibana-plugin-core-public.applicationsetup.md) |
|
||||
| [context](./kibana-plugin-core-public.coresetup.context.md) | <code>ContextSetup</code> | [ContextSetup](./kibana-plugin-core-public.contextsetup.md) |
|
||||
| [fatalErrors](./kibana-plugin-core-public.coresetup.fatalerrors.md) | <code>FatalErrorsSetup</code> | [FatalErrorsSetup](./kibana-plugin-core-public.fatalerrorssetup.md) |
|
||||
| [getStartServices](./kibana-plugin-core-public.coresetup.getstartservices.md) | <code>StartServicesAccessor<TPluginsStart></code> | [StartServicesAccessor](./kibana-plugin-core-public.startservicesaccessor.md) |
|
||||
| [getStartServices](./kibana-plugin-core-public.coresetup.getstartservices.md) | <code>StartServicesAccessor<TPluginsStart, TStart></code> | [StartServicesAccessor](./kibana-plugin-core-public.startservicesaccessor.md) |
|
||||
| [http](./kibana-plugin-core-public.coresetup.http.md) | <code>HttpSetup</code> | [HttpSetup](./kibana-plugin-core-public.httpsetup.md) |
|
||||
| [injectedMetadata](./kibana-plugin-core-public.coresetup.injectedmetadata.md) | <code>{</code><br/><code> getInjectedVar: (name: string, defaultValue?: any) => unknown;</code><br/><code> }</code> | exposed temporarily until https://github.com/elastic/kibana/issues/41990 done use \*only\* to retrieve config values. There is no way to set injected values in the new platform. Use the legacy platform API instead. |
|
||||
| [notifications](./kibana-plugin-core-public.coresetup.notifications.md) | <code>NotificationsSetup</code> | [NotificationsSetup](./kibana-plugin-core-public.notificationssetup.md) |
|
||||
|
|
|
@ -13,7 +13,7 @@ Setup interface exposed to the legacy platform via the `ui/new_platform` module.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface LegacyCoreSetup extends CoreSetup<any>
|
||||
export interface LegacyCoreSetup extends CoreSetup<any, any>
|
||||
```
|
||||
|
||||
## Remarks
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
setup(core: CoreSetup<TPluginsStart>, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
setup(core: CoreSetup<TPluginsStart, TStart>, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| core | <code>CoreSetup<TPluginsStart></code> | |
|
||||
| core | <code>CoreSetup<TPluginsStart, TStart></code> | |
|
||||
| plugins | <code>TPluginsSetup</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
|
|
@ -9,5 +9,5 @@ Allows plugins to get access to APIs available in start inside async handlers, s
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type StartServicesAccessor<TPluginsStart extends object = object> = () => Promise<[CoreStart, TPluginsStart]>;
|
||||
export declare type StartServicesAccessor<TPluginsStart extends object = object, TStart = unknown> = () => Promise<[CoreStart, TPluginsStart, TStart]>;
|
||||
```
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getStartServices: StartServicesAccessor<TPluginsStart>;
|
||||
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@ Context passed to the plugins `setup` method.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface CoreSetup<TPluginsStart extends object = object>
|
||||
export interface CoreSetup<TPluginsStart extends object = object, TStart = unknown>
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
@ -19,7 +19,7 @@ export interface CoreSetup<TPluginsStart extends object = object>
|
|||
| [capabilities](./kibana-plugin-core-server.coresetup.capabilities.md) | <code>CapabilitiesSetup</code> | [CapabilitiesSetup](./kibana-plugin-core-server.capabilitiessetup.md) |
|
||||
| [context](./kibana-plugin-core-server.coresetup.context.md) | <code>ContextSetup</code> | [ContextSetup](./kibana-plugin-core-server.contextsetup.md) |
|
||||
| [elasticsearch](./kibana-plugin-core-server.coresetup.elasticsearch.md) | <code>ElasticsearchServiceSetup</code> | [ElasticsearchServiceSetup](./kibana-plugin-core-server.elasticsearchservicesetup.md) |
|
||||
| [getStartServices](./kibana-plugin-core-server.coresetup.getstartservices.md) | <code>StartServicesAccessor<TPluginsStart></code> | [StartServicesAccessor](./kibana-plugin-core-server.startservicesaccessor.md) |
|
||||
| [getStartServices](./kibana-plugin-core-server.coresetup.getstartservices.md) | <code>StartServicesAccessor<TPluginsStart, TStart></code> | [StartServicesAccessor](./kibana-plugin-core-server.startservicesaccessor.md) |
|
||||
| [http](./kibana-plugin-core-server.coresetup.http.md) | <code>HttpServiceSetup</code> | [HttpServiceSetup](./kibana-plugin-core-server.httpservicesetup.md) |
|
||||
| [metrics](./kibana-plugin-core-server.coresetup.metrics.md) | <code>MetricsServiceSetup</code> | [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) |
|
||||
| [savedObjects](./kibana-plugin-core-server.coresetup.savedobjects.md) | <code>SavedObjectsServiceSetup</code> | [SavedObjectsServiceSetup](./kibana-plugin-core-server.savedobjectsservicesetup.md) |
|
||||
|
|
|
@ -9,5 +9,5 @@ Allows plugins to get access to APIs available in start inside async handlers. P
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type StartServicesAccessor<TPluginsStart extends object = object> = () => Promise<[CoreStart, TPluginsStart]>;
|
||||
export declare type StartServicesAccessor<TPluginsStart extends object = object, TStart = unknown> = () => Promise<[CoreStart, TPluginsStart, TStart]>;
|
||||
```
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup, AppMountParameters, CoreStart } from 'kibana/public';
|
||||
import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public';
|
||||
import { PluginSetupContract as AlertingSetup } from '../../../x-pack/plugins/alerting/public';
|
||||
import { ChartsPluginStart } from '../../../src/plugins/charts/public';
|
||||
import { TriggersAndActionsUIPublicPluginSetup } from '../../../x-pack/plugins/triggers_actions_ui/public';
|
||||
|
@ -43,17 +43,14 @@ export interface AlertingExamplePublicStartDeps {
|
|||
|
||||
export class AlertingExamplePlugin implements Plugin<Setup, Start, AlertingExamplePublicSetupDeps> {
|
||||
public setup(
|
||||
core: CoreSetup<AlertingExamplePublicStartDeps>,
|
||||
core: CoreSetup<AlertingExamplePublicStartDeps, Start>,
|
||||
{ alerting, triggers_actions_ui }: AlertingExamplePublicSetupDeps
|
||||
) {
|
||||
core.application.register({
|
||||
id: 'AlertingExample',
|
||||
title: 'Alerting Example',
|
||||
async mount(params: AppMountParameters) {
|
||||
const [coreStart, depsStart]: [
|
||||
CoreStart,
|
||||
AlertingExamplePublicStartDeps
|
||||
] = await core.getStartServices();
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
const { renderApp } = await import('./application');
|
||||
return renderApp(coreStart, depsStart, params);
|
||||
},
|
||||
|
|
|
@ -34,7 +34,10 @@ export interface BfetchExplorerStartPlugins {
|
|||
}
|
||||
|
||||
export class BfetchExplorerPlugin implements Plugin {
|
||||
public setup(core: CoreSetup<BfetchExplorerStartPlugins>, plugins: BfetchExplorerSetupPlugins) {
|
||||
public setup(
|
||||
core: CoreSetup<BfetchExplorerStartPlugins, void>,
|
||||
plugins: BfetchExplorerSetupPlugins
|
||||
) {
|
||||
const double = plugins.bfetch.batchedFunction<{ num: number }, { num: number }>({
|
||||
url: '/bfetch_explorer/double',
|
||||
});
|
||||
|
|
|
@ -26,9 +26,18 @@ export {
|
|||
export { ListContainer, LIST_CONTAINER } from './list_container';
|
||||
export { TODO_EMBEDDABLE } from './todo';
|
||||
|
||||
import { EmbeddableExamplesPlugin } from './plugin';
|
||||
import {
|
||||
EmbeddableExamplesPlugin,
|
||||
EmbeddableExamplesSetupDependencies,
|
||||
EmbeddableExamplesStartDependencies,
|
||||
} from './plugin';
|
||||
|
||||
export { SearchableListContainer, SEARCHABLE_LIST_CONTAINER } from './searchable_list_container';
|
||||
export { MULTI_TASK_TODO_EMBEDDABLE } from './multi_task_todo';
|
||||
|
||||
export const plugin: PluginInitializer<void, void> = () => new EmbeddableExamplesPlugin();
|
||||
export const plugin: PluginInitializer<
|
||||
void,
|
||||
void,
|
||||
EmbeddableExamplesSetupDependencies,
|
||||
EmbeddableExamplesStartDependencies
|
||||
> = () => new EmbeddableExamplesPlugin();
|
||||
|
|
|
@ -28,11 +28,11 @@ import {
|
|||
} from './searchable_list_container';
|
||||
import { LIST_CONTAINER, ListContainerFactory } from './list_container';
|
||||
|
||||
interface EmbeddableExamplesSetupDependencies {
|
||||
export interface EmbeddableExamplesSetupDependencies {
|
||||
embeddable: EmbeddableSetup;
|
||||
}
|
||||
|
||||
interface EmbeddableExamplesStartDependencies {
|
||||
export interface EmbeddableExamplesStartDependencies {
|
||||
embeddable: EmbeddableStart;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public';
|
|||
import { AppPluginStartDependencies } from './types';
|
||||
|
||||
export class SearchExplorerPlugin implements Plugin {
|
||||
public setup(core: CoreSetup<AppPluginStartDependencies>) {
|
||||
public setup(core: CoreSetup<AppPluginStartDependencies, void>) {
|
||||
core.application.register({
|
||||
id: 'searchExplorer',
|
||||
title: 'Search Explorer',
|
||||
|
|
|
@ -177,13 +177,18 @@ export { MountPoint, UnmountCallback, PublicUiSettingsParams } from './types';
|
|||
/**
|
||||
* Core services exposed to the `Plugin` setup lifecycle
|
||||
*
|
||||
* @typeParam TPluginsStart - the type of the consuming plugin's start dependencies. Should be the same
|
||||
* as the consuming {@link Plugin}'s `TPluginsStart` type. Used by `getStartServices`.
|
||||
* @typeParam TStart - the type of the consuming plugin's start contract. Should be the same as the
|
||||
* consuming {@link Plugin}'s `TStart` type. Used by `getStartServices`.
|
||||
*
|
||||
* @public
|
||||
*
|
||||
* @internalRemarks We document the properties with \@link tags to improve
|
||||
* navigation in the generated docs until there's a fix for
|
||||
* https://github.com/Microsoft/web-build-tools/issues/1237
|
||||
*/
|
||||
export interface CoreSetup<TPluginsStart extends object = object> {
|
||||
export interface CoreSetup<TPluginsStart extends object = object, TStart = unknown> {
|
||||
/** {@link ApplicationSetup} */
|
||||
application: ApplicationSetup;
|
||||
/**
|
||||
|
@ -209,7 +214,7 @@ export interface CoreSetup<TPluginsStart extends object = object> {
|
|||
getInjectedVar: (name: string, defaultValue?: any) => unknown;
|
||||
};
|
||||
/** {@link StartServicesAccessor} */
|
||||
getStartServices: StartServicesAccessor<TPluginsStart>;
|
||||
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,9 +224,10 @@ export interface CoreSetup<TPluginsStart extends object = object> {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
export type StartServicesAccessor<TPluginsStart extends object = object> = () => Promise<
|
||||
[CoreStart, TPluginsStart]
|
||||
>;
|
||||
export type StartServicesAccessor<
|
||||
TPluginsStart extends object = object,
|
||||
TStart = unknown
|
||||
> = () => Promise<[CoreStart, TPluginsStart, TStart]>;
|
||||
|
||||
/**
|
||||
* Core services exposed to the `Plugin` start lifecycle
|
||||
|
@ -274,7 +280,7 @@ export interface CoreStart {
|
|||
* @public
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyCoreSetup extends CoreSetup<any> {
|
||||
export interface LegacyCoreSetup extends CoreSetup<any, any> {
|
||||
/** @deprecated */
|
||||
injectedMetadata: InjectedMetadataSetup;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ export class LegacyPlatformService {
|
|||
public readonly legacyId = Symbol();
|
||||
private bootstrapModule?: BootstrapModule;
|
||||
private targetDomElement?: HTMLElement;
|
||||
private readonly startDependencies$ = new Subject<[LegacyCoreStart, object]>();
|
||||
private readonly startDependencies$ = new Subject<[LegacyCoreStart, object, {}]>();
|
||||
private readonly startDependencies = this.startDependencies$.pipe(first()).toPromise();
|
||||
|
||||
constructor(private readonly params: LegacyPlatformParams) {}
|
||||
|
@ -129,7 +129,7 @@ export class LegacyPlatformService {
|
|||
},
|
||||
};
|
||||
|
||||
this.startDependencies$.next([legacyCore, plugins]);
|
||||
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
|
||||
|
|
|
@ -49,13 +49,22 @@ export { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock';
|
|||
export { savedObjectsServiceMock } from './saved_objects/saved_objects_service.mock';
|
||||
export { scopedHistoryMock } from './application/scoped_history.mock';
|
||||
|
||||
function createCoreSetupMock({ basePath = '' } = {}) {
|
||||
function createCoreSetupMock({
|
||||
basePath = '',
|
||||
pluginStartDeps = {},
|
||||
pluginStartContract,
|
||||
}: {
|
||||
basePath?: string;
|
||||
pluginStartDeps?: object;
|
||||
pluginStartContract?: any;
|
||||
} = {}) {
|
||||
const mock = {
|
||||
application: applicationServiceMock.createSetupContract(),
|
||||
context: contextServiceMock.createSetupContract(),
|
||||
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
|
||||
getStartServices: jest.fn<Promise<[ReturnType<typeof createCoreStartMock>, object]>, []>(() =>
|
||||
Promise.resolve([createCoreStartMock({ basePath }), {}])
|
||||
getStartServices: jest.fn<Promise<[ReturnType<typeof createCoreStartMock>, object, any]>, []>(
|
||||
() =>
|
||||
Promise.resolve([createCoreStartMock({ basePath }), pluginStartDeps, pluginStartContract])
|
||||
),
|
||||
http: httpServiceMock.createSetupContract({ basePath }),
|
||||
notifications: notificationServiceMock.createSetupContract(),
|
||||
|
|
|
@ -109,6 +109,10 @@ describe('PluginWrapper', () => {
|
|||
test("`start` resolves `startDependencies` Promise after plugin's start", async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const pluginStartContract = {
|
||||
someApi: () => 'foo',
|
||||
};
|
||||
|
||||
let startDependenciesResolved = false;
|
||||
mockPluginLoader.mockResolvedValueOnce(() => ({
|
||||
setup: jest.fn(),
|
||||
|
@ -116,6 +120,7 @@ describe('PluginWrapper', () => {
|
|||
// 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);
|
||||
return pluginStartContract;
|
||||
},
|
||||
}));
|
||||
await plugin.load(addBasePath);
|
||||
|
@ -127,7 +132,7 @@ describe('PluginWrapper', () => {
|
|||
// called.
|
||||
const startDependenciesCheck = plugin.startDependencies.then(res => {
|
||||
startDependenciesResolved = true;
|
||||
expect(res).toEqual([context, deps]);
|
||||
expect(res).toEqual([context, deps, pluginStartContract]);
|
||||
});
|
||||
await plugin.start(context, deps);
|
||||
await startDependenciesCheck;
|
||||
|
|
|
@ -35,7 +35,7 @@ export interface Plugin<
|
|||
TPluginsSetup extends object = object,
|
||||
TPluginsStart extends object = object
|
||||
> {
|
||||
setup(core: CoreSetup<TPluginsStart>, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
setup(core: CoreSetup<TPluginsStart, TStart>, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise<TStart>;
|
||||
stop?(): void;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ export class PluginWrapper<
|
|||
private initializer?: PluginInitializer<TSetup, TStart, TPluginsSetup, TPluginsStart>;
|
||||
private instance?: Plugin<TSetup, TStart, TPluginsSetup, TPluginsStart>;
|
||||
|
||||
private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart]>();
|
||||
private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart, TStart]>();
|
||||
public readonly startDependencies = this.startDependencies$.pipe(first()).toPromise();
|
||||
|
||||
constructor(
|
||||
|
@ -105,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<TPluginsStart>, plugins: TPluginsSetup) {
|
||||
public async setup(setupContext: CoreSetup<TPluginsStart, TStart>, plugins: TPluginsSetup) {
|
||||
this.instance = await this.createPluginInstance();
|
||||
|
||||
return await this.instance.setup(setupContext, plugins);
|
||||
|
@ -125,7 +125,7 @@ export class PluginWrapper<
|
|||
|
||||
const startContract = await this.instance.start(startContext, plugins);
|
||||
|
||||
this.startDependencies$.next([startContext, plugins]);
|
||||
this.startDependencies$.next([startContext, plugins, startContract]);
|
||||
|
||||
return startContract;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ export interface PluginsServiceStart {
|
|||
*/
|
||||
export class PluginsService implements CoreService<PluginsServiceSetup, PluginsServiceStart> {
|
||||
/** Plugin wrappers in topological order. */
|
||||
private readonly plugins = new Map<PluginName, PluginWrapper<unknown, Record<string, unknown>>>();
|
||||
private readonly plugins = new Map<PluginName, PluginWrapper<unknown, unknown>>();
|
||||
private readonly pluginDependencies = new Map<PluginName, PluginName[]>();
|
||||
|
||||
private readonly satupPlugins: PluginName[] = [];
|
||||
|
|
|
@ -371,7 +371,7 @@ export interface CoreContext {
|
|||
}
|
||||
|
||||
// @public
|
||||
export interface CoreSetup<TPluginsStart extends object = object> {
|
||||
export interface CoreSetup<TPluginsStart extends object = object, TStart = unknown> {
|
||||
// (undocumented)
|
||||
application: ApplicationSetup;
|
||||
// @deprecated (undocumented)
|
||||
|
@ -379,7 +379,7 @@ export interface CoreSetup<TPluginsStart extends object = object> {
|
|||
// (undocumented)
|
||||
fatalErrors: FatalErrorsSetup;
|
||||
// (undocumented)
|
||||
getStartServices: StartServicesAccessor<TPluginsStart>;
|
||||
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
|
||||
// (undocumented)
|
||||
http: HttpSetup;
|
||||
// @deprecated
|
||||
|
@ -807,7 +807,7 @@ export interface IUiSettingsClient {
|
|||
}
|
||||
|
||||
// @public @deprecated
|
||||
export interface LegacyCoreSetup extends CoreSetup<any> {
|
||||
export interface LegacyCoreSetup extends CoreSetup<any, any> {
|
||||
// Warning: (ae-forgotten-export) The symbol "InjectedMetadataSetup" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @deprecated (undocumented)
|
||||
|
@ -907,7 +907,7 @@ export interface PackageInfo {
|
|||
// @public
|
||||
export interface Plugin<TSetup = void, TStart = void, TPluginsSetup extends object = object, TPluginsStart extends object = object> {
|
||||
// (undocumented)
|
||||
setup(core: CoreSetup<TPluginsStart>, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
setup(core: CoreSetup<TPluginsStart, TStart>, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
// (undocumented)
|
||||
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise<TStart>;
|
||||
// (undocumented)
|
||||
|
@ -1237,7 +1237,7 @@ export class SimpleSavedObject<T = unknown> {
|
|||
}
|
||||
|
||||
// @public
|
||||
export type StartServicesAccessor<TPluginsStart extends object = object> = () => Promise<[CoreStart, TPluginsStart]>;
|
||||
export type StartServicesAccessor<TPluginsStart extends object = object, TStart = unknown> = () => Promise<[CoreStart, TPluginsStart, TStart]>;
|
||||
|
||||
// @public
|
||||
export type StringValidation = StringValidationRegex | StringValidationRegexString;
|
||||
|
|
|
@ -333,9 +333,13 @@ export interface RequestHandlerContext {
|
|||
/**
|
||||
* Context passed to the plugins `setup` method.
|
||||
*
|
||||
* @typeParam TPluginsStart - the type of the consuming plugin's start dependencies. Should be the same
|
||||
* as the consuming {@link Plugin}'s `TPluginsStart` type. Used by `getStartServices`.
|
||||
* @typeParam TStart - the type of the consuming plugin's start contract. Should be the same as the
|
||||
* consuming {@link Plugin}'s `TStart` type. Used by `getStartServices`.
|
||||
* @public
|
||||
*/
|
||||
export interface CoreSetup<TPluginsStart extends object = object> {
|
||||
export interface CoreSetup<TPluginsStart extends object = object, TStart = unknown> {
|
||||
/** {@link CapabilitiesSetup} */
|
||||
capabilities: CapabilitiesSetup;
|
||||
/** {@link ContextSetup} */
|
||||
|
@ -353,7 +357,7 @@ export interface CoreSetup<TPluginsStart extends object = object> {
|
|||
/** {@link MetricsServiceSetup} */
|
||||
metrics: MetricsServiceSetup;
|
||||
/** {@link StartServicesAccessor} */
|
||||
getStartServices: StartServicesAccessor<TPluginsStart>;
|
||||
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -364,9 +368,10 @@ export interface CoreSetup<TPluginsStart extends object = object> {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
export type StartServicesAccessor<TPluginsStart extends object = object> = () => Promise<
|
||||
[CoreStart, TPluginsStart]
|
||||
>;
|
||||
export type StartServicesAccessor<
|
||||
TPluginsStart extends object = object,
|
||||
TStart = unknown
|
||||
> = () => Promise<[CoreStart, TPluginsStart, TStart]>;
|
||||
|
||||
/**
|
||||
* Context passed to the plugins `start` method.
|
||||
|
|
|
@ -312,7 +312,7 @@ export class LegacyService implements CoreService {
|
|||
uuid: {
|
||||
getInstanceUuid: setupDeps.core.uuid.getInstanceUuid,
|
||||
},
|
||||
getStartServices: () => Promise.resolve([coreStart, startDeps.plugins]),
|
||||
getStartServices: () => Promise.resolve([coreStart, startDeps.plugins, {}]),
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
|
|
|
@ -96,7 +96,13 @@ function pluginInitializerContextMock<T>(config: T = {} as T) {
|
|||
|
||||
type CoreSetupMockType = MockedKeys<CoreSetup> & jest.Mocked<Pick<CoreSetup, 'getStartServices'>>;
|
||||
|
||||
function createCoreSetupMock() {
|
||||
function createCoreSetupMock({
|
||||
pluginStartDeps = {},
|
||||
pluginStartContract,
|
||||
}: {
|
||||
pluginStartDeps?: object;
|
||||
pluginStartContract?: any;
|
||||
} = {}) {
|
||||
const httpService = httpServiceMock.createSetupContract();
|
||||
const httpMock: jest.Mocked<CoreSetup['http']> = {
|
||||
createCookieSessionStorageFactory: httpService.createCookieSessionStorageFactory,
|
||||
|
@ -131,8 +137,8 @@ function createCoreSetupMock() {
|
|||
uuid: uuidServiceMock.createSetupContract(),
|
||||
metrics: metricsServiceMock.createSetupContract(),
|
||||
getStartServices: jest
|
||||
.fn<Promise<[ReturnType<typeof createCoreStartMock>, object]>, []>()
|
||||
.mockResolvedValue([createCoreStartMock(), {}]),
|
||||
.fn<Promise<[ReturnType<typeof createCoreStartMock>, object, any]>, []>()
|
||||
.mockResolvedValue([createCoreStartMock(), pluginStartDeps, pluginStartContract]),
|
||||
};
|
||||
|
||||
return mock;
|
||||
|
|
|
@ -107,7 +107,7 @@ describe('PluginsService', () => {
|
|||
});
|
||||
|
||||
it("properly resolves `getStartServices` in plugin's lifecycle", async () => {
|
||||
expect.assertions(5);
|
||||
expect.assertions(6);
|
||||
|
||||
const pluginPath = 'plugin-path';
|
||||
|
||||
|
@ -125,20 +125,25 @@ describe('PluginsService', () => {
|
|||
let contextFromStart: any = null;
|
||||
let contextFromStartService: any = null;
|
||||
|
||||
const pluginStartContract = {
|
||||
someApi: () => 'foo',
|
||||
};
|
||||
|
||||
const pluginInitializer = () =>
|
||||
({
|
||||
setup: async (coreSetup, deps) => {
|
||||
coreSetup.getStartServices().then(([core, plugins]) => {
|
||||
coreSetup.getStartServices().then(([core, plugins, pluginStart]) => {
|
||||
startDependenciesResolved = true;
|
||||
contextFromStartService = { core, plugins };
|
||||
contextFromStartService = { core, plugins, pluginStart };
|
||||
});
|
||||
},
|
||||
start: async (core, plugins) => {
|
||||
contextFromStart = { core, plugins };
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
expect(startDependenciesResolved).toBe(false);
|
||||
return pluginStartContract;
|
||||
},
|
||||
} as Plugin);
|
||||
} as Plugin<void, typeof pluginStartContract, {}, {}>);
|
||||
|
||||
jest.doMock(
|
||||
join(pluginPath, 'server'),
|
||||
|
@ -163,5 +168,6 @@ describe('PluginsService', () => {
|
|||
expect(startDependenciesResolved).toBe(true);
|
||||
expect(contextFromStart!.core).toEqual(contextFromStartService!.core);
|
||||
expect(contextFromStart!.plugins).toEqual(contextFromStartService!.plugins);
|
||||
expect(contextFromStartService!.pluginStart).toEqual(pluginStartContract);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -250,6 +250,9 @@ test("`start` resolves `startDependencies` Promise after plugin's start", async
|
|||
});
|
||||
const startContext = { any: 'thing' } as any;
|
||||
const pluginDeps = { someDep: 'value' };
|
||||
const pluginStartContract = {
|
||||
someApi: () => 'foo',
|
||||
};
|
||||
|
||||
let startDependenciesResolved = false;
|
||||
|
||||
|
@ -259,6 +262,7 @@ test("`start` resolves `startDependencies` Promise after plugin's start", async
|
|||
// 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);
|
||||
return pluginStartContract;
|
||||
},
|
||||
};
|
||||
mockPluginInitializer.mockReturnValue(mockPluginInstance);
|
||||
|
@ -267,7 +271,7 @@ test("`start` resolves `startDependencies` Promise after plugin's start", async
|
|||
|
||||
const startDependenciesCheck = plugin.startDependencies.then(resolvedStartDeps => {
|
||||
startDependenciesResolved = true;
|
||||
expect(resolvedStartDeps).toEqual([startContext, pluginDeps]);
|
||||
expect(resolvedStartDeps).toEqual([startContext, pluginDeps, pluginStartContract]);
|
||||
});
|
||||
|
||||
await plugin.start(startContext, pluginDeps);
|
||||
|
|
|
@ -61,7 +61,7 @@ export class PluginWrapper<
|
|||
|
||||
private instance?: Plugin<TSetup, TStart, TPluginsSetup, TPluginsStart>;
|
||||
|
||||
private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart]>();
|
||||
private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart, TStart]>();
|
||||
public readonly startDependencies = this.startDependencies$.pipe(first()).toPromise();
|
||||
|
||||
constructor(
|
||||
|
@ -115,7 +115,7 @@ export class PluginWrapper<
|
|||
this.log.debug('Starting plugin');
|
||||
|
||||
const startContract = await this.instance.start(startContext, plugins);
|
||||
this.startDependencies$.next([startContext, plugins]);
|
||||
this.startDependencies$.next([startContext, plugins, startContract]);
|
||||
return startContract;
|
||||
}
|
||||
|
||||
|
|
|
@ -622,7 +622,7 @@ export interface ContextSetup {
|
|||
export type CoreId = symbol;
|
||||
|
||||
// @public
|
||||
export interface CoreSetup<TPluginsStart extends object = object> {
|
||||
export interface CoreSetup<TPluginsStart extends object = object, TStart = unknown> {
|
||||
// (undocumented)
|
||||
capabilities: CapabilitiesSetup;
|
||||
// (undocumented)
|
||||
|
@ -630,7 +630,7 @@ export interface CoreSetup<TPluginsStart extends object = object> {
|
|||
// (undocumented)
|
||||
elasticsearch: ElasticsearchServiceSetup;
|
||||
// (undocumented)
|
||||
getStartServices: StartServicesAccessor<TPluginsStart>;
|
||||
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
|
||||
// (undocumented)
|
||||
http: HttpServiceSetup;
|
||||
// (undocumented)
|
||||
|
@ -2270,7 +2270,7 @@ export type SharedGlobalConfig = RecursiveReadonly_2<{
|
|||
}>;
|
||||
|
||||
// @public
|
||||
export type StartServicesAccessor<TPluginsStart extends object = object> = () => Promise<[CoreStart, TPluginsStart]>;
|
||||
export type StartServicesAccessor<TPluginsStart extends object = object, TStart = unknown> = () => Promise<[CoreStart, TPluginsStart, TStart]>;
|
||||
|
||||
// @public
|
||||
export type StringValidation = StringValidationRegex | StringValidationRegexString;
|
||||
|
|
|
@ -24,7 +24,7 @@ import { VisualizationsSetup, VisualizationsStart } from '../../visualizations/p
|
|||
import { createInputControlVisFn } from './input_control_fn';
|
||||
import { createInputControlVisTypeDefinition } from './input_control_vis_type';
|
||||
|
||||
type InputControlVisCoreSetup = CoreSetup<InputControlVisPluginStartDependencies>;
|
||||
type InputControlVisCoreSetup = CoreSetup<InputControlVisPluginStartDependencies, void>;
|
||||
|
||||
export interface InputControlVisDependencies {
|
||||
core: InputControlVisCoreSetup;
|
||||
|
@ -46,7 +46,7 @@ export interface InputControlVisPluginStartDependencies {
|
|||
}
|
||||
|
||||
/** @internal */
|
||||
export class InputControlVisPlugin implements Plugin<Promise<void>, void> {
|
||||
export class InputControlVisPlugin implements Plugin<void, void> {
|
||||
constructor(public initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public async setup(
|
||||
|
|
|
@ -91,7 +91,7 @@ export class DiscoverPlugin implements Plugin<void, void> {
|
|||
public initializeInnerAngular?: () => void;
|
||||
public initializeServices?: () => Promise<{ core: CoreStart; plugins: DiscoverStartPlugins }>;
|
||||
|
||||
setup(core: CoreSetup<DiscoverStartPlugins>, plugins: DiscoverSetupPlugins) {
|
||||
setup(core: CoreSetup<DiscoverStartPlugins, void>, plugins: DiscoverSetupPlugins) {
|
||||
const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({
|
||||
baseUrl: core.http.basePath.prepend('/app/kibana'),
|
||||
defaultSubUrl: '#/discover',
|
||||
|
|
|
@ -35,7 +35,7 @@ import { getTimelionVisualizationConfig } from './timelion_vis_fn';
|
|||
import { getTimelionVisDefinition } from './timelion_vis_type';
|
||||
import { setIndexPatterns, setSavedObjectsClient } from './helpers/plugin_services';
|
||||
|
||||
type TimelionVisCoreSetup = CoreSetup<TimelionVisSetupDependencies>;
|
||||
type TimelionVisCoreSetup = CoreSetup<TimelionVisSetupDependencies, void>;
|
||||
|
||||
/** @internal */
|
||||
export interface TimelionVisDependencies extends Partial<CoreStart> {
|
||||
|
|
|
@ -62,10 +62,10 @@ export interface VisTypeVislibPluginStartDependencies {
|
|||
data: DataPublicPluginStart;
|
||||
}
|
||||
|
||||
type VisTypeVislibCoreSetup = CoreSetup<VisTypeVislibPluginStartDependencies>;
|
||||
type VisTypeVislibCoreSetup = CoreSetup<VisTypeVislibPluginStartDependencies, void>;
|
||||
|
||||
/** @internal */
|
||||
export class VisTypeVislibPlugin implements Plugin<Promise<void>, void> {
|
||||
export class VisTypeVislibPlugin implements Plugin<void, void> {
|
||||
constructor(public initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public async setup(
|
||||
|
|
|
@ -47,10 +47,10 @@ export interface VisTypeXyPluginStartDependencies {
|
|||
visualizations: VisualizationsStart;
|
||||
}
|
||||
|
||||
type VisTypeXyCoreSetup = CoreSetup<VisTypeXyPluginStartDependencies>;
|
||||
type VisTypeXyCoreSetup = CoreSetup<VisTypeXyPluginStartDependencies, void>;
|
||||
|
||||
/** @internal */
|
||||
export class VisTypeXyPlugin implements Plugin<Promise<void>, void> {
|
||||
export class VisTypeXyPlugin implements Plugin<void, void> {
|
||||
constructor(public initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public async setup(
|
||||
|
|
|
@ -50,7 +50,9 @@ export interface HomePluginSetupDependencies {
|
|||
kibanaLegacy: KibanaLegacySetup;
|
||||
}
|
||||
|
||||
export class HomePublicPlugin implements Plugin<HomePublicPluginSetup, void> {
|
||||
export class HomePublicPlugin
|
||||
implements
|
||||
Plugin<HomePublicPluginSetup, void, HomePluginSetupDependencies, HomePluginStartDependencies> {
|
||||
private readonly featuresCatalogueRegistry = new FeatureCatalogueRegistry();
|
||||
private readonly environmentService = new EnvironmentService();
|
||||
private readonly tutorialService = new TutorialService();
|
||||
|
|
|
@ -175,7 +175,7 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi
|
|||
|
||||
const usageCollection = plugins.usageCollection;
|
||||
if (usageCollection) {
|
||||
core.getStartServices().then(async ([coreStart, startPlugins]: [CoreStart, any]) => {
|
||||
core.getStartServices().then(async ([, startPlugins]: [CoreStart, any, any]) => {
|
||||
registerActionsUsageCollector(usageCollection, startPlugins.taskManager);
|
||||
|
||||
initializeActionsTelemetry(
|
||||
|
|
|
@ -143,7 +143,7 @@ export class AlertingPlugin {
|
|||
|
||||
const usageCollection = plugins.usageCollection;
|
||||
if (usageCollection) {
|
||||
core.getStartServices().then(async ([coreStart, startPlugins]: [CoreStart, any]) => {
|
||||
core.getStartServices().then(async ([, startPlugins]: [CoreStart, any, any]) => {
|
||||
registerAlertsUsageCollector(usageCollection, startPlugins.taskManager);
|
||||
|
||||
initializeAlertingTelemetry(
|
||||
|
|
|
@ -32,7 +32,9 @@ export interface IngestManagerStartDeps {
|
|||
data: DataPublicPluginStart;
|
||||
}
|
||||
|
||||
export class IngestManagerPlugin implements Plugin {
|
||||
export class IngestManagerPlugin
|
||||
implements
|
||||
Plugin<IngestManagerSetup, IngestManagerStart, IngestManagerSetupDeps, IngestManagerStartDeps> {
|
||||
private config: IngestManagerConfigType;
|
||||
|
||||
constructor(private readonly initializerContext: PluginInitializerContext) {
|
||||
|
@ -50,7 +52,8 @@ export class IngestManagerPlugin implements Plugin {
|
|||
async mount(params: AppMountParameters) {
|
||||
const [coreStart, startDeps] = (await core.getStartServices()) as [
|
||||
CoreStart,
|
||||
IngestManagerStartDeps
|
||||
IngestManagerStartDeps,
|
||||
IngestManagerStart
|
||||
];
|
||||
const { renderApp } = await import('./applications/ingest_manager');
|
||||
return renderApp(coreStart, params, deps, startDeps, config);
|
||||
|
|
|
@ -6,8 +6,19 @@
|
|||
|
||||
import { PluginInitializer } from 'kibana/public';
|
||||
import './index.scss';
|
||||
import { MlPlugin, MlPluginSetup, MlPluginStart } from './plugin';
|
||||
import {
|
||||
MlPlugin,
|
||||
MlPluginSetup,
|
||||
MlPluginStart,
|
||||
MlSetupDependencies,
|
||||
MlStartDependencies,
|
||||
} from './plugin';
|
||||
|
||||
export const plugin: PluginInitializer<MlPluginSetup, MlPluginStart> = () => new MlPlugin();
|
||||
export const plugin: PluginInitializer<
|
||||
MlPluginSetup,
|
||||
MlPluginStart,
|
||||
MlSetupDependencies,
|
||||
MlStartDependencies
|
||||
> = () => new MlPlugin();
|
||||
|
||||
export { MlPluginSetup, MlPluginStart };
|
||||
|
|
|
@ -31,7 +31,7 @@ export interface MlSetupDependencies {
|
|||
}
|
||||
|
||||
export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
|
||||
setup(core: CoreSetup<MlStartDependencies>, pluginsSetup: MlSetupDependencies) {
|
||||
setup(core: CoreSetup<MlStartDependencies, MlPluginStart>, pluginsSetup: MlSetupDependencies) {
|
||||
core.application.register({
|
||||
id: PLUGIN_ID,
|
||||
title: i18n.translate('xpack.ml.plugin.title', {
|
||||
|
|
|
@ -224,7 +224,7 @@ export class Plugin {
|
|||
this.monitoringCore = this.getLegacyShim(
|
||||
config,
|
||||
legacyConfig,
|
||||
core.getStartServices as () => Promise<[CoreStart, PluginsStart]>,
|
||||
core.getStartServices as () => Promise<[CoreStart, PluginsStart, {}]>,
|
||||
this.licenseService,
|
||||
this.cluster
|
||||
);
|
||||
|
@ -293,7 +293,7 @@ export class Plugin {
|
|||
getLegacyShim(
|
||||
config: MonitoringConfig,
|
||||
legacyConfig: any,
|
||||
getCoreServices: () => Promise<[CoreStart, PluginsStart]>,
|
||||
getCoreServices: () => Promise<[CoreStart, PluginsStart, {}]>,
|
||||
licenseService: MonitoringLicenseService,
|
||||
cluster: ICustomClusterClient
|
||||
): MonitoringCore {
|
||||
|
|
|
@ -38,7 +38,7 @@ describe('accountManagementApp', () => {
|
|||
it('properly sets breadcrumbs and renders application', async () => {
|
||||
const coreSetupMock = coreMock.createSetup();
|
||||
const coreStartMock = coreMock.createStart();
|
||||
coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, {}]);
|
||||
coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, {}, {}]);
|
||||
|
||||
const authcMock = securityMock.createSetup().authc;
|
||||
const containerMock = document.createElement('div');
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('loggedOutApp', () => {
|
|||
it('properly renders application', async () => {
|
||||
const coreSetupMock = coreMock.createSetup();
|
||||
const coreStartMock = coreMock.createStart();
|
||||
coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, {}]);
|
||||
coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, {}, {}]);
|
||||
|
||||
const containerMock = document.createElement('div');
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ describe('loginApp', () => {
|
|||
it('properly renders application', async () => {
|
||||
const coreSetupMock = coreMock.createSetup();
|
||||
const coreStartMock = coreMock.createStart();
|
||||
coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, {}]);
|
||||
coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, {}, {}]);
|
||||
const containerMock = document.createElement('div');
|
||||
|
||||
loginApp.create({
|
||||
|
|
|
@ -37,7 +37,7 @@ describe('overwrittenSessionApp', () => {
|
|||
it('properly sets breadcrumbs and renders application', async () => {
|
||||
const coreSetupMock = coreMock.createSetup();
|
||||
const coreStartMock = coreMock.createStart();
|
||||
coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, {}]);
|
||||
coreSetupMock.getStartServices.mockResolvedValue([coreStartMock, {}, {}]);
|
||||
|
||||
const authcMock = securityMock.createSetup().authc;
|
||||
const containerMock = document.createElement('div');
|
||||
|
|
|
@ -6,13 +6,22 @@
|
|||
|
||||
import './index.scss';
|
||||
import { PluginInitializer, PluginInitializerContext } from 'src/core/public';
|
||||
import { SecurityPlugin, SecurityPluginSetup, SecurityPluginStart } from './plugin';
|
||||
import {
|
||||
SecurityPlugin,
|
||||
SecurityPluginSetup,
|
||||
SecurityPluginStart,
|
||||
PluginSetupDependencies,
|
||||
PluginStartDependencies,
|
||||
} from './plugin';
|
||||
|
||||
export { SecurityPluginSetup, SecurityPluginStart };
|
||||
export { SessionInfo } from './types';
|
||||
export { AuthenticatedUser } from '../common/model';
|
||||
export { SecurityLicense, SecurityLicenseFeatures } from '../common/licensing';
|
||||
|
||||
export const plugin: PluginInitializer<SecurityPluginSetup, SecurityPluginStart> = (
|
||||
initializerContext: PluginInitializerContext
|
||||
) => new SecurityPlugin(initializerContext);
|
||||
export const plugin: PluginInitializer<
|
||||
SecurityPluginSetup,
|
||||
SecurityPluginStart,
|
||||
PluginSetupDependencies,
|
||||
PluginStartDependencies
|
||||
> = (initializerContext: PluginInitializerContext) => new SecurityPlugin(initializerContext);
|
||||
|
|
|
@ -51,7 +51,7 @@ async function mountApp(basePath: string, spaceId?: string) {
|
|||
.create({
|
||||
spacesManager,
|
||||
securityLicense,
|
||||
getStartServices: async () => [coreStart, pluginsStart as PluginsStart],
|
||||
getStartServices: async () => [coreStart, pluginsStart as PluginsStart, {}],
|
||||
})
|
||||
.mount({ basePath, element: container, setBreadcrumbs });
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ const setup = (space: Space) => {
|
|||
coreSetup.getStartServices.mockResolvedValue([
|
||||
coreMock.createStart(),
|
||||
{ features: featuresStart },
|
||||
{},
|
||||
]);
|
||||
|
||||
const spacesService = spacesServiceMock.createSetupContract();
|
||||
|
|
|
@ -5,6 +5,15 @@
|
|||
*/
|
||||
|
||||
import { PluginInitializer } from 'kibana/public';
|
||||
import { ResolverTestPlugin } from './plugin';
|
||||
import {
|
||||
ResolverTestPlugin,
|
||||
ResolverTestPluginSetupDependencies,
|
||||
ResolverTestPluginStartDependencies,
|
||||
} from './plugin';
|
||||
|
||||
export const plugin: PluginInitializer<void, void> = () => new ResolverTestPlugin();
|
||||
export const plugin: PluginInitializer<
|
||||
void,
|
||||
void,
|
||||
ResolverTestPluginSetupDependencies,
|
||||
ResolverTestPluginStartDependencies
|
||||
> = () => new ResolverTestPlugin();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue