PluginExtensions: Exposing registry meta for components returned via usePluginComponents (#100587)
Exposing meta information from registry via Component.meta.
This commit is contained in:
@@ -548,6 +548,7 @@ export {
|
||||
type PluginExtension,
|
||||
type PluginExtensionLink,
|
||||
type PluginExtensionComponent,
|
||||
type PluginExtensionComponentMeta,
|
||||
type PluginExtensionConfig,
|
||||
type PluginExtensionFunction,
|
||||
type PluginExtensionLinkConfig,
|
||||
|
||||
@@ -32,6 +32,8 @@ export type PluginExtensionLink = PluginExtensionBase & {
|
||||
category?: string;
|
||||
};
|
||||
|
||||
export type PluginExtensionComponentMeta = Omit<PluginExtensionComponent, 'component'>;
|
||||
|
||||
export type PluginExtensionComponent<Props = {}> = PluginExtensionBase & {
|
||||
type: PluginExtensionTypes.component;
|
||||
component: React.ComponentType<Props>;
|
||||
|
||||
@@ -3,6 +3,7 @@ import type {
|
||||
PluginExtensionLink,
|
||||
PluginExtensionComponent,
|
||||
PluginExtensionFunction,
|
||||
PluginExtensionComponentMeta,
|
||||
} from '@grafana/data';
|
||||
|
||||
import { isPluginExtensionComponent, isPluginExtensionLink } from './utils';
|
||||
@@ -42,7 +43,7 @@ export type UsePluginComponentResult<Props = {}> = {
|
||||
};
|
||||
|
||||
export type UsePluginComponentsResult<Props = {}> = {
|
||||
components: Array<React.ComponentType<Props>>;
|
||||
components: Array<React.ComponentType<Props> & { meta: PluginExtensionComponentMeta }>;
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -159,6 +159,50 @@ describe('usePluginComponents()', () => {
|
||||
expect(screen.queryByText('Hello World3')).toBeNull();
|
||||
});
|
||||
|
||||
it('should return component with meta information attached to it', async () => {
|
||||
registries.addedComponentsRegistry.register({
|
||||
pluginId,
|
||||
configs: [
|
||||
{
|
||||
targets: extensionPointId,
|
||||
title: '1',
|
||||
description: '1',
|
||||
component: () => <div>Hello World1</div>,
|
||||
},
|
||||
{
|
||||
targets: extensionPointId,
|
||||
title: '2',
|
||||
description: '2',
|
||||
component: () => <div>Hello World2</div>,
|
||||
},
|
||||
{
|
||||
targets: 'plugins/another-extension/v1',
|
||||
title: '3',
|
||||
description: '3',
|
||||
component: () => <div>Hello World3</div>,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => usePluginComponents({ extensionPointId }), { wrapper });
|
||||
|
||||
expect(result.current.components.length).toBe(2);
|
||||
expect(result.current.components[0].meta).toEqual({
|
||||
pluginId,
|
||||
title: '1',
|
||||
description: '1',
|
||||
id: '-1921123020',
|
||||
type: 'component',
|
||||
});
|
||||
expect(result.current.components[1].meta).toEqual({
|
||||
pluginId,
|
||||
title: '2',
|
||||
description: '2',
|
||||
id: '-1921123019',
|
||||
type: 'component',
|
||||
});
|
||||
});
|
||||
|
||||
it('should dynamically update the extensions registered for a certain extension point', () => {
|
||||
let { result, rerender } = renderHook(() => usePluginComponents({ extensionPointId }), { wrapper });
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useObservable } from 'react-use';
|
||||
|
||||
import { usePluginContext } from '@grafana/data';
|
||||
import { PluginExtensionComponentMeta, PluginExtensionTypes, usePluginContext } from '@grafana/data';
|
||||
import {
|
||||
UsePluginComponentOptions,
|
||||
UsePluginComponentsResult,
|
||||
@@ -10,8 +10,9 @@ import {
|
||||
import { useAddedComponentsRegistry } from './ExtensionRegistriesContext';
|
||||
import * as errors from './errors';
|
||||
import { log } from './logs/log';
|
||||
import { AddedComponentRegistryItem } from './registry/AddedComponentsRegistry';
|
||||
import { useLoadAppPlugins } from './useLoadAppPlugins';
|
||||
import { getExtensionPointPluginDependencies, isGrafanaDevMode } from './utils';
|
||||
import { generateExtensionId, getExtensionPointPluginDependencies, isGrafanaDevMode } from './utils';
|
||||
import { isExtensionPointIdValid, isExtensionPointMetaInfoMissing } from './validators';
|
||||
|
||||
// Returns an array of component extensions for the given extension point
|
||||
@@ -27,7 +28,7 @@ export function usePluginComponents<Props extends object = {}>({
|
||||
return useMemo(() => {
|
||||
// For backwards compatibility we don't enable restrictions in production or when the hook is used in core Grafana.
|
||||
const enableRestrictions = isGrafanaDevMode() && pluginContext;
|
||||
const components: Array<React.ComponentType<Props>> = [];
|
||||
const components: Array<React.ComponentType<Props> & { meta: PluginExtensionComponentMeta }> = [];
|
||||
const extensionsByPlugin: Record<string, number> = {};
|
||||
const pluginId = pluginContext?.meta.id ?? '';
|
||||
const pointLog = log.child({
|
||||
@@ -66,7 +67,12 @@ export function usePluginComponents<Props extends object = {}>({
|
||||
extensionsByPlugin[pluginId] = 0;
|
||||
}
|
||||
|
||||
components.push(registryItem.component as React.ComponentType<Props>);
|
||||
const component = createComponentWithMeta<Props>(
|
||||
registryItem as AddedComponentRegistryItem<Props>,
|
||||
extensionPointId
|
||||
);
|
||||
|
||||
components.push(component);
|
||||
extensionsByPlugin[pluginId] += 1;
|
||||
}
|
||||
|
||||
@@ -76,3 +82,27 @@ export function usePluginComponents<Props extends object = {}>({
|
||||
};
|
||||
}, [extensionPointId, limitPerPlugin, pluginContext, registryState, isLoadingAppPlugins]);
|
||||
}
|
||||
|
||||
function createComponentWithMeta<Props extends JSX.IntrinsicAttributes>(
|
||||
registryItem: AddedComponentRegistryItem<Props>,
|
||||
extensionPointId: string
|
||||
): React.ComponentType<Props> & { meta: PluginExtensionComponentMeta } {
|
||||
const { component: Component, ...config } = registryItem;
|
||||
function ComponentWithMeta(props: Props) {
|
||||
return <Component {...props} />;
|
||||
}
|
||||
|
||||
ComponentWithMeta.displayName = Component.displayName;
|
||||
ComponentWithMeta.defaultProps = Component.defaultProps;
|
||||
ComponentWithMeta.propTypes = Component.propTypes;
|
||||
ComponentWithMeta.contextTypes = Component.contextTypes;
|
||||
ComponentWithMeta.meta = {
|
||||
pluginId: config.pluginId,
|
||||
title: config.title ?? '',
|
||||
description: config.description ?? '',
|
||||
id: generateExtensionId(config.pluginId, extensionPointId, config.title),
|
||||
type: PluginExtensionTypes.component,
|
||||
} satisfies PluginExtensionComponentMeta;
|
||||
|
||||
return ComponentWithMeta;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user