How to subscribe to Grafana application events

If you’re building a panel plugin, Grafana already provides the data you need to configure and render your panel. If not, you can retrieve the information you need from any of the runtime services, like BackendSrv and TemplateSrv. In some cases though, you want your plugin to react to changes outside of your plugin. For example, when the user hovers their cursor over data in another panel. In this post, you’ll learn how to make your plugin react to events in Grafana.

Note: If you’ve previously built plugins using Angular, note that you don’t need to subscribe to render events to update your visualization in React. React components automatically re-renders whenever any of its dependencies has changed.

Grafana uses an event bus to publish application events to notify different parts of Grafana when the user performs an action. Your plugin can react to these actions by subscribing to one or more events.

Events are identified by a unique string, and can have an optional payload. In the following example the ZoomOutEvent is identified by the zoom-out string and carries a number as a payload.

class ZoomOutEvent extends BusEventWithPayload<number> {
  static type = 'zoom-out';
}

Here are a few other events you can subscribe to:

You can access the event bus available from the panel props, and subscribe to events of a certain type using the getStream() method. The callback passed to the subscribe method will be called for every new event.

import React, { useEffect } from 'react';
import { RefreshEvent } from '@grafana/runtime';

// ...

interface Props extends PanelProps<MyOptions> {}

export const MyPanel: React.FC<Props> = ({ eventBus }) => {
  useEffect(() => {
    const subscriber = eventBus.getStream(RefreshEvent).subscribe(event => {
      console.log(`Received event: ${event.type}`);
    })

    return () => {
      subscriber.unsubscribe();
    }
  }, [eventBus]);

  return <div>Event bus example</div>;
}

Important: Remember to call unsubscribe() your subscriber to avoid memory leaks.

Note that while many event types are available but not yet exported, such as the PanelEditEnteredEvent, you can still subscribe to them by re-implementing the event type yourself:

class MyPanelEditEnteredEvent extends BusEventWithPayload<number> {
  static type = 'panel-edit-started';
}

While there’s no official documentation of the supported events, you can figure out the available events by searching for static type = '.*'; in the Grafana repository.

We’ll be improving the event bus and adding more events in the future. Let me know how you’re using the event bus, and any events you think would be useful to your plugin!

3 Likes

Hi @marcusolsson ,

Thanks for writing an official documentation about events in Grafana.
I’ve followed step by step your sample and implemented on my grafana plugin panel. I’m trying to get all DataHoverEvents and LegacyGraphHoverEvent from others to my custom panel.

The thing is DataHoverEvents and LegacyGraphHoverEvent events are not firing.
I’ve fired a DataHoverEvent manually after X seconds for testing I am subscribing properly to these events and my subscription works, so the only thing I can assume is the events are not firing from panels.

I can check how the RefreshEvent is working properly but not the events I need.
I cannot see any kind of errors or any weird logs. The tooltip from panels is working but the event is not firing.

Why is happening this?

I am using docker-compose with:

  • Grafana: grafana:9.2.15-ubuntu
  • MySQL: mysql:latest

My code:

export const VideoPanel: React.FC<Props> = ({
	options,
	data,
	eventBus,
  }) => {

	const [timestampState, setTimestampState] = useState(-1);
	const [valueState, setValueState] = useState(-1);
 
  
	useEffect(() => {
  
	  const subscriber = eventBus.getStream(RefreshEvent).subscribe(event => {
		console.log(`Received event: ${event.type}`);
	  });
  
	  const subscriber2 = eventBus.getStream(DataHoverEvent).subscribe(event => {
		console.log(`Received event: ${event.type}`);
	  })
  
	  const subscriber3 = eventBus.getStream(LegacyGraphHoverEvent).subscribe(event => {
		console.log(`Received event: ${event.type}`);
	  })
  
	  return () => {
		subscriber.unsubscribe();
		subscriber2.unsubscribe();
		subscriber3.unsubscribe();

	  };
	}, [eventBus]);
  
	return (
	  <div className="video-panel" style={{ overflow: 'auto' }}>
  		  <div>
			<div>DATA event</div>  
			<div>Timestamp: {timestampState}</div>
			<div>Value: {valueState}</div>
		  </div>
	  </div>
	);
  };

Update:

The DataHoverEvent is only fired when I hover the legend, which is useless… I have attached a video for clarifying
grafana

1 Like

@csantosm You can check the Time Series panel code if there are any other events that are fired on hover.

Alternatively, look at the Apache ECharts panel, which supports event handling and can update environment variables using locationService or fire an event using the eventBus.