front/core: add plugin api hooks and output for widgets

This commit is contained in:
Patrik Oldsberg
2020-02-07 13:27:43 +01:00
parent ea35a14f68
commit bb450005af
3 changed files with 53 additions and 7 deletions
@@ -1,6 +1,7 @@
import { ComponentType } from 'react';
import { PluginOutput, RoutePath, RouteOptions } from './types';
import { IconComponent } from '../types';
import { Widget } from '../widgetView/types';
export type PluginConfig = {
id: string;
@@ -10,6 +11,7 @@ export type PluginConfig = {
export type PluginHooks = {
router: RouterHooks;
entityPage: EntityPageHooks;
widgets: WidgetHooks;
};
export type RouterHooks = {
@@ -41,6 +43,10 @@ export type EntityPageHooks = {
): void;
};
export type WidgetHooks = {
add(widget: Widget): void;
};
export const registerSymbol = Symbol('plugin-register');
export const outputSymbol = Symbol('plugin-output');
@@ -98,6 +104,11 @@ export default class Plugin {
});
},
},
widgets: {
add(widget: Widget) {
outputs.push({ type: 'widget', widget });
},
},
});
this.storedOutput = outputs;
@@ -1,5 +1,6 @@
import { ComponentType } from 'react';
import { IconComponent } from '../types';
import { Widget } from '../widgetView/types';
export type RouteOptions = {
// Whether the route path must match exactly, defaults to true.
@@ -22,6 +23,11 @@ export type RedirectRouteOutput = {
options?: RouteOptions;
};
export type WidgetOutput = {
type: 'widget';
widget: Widget;
};
export type EntityPageViewRouteOutput = {
type: 'entity-page-view-route';
path: RoutePath;
@@ -39,5 +45,6 @@ export type EntityPageNavItemOutput = {
export type PluginOutput =
| RouteOutput
| RedirectRouteOutput
| WidgetOutput
| EntityPageViewRouteOutput
| EntityPageNavItemOutput;
@@ -1,12 +1,18 @@
import React, { ComponentType } from 'react';
import { App, AppComponentBuilder } from '../app/types';
import { Widget } from './types';
import BackstagePlugin from '../plugin/Plugin';
import DefaultWidgetView from '../../components/DefaultWidgetView';
type WidgetViewRegistration = {
type: 'component';
widget: Widget;
};
type WidgetViewRegistration =
| {
type: 'component';
widget: Widget;
}
| {
type: 'plugin';
plugin: BackstagePlugin;
};
export default class WidgetViewBuilder extends AppComponentBuilder {
private readonly registrations = new Array<WidgetViewRegistration>();
@@ -17,19 +23,41 @@ export default class WidgetViewBuilder extends AppComponentBuilder {
return this;
}
register(plugin: BackstagePlugin): WidgetViewBuilder {
this.registrations.push({ type: 'plugin', plugin });
return this;
}
build(_app: App): ComponentType<any> {
if (this.output) {
return this.output;
}
const widgets = this.registrations.map(reg => {
const widgets = new Array<Widget>();
for (const reg of this.registrations) {
switch (reg.type) {
case 'component':
return reg.widget;
widgets.push(reg.widget);
break;
case 'plugin':
let added = false;
for (const output of reg.plugin.output()) {
if (output.type === 'widget') {
widgets.push(output.widget);
added = true;
}
}
if (!added) {
throw new Error(
`Plugin ${reg.plugin} was registered as widget provider, but did not provide any widgets`,
);
}
break;
default:
throw new Error(`Unknown WidgetViewBuilder registration`);
}
});
}
this.output = () => <DefaultWidgetView widgets={widgets} />;
return this.output;