Dashboards & Visualizations

my Dashboard row render is showing wrong result for a while and update to correct one after some time.

jat_ashish
Explorer

i'm using table_row_expansion.js file whose source code is written below:  please give me your input here.

require([
'splunkjs/mvc/tableview',
'splunkjs/mvc/chartview',
'splunkjs/mvc/dataview',
'splunkjs/mvc/searchmanager',
'splunkjs/mvc/postprocessmanager',
'splunkjs/mvc',
'underscore',
'splunkjs/mvc/simplexml/ready!'],function(
TableView,
ChartView,
DataView,
SearchManager,
PostProcessManager,
mvc,
_
){

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({
id: 'details-search-manager',
preview: false
});
this._baseSearchManager = new SearchManager({
id: 'base-search-manager',
search: '| loadjob savedsearch="debie2scmi:duerr_it_vuln_management:saved-plugin_outputv2"',
preview: false
});
this._postproc_pluginOutput = new PostProcessManager({
id: 'postproc-plugin-output',
managerid: 'base-search-manager',
});
this._tableView = new TableView({
managerid: 'details-search-manager',
'charting.legend.placement': 'none'
});
this._plugintableView = new TableView({
managerid: 'postproc-plugin-output',
'charting.legend.placement': 'none'
});

//this._dataView = new DataView({
// managerid: 'details-search-manager',
// template: "<b>Solution:</b> <p><%= results[0].solution %></p>"
//});
},

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 findingCell = _(rowData.cells).find(function (cell) {
return cell.field === 'finding';
});
// get plugin and ip
var result = findingCell.value.split("#");
//update the searches
this._searchManager.set({ search: '| inputlookup nessus_plugin_solution.csv | search id=' + result[1] + ' | fields solution | append [| makeresults | eval solution="No data available." | fields - _time ] | head 1'});
// the rex is a workaround for splunk not implementing linebreaks in the details tables correctly, only mv fields seem to work
this._postproc_pluginOutput.set({search: '| search pokey="' + result[3] + '" | fields plugin_output | rex mode=sed field=plugin_output "s/(\\n)/\\1 #BREAK#/g" | makemv delim="#BREAK#" plugin_output | append [| makeresults | eval plugin_output="No data available." | fields - _time ] | head 1' });

// $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._tableView.render().el);
$container.append(this._plugintableView.render().el);
// $container.append("IP: " + result[0] + " Plugin: " + result[1] );
}
});

var CustomLinkRenderer = TableView.BaseCellRenderer.extend({
canRender: function(cell) {
return cell.field === 'solved';
},
render: function($td, cell) {
var solved = cell.value;
var solved_result = solved.split("-");
//var a = $('<a>').attr("href", "www.test.de").text("testlink");
//var a = $('<input>').attr('type','checkbox');
//var a = $('<div>').attr({"id":"chk-sourcetype"+cell.value,"value":cell.value}).attr('class','icon-minus-circle');
var a = $('<div>').attr({"id":"chk-sourcetype"+cell.value,"value":cell.value});
// check if marked as solved
if(solved_result[1] == 1)
{
a.attr('class','icon-check-circle');
}
else
{
a.attr('class','icon-minus-circle');
}
$td.empty().append(a);

a.click(function(e) {
e.preventDefault();
//window.location = $(e.currentTarget).attr('href');
// or for popup:
// window.open($(e.currentTarget).attr('href'));
if($(e.currentTarget).attr('class') == 'icon-minus-circle')
{
$(e.currentTarget).attr('class','icon-gear');
var updatestring = '| inputlookup lkp-all-findings | eval key=_key | where key="' + solved_result[2] +'" | eval lastchecked=1 | outputlookup append=t lkp-all-findings';
var kvupdate = new SearchManager({
preview: false
});
kvupdate.set({search: updatestring});
kvupdate.on('search:done', function(properties) {
//console.log("DONE!\nSearch job properties:", properties.content);
// Set new value when search is done
$(e.currentTarget).attr('class','icon-check-circle');
});
}
else
{
$(e.currentTarget).attr('class','icon-gear');
var updatestring = '| inputlookup lkp-all-findings | eval key=_key | where key="' + solved_result[2] +'" | eval lastchecked=0 | outputlookup append=t lkp-all-findings';
var kvupdate = new SearchManager({
preview: false
});
kvupdate.set({search: updatestring});
kvupdate.on('search:done', function(properties) {
//console.log("DONE!\nSearch job properties:", properties.content);
// Set new value when search is done
$(e.currentTarget).attr('class','icon-minus-circle');
});
}

});
}
});

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

@splunk @BSplunk @techiesid @kamlesh_vaghela  please help.

Labels (3)
0 Karma
1 Solution

kamlesh_vaghela
SplunkTrust
SplunkTrust

@jat_ashish 

Yeah. That might be delayed at JS level. Can you please update JS and try?

render: function($container, rowData) {
//Add below line for cleaning previous content
$container.html("");

 

thanks 

View solution in original post

kamlesh_vaghela
SplunkTrust
SplunkTrust

@jat_ashish 

Can you please share your sample XML and JS in below format?  You can find "Insert/Edit Code Sample" button in toolbar.

This is sample code

 

 

0 Karma

jat_ashish
Explorer

@kamlesh_vaghela please find the code.

1) XML code 

 

<form script="table_row_expansion.js" theme="dark">
  <label>Scan reports v3</label>
  <fieldset submitButton="false" autoRun="true"></fieldset>
  <row>
    <panel>
      <title>Vulnerability report</title>
      <input type="checkbox" token="srStatus">
        <label>Status</label>
        <choice value="1">solved</choice>
        <choice value="0">unsolved</choice>
        <default>1,0</default>
        <prefix>(</prefix>
        <suffix>)</suffix>
        <initialValue>1,0</initialValue>
        <valuePrefix>is_solved=</valuePrefix>
        <delimiter> OR </delimiter>
      </input>
      <input type="checkbox" token="rsSeverity">
        <label>Severity</label>
        <choice value="critical">critical</choice>
        <choice value="high">high</choice>
        <choice value="medium">medium</choice>
        <choice value="low">low</choice>
        <choice value="informational">informational</choice>
        <default>critical,high,medium,low,informational</default>
        <prefix>(</prefix>
        <suffix>)</suffix>
        <initialValue>critical,high,medium,low,informational</initialValue>
        <valuePrefix>severity=</valuePrefix>
        <delimiter> OR </delimiter>
      </input>
      <input type="dropdown" token="srAsset">
        <label>Asset Group</label>
        <choice value="*">All</choice>
        <default>*</default>
        <fieldForLabel>Asset_Gruppe</fieldForLabel>
        <fieldForValue>Asset_Gruppe</fieldForValue>
        <search>
          <query>| inputlookup lkp-asset-list-master | stats count by Asset_Gruppe</query>
        </search>
      </input>
      <input type="dropdown" token="srCcode">
        <label>Company Code</label>
        <choice value="*">All</choice>
        <default>*</default>
        <fieldForLabel>Company Code</fieldForLabel>
        <fieldForValue>Company Code</fieldForValue>
        <search>
          <query>| inputlookup lkp-GlobalIPRange | dedup "Company Code"</query>
          <earliest>-24h@h</earliest>
          <latest>now</latest>
        </search>
      </input>
      <input type="dropdown" token="srCompany">
        <label>Homag / Dürr</label>
        <choice value="*">All</choice>
        <fieldForLabel>Scan-Company</fieldForLabel>
        <fieldForValue>Scan-Company</fieldForValue>
        <search>
          <query>| inputlookup lkp-asset-list-master | eval Scan-Company=substr('Scan-Company',0,1).lower(substr('Scan-Company',2)) | stats count by Scan-Company</query>
        </search>
        <default>*</default>
      </input>
      <input type="dropdown" token="srLocation">
        <label>Location</label>
        <choice value="*">All</choice>
        <default>*</default>
        <fieldForLabel>Location</fieldForLabel>
        <fieldForValue>Location</fieldForValue>
        <search>
          <query>| inputlookup lkp-asset-list-master | stats count by Location</query>
        </search>
      </input>
      <input type="dropdown" token="srScanner">
        <label>Scanner</label>
        <choice value="*">All</choice>
        <default>*</default>
        <fieldForLabel>Scanner</fieldForLabel>
        <fieldForValue>Scanner</fieldForValue>
        <search>
          <query>| inputlookup lkp-asset-list-master | stats count by Scanner</query>
        </search>
      </input>
      <input type="text" token="srHostname">
        <label>Hostname</label>
        <default>*</default>
      </input>
      <input type="text" token="srIp">
        <label>IP</label>
        <default>*</default>
      </input>
      <input type="text" token="srPluginname">
        <label>Plugin name</label>
        <default>*</default>
      </input>
      <input type="text" token="srScanDate">
        <label>Scan Date</label>
        <default>*</default>
      </input>
      <table id="reports_table">
        <search>
          <query>| inputlookup lkp-all-findings
| lookup lkp-findings-blacklist.csv blfinding as finding OUTPUTNEW blfinding
| lookup lkp-asset-list-master "IP Adresse" as ip OUTPUTNEW Asset_Gruppe Scan-Company Scanner Scan-Location Location "DNS Name" as dns_name
| lookup lkp-GlobalIpRange 3-Letter-Code as Location OUTPUTNEW "Company Code"
| eval key=_key,is_solved=if(lastchecked&gt;lastfound OR lastchecked == 1,1,0),solved=finding."-".is_solved."-".key,blacklisted=if(isnull(blfinding),0,1),scandate=strftime(lastfound,"%Y-%m-%d %H:%M:%S"),lastchecked=strftime(lastchecked,"%Y-%m-%d %H:%M:%S")
| fillnull value="N.A." Asset_Gruppe Scan-Company Scanner Scan-Location Location hostname
| search $srStatus$ $rsSeverity$ blacklisted=0 Asset_Gruppe="$srAsset$" Scan-Company="$srCompany$" Location="$srLocation$" Scanner="$srScanner$" dns="$srHostname$" pluginname="$srPluginname$" ip="$srIp$" scandate="*$srScanDate$*" "Company Code"="$srCcode$"
| strcat finding "#" NessusHost sid hostid pluginid finding
| fields dns ip lastchecked severity pluginid pluginname scandate Asset_Gruppe Location Scan-Company "Company Code" Scan-Location Scanner solved finding
| rename dns as Hostname,ip as IP</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="refresh.display">progressbar</option>
        <option name="rowNumbers">false</option>
        <option name="totalsRow">false</option>
        <option name="wrap">true</option>
        <format type="color" field="severity">
          <colorPalette type="map">{"critical":#ff0000,"high":#ff631e,"medium":#ffb750,"low":#fffcab,"informational":#8ba6ff}</colorPalette>
          <scale type="category"></scale>
        </format>
      </table>
    </panel>
  </row>
</form>

 

 2) JS code

 

require([
    'splunkjs/mvc/tableview',
    'splunkjs/mvc/chartview',
    'splunkjs/mvc/dataview',
    'splunkjs/mvc/searchmanager',
    'splunkjs/mvc/postprocessmanager',
    'splunkjs/mvc',
    'underscore',
    'splunkjs/mvc/simplexml/ready!'],function(
    TableView,
    ChartView,
    DataView,
    SearchManager,
    PostProcessManager,
    mvc,
    _
    ){

    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({
                id: 'details-search-manager',
                preview: false
            });
            this._baseSearchManager = new SearchManager({
                id: 'base-search-manager',
                search: '| loadjob savedsearch="debie2scmi:duerr_it_vuln_management:saved-plugin_outputv2"',
                preview: false
            });
            this._postproc_pluginOutput = new PostProcessManager({
                id: 'postproc-plugin-output',
                managerid: 'base-search-manager',
            });
            this._tableView = new TableView({
                managerid: 'details-search-manager',
                'charting.legend.placement': 'none'
            });
            this._plugintableView = new TableView({
                managerid: 'postproc-plugin-output',
                'charting.legend.placement': 'none'
            });

            //this._dataView = new DataView({
            //    managerid: 'details-search-manager',
            //    template: "<b>Solution:</b> <p><%= results[0].solution %></p>"
            //});
        },

        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 findingCell = _(rowData.cells).find(function (cell) {
               return cell.field === 'finding';
            });
            // get plugin and ip
            var result = findingCell.value.split("#");
            //update the searches
            this._searchManager.set({ search: '| inputlookup nessus_plugin_solution.csv | search id=' + result[1] + ' | fields solution | append [| makeresults | eval solution="No data available." | fields - _time ] | head 1'});
            // the rex is a workaround for splunk not implementing linebreaks in the details tables correctly, only mv fields seem to work
            this._postproc_pluginOutput.set({search: '| search pokey="' + result[3] + '" | fields plugin_output  | rex mode=sed field=plugin_output "s/(\\n)/\\1 #BREAK#/g" | makemv delim="#BREAK#" plugin_output | append [| makeresults | eval plugin_output="No data available." | fields - _time ] | head 1' });

            // $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._tableView.render().el);
            $container.append(this._plugintableView.render().el);
            // $container.append("IP: " + result[0] + " Plugin: " + result[1] );
        }
    });

    var CustomLinkRenderer = TableView.BaseCellRenderer.extend({
        canRender: function(cell) {
            return cell.field === 'solved';
        },
        render: function($td, cell) {
            var solved = cell.value;
            var solved_result = solved.split("-");
            //var a = $('<a>').attr("href", "www.test.de").text("testlink");
            //var a = $('<input>').attr('type','checkbox');
            //var a = $('<div>').attr({"id":"chk-sourcetype"+cell.value,"value":cell.value}).attr('class','icon-minus-circle');
            var a = $('<div>').attr({"id":"chk-sourcetype"+cell.value,"value":cell.value});
            // check if marked as solved 
            if(solved_result[1] == 1)
            {
                a.attr('class','icon-check-circle');
            }
            else
            {
                a.attr('class','icon-minus-circle');
            }
            $td.empty().append(a);
                              
            a.click(function(e) {
              e.preventDefault();
              //window.location = $(e.currentTarget).attr('href');
              // or for popup:
              // window.open($(e.currentTarget).attr('href'));
              if($(e.currentTarget).attr('class') == 'icon-minus-circle')
              {
                $(e.currentTarget).attr('class','icon-gear');
                var updatestring = '| inputlookup lkp-all-findings | eval key=_key | where key="' + solved_result[2] +'" | eval lastchecked=1 | outputlookup append=t lkp-all-findings';
                var kvupdate = new SearchManager({
                    preview: false
                });
                kvupdate.set({search: updatestring});
                kvupdate.on('search:done', function(properties) {
                    //console.log("DONE!\nSearch job properties:", properties.content);
                    // Set new value when search is done
                    $(e.currentTarget).attr('class','icon-check-circle');
                });
              }
              else 
              {
                $(e.currentTarget).attr('class','icon-gear');
                var updatestring = '| inputlookup lkp-all-findings | eval key=_key | where key="' + solved_result[2] +'" | eval lastchecked=0 | outputlookup append=t lkp-all-findings';
                var kvupdate = new SearchManager({
                    preview: false
                });
                kvupdate.set({search: updatestring});
                kvupdate.on('search:done', function(properties) {
                    //console.log("DONE!\nSearch job properties:", properties.content);
                    // Set new value when search is done
                    $(e.currentTarget).attr('class','icon-minus-circle');
                });
              }
              
            });
        }
    });

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

 

 

0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust
@jat_ashish
I have executed your code by adding `makeresults` search and it is working as expected. Can you please tell me which wrong results you are getting for sometime? Is it showing all record OR few records?

Meanwhile can you please console the same search and check how many times it gets printed and executed.. I'm interested in earlier search which shows wrong result and new search which giving correct results. This will help us to get more pointers on this issue.

0 Karma

jat_ashish
Explorer

@kamlesh_vaghela 

when I click on > button of any  row in my dashboard it shows desired result , now if I click on any other row > button , then the result of first row reflect in the area for some time and automatically reloaded to desired output.

so, I guess there is delay in JS output or may be JS through some cache for time being.

 

 

 

0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@jat_ashish 

Yeah. That might be delayed at JS level. Can you please update JS and try?

render: function($container, rowData) {
//Add below line for cleaning previous content
$container.html("");

 

thanks 

jat_ashish
Explorer
0 Karma

jat_ashish
Explorer

thank you @kamlesh_vaghela , it works like a charm.😊

0 Karma
Get Updates on the Splunk Community!

Index This | I am a number, but when you add ‘G’ to me, I go away. What number am I?

March 2024 Edition Hayyy Splunk Education Enthusiasts and the Eternally Curious!  We’re back with another ...

What’s New in Splunk App for PCI Compliance 5.3.1?

The Splunk App for PCI Compliance allows customers to extend the power of their existing Splunk solution with ...

Extending Observability Content to Splunk Cloud

Register to join us !   In this Extending Observability Content to Splunk Cloud Tech Talk, you'll see how to ...