Dashboards & Visualizations

How can we create Tabs using Link List in Splunk with only CSS Override NO SplunkXML JS Extension?

niketnilay
Legend

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 🙂

alt text

____________________________________________
| makeresults | eval message= "Happy Splunking!!!"
1 Solution

niketnilay
Legend

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).

alt text

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>
____________________________________________
| makeresults | eval message= "Happy Splunking!!!"

View solution in original post

niketnilay
Legend

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).

alt text

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>
____________________________________________
| makeresults | eval message= "Happy Splunking!!!"

View solution in original post

jacobandrews1
Observer

Do this solution provide load-on-click tab functionality?
Or is this purely cosmetic?

Thanks.

@niketnilay 

0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@jacobandrews1 

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.

0 Karma

bowesmana
Champion

This is a great post @niketnilay 

The power of using in-panel CSS to manipulate the layout is amazing. 

Thanks for this really useful post.

 

0 Karma

niketnilay
Legend

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 

____________________________________________
| makeresults | eval message= "Happy Splunking!!!"

kurdbahr
Path Finder

Thanks! Great job!

Register for .conf21 Now! Go Vegas or Go Virtual!

How will you .conf21? You decide! Go in-person in Las Vegas, 10/18-10/21, or go online with .conf21 Virtual, 10/19-10/20.