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!

Built-in Service Level Objectives Management to Bridge the Gap Between Service & ...

Wednesday, May 29, 2024  |  11AM PST / 2PM ESTRegister now and join us to learn more about how you can ...

Get Your Exclusive Splunk Certified Cybersecurity Defense Engineer Certification at ...

We’re excited to announce a new Splunk certification exam being released at .conf24! If you’re headed to Vegas ...

Share Your Ideas & Meet the Lantern team at .Conf! Plus All of This Month’s New ...

Splunk Lantern is Splunk’s customer success center that provides advice from Splunk experts on valuable data ...