Making a dashboard with tabs (and searches that run when clicked)

In this post I am going to walk through how to make a dashboard with content separated into tabs. Not only will the content be divided into tabs, but the searches in the panels will not execute until the tabs are clicked. This prevents the dashboard from running all of the searches at once when the view is first opened.

Using tabs in this way serves two purposes:

  1. Prevent showing too much to a user all at once; a dashboard with more than 4 panels will require scrolling and may overwhelm the user
  2. Prevent too many searches from executing at once; this will improve load times, prevent time outs, and reduce load

The best way to walk through this tutorial is to download the sample app that I made and walk through each step. You can get the sample app here: tabs.tar.gz

Step 1: make your dashboard

The first step is to make your dashboard as you usually would. You can use Splunk’s UI to do this. Don’t worry about the tab logic yet, we will add that in later.

See the view titled “Step 1” in the tabs app to see the initial view.

So far, the view looks like this:

step1

 

This view has four panels, two of them are for the internal index and two are for non-internal indexes. I want to put the panels for internal and non-internal indexes in separate tabs.

Step 2: add the tab helper Javascript and CSS

I made some Javascript and CSS that will help you wire up the tabs. Go ahead and add it in. You can do this by copying the Javascript file “tabs.js” and “tabs.css” to the appserver/static directory of the app that has the view you want to add tabs to. For example, if the app is in the app “myapp”, then add the Javascript to “etc/apps/myapp/appserver/static/tabs.js” and the stylesheet to “etc/apps/myapp/appserver/static/tabs.css”. The files are available for download here:

Next, update your view to reference the css and js file. You can do this by declaring the script and stylesheet in the form or view tag. Here is an example:

<form script="tabs.js" stylesheet="tabs.css">

You will need to edit the source directly to make this change. Make sure to click “Edit source” in order to add this. You won’t notice any changes in your view yet even after you make the change. That’s ok, you will soon.

Step 3: declare your tabs

Now, lets add your tabs. You can do this by copying in a bit of HTML into your view. The tabs are going to be added in an html tag and the tabs themselves will be Bootstrap tabs (see the Bootstrap docs for details).

Put this just after your fieldset (or at the top if you have no fieldset tag). The top of my view now looks like this (changes in red):

<form script="tabs.js" stylesheet="tabs.css">
	<label>Tabs</label>
	<fieldset submitButton="true" autoRun="false">
	    <input type="time" token="field1" searchWhenChanged="false">
	      <label></label>
	      <default>
	        <earliest>-24h@h</earliest>
	        <latest>now</latest>
	      </default>
	    </input>
	</fieldset>
	<row id="tabs">
	   <panel>
	      <html>
	         <ul id="tabs" class="nav nav-tabs">
                    <li class="active">
                        <a href="#" class="toggle-tab" data-toggle="tab">Non-internal Indexes</a>
                    </li>
		    <li>
			<a href="#" class="toggle-tab" data-toggle="tab">Internal Index</a>
		    </li>
		 </ul>
	      </html>
	   </panel>
	</row>

This will make two Bootstrap tabs. The one named “Non-internal Indexes” is going to be the one that is shown by default since it has the “active” class associated with it.

Reload your view and you should find that you now have tabs! The tabs won’t do anything yet, we will wire them up next. The view should look something like this now:

step3

Step 4: wire up your tabs

Now, we will setup the tabs so that they show and hide the panels.

You will need to first set an id for each row that you want to be shown and hidden. To do this, just set the “id” to something that describes the tab. For example, I will name the first panel “tab_sourcetype” and the XML will look like this:

<row id="tab_sourcetype">

Do this for all of the panels that you want to be controlled by tabs. Then, create a “data-elements” attribute for each tab that indicates which rows to show and hide. The elements need to match exactly the id you set for each tab. Use a comma separated list if you have multiple rows that you want to be controlled by the tab. In my case, I have the following (note the “data-elements” attribute:

	<row id="tabs">
	   <panel>
	      <html>
	         <ul id="tabs" class="nav nav-tabs">
                    <li class="active">
                        <a href="#" class="toggle-tab" data-toggle="tab" data-elements="tab_source,tab_sourcetype">Non-internal Indexes</a>
                    </li>
		    <li>
		        <a href="#" class="toggle-tab" data-toggle="tab" data-elements="tab_source_internal,tab_sourcetype_internal">Internal Index</a>
		    </li>
		 </ul>
	      </html>
	    </panel>
	</row>

Once you reload the view, you should find that your tabs will show and hide the rows. The view will now look something like this:

step4

Step 5: wire up the tokens to prevent searches from running until the tab is clicked

This step is only required if you want to prevent the searches within the tabs from executing until the tab is clicked. To make this work, we are going to set some tokens that will only be defined when the tab is clicked. Splunk won’t try to run searches when the token isn’t defined and the tabs.js Javascript file won’t define the tokens until the tab is clicked. Thus, the searches won’t fire until the tab is clicked.

To make this work, first define a “data-token” attribute in each tab. Here are my tabs with the tokens defined:

	<row id="tabs">
	   <panel>
	      <html>
	         <ul id="tabs" class="nav nav-tabs">
                    <li class="active">
                        <a href="#" class="toggle-tab" data-toggle="tab" data-elements="tab_source,tab_sourcetype" data-token="control_token_non_internal">Non-internal Indexes</a>
                    </li>
		    <li>
			<a href="#" class="toggle-tab" data-toggle="tab" data-elements="tab_source_internal,tab_sourcetype_internal" data-token="control_token_internal">Internal Index</a>
		    </li>
		 </ul>
	      </html>
	   </panel>
	</row>

Next, add the the tokens to the searches. The name of the token should correspond to the tab that the search results will be available in. For example, I want the “Sourcetypes (internal)” and the “Source (internal)” panels to only execute when the “Internal Index” tab is clicked. Since the “Internal Index” tab has a token of “control_token_internal”, I’ll add that “control_token_internal” to the searches within that panel. Where you put the tokens doesn’t matter (the tokens are going to be removed when the searches run). You will need to surround them with dollar signs to denote them as tokens. In my case, the panels will look like this:

  <row id="tab_sourcetype_internal">
    <panel>
      <title>Sourcetypes (internal)</title>
      <table>
        <search>
          <query>| search * $control_token_internal$ index=_internal | stats count by sourcetype</query>
          <earliest>$field1.earliest$</earliest>
          <latest>$field1.latest$</latest>
        </search>
        <option name="count">10</option>
      </table>
    </panel>
  </row>
  
  <row id="tab_source_internal">
    <panel>
      <title>Source (internal)</title>
      <table>
        <search>
          <query>| search * $control_token_internal$ index=_internal | stats count by source</query>
          <earliest>$field1.earliest$</earliest>
          <latest>$field1.latest$</latest>
        </search>
        <option name="count">10</option>
      </table>
    </panel>
  </row>

Once you reload the view, you should find that the tokens for the panels will not execute until you click the tabs.

Wrapping up

I made a sample app that illustrates each step. Feel free to download the app and play around with it. Get the file here: tabs.tar.gz

How can i used this sample app in splunk 6.0.
I am getting error

400 Bad Request

XML Syntax Error: Cannot find object mapper for panel type: title

Rahul
April 23, 2015

Hey,
Thanks for the writeup I was able to get this working on one of my dashboards.

I think I found a bug though which I was able to reproduce in your uploaded app example.

This bug seems to happen if you have your dashboard panels using charts instead of tables. If you load the dashboard and start to click on the tabs before the search finishes one or more of the charts will only take up less than half of the panel space. Its as if it thinks there are more charts in the panel row which aren’t really there.

Joe Cramastra
May 1, 2015

As Joe said that bug exists, there is a solution to that bug or not?
Thanks for this precious help Luke!
Best regards,
João Amorim

João Amorim
June 16, 2015

Very nice description! Helped me a lot!

Kevin
July 3, 2015

Hi,
I was suffering from the same ‘half width’ issue as mentioned above. Try the following:

Source (internal)

| search * index=_internal | stats count by source
$field1.earliest$
$field1.latest$

10

ie remove ‘$control_token_internal$’ from the search and add it as ‘ depends=”$control_token_internal$”‘ within your or tag.

The added beauty of this is that A) you don’t have to alter your searches that may be running elsewhere and B)It works with scheduled reports (this was my requirement)

Let me know how you get on…

Chris Stevens
September 8, 2015

(my last attempt stripped all of the code markup out, replaced the brackets with square brackets)

Hi,
I was suffering from the same ‘half width’ issue as mentioned above. Try the following:

[row id=”tab_source_internal”]
[panel]
[title]Source (internal)[/title]
[table depends=”$control_token_internal$”]
[search]
[query]| search * index=_internal | stats count by source[/query]
[earliest]$field1.earliest$[/earliest]
[latest]$field1.latest$[/latest]
[/search]
[option name=”count”]10[/option]
[/table]
[/panel]
[/row]

ie remove ‘$control_token_internal$’ from the search and add it as ‘ depends=”$control_token_internal$”‘ within your [table] or [chart] tag.

The added beauty of this is that A) you don’t have to alter your searches that may be running elsewhere and B)It works with scheduled reports (this was my requirement)

Let me know how you get on…

PS. For future reference, how do I embed a code snippet in my comment without it stripping all the tags out?

Chris Stevens
September 8, 2015

Every time I try to load the tabs.js and tabs.css using , all my existing panels just stop working and say “Search is waiting for input…”. I have even tried to create a blank dashboard and add a generic panel and as soon as I add the script=”tabs.js” stylesheet=”tabs.css” it breaks.

Any reason for this, it seems to be related to having a open variable or something to that nature but I don’t know enough about it to troubleshoot it.

Shawn Nix
October 12, 2015

I just tested this; it reproduces for me too. I’ll take a look and get a fix out.

Update: actually, I’m not finding this to be a problem.

Luke Murphey
October 12, 2015

Luke –

Thanks for this post, I found it very helpful. I would advise including this in the “6.X dashboard examples” application.

Thanks!

Joel
November 12, 2015

Luke – Thanks for this useful write up. I found it very useful and in the latest Splunk version 6.3.1, the ‘half width’ problem did not occur for me. I created new dashboard following your steps. I guess the latest version had fixed these issues.

Murali
December 16, 2015

3 Trackbacks

  1. […] 1.首先去下载Splunk提供的tabs.js和tabs.css文件,链接在http://blogs.splunk.com/2015/03/30/making-a-dashboard-with-tabs-and-searches-that-run-when-clicked/ […]

  2. […] 1.首先去下载Splunk提供的tabs.js和tabs.css文件,链接在http://blogs.splunk.com/2015/03/30/making-a-dashboard-with-tabs-and-searches-that-run-when-clicked/ […]

  3. […] prevented searches from running at the same time. LukeMurphey formally composed his answer as an awesome blog post. Check it out! […]