Timepicker values in scripted dashboards

How does the javascript in a scripted dashboard pick up the latest set value of the timepicker? It can pick up ARGS.to and ARGS.from, but only the value on the url that was used to load the page. When you select a different time frame, it doesn’t seem to pick it up. Also, I need the graphs to refresh when the timepicker is changed. Essentially, I have the same questions as this person: https://groups.io/g/grafana/topic/3305655?p=,,,20,0,0,0::,,,0,0,0,3305655 Thanks

Also, the timepicker values don’t seem to work with templating variables in the scripted dashboard. The $timeFilter is undefined in the templating queries in scripted dashboard. How can I get this to work?


So this should work, since the script is only used to create the dashboard it should not affect the time picker functionality.

Are you sure that your query is properly working? Are there any errors? (How to troubleshoot metric query issues)

Thanks for your help. The timepicker works great both on initial load and after adjustment on queries set as a target to a panel. There are two cases where it is not working:

First, with queries associated with template variables.

Second, with queries performed inline in the script (ie. not set as panel targets, but posted and parsed manually within the javascript).

To help explain these two problems, please see dashboard code below. Look especially for the comments which start with the substring “PROBLEM:” There are two such comments. The first is in the “getTemplating” function and the second one is in the “getRouterTotalByDataSourceId” function.

Thank you again for your help.

/* global _ */

'use strict';

// accessible variables in this scope
var window, document, ARGS, $, jQuery, moment, kbn;
// Setup some variables
var dashboard;

// All url parameters are available via the ARGS object
var ARGS;

// Initialize a skeleton with nothing but a rows array and service object
dashboard = {
  rows : [],

// Set a title
dashboard.title = 'Networking Team Daily Dashboard';

// Set default time
// time can be overridden in the url using from/to parameters, but this is
// handled automatically in grafana core during dashboard initialization
dashboard.time = {
  from: "now-6h",
  to: "now"

var rows = 1;
var seriesName = 'argName';

if(!_.isUndefined(ARGS.rows)) {
  rows = parseInt(ARGS.rows, 10);

if(!_.isUndefined(ARGS.name)) {
  seriesName = ARGS.name;

var stack = "test";
var regions = ["lon6r1", "tuk6r2", "tuk6r1"];

/////////////////////BEGIN FUNCTIONS//////////////////////
function getTemplating() {
  var templating = {"list":[]};
  for (var i=0;i<regions.length;i++) {
      var aVar = {
          "allValue": null,
          "current": {
            "text": "All",
            "value": "All"
          "definition": "high_cpu_host_definition",
          "includeAll": true,
          "multi": true,
          "query": "select \"host\" from (select bottom(\"bottom\",3),\"host\" from (select bottom(\"usage_idle\",1),\"host\" from cpu where  \"cpu\" = 'cpu0' and time>now()-6h group by \"host\"))",
          // PROBLEM: query below fails with $timeFilter on a scripted dashboard.
          // It seems like it doesn't know what $timeFilter is.  Probably not intialized when executed..
          // Note, the $timeFilter works with  template vars fine in non-scripted dashboards.
          // As a result, I have to use the hard coded 'time>now()-6h' above in scripted dashboards.
          // Of course, this will not work in real use; the template var queries need to work with
          // the timepicker in my scripted dashboards.
          //"query": "select \"host\" from (select bottom(\"bottom\",3),\"host\" from (select bottom(\"usage_idle\",1),\"host\" from cpu where  \"cpu\" = 'cpu0' and $timeFilter group by \"host\"))",
          "refresh": 2,
          "type": "query",
    aVar["datasource"] = stack + "/"+regions[i]+"-virtual_gateway_router";
    aVar["label"] = "high_cpu_hosts_" + regions[i];
    aVar["name"] = "high_cpu_hosts_" + regions[i];
  return templating;
function getRouterUsedPercentageTargets() {
  var allTargets = [];
  for (var i = 0; i<regions.length; i++) {
    var oneTarget = {
          "groupBy": [
              "params": [
              "type": "time"
          "measurement": "PerformanceMetrics",
          "query": "SELECT 100-mean(\"value\") FROM \"PerformanceMetrics\" WHERE (\"metric_id\" = 'router_free_percentage') AND $timeFilter GROUP BY time($__interval) fill(null)",
          "rawQuery": true,
    oneTarget["alias"] = regions[i];
    oneTarget["datasource"] = stack + "/" + regions[i] + "-networkadmin";
  return allTargets;

function getHighCPUVGRPanels() {
  var highCPUVGRPanels = [];

  for (var i = 0; i<regions.length; i++) {
    var highCPUVGRPanel = {};
    highCPUVGRPanel['type'] = "graph";
    highCPUVGRPanel['targets'] = [{"rawQuery":Boolean(1), "query" : "SELECT 100-mean(\"usage_idle\") FROM \"cpu\" WHERE (\"host\" =~ /^$high_cpu_hosts_daa1r1$/) AND $timeFilter GROUP BY time($__interval),\"host\" fill(null)"}];

    highCPUVGRPanel["title"] = regions[i] + "; High CPU VGR";
    highCPUVGRPanel["datasource"] = stack + "/" + regions[i] + "-virtual_gateway_router";
    highCPUVGRPanel["id"] = 300+i;
    highCPUVGRPanel["targets"][0]["query"] = "SELECT 100-mean(\"usage_idle\") FROM \"cpu\" WHERE (\"host\" =~ /^$high_cpu_hosts_"+regions[i]+"$/) AND $timeFilter GROUP BY time($__interval),\"host\" fill(null)",
  return highCPUVGRPanels;

function getRouterPanel(title, dataArray) {
  var txt = "";
  for (var i=0;i<dataArray.length; i++) {
    txt = txt + dataArray[i].toString() + ',';
  var customTarget = {
          "scenarioId": "csv_metric_values",
          "stringInput": txt 
  var routerPanel = {};
  routerPanel['title'] = title;
  routerPanel['type'] = 'graph';
  routerPanel['datasource'] = 'TestData DB';
  routerPanel['targets'] = [customTarget];
  routerPanel['span'] = 12;
  return routerPanel;

function getDatasourceToIdMap(regions) {
    var regionToDataSourceMap = {};
    var data_sources_search_url = 'http://'+location.hostname+':'+location.port+'/api/datasources';
    var results = [];
    var request = new XMLHttpRequest();
    request.open('GET', data_sources_search_url, false);
    var obj = JSON.parse(request.responseText);
    for (var i = 0; i < obj.length; i++) {
        regionToDataSourceMap[obj[i]['name']] = obj[i]['id'];
    return regionToDataSourceMap;

function getRouterTotalByDataSourceId(dataSourceId) {
    var points = [];
    // PROBLEM: ARGS is correct here the first time the page loads.  But when the timepicker is adjusted,
    // the new values are not not updated.  I need the ARGS to be updated here when I re-do the query
    // below. Because I don't get updated ARGS here when the timepicker is adjusted, I have to do a hard
    // coded timeframe in the query below.  I don't expect to get $timeFrame to work in the query below,
    // as I am submitting it to the grafana api manually and parsing the result.  If there is a way
    // to get $timeFrame to work in the query, great.  If not, I am fine as long as I have ARGS updated
    // here each time the timepicker is adjusted.  Of course, I am assuming this code gets re-executed
    // each time the timepicker is adjusted.
    // Why do I want to post my own query and parse it out manually instead of setting it as a panel target?
    // It is important for us to be able to query influxDB NOT as part of the target of a panel for 2 reasons.
    // First, some complex queries we want are NOT suppported by subqueries in influxDB, so they require
    // an initial query to compose the second query.  Second, for some queries we want to do post-query
    // manipulations on the data before we display it because, again, influxDB does not support 
    // all the manipulations we want within one query.  The query below is, admittedly, NOT an example
    // of either need.  Yes, the query below could easily be a target to a panel.  But in real use,
    // that is not the case.  See comment below on all_routers.
    var query = "SELECT \"value\" FROM \"PerformanceMetrics\" WHERE (\"metric_id\" = 'router_concurrent') AND time>now()-6h fill(null)";
    var queryEncoded = encodeURI(query);
    var search_url = 'http://'+location.hostname+':'+location.port+'/api/datasources/proxy/'+dataSourceId+'/query?pretty=true&db=networkadmin&q=' + queryEncoded; 
    var request = new XMLHttpRequest();
    request.open('GET', search_url, false);
    var obj = JSON.parse(request.responseText);
    // In this example, I hard code all_routers.  But in reality, I'll need to do a query first to find it 
    // first, which is why this query really can't be a target in a panel
    var all_routers = 300;
    for(var i=0;i<obj['results'][0]['series'][0]['values'].length;i++) {
        points.push(all_routers - parseInt(obj['results'][0]['series'][0]['values'][i][1]));
    return points;
function getRouterAvailablePanels(regions) {
    var panels = [];
    var datasourceToIdMap = getDatasourceToIdMap(regions);
    var datasourceToIdMapKeys = Object.keys(datasourceToIdMap);
    for(var i=0;i<regions.length;i++) {
        var dataSourceName = stack + '/' + regions[i] + '-networkadmin';
        var router_total_points = getRouterTotalByDataSourceId(datasourceToIdMap[dataSourceName]);
        panels.push( getRouterPanel(regions[i] + '; Router Available', router_total_points));
    return panels;

/////////////////////END FUNCTIONS//////////////////////

dashboard.templating = getTemplating();
dashboard.rows.push( {'panels' : getHighCPUVGRPanels()} );
dashboard.rows.push( {'panels' : getRouterAvailablePanels(regions) } );

return dashboard;

Part of the problem with the timepicker values and template vars is probably that the refresh definition that I specify in my script seems to be lost.

I specify “refresh”: 2. That is for refresh on time range change, which is necessary for the timepicker
to work with template vars, as described here:

However, when the script is executed, that value is lost, and the final dashboard that loads in grafana has “refresh”: 1.

So, the correct value that I specify, as advised in the github post above, is lost in script execution. This sounds like a bug.