import { useMemo } from 'react'; import { useObservable } from 'react-use'; import { usePluginContext } from '@grafana/data'; import { UsePluginComponentOptions, UsePluginComponentsResult, } from '@grafana/runtime/src/services/pluginExtensions/getPluginExtensions'; import { useAddedComponentsRegistry } from './ExtensionRegistriesContext'; import { isExtensionPointMetaInfoMissing, isGrafanaDevMode, logWarning } from './utils'; import { isExtensionPointIdValid } from './validators'; // Returns an array of component extensions for the given extension point export function usePluginComponents({ limitPerPlugin, extensionPointId, }: UsePluginComponentOptions): UsePluginComponentsResult { const registry = useAddedComponentsRegistry(); const registryState = useObservable(registry.asObservable()); const pluginContext = usePluginContext(); 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> = []; const extensionsByPlugin: Record = {}; const pluginId = pluginContext?.meta.id ?? ''; if (enableRestrictions && !isExtensionPointIdValid({ extensionPointId, pluginId })) { logWarning( `Extension point usePluginComponents("${extensionPointId}") - the id should be prefixed with your plugin id ("${pluginId}/").` ); return { isLoading: false, components: [], }; } if (enableRestrictions && isExtensionPointMetaInfoMissing(extensionPointId, pluginContext)) { logWarning( `usePluginComponents("${extensionPointId}") - The extension point is missing from the "plugin.json" file.` ); return { isLoading: false, components: [], }; } for (const registryItem of registryState?.[extensionPointId] ?? []) { const { pluginId } = registryItem; // Only limit if the `limitPerPlugin` is set if (limitPerPlugin && extensionsByPlugin[pluginId] >= limitPerPlugin) { continue; } if (extensionsByPlugin[pluginId] === undefined) { extensionsByPlugin[pluginId] = 0; } components.push(registryItem.component as React.ComponentType); extensionsByPlugin[pluginId] += 1; } return { isLoading: false, components, }; }, [extensionPointId, limitPerPlugin, pluginContext, registryState]); }