The Splunk Dev Blog by Luke Murphy provides details on Making a dashboard with tabs (and searches that run when clicked). It uses Simple XML CSS and JS extensions to create Tabs in Splunk Dashboard through Splunk Dashboard Tabs Example code shared on Github.
This question is more to document a different approach with the use of Splunk Link List input with CSS Override and Link List change event handler to make it appear and function like a Tab in Splunk. This does so without using JS
🙂
You can have many Link Lists within same Dashboard which implies many tabs within same Dashboard as per your need and implementation. Hope you find this useful 🙂
Following is a run anywhere example based on Splunk's _internal index.
Step 1. Create a panel with Link Input as per the requirement of tabs. In above example Sourcetype, Component, Log Level
are three tabs.
Step 2. Set the required token from Link input in SPL or through <change>
event handler of the Link Input to change SPL or hide/show panel using depends respectively. For simplicity, this example changes underlying SPL, there are several examples of depends/rejects on Splunk Docs, Blogs and Splunk Answers.
Step 3. Add <html>
panel with horizontal line <hr>
to mark border of Link input.
Step 4. Apply CSS override (can be through dashboard <style>
section for testing/simplicity or prebuilt-panel, or static CSS file)
PS: CSS applied as per 7.1.x + and may also need some tweaking for Dark Theme vs Light Theme (white Border is used in the Dark Theme example).
Following is the run anywhere dashboard example using Simple XML and CSS (NO JS REQUIRED)
. Please try out and let me know any feedback 🙂
<form theme="dark">
<label>Tabs using Links</label>
<!-- Base Search to Pull Error Data -->
<search id="bAllErrorData">
<query>index=_internal
| bin _time span=1h
| stats count by _time sourcetype component date_hour log_level
</query>
<earliest>$tokTime.earliest$</earliest>
<latest>$tokTime.latest$</latest>
</search>
<fieldset submitButton="false">
<input id="input_time" type="time" token="tokTime">
<label></label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
</fieldset>
<row>
<panel id="panel_layout">
<input id="input_link_split_by" type="link" token="tokSplit" searchWhenChanged="true">
<label></label>
<choice value="sourcetype">Sourcetype</choice>
<choice value="component">Component</choice>
<choice value="log_level">Log Level</choice>
<default>log_level</default>
</input>
<html>
<style>
/* This Layout Panel Bottom Padding removed to merge Link Input with horizontal line */
#panel_layout .fieldset{
padding: 10px 12px 0px 12px !important;
}
/* Increase width of Link input to have options in Single Line */
#input_link_split_by.input-link{
width: 720px !important;
}
/* Change from flex to -webkit-box for side by side layout */
#input_radio_split_by.input-link div[data-component="splunk-core:/splunkjs/mvc/components/LinkList"]{
display: -webkit-box !important;
}
/* Create Button Border to make them appear as Tabs */
#input_link_split_by.input-link button{
width: 120px !important;
border-top-color: rgb(255, 255, 255);
border-top-style: solid;
border-top-width: 1px;
border-right-color: rgb(255, 255, 255);
border-right-style: solid;
border-right-width: 1px;
border-left-color: rgb(255, 255, 255);
border-left-style: solid;
border-left-width: 1px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
/* Hide link input bottom message section to merge with Horizontal line */
.dashboard-panel #input_link_split_by label,
#input_link_split_by .splunk-choice-input-message{
display: none !important;
}
/* Remove padding from horizontal line */
#panel_layout .panel-body.html{
padding: 0px !important;
}
</style>
<hr style="height:1px;border-width:0;color: black;background-color: white;margin: 0px;"/>
</html>
</panel>
</row>
<row>
<panel id="panel_single_snapshot">
<html depends="$alwaysHideCSSOverrideForDashboard$">
<style>
#panel_chart_line_error_trend{
width: 70% !important;
}
#panel_chart_pie_error_split{
width: 30% !important;
}
/* Font Size Color Adjustment for Series Compare in Chart Legend */
div#chart_line_error_trending svg g.highcharts-legend g.highcharts-legend-item text tspan:nth-child(2){
font-size: 120% !important;
fill: cyan !important;
font-weight: bold !important;
}
/* Trellis Layout CSS */
#single_snapshot #facet-viz_groupby_field_log_level_groupby_value_INFO rect{
fill: #006D9C !important;
}
#single_snapshot #facet-viz_groupby_field_log_level_groupby_value_WARN rect{
fill: #F8BE34 !important;
}
#single_snapshot #facet-viz_groupby_field_log_level_groupby_value_WARNING rect{
fill: #F8BE34 !important;
}
#single_snapshot #facet-viz_groupby_field_log_level_groupby_value_ERROR rect{
fill: #DC4E41 !important;
}
</style>
</html>
<single id="single_snapshot">
<search base="bAllErrorData">
<query>
| stats count by $tokSplit|s$</query>
</search>
<option name="colorMode">block</option>
<option name="drilldown">none</option>
<option name="height">275</option>
<option name="rangeColors">["0x53a051","0x0877a6","0xf8be34","0xf1813f","0xdc4e41"]</option>
<option name="trellis.enabled">1</option>
<option name="trellis.size">small</option>
<option name="useColors">1</option>
</single>
</panel>
</row>
<row>
<panel id="panel_chart_line_error_trend">
<chart id="chart_line_error_trending">
<search base="bAllErrorData">
<query>
| timechart count by $tokSplit|s$</query>
</search>
<option name="charting.fieldColors">{"INFO":"#006D9C","WARN":"#F8BE34","WARNING":"#F8BE34","ERROR":"#DC4E41"}</option>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">area</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">zero</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">seriesCompare</option>
<option name="charting.legend.placement">right</option>
<option name="charting.lineWidth">2</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
<panel id="panel_chart_pie_error_split">
<chart id="chart_pie_errors">
<search base="bAllErrorData">
<query>
| stats count by $tokSplit|s$</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">zero</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.fieldColors">{"INFO":"#006D9C","WARN":"#F8BE34","WARNING":"#F8BE34","ERROR":"#DC4E41"}</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">seriesCompare</option>
<option name="charting.legend.placement">right</option>
<option name="charting.lineWidth">2</option>
<option name="refresh.display">progressbar</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
</row>
</form>
Hi, great job it looks good. However, when i click on different tabs, the presented charts don't change. Can you post an example so if I click on tab : 'compenent', I would see a different chart compared to clicking on tab:source type?
In addition, i do not really understand, can you explain please what is 'tokSplit'? and $tokSplit|s$? and how to define them?
thanks a lot!
Yes, when you click on the tab, it will execute the search. The token 'tokSplit' which is set on click of the tab is used in search which makes it execute. So when you change the tab, tokSplit token will be changed and the search with tokSplit token will execute. If your charts don't change means you need to define a tab-specific token that will be used in the search.
like, if tab = sourcetype then set tkn_sourcetype with " " values else unset tkn_sourcetype. do it for all tabs.
and just put tkn_sourcetype token in your chart search.
like, YOUR_SEARCH $tkn_sourcetype$
search login won't be impacted as tkn_sourcetype token value is " " (single space).
I hope this will help you.
Thanks
KV
If any of my replies help you to solve the problem Or gain knowledge, an upvote would be appreciated.
Hi,
Thanks for your reply. I need to create a dashboard with tabs (tab for different topic) without connection to tokens (and without JS script). I also need that because my dashboard performance is too slow, so maybe tabs will help.
I will try to set the token to "" (empty value) as you said.
can you write me an example please of where to set the token to:"" ?
and do you have an example maybe from a different post to my need? because now i need to add $toekn$ to my search when i don't need that.
thanks a lot
set " " (single space) instead of "" (empty). I don't have this example handy but you ask if you need help somewhere. Here I also suggest posting new questions to start a fresh thread.
KV
ok, thanks a lot!! 🙂
finally, i used this one:
https://community.splunk.com/t5/Dashboards-Visualizations/Is-there-a-way-to-implement-multiple-tabs-...
Following is a run anywhere example based on Splunk's _internal index.
Step 1. Create a panel with Link Input as per the requirement of tabs. In above example Sourcetype, Component, Log Level
are three tabs.
Step 2. Set the required token from Link input in SPL or through <change>
event handler of the Link Input to change SPL or hide/show panel using depends respectively. For simplicity, this example changes underlying SPL, there are several examples of depends/rejects on Splunk Docs, Blogs and Splunk Answers.
Step 3. Add <html>
panel with horizontal line <hr>
to mark border of Link input.
Step 4. Apply CSS override (can be through dashboard <style>
section for testing/simplicity or prebuilt-panel, or static CSS file)
PS: CSS applied as per 7.1.x + and may also need some tweaking for Dark Theme vs Light Theme (white Border is used in the Dark Theme example).
Following is the run anywhere dashboard example using Simple XML and CSS (NO JS REQUIRED)
. Please try out and let me know any feedback 🙂
<form theme="dark">
<label>Tabs using Links</label>
<!-- Base Search to Pull Error Data -->
<search id="bAllErrorData">
<query>index=_internal
| bin _time span=1h
| stats count by _time sourcetype component date_hour log_level
</query>
<earliest>$tokTime.earliest$</earliest>
<latest>$tokTime.latest$</latest>
</search>
<fieldset submitButton="false">
<input id="input_time" type="time" token="tokTime">
<label></label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
</fieldset>
<row>
<panel id="panel_layout">
<input id="input_link_split_by" type="link" token="tokSplit" searchWhenChanged="true">
<label></label>
<choice value="sourcetype">Sourcetype</choice>
<choice value="component">Component</choice>
<choice value="log_level">Log Level</choice>
<default>log_level</default>
</input>
<html>
<style>
/* This Layout Panel Bottom Padding removed to merge Link Input with horizontal line */
#panel_layout .fieldset{
padding: 10px 12px 0px 12px !important;
}
/* Increase width of Link input to have options in Single Line */
#input_link_split_by.input-link{
width: 720px !important;
}
/* Change from flex to -webkit-box for side by side layout */
#input_radio_split_by.input-link div[data-component="splunk-core:/splunkjs/mvc/components/LinkList"]{
display: -webkit-box !important;
}
/* Create Button Border to make them appear as Tabs */
#input_link_split_by.input-link button{
width: 120px !important;
border-top-color: rgb(255, 255, 255);
border-top-style: solid;
border-top-width: 1px;
border-right-color: rgb(255, 255, 255);
border-right-style: solid;
border-right-width: 1px;
border-left-color: rgb(255, 255, 255);
border-left-style: solid;
border-left-width: 1px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
/* Hide link input bottom message section to merge with Horizontal line */
.dashboard-panel #input_link_split_by label,
#input_link_split_by .splunk-choice-input-message{
display: none !important;
}
/* Remove padding from horizontal line */
#panel_layout .panel-body.html{
padding: 0px !important;
}
</style>
<hr style="height:1px;border-width:0;color: black;background-color: white;margin: 0px;"/>
</html>
</panel>
</row>
<row>
<panel id="panel_single_snapshot">
<html depends="$alwaysHideCSSOverrideForDashboard$">
<style>
#panel_chart_line_error_trend{
width: 70% !important;
}
#panel_chart_pie_error_split{
width: 30% !important;
}
/* Font Size Color Adjustment for Series Compare in Chart Legend */
div#chart_line_error_trending svg g.highcharts-legend g.highcharts-legend-item text tspan:nth-child(2){
font-size: 120% !important;
fill: cyan !important;
font-weight: bold !important;
}
/* Trellis Layout CSS */
#single_snapshot #facet-viz_groupby_field_log_level_groupby_value_INFO rect{
fill: #006D9C !important;
}
#single_snapshot #facet-viz_groupby_field_log_level_groupby_value_WARN rect{
fill: #F8BE34 !important;
}
#single_snapshot #facet-viz_groupby_field_log_level_groupby_value_WARNING rect{
fill: #F8BE34 !important;
}
#single_snapshot #facet-viz_groupby_field_log_level_groupby_value_ERROR rect{
fill: #DC4E41 !important;
}
</style>
</html>
<single id="single_snapshot">
<search base="bAllErrorData">
<query>
| stats count by $tokSplit|s$</query>
</search>
<option name="colorMode">block</option>
<option name="drilldown">none</option>
<option name="height">275</option>
<option name="rangeColors">["0x53a051","0x0877a6","0xf8be34","0xf1813f","0xdc4e41"]</option>
<option name="trellis.enabled">1</option>
<option name="trellis.size">small</option>
<option name="useColors">1</option>
</single>
</panel>
</row>
<row>
<panel id="panel_chart_line_error_trend">
<chart id="chart_line_error_trending">
<search base="bAllErrorData">
<query>
| timechart count by $tokSplit|s$</query>
</search>
<option name="charting.fieldColors">{"INFO":"#006D9C","WARN":"#F8BE34","WARNING":"#F8BE34","ERROR":"#DC4E41"}</option>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">area</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">zero</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">seriesCompare</option>
<option name="charting.legend.placement">right</option>
<option name="charting.lineWidth">2</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
<panel id="panel_chart_pie_error_split">
<chart id="chart_pie_errors">
<search base="bAllErrorData">
<query>
| stats count by $tokSplit|s$</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">zero</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.fieldColors">{"INFO":"#006D9C","WARN":"#F8BE34","WARNING":"#F8BE34","ERROR":"#DC4E41"}</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">seriesCompare</option>
<option name="charting.legend.placement">right</option>
<option name="charting.lineWidth">2</option>
<option name="refresh.display">progressbar</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
</row>
</form>
Great solution. Chipping in my 10 cents:
#input_link_split_by.input-link button[aria-checked="true"] {
background-color: green !important;
}
If you want to keep highlighted the last selection on the tabs to make it more visible
Do this solution provide load-on-click tab functionality?
Or is this purely cosmetic?
Thanks.
@niketn
Yes, when you click on tab. it will execute the search. The token 'tokSplit' which is set on click of tab is used in search which makes it execute. So if you are taking reference of this dashboard just take care of tokens.
Thanks
KV
▄︻̷̿┻̿═━一
If any of my reply helps you to solve the problem Or gain knowledge, an upvote would be appreciated.
This is a great post @niketn
The power of using in-panel CSS to manipulate the layout is amazing.
Thanks for this really useful post.
Thanks @bowesmana one of my recently published examples app for our upcoming Splunk .Conf20 session Itsy Bitsy App for Splunk shows two CSS overrides (on similar lines to create Tabs using Dashboard Names Navigation menu and Links within dashboard. Do check out the SplunkTrust track talk TRU1276C: Splunk dashboard journey: Past, Present and Future with amazing @cmerriman
Thanks! Great job!