mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* feat: add a reactive extension registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: add hooks to work with the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: start using the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "command palette" extension point to use the hook * feat: update the "alerting" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "explore" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "datasources config" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "panel menu" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "pyroscope datasource" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "user profile page" extension point to use the hooks * chore: update betterer * fix: update the hooks to not re-render unnecessarily * chore: remove the old `createPluginExtensionRegistry` impementation * chore: add "TODO" for `PanelMenuBehaviour` extension point * feat: update the return value of the hooks to contain a `{ isLoading }` param * tests: add more tests for the usePluginExtensions() hook * fix: exclude the cloud-home-app from being non-awaited * refactor: use uuidv4() for random ID generation (for the registry object) * fix: linting issue * feat: use the hooks for the new alerting extension point * feat: use `useMemo()` for `AlertInstanceAction` extension point context --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
55 lines
1.9 KiB
TypeScript
55 lines
1.9 KiB
TypeScript
import { useObservable } from 'react-use';
|
|
|
|
import { PluginExtension } from '@grafana/data';
|
|
import { GetPluginExtensionsOptions, UsePluginExtensionsResult } from '@grafana/runtime';
|
|
|
|
import { getPluginExtensions } from './getPluginExtensions';
|
|
import { ReactivePluginExtensionsRegistry } from './reactivePluginExtensionRegistry';
|
|
|
|
export function createPluginExtensionsHook(extensionsRegistry: ReactivePluginExtensionsRegistry) {
|
|
const observableRegistry = extensionsRegistry.asObservable();
|
|
const cache: {
|
|
id: string;
|
|
extensions: Record<string, { context: GetPluginExtensionsOptions['context']; extensions: PluginExtension[] }>;
|
|
} = {
|
|
id: '',
|
|
extensions: {},
|
|
};
|
|
|
|
return function usePluginExtensions(options: GetPluginExtensionsOptions): UsePluginExtensionsResult<PluginExtension> {
|
|
const registry = useObservable(observableRegistry);
|
|
|
|
if (!registry) {
|
|
return { extensions: [], isLoading: false };
|
|
}
|
|
|
|
if (registry.id !== cache.id) {
|
|
cache.id = registry.id;
|
|
cache.extensions = {};
|
|
}
|
|
|
|
// `getPluginExtensions` will return a new array of objects even if it is called with the same options, as it always constructing a frozen objects.
|
|
// Due to this we are caching the result of `getPluginExtensions` to avoid unnecessary re-renders for components that are using this hook.
|
|
// (NOTE: we are only checking referential equality of `context` object, so it is important to not mutate the object passed to this hook.)
|
|
const key = `${options.extensionPointId}-${options.limitPerPlugin}`;
|
|
if (cache.extensions[key] && cache.extensions[key].context === options.context) {
|
|
return {
|
|
extensions: cache.extensions[key].extensions,
|
|
isLoading: false,
|
|
};
|
|
}
|
|
|
|
const { extensions } = getPluginExtensions({ ...options, registry });
|
|
|
|
cache.extensions[key] = {
|
|
context: options.context,
|
|
extensions,
|
|
};
|
|
|
|
return {
|
|
extensions,
|
|
isLoading: false,
|
|
};
|
|
};
|
|
}
|