Dashboards & Visualizations

How to create a table row expansion?

aru949
Explorer

Hi
I have a table like this :

aru949_0-1679757909946.png

What I want to do is when I click on the "Test Case" value of a particular row, it should expand that row ( if possible only that particular cell) and display a table like this:

aru949_1-1679758064970.png

Also I am using token (when clicking on the Test Case) to pass value to the second table. Any help would be appreciated 

0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@aru949 

Please see my this answer. I hope this will help you.

https://community.splunk.com/t5/Building-for-the-Splunk-Platform/Table-row-expansion-with-dynamic-se...

 

Thanks
KV
If any of my replies help you to solve the problem Or gain knowledge, an upvote would be appreciated.

 

aru949
Explorer

I tried using this approach but it's getting a bit complicated for me as I'm new to splunk and it didn't work

0 Karma

aru949
Explorer

How to handle the tokens in the query?

require([
    'splunkjs/mvc/tableview',
    'splunkjs/mvc/chartview',
    'splunkjs/mvc/searchmanager',
    'splunkjs/mvc',
    'underscore',
    'splunkjs/mvc/simplexml/ready!'
], function(
    TableView,
    ChartView,
    SearchManager,
    mvc,
    _
) {
    console.log("HIe");
    var CustomRangeRenderer = TableView.BaseCellRenderer.extend({
        canRender: function(cell) {
            return cell.field;
        },
        render: function($container, rowData) {
            console.log(rowData.value);
            if (rowData.field === "Test Case") {
                $container.html(rowData.value.split("@@")[0])
            } else {
                $container.html(rowData.value)
            }
        }
    });
    var EventSearchBasedRowExpansionRenderer = TableView.BaseRowExpansionRenderer.extend({
        initialize: function(args) {
            // initialize will run once, so we will set up a search and a chart to be reused.
            this._searchManager = new SearchManager({
                preview: false
            }, { tokens: true, tokenNamespace: "submitted" });
            //this._chartView = new ChartView({
            //    managerid: 'details-search-manager',
            //    'charting.legend.placement': 'none'
            //});
            this._TableView = new TableView({
                managerid: this._searchManager.name,
                drilldown: 'cell'
            });
        },

        canRender: function(rowData) {
            // Since more than one row expansion renderer can be registered we let each decide if they can handle that
            // data
            // Here we will always handle it.
            return true;
        },

        render: function($container, rowData) {
            // rowData contains information about the row that is expanded.  We can see the cells, fields, and values
            // We will find the sourcetype cell to use its value
            var processCell = _(rowData.cells).find(function(cell) {
                return cell.field === 'Test Case';
            });

                //update the search with the sourcetype that we are interested in
                // this._searchManager.set({ search: 'index= "' + processCell.value + '" ' });
            value = processCell.value.split("@@")
            value = value[value.length - 1];
            this._searchManager.set({ search: 'index="fakt-remote" splunk_id=$splunk_id$ | spath output=meta_data path=campaign_test_case_meta_data{} | mvexpand meta_data | eval _raw=meta_data| kv | rename testcases{}.codec_type as "Codec Type" testcases{}.bit_rate as Bitrate testcases{}.mode as Mode testcases{}.level as Level testcases{}.pl_rate as "PL Rate" testcases{}.jitter as Jitter testcases{}.call_type as "Call Type" testcases{}.test_mode as "Test Mode" | search testcases{}.test_case_name = $name$ | table "Codec Type" Bitrate Mode Level "PL Rate" Jitter "Call Type" "Test Mode"'});

            // $container is the jquery object where we can put out content.
            // In this case we will render our chart and add it to the $container
            //$container.append(this._chartView.render().el);
            $container.append(this._TableView.render().el);
        }
    });

    var tableElement = mvc.Components.getInstance("expand_with_events");
    tableElement.getVisualization(function(tableView) {
        // Add custom cell renderer, the table will re-render automatically.
        tableView.table.addCellRenderer(new CustomRangeRenderer());
        tableView.render();
        tableView.addRowExpansionRenderer(new EventSearchBasedRowExpansionRenderer());
    });
});
0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@aru949 

Your code looks good to me. Maybe you need to do some changes in the table search. Can you please share your sample dashboard XML?

Sharing my Samlpe XML.

<dashboard script="expand_with_events.js">
  <label>expand_with_events</label>
  <row>
    <panel>
      <table id="expand_with_events">
        <search>
          <query>index="_internal" | stats count by source | eval "Test Case" = source. "@@". count</query>
          <earliest>-1w@w1</earliest>
          <latest>@w1</latest>
        </search>
        <option name="drilldown">row</option>
        <option name="refresh.display">progressbar</option>
        <drilldown>
          <condition></condition>
        </drilldown>
      </table>
    </panel>
  </row>
</dashboard>

 

Screenshot

Screenshot 2023-03-27 at 11.31.48 AM.png

 

Thanks
KV
If any of my replies help you to solve the problem Or gain knowledge, an upvote would be appreciated.

0 Karma

aru949
Explorer
<form version="1.1" script="a13.js">
  <label>Detailed Campaign Classic</label>
  <fieldset submitButton="false">
    <input type="dropdown" token="campaign">
      <label>Campaign Selected</label>
      <choice value="*">All</choice>
      <fieldForLabel>campaign_name</fieldForLabel>
      <fieldForValue>campaign_name</fieldForValue>
      <search>
        <query>index="fakt-remote" 
| search splunk_id=$splunk_id$
| spath output=testcase path=campaign_kpi_metrics{}
| mvexpand testcase | eval _raw=testcase | kv
| stats count by campaign_name</query>
      </search>
      <default>$campaign$</default>
    </input>
    <input type="dropdown" token="verdict" searchWhenChanged="true">
      <label>Verdict</label>
      <search>
        <query/>
      </search>
      <choice value="*">All</choice>
      <choice value="Passed">Passed</choice>
      <choice value="Failed">Failed</choice>
      <default>$verdict$</default>
    </input>
  </fieldset>
  <row depends="$hidden$">
    <panel>
      <html>
        <style>
          td {
           line-height: 50px !important;
          }
        </style>
      </html>
    </panel>
  </row>
  <row>
    <panel>
      <table id="expand_with_events">
        <search>
          <query>index="fakt-remote" splunk_id=$splunk_id$
| spath output=testcase path=campaign_kpi_metrics{}
| mvexpand testcase | eval _raw=testcase | kv
| rename testcases{}.verdict as Verdict, testcases{}.name as "Test Case" testcases{}.min_polqa as min_polqa testcases{}.min_polqa_thres as min_polqa_thres testcases{}.avg_polqa as avg_polqa testcases{}.avg_polqa_thres as avg_polqa_thres testcases{}.max_polqa as max_polqa testcases{}.max_polqa_thres as max_polqa_thres
| eval "Minimum / Threshold" = min_polqa." / ".min_polqa_thres, "Average / Threshold" = avg_polqa." / ".avg_polqa_thres, "Maximum / Threshold" = max_polqa." / ".max_polqa_thres
| search Verdict=$verdict$ campaign_name=$campaign$
| table "Test Case" "Minimum / Threshold" "Average / Threshold" "Maximum / Threshold" Verdict</query>
          <earliest>0</earliest>
          <latest></latest>
          <sampleRatio>1</sampleRatio>
        </search>
        <option name="count">100</option>
        <option name="dataOverlayMode">none</option>
        <option name="drilldown">none</option>
        <option name="percentagesRow">false</option>
        <option name="rowNumbers">false</option>
        <option name="totalsRow">false</option>
        <option name="wrap">true</option>
        <format type="color" field="Verdict">
          <colorPalette type="map">{"Passed":#118832,"Failed":#D41F1F}</colorPalette>
        </format>
      </table>
    </panel>
  </row>
</form>
0 Karma

aru949
Explorer

Here is my js file

require([
    'splunkjs/mvc/tableview',
    'splunkjs/mvc/chartview',
    'splunkjs/mvc/searchmanager',
    'splunkjs/mvc',
    'underscore',
    'splunkjs/mvc/simplexml/ready!'
], function(
    TableView,
    ChartView,
    SearchManager,
    mvc,
    _
) {
    console.log("HIe");
    var CustomRangeRenderer = TableView.BaseCellRenderer.extend({
        canRender: function(cell) {
            return cell.field;
        },
        render: function($container, rowData) {
            console.log(rowData.value);
            $container.html(rowData.value)
        }
    });
    var EventSearchBasedRowExpansionRenderer = TableView.BaseRowExpansionRenderer.extend({
        initialize: function(args) {
            // initialize will run once, so we will set up a search and a chart to be reused.
            this._searchManager = new SearchManager({
                preview: false
            }, { tokens: true, tokenNamespace: "submitted" });
            //this._chartView = new ChartView({
            //    managerid: 'details-search-manager',
            //    'charting.legend.placement': 'none'
            //});
            this._TableView = new TableView({
                managerid: this._searchManager.name,
                drilldown: 'cell'
            });
        },

        canRender: function(rowData) {
            // Since more than one row expansion renderer can be registered we let each decide if they can handle that
            // data
            // Here we will always handle it.
            return true;
        },

        render: function($container, rowData) {
            // rowData contains information about the row that is expanded.  We can see the cells, fields, and values
            // We will find the sourcetype cell to use its value
            var processCell = _(rowData.cells).find(function(cell) {
                return cell.field === 'Test Case';
            });

                //update the search with the sourcetype that we are interested in
                // this._searchManager.set({ search: 'index= "' + processCell.value + '" ' });
            value = processCell.value
            // value = value[value.length - 1];
            var tokens = mvc.Components.get("default")
            var id = tokens.get("splunk_id")
            this._searchManager.set({ search: 'index="fakt-remote" splunk_id="' + id + '" | spath output=meta_data path=campaign_test_case_meta_data{}.testcases{} | mvexpand meta_data | eval _raw=meta_data| kv | search test_case_name="' + value + '" | rename bit_rate as Bitrate call_type as "Call Type" codec_type as "Codec Type" delay as Delay disabled as Disabled dtx as DTX inp_file as "Input File" jitter as Jitter level as Level mode as Mode pl_rate as "PL Rate" polqa_iteration as "POLQA Iteration" ref_file as "Reference File" test_mode as "Test Mode" video as Video | table Bitrate "Call Type" "Codec Type" Delay Disabled DTX "Input File" Jitter Level Mode "PL Rate" "POLQA Iteration" "Reference File" "Test Mode" Video | eval name="Values" | transpose 0 header_field=name | rename column as Parameter'});

            // $container is the jquery object where we can put out content.
            // In this case we will render our chart and add it to the $container
            //$container.append(this._chartView.render().el);
            $container.append(this._TableView.render().el);
        }
    });

    var tableElement = mvc.Components.getInstance("expand_with_events");
    tableElement.getVisualization(function(tableView) {
        // Add custom cell renderer, the table will re-render automatically.
        tableView.table.addCellRenderer(new CustomRangeRenderer());
        tableView.render();
        tableView.addRowExpansionRenderer(new EventSearchBasedRowExpansionRenderer());
    });
});
0 Karma

aru949
Explorer

Im not able to click on the page 2 or Next in the expanded row

aru949_0-1679911640113.png

 

0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@aru949 

Your JS looks good and working fine.

 

Screenshot 2023-03-30 at 11.13.06 AM.png

 

I'm sharing js and XML both. Can you please create a new dashboard with it and trace back your code?

 

require([
    'splunkjs/mvc/tableview',
    'splunkjs/mvc/chartview',
    'splunkjs/mvc/searchmanager',
    'splunkjs/mvc',
    'underscore',
    'splunkjs/mvc/simplexml/ready!'
], function(
    TableView,
    ChartView,
    SearchManager,
    mvc,
    _
) {
    console.log("HIe");
    var CustomRangeRenderer = TableView.BaseCellRenderer.extend({
        canRender: function(cell) {
            return cell.field;
        },
        render: function($container, rowData) {
            console.log(rowData.value);
            $container.html(rowData.value)
        }
    });
    var EventSearchBasedRowExpansionRenderer = TableView.BaseRowExpansionRenderer.extend({
        initialize: function(args) {
            // initialize will run once, so we will set up a search and a chart to be reused.
            this._searchManager = new SearchManager({
                preview: false
            }, { tokens: true, tokenNamespace: "submitted" });
            //this._chartView = new ChartView({
            //    managerid: 'details-search-manager',
            //    'charting.legend.placement': 'none'
            //});
            this._TableView = new TableView({
                managerid: this._searchManager.name,
                drilldown: 'cell'
            });
        },

        canRender: function(rowData) {
            // Since more than one row expansion renderer can be registered we let each decide if they can handle that
            // data
            // Here we will always handle it.
            return true;
        },

        render: function($container, rowData) {
            // rowData contains information about the row that is expanded.  We can see the cells, fields, and values
            // We will find the sourcetype cell to use its value
            var processCell = _(rowData.cells).find(function(cell) {
                return cell.field === 'Test Case';
            });

                //update the search with the sourcetype that we are interested in
                // this._searchManager.set({ search: 'index= "' + processCell.value + '" ' });
            value = processCell.value
            // value = value[value.length - 1];
            var tokens = mvc.Components.get("default")
            var id = tokens.get("splunk_id")
            this._searchManager.set({ search: '|makeresults count=100 | eval a="A", value="'+value+'",c=1 | accum c '});

            // $container is the jquery object where we can put out content.
            // In this case we will render our chart and add it to the $container
            //$container.append(this._chartView.render().el);
            $container.append(this._TableView.render().el);
        }
    });

    var tableElement = mvc.Components.getInstance("expand_with_events");
    tableElement.getVisualization(function(tableView) {
        // Add custom cell renderer, the table will re-render automatically.
        tableView.table.addCellRenderer(new CustomRangeRenderer());
        tableView.render();
        tableView.addRowExpansionRenderer(new EventSearchBasedRowExpansionRenderer());
    });
});

 

<dashboard script="expand_with_events.js">
  <label>expand_with_events</label>
  <row>
    <panel>
      <table id="expand_with_events">
        <search>
          <query>index="_internal" | stats count by source | eval "Test Case" = source. "@@". count</query>
          <earliest>-1w@w1</earliest>
          <latest>@w1</latest>
        </search>
        <option name="drilldown">row</option>
        <option name="refresh.display">progressbar</option>
        <drilldown>
          <condition></condition>
        </drilldown>
      </table>
    </panel>
  </row>
</dashboard>

 

Thanks
KV
If any of my replies help you to solve the problem Or gain knowledge, an upvote would be appreciated.

 

0 Karma
Get Updates on the Splunk Community!

Routing logs with Splunk OTel Collector for Kubernetes

The Splunk Distribution of the OpenTelemetry (OTel) Collector is a product that provides a way to ingest ...

Welcome to the Splunk Community!

(view in My Videos) We're so glad you're here! The Splunk Community is place to connect, learn, give back, and ...

Tech Talk | Elevating Digital Service Excellence: The Synergy of Splunk RUM & APM

Elevating Digital Service Excellence: The Synergy of Real User Monitoring and Application Performance ...