[Canvas] Register addons async (#86977)

* Make canvas registries accept async functions

* Remove some comments

* Remove comment

* Update x-pack/plugins/canvas/public/registries.ts

Co-authored-by: Clint Andrew Hall <clint@clintandrewhall.com>

* Update x-pack/plugins/canvas/public/registries.ts

Co-authored-by: Clint Andrew Hall <clint@clintandrewhall.com>

* Add ts error types

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Clint Andrew Hall <clint@clintandrewhall.com>
This commit is contained in:
Corey Robertson 2021-01-07 15:45:46 -05:00 committed by GitHub
parent 1c30525d46
commit fdfe6559b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 40 deletions

View file

@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
// @ts-expect-error Untyped Local
export * from './uis/datasources';
export * from './elements';
// @ts-expect-error Untyped Local
export * from './uis/models';
export * from './uis/views';
export * from './uis/arguments';
export * from './uis/tags';
// @ts-expect-error Untyped Local
export * from './uis/transforms';

View file

@ -14,17 +14,6 @@ import { Start as InspectorStart } from '../../../../src/plugins/inspector/publi
import { functions } from './functions/browser';
import { typeFunctions } from './expression_types';
import { renderFunctions, renderFunctionFactories } from './renderers';
import { initializeElements } from './elements';
// @ts-expect-error untyped local
import { transformSpecs } from './uis/transforms';
// @ts-expect-error untyped local
import { datasourceSpecs } from './uis/datasources';
// @ts-expect-error untyped local
import { modelSpecs } from './uis/models';
import { initializeViews } from './uis/views';
import { initializeArgs } from './uis/arguments';
import { tagSpecs } from './uis/tags';
interface SetupDeps {
canvas: CanvasSetup;
}
@ -53,13 +42,44 @@ export class CanvasSrcPlugin implements Plugin<void, void, SetupDeps, StartDeps>
);
});
plugins.canvas.addElements(initializeElements(core, plugins));
plugins.canvas.addDatasourceUIs(datasourceSpecs);
plugins.canvas.addModelUIs(modelSpecs);
plugins.canvas.addViewUIs(initializeViews(core, plugins));
plugins.canvas.addArgumentUIs(initializeArgs(core, plugins));
plugins.canvas.addTagUIs(tagSpecs);
plugins.canvas.addTransformUIs(transformSpecs);
plugins.canvas.addDatasourceUIs(async () => {
// @ts-expect-error
const { datasourceSpecs } = await import('./canvas_addons');
return datasourceSpecs;
});
plugins.canvas.addElements(async () => {
const { initializeElements } = await import('./canvas_addons');
return initializeElements(core, plugins);
});
plugins.canvas.addModelUIs(async () => {
// @ts-expect-error Untyped local
const { modelSpecs } = await import('./canvas_addons');
return modelSpecs;
});
plugins.canvas.addViewUIs(async () => {
const { initializeViews } = await import('./canvas_addons');
return initializeViews(core, plugins);
});
plugins.canvas.addArgumentUIs(async () => {
const { initializeArgs } = await import('./canvas_addons');
return initializeArgs(core, plugins);
});
plugins.canvas.addTagUIs(async () => {
const { tagSpecs } = await import('./canvas_addons');
return tagSpecs;
});
plugins.canvas.addTransformUIs(async () => {
// @ts-expect-error Untyped local
const { transformSpecs } = await import('./canvas_addons');
return transformSpecs;
});
}
public start(core: CoreStart, plugins: StartDeps) {}

View file

@ -103,7 +103,7 @@ export const initializeCanvas = async (
// Init Registries
initRegistries();
populateRegistries(registries);
await populateRegistries(registries);
// Set Badge
coreStart.chrome.setBadge(

View file

@ -26,9 +26,6 @@ import { EmbeddableStart } from '../../../../src/plugins/embeddable/public';
import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public';
import { Start as InspectorStart } from '../../../../src/plugins/inspector/public';
import { BfetchPublicSetup } from '../../../../src/plugins/bfetch/public';
// @ts-expect-error untyped local
import { argTypeSpecs } from './expression_types/arg_types';
import { transitions } from './transitions';
import { getPluginApi, CanvasApi } from './plugin_api';
import { CanvasSrcPlugin } from '../canvas_plugin_src/plugin';
export { CoreStart, CoreSetup };
@ -123,8 +120,15 @@ export class CanvasPlugin
plugins.home.featureCatalogue.register(featureCatalogueEntry);
}
canvasApi.addArgumentUIs(argTypeSpecs);
canvasApi.addTransitions(transitions);
canvasApi.addArgumentUIs(async () => {
// @ts-expect-error
const { argTypeSpecs } = await import('./expression_types/arg_types');
return argTypeSpecs;
});
canvasApi.addTransitions(async () => {
const { transitions } = await import('./transitions');
return transitions;
});
return {
...canvasApi,

View file

@ -12,24 +12,26 @@ import {
import { ElementFactory } from '../types';
import { ExpressionsSetup } from '../../../../src/plugins/expressions/public';
type AddToRegistry<T extends any> = (add: T[]) => void;
type SpecPromiseFn<T extends any> = () => Promise<T[]>;
type AddToRegistry<T extends any> = (add: T[] | SpecPromiseFn<T>) => void;
type AddSpecsToRegistry<T extends any> = (add: T[]) => void;
export interface CanvasApi {
addArgumentUIs: AddToRegistry<any>;
addDatasourceUIs: AddToRegistry<any>;
addElements: AddToRegistry<ElementFactory>;
addFunctions: AddToRegistry<() => AnyExpressionFunctionDefinition>;
addFunctions: AddSpecsToRegistry<() => AnyExpressionFunctionDefinition>;
addModelUIs: AddToRegistry<any>;
addRenderers: AddToRegistry<AnyRendererFactory>;
addRenderers: AddSpecsToRegistry<AnyRendererFactory>;
addTagUIs: AddToRegistry<any>;
addTransformUIs: AddToRegistry<any>;
addTransitions: AddToRegistry<any>;
addTypes: AddToRegistry<() => AnyExpressionTypeDefinition>;
addTypes: AddSpecsToRegistry<() => AnyExpressionTypeDefinition>;
addViewUIs: AddToRegistry<any>;
}
export interface SetupRegistries {
elements: ElementFactory[];
export interface SetupRegistries extends Record<string, any[]> {
elements: Array<ElementFactory | SpecPromiseFn<ElementFactory>>;
transformUIs: any[];
datasourceUIs: any[];
modelUIs: any[];
@ -53,6 +55,16 @@ export function getPluginApi(
transitions: [],
};
const addToRegistry = <T>(registry: Array<T | SpecPromiseFn<T>>) => {
return (entries: T[] | SpecPromiseFn<T>) => {
if (Array.isArray(entries)) {
registry.push(...entries);
} else {
registry.push(entries);
}
};
};
const api: CanvasApi = {
// Functions, types and renderers are registered directly to expression plugin
addFunctions: (fns) => {
@ -75,14 +87,14 @@ export function getPluginApi(
},
// All these others are local to canvas, and they will only register on start
addElements: (elements) => registries.elements.push(...elements),
addTransformUIs: (transforms) => registries.transformUIs.push(...transforms),
addDatasourceUIs: (datasources) => registries.datasourceUIs.push(...datasources),
addModelUIs: (models) => registries.modelUIs.push(...models),
addViewUIs: (views) => registries.viewUIs.push(...views),
addArgumentUIs: (args) => registries.argumentUIs.push(...args),
addTagUIs: (tags) => registries.tagUIs.push(...tags),
addTransitions: (transitions) => registries.transitions.push(...transitions),
addElements: addToRegistry(registries.elements),
addTransformUIs: addToRegistry(registries.transformUIs),
addDatasourceUIs: addToRegistry(registries.datasourceUIs),
addModelUIs: addToRegistry(registries.modelUIs),
addViewUIs: addToRegistry(registries.viewUIs),
addArgumentUIs: addToRegistry(registries.argumentUIs),
addTagUIs: addToRegistry(registries.tagUIs),
addTransitions: addToRegistry(registries.transitions),
};
return { api, registries };

View file

@ -40,8 +40,24 @@ export function initRegistries() {
});
}
export function populateRegistries(setupRegistries: SetupRegistries) {
register(registries, setupRegistries);
export async function populateRegistries(setupRegistries: SetupRegistries) {
// Our setup registries could contain definitions or a function that would
// return a promise of definitions.
// We need to call all the fns and then wait for all of the promises to be resolved
const resolvedRegistries: Record<string, any[]> = {};
const promises = Object.entries(setupRegistries).map(async ([key, specs]) => {
const resolved = await (
await Promise.all(specs.map((fn) => (typeof fn === 'function' ? fn() : fn)))
).flat();
resolvedRegistries[key] = resolved;
});
// Now, wait for all of the promise registry promises to resolve and our resolved registry will be ready
// and we can proceeed
await Promise.all(promises);
register(registries, resolvedRegistries);
}
export function destroyRegistries() {