Skip to main content

Use extension points for general functions

An extension point is a part of your plugin or Grafana UI where you can render content (links, functions or React components) from other plugins. Use them to extend your users' experience based on a context exposed by the extension point.

note

Read more about extensions under key concepts.
For reference documentation, including the APIs, see UI extensions reference guide.

Best practices for function extensions​

  • Share contextual information
    Think about what contextual information could be useful for other plugins and pass this as parameters to the function.
  • Handle errors
    Make sure to handle any errors that could be thrown by the function extensions.

Create an extension point for functions​

import { usePluginFunctions } from '@grafana/runtime';

export const MyComponent = () => {
// This is unique ID for your extension point.
// This is also what other plugins (content providers) use when they call `AppPlugin.addFunction({...})`
// - postfix the ID with a version number (in this example "/v1")
// - prefix the ID with your plugin id (in this example "myorg-foo-app/"),
// or with "grafana/" for core Grafana extension points
const extensionPointId = 'myorg-foo-app/myfunction/v1';
const { functions, isLoading } = usePluginFunctions({ extensionPointId });
const onClick = useCallback(() => {
functions.forEach((fn) => {
try {
fn();
} catch (err) {
// Handle errors here
}
});
}, [functions]);

if (isLoading) {
return <div>Loading...</div>;
}

return <Button onClick={onClick}>Click</Button>;
};

Passing data to the functions​

We are building on top of the previous example, but this time we are also passing some contextual data to the functions:

import { usePluginFunctions } from '@grafana/runtime';

// Exposing the type for better developer experience
// (Check the next section for how to share this type with other plugins)
export type Fn = (params: { activeProjectId: string }) => void;

export const MyComponent = () => {
const extensionPointId = 'myorg-foo-app/myfunction/v1';
const { projectId } = useActiveProject();
// Using the `Fn` type as a generic
const { functions, isLoading } = usePluginFunctions<Fn>({ extensionPointId });
const onClick = useCallback(() => {
functions.forEach((fn) => {
try {
fn({ activeProjectId: projectId });
} catch (err) {
// Handle errors here
}
});
}, [functions, projectId]);

if (isLoading) {
return <div>Loading...</div>;
}

return <Button onClick={onClick}>Click</Button>;
};

Limit which plugins can register functions in your extension point​

import { usePluginFunctions } from '@grafana/runtime';

export type Fn = (params: { activeProjectId: string }) => void;

export const MyComponent = () => {
const extensionPointId = 'myorg-foo-app/myfunction/v1';
const allowedPluginIds = ['myorg-a-app', 'myorg-b-app'];
const { projectId } = useActiveProject();
const { functions, isLoading } = usePluginFunctions<Fn>({ extensionPointId });
const onClick = useCallback(() => {
functions
.filter(({ pluginId }) => allowedPluginIds.includes(pluginId))
.forEach((fn) => {
try {
fn({ activeProjectId: projectId });
} catch (err) {
// Handle errors here
}
});
}, [functions, projectId]);

if (isLoading) {
return <div>Loading...</div>;
}

return <Button onClick={onClick}>Click</Button>;
};