Need to refresh a "Business Charts" panel from within panel itself using JavaScript

Grafana v11.2.2 (c47b921ef4)

I built a Dashboard with a “Business Charts” (Apache EChart) Graph panel. The graph visualizes a status of the jobflow for several environments. Postgres is used as a datasource. Information about nodes and edges is stored in separate tables. This part - drawing graph works well, no complaints.
There are two Dashboard variables: “env” and “batch_dt”. Correspondingly there are 2 drop-down combos that let me change env and date. This works smoothly.
I want to make this Dashboard more tailored to my needs. I am adding dozen of buttons (one per each environment). They will have two functions:

  1. indicate the overall status of the environment (button is green if everything is ok, red - if there is an issue)
  2. serve as a quick switch between environments.

I tried several methods: HTML panel, Text panel. I was able to make it work with the Text panel. See screenshot below. Text panel on the left, Business Chart on the right.

Indeed it switches to the right environment on a button click and sets proper URL. However, I am not happy. Every time I click a button in the Text panel the whole Dashboard (rather web page) is reloaded.

http_here://agas01:3000/d/be1vhlg56tm9sf/02-jobflow?orgId=1&var-env=cox&var-batch_dt=2024-11-18&refresh=1m&editPanel=3

Partial HTML in Text panel:

<body>
    <div class="button-container">
        <!-- Buttons arranged in two columns -->
        <button class="button" onclick="handleClick(this, 'nea')">NEA</button>
        <button class="button" onclick="handleClick(this, 'cea')">CEA</button>
    </div>

    <script>
        function handleClick(button, newValue) {
            // Part 2: Update Grafana Dashboard Variable
            const currentUrl = new URL(window.location.href); // Get the current dashboard URL
            currentUrl.searchParams.set('var-env', newValue);

            // Reload the page with the updated variable to apply the change
            window.location.href = currentUrl.toString();
        }
    </script>
</body>

Reloading page is not very elegant solution. I would like only the affected (Business Chart) panel to refresh. I could not find the way to refresh a single panel from another panel.
I decided to try a different approach. Buttons were added to the Graph panel itself. I expected I would have more control over the panel state with this setup.

I tired to use different methods but nothing seems working. Here are some methods I have tried to handle button click event.

// Working. Full page reload. Not exactly what I need

function handleButtonClick(buttonEnv) {
  const variableName = 'var-env';
  const newValue = `${buttonEnv}`;

  const currentUrl = new URL(window.location.href); // Get the current dashboard URL
  currentUrl.searchParams.set('var-env', newValue);
  window.location.href = currentUrl.toString();
}
  
// method 2. not working

function handleButtonClick(buttonEnv) {
  const variableName = 'var-env';
  const newValue = `${buttonEnv}`;
  const currentUrl = new URL(window.location.href);
  currentUrl.searchParams.set('var-env', newValue);  // Update the variable in the URL
  // Change the URL without reloading the page
  window.history.pushState({}, '', currentUrl.toString());

  // Optionally trigger a refresh of the panels if needed
  const event = new Event('grafana-variable-changed');
  window.dispatchEvent(event);
}

Besides I found some info that the refresh() or runQuery() methods can be used but I have no idea how.
There were some ideas about using angular but support for angular will be dropped in Grafana 12.

I do not see any errors in the console when adding console.log() with different arguments through the code.
I can’t list all Community post I went through but looks like I am not the only one who is looking for solution.
I am open to ideas.

@unclegasya EventBus may work in your case. Check out one of our blogs:

Thank you Mikhail.

I think I have made some progress. I created a Publisher and a Subscriber. A test button creates an event and the Subscriber responds with some action.
Missing last part - chart is not loading new data and is not refreshing.
Here is my code.

// Subscriber: Listen for variable updates and refresh panel
const subscription = context.grafana.eventBus.subscribe(
  { type: 'variables-changed-in-url' },
  (event) => {
    console.log(`Variable ${event.payload.name} updated to ${event.payload.value}`);

    // Force the chart to rerun its query
    if (context.panel) {
      console.log('Triggering query execution.');
      context.panel.queryRunner && context.panel.queryRunner.run();

      // Optionally trigger a panel refresh
      context.panel.refresh();
      console.log('Panel refresh triggered.');
    }
  }
);

// Publisher: Update variable and publish event
const updateVariable = () => {
  // Update URL variable (ensures Grafana syncs the change)
  const currentUrl = new URL(window.location.href); // Get the current dashboard URL
  const variableName = 'env'; // Variable to update
  const newValue = 'ney'; // New value for the variable

  console.log('Old value:', currentUrl.searchParams.get(`var-${variableName}`));
  currentUrl.searchParams.set(`var-${variableName}`, newValue);
  window.history.pushState({}, '', currentUrl.toString());
  console.log('URL updated:', currentUrl.toString());

  // Publish event for the updated variable
  context.grafana.eventBus.publish({
    type: 'variables-changed-in-url',
    payload: {
      name: variableName,
      value: newValue,
    },
  });
  console.log('Event published: Variable updated!');
};


const switchButton = document.createElement('utton');
switchButton.innerText = 'Set env to ney';
// Set styles to make it float
switchButton.style.position = 'fixed';
switchButton.style.bottom = '20px';
switchButton.style.left = '20px';
switchButton.style.padding = '10px 20px';
switchButton.style.width = '150px';
switchButton.style.height = '40px';
switchButton.style.backgroundColor = '#007bff';
switchButton.style.color = '#fff';
switchButton.style.border = 'none';
switchButton.style.borderRadius = '5px';
switchButton.style.cursor = 'pointer';
// switchButton.style.boxShadow = '0px 4px 8px rgba(0, 0, 0, 0.2)';
switchButton.onclick = updateVariable;
context.panel.chart.getDom().appendChild(switchButton);

... and at the very bottom of return

      data: nodes,
      edges: connections
    }
  ],
  unsubscribe: () => {
    subscription.unsubscribe();
    console.log("Unsubscribed");
  },
};

Button is as simple as possible: it switches current ‘env’ value to predefined ‘ney’.
Observing following in the console on button click.

Original URL:
http_here://agas01:3000/d/fe4n7qubip7gga/interpanel-01a?orgId=1&viewPanel=2&var-env=nea&var-batch_dt=2024-11-05
After button click:
http_here://agas01:3000/d/fe4n7qubip7gga/interpanel-01a?orgId=1&viewPanel=2&var-env=ney&var-batch_dt=2024-11-05

The test panel looks like below.


Two dashboard vars are defined and used in SELECT.
There are two SQL queries pulling nodes and edges from Postgres filtered by the dashboard vars.

SELECT * FROM nodes WHERE env = ‘$env’ AND batch_dt = ‘$batch_dt’;
SELECT * FROM edges WHERE batch_dt = ‘$batch_dt’ AND env = ‘$env’;

The part with the chart itself works, no complaints. Dynamic switch w/o refreshing whole webpage does not.

I wonder if I am missing Grafana/“Business Charts” philosophy how the data is pulled from the datasource and a chart gets refreshed. I am expecting once the url changed and queryRunner.run()/refresh() called the dashboard/panel will pull new data and redraw the chart.
Help me understand. I spent a lot of time on Grafana Crash Course | Volkov Labs for sure :wink:
Thank you.

Are you using the latest Business Charts 6.5.0 release? Dashboard refresh and variables functionality was updated in Grafana 11 and especially Scenes framework:

Variables events were updated, removed and not working in G11 anymore.