Hello guys !
I'm trying to create a custom row expansion, which seemed to be simple task and became a big headache.
Before i even will try to add a meaningful data, i am just trying to add generic data to the rows.
This is my JS :
require([
'splunkjs/mvc/tableview',
'splunkjs/mvc/chartview',
'splunkjs/mvc/searchmanager',
'splunkjs/mvc',
'underscore',
'splunkjs/mvc/simplexml/ready!'],function(
TableView,
ChartView,
SearchManager,
mvc,
_
){
// Create a search manager
var mysearch = new SearchManager({
id: "main-search",
preview: false,
cache: false,
search: "| makeresults | eval check=3 | fields - _time"
});
// Create a table
var myTableView = new TableView({
id: "mytable",
managerid: "main-search",
drilldown: "none",
el: $("#mytable")
});
//create row renderer
var EventSearchBasedRowExpansionRenderer = TableView.BaseRowExpansionRenderer.extend({
canRender: function(rowData) {
console.log("RowData: ", rowData);
return true;
},
render: function($container, rowData) {
// Print the rowData object to the console
console.log("RowData: ", rowData);
$container.append(mysearch);
}
});
// Create an instance of the basic row renderer
var tableRowRender = new EventSearchBasedRowExpansionRenderer();
// Add the row renderer to the table
myTableView.addRowExpansionRenderer(tableRowRender);
// Render the table
myTableView.render();
});
});
In addition i added to the source of the dashboard the script="custom_table_row_expansion.js" and the table id="myTableView".
Can anyone help me with that ?
Thanks.
Hi @astatrial
Try this sample
<form script="custom.js">
<label>custom_row</label>
<fieldset submitButton="false">
<input type="time" token="timepicker">
<label></label>
<default>
<earliest></earliest>
<latest></latest>
</default>
</input>
</fieldset>
<row>
<panel>
<table id="expand_table_row">
<search>
<query>index=_* type="threat" severity="medium" | table host source sourcetype search_id</query>
<earliest>$timepicker.earliest$</earliest>
<latest>$timepicker.latest$</latest>
</search>
<option name="drilldown">none</option>
</table>
</panel>
</row>
</form>
custom.js
require([
'splunkjs/mvc/tableview',
'splunkjs/mvc/eventsviewerview',
"splunkjs/mvc/chartview",
'splunkjs/mvc/searchmanager',
'splunkjs/mvc',
'underscore',
'splunkjs/mvc/simplexml/ready!'
],function(
TableView,
EventsViewer,
ChartView,
SearchManager,
mvc,
_
){
var EventSearchBasedRowExpansionRenderer = TableView.BaseRowExpansionRenderer.extend({
initialize: function(args) {
// initialize will run once, so we will set up a search and events to be reused.
this._searchManager = new SearchManager({
id: 'details-search-manager',
preview: false
});
this.chartViewer = new ChartView({
type: "bar",
managerid: 'details-search-manager'
});
},
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 search_idCell = _(rowData.cells).find(function (cell) {
return cell.field === 'search_id';
});
console.log(search_idCell);
//update the search with the sourcetype that we are interested in
this._searchManager.set({
earliest_time: "$form.timepicker.earliest$",
latest_time: "$form.timepicker.latest$",
search: 'index=_* type="threat" severity="medium" search_id=' + search_idCell.value +' | stats count by host'
}, {tokens: true});
// $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.chartViewer.render().el);
}
});
var tableElement = mvc.Components.getInstance("expand_table_row");
tableElement.getVisualization(function(tableView) {
// Add custom cell renderer, the table will re-render automatically.
tableView.addRowExpansionRenderer(new EventSearchBasedRowExpansionRenderer());
});
});
Hello @vnravikumar I have a similar question, Please let me know if we can do it with HTML or CSS? We are Splunk cloud so it is bit hard for us with javascript.
you can not do it without using JS.
Hi @astatrial
Try this sample
<form script="custom.js">
<label>custom_row</label>
<fieldset submitButton="false">
<input type="time" token="timepicker">
<label></label>
<default>
<earliest></earliest>
<latest></latest>
</default>
</input>
</fieldset>
<row>
<panel>
<table id="expand_table_row">
<search>
<query>index=_* type="threat" severity="medium" | table host source sourcetype search_id</query>
<earliest>$timepicker.earliest$</earliest>
<latest>$timepicker.latest$</latest>
</search>
<option name="drilldown">none</option>
</table>
</panel>
</row>
</form>
custom.js
require([
'splunkjs/mvc/tableview',
'splunkjs/mvc/eventsviewerview',
"splunkjs/mvc/chartview",
'splunkjs/mvc/searchmanager',
'splunkjs/mvc',
'underscore',
'splunkjs/mvc/simplexml/ready!'
],function(
TableView,
EventsViewer,
ChartView,
SearchManager,
mvc,
_
){
var EventSearchBasedRowExpansionRenderer = TableView.BaseRowExpansionRenderer.extend({
initialize: function(args) {
// initialize will run once, so we will set up a search and events to be reused.
this._searchManager = new SearchManager({
id: 'details-search-manager',
preview: false
});
this.chartViewer = new ChartView({
type: "bar",
managerid: 'details-search-manager'
});
},
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 search_idCell = _(rowData.cells).find(function (cell) {
return cell.field === 'search_id';
});
console.log(search_idCell);
//update the search with the sourcetype that we are interested in
this._searchManager.set({
earliest_time: "$form.timepicker.earliest$",
latest_time: "$form.timepicker.latest$",
search: 'index=_* type="threat" severity="medium" search_id=' + search_idCell.value +' | stats count by host'
}, {tokens: true});
// $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.chartViewer.render().el);
}
});
var tableElement = mvc.Components.getInstance("expand_table_row");
tableElement.getVisualization(function(tableView) {
// Add custom cell renderer, the table will re-render automatically.
tableView.addRowExpansionRenderer(new EventSearchBasedRowExpansionRenderer());
});
});
I don't want a chart, i just want a table.
I came across this example already.
Hi @astatrial
Try this javascript it will render a table and please let me know your requirement clearly
require([
'splunkjs/mvc/tableview',
'splunkjs/mvc/eventsviewerview',
"splunkjs/mvc/chartview",
'splunkjs/mvc/searchmanager',
'splunkjs/mvc',
'underscore',
'splunkjs/mvc/simplexml/ready!'
],function(
TableView,
EventsViewer,
ChartView,
SearchManager,
mvc,
_
){
var EventSearchBasedRowExpansionRenderer = TableView.BaseRowExpansionRenderer.extend({
initialize: function(args) {
// initialize will run once, so we will set up a search and events to be reused.
this._searchManager = new SearchManager({
id: 'details-search-manager',
preview: false
});
this.tableViewer = new TableView({
pageSize: "5",
id: "example-table",
managerid: 'details-search-manager'
});
},
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 search_idCell = _(rowData.cells).find(function (cell) {
return cell.field === 'search_id';
});
console.log(search_idCell);
//update the search with the sourcetype that we are interested in
this._searchManager.set({
earliest_time: "$form.timepicker.earliest$",
latest_time: "$form.timepicker.latest$",
search: 'index=_* type="threat" severity="medium" search_id=' + search_idCell.value +' | stats count by host'
}, {tokens: true});
// $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.tableViewer.render().el);
}
});
var tableElement = mvc.Components.getInstance("expand_table_row");
tableElement.getVisualization(function(tableView) {
// Add custom cell renderer, the table will re-render automatically.
tableView.addRowExpansionRenderer(new EventSearchBasedRowExpansionRenderer());
});
});
Hi @vnravikumar
I would like to know whether we can pass the entire splunk search dynamically which is used in JS for row expansion? Instead of hardcoding the search is there a way to pass the entire search dynamically to the javascript.
The problem I am facing is, i need to keep on updating the search in the JS whenever I want to add a column. So if I could pass the entire search dynamically from Splunk to the JS and the JS helps in row expansion.
Thanks,
It would be great if you can share your issue details with sample code OR usecase in new question.
We are glad to help you in any JS issue
Happy Splunking
🙂
Hi @kamlesh_vaghela,
I created a new question https://community.splunk.com/t5/Developing-for-Splunk-Enterprise/Table-row-expansion-with-dynamic-se...
Thanks 🙂
Hi @kamlesh_vaghela,
Thank you for acknowledging my question. Below is the JS which I have for table row expansion which works fine for my requirement. I want the search given in the JS should be passed from my Splunk dashboard instead of hardcoding it here. This is because I don't to update the JS whenever I want to add or delete anything in my search.
Below search in JS which I want to be passed through Splunk dynamically instead of hardcoding in JS:
this._searchManager.set({ search: 'index=idx_omn source=vs.csv | eval key=process+" "+oprocess_start_date | search key="' + processCell.value + '" | stats values(process) as process values(oprocess_start_date) as oprocess_start_date values(oprocess_end_date) as oprocess_end_date values(otrans) as otrans values(otpm) as otpm values(oelapsed_mins) as oelapsed_mins values(total_count) as total_count values(local_currency) as local_currency values(local_swift) as local_swift values(local_amt) as local_amt values(eur_local) as eur_local BY file_number_list| table process,oprocess_start_date,oprocess_end_date,file_number_list,otrans,otpm,oelapsed_mins,total_count,local_currency,local_swift,local_amt,eur_local '});
XML:
<dashboard script="custom_table_row_expansion1.js">
<label>Visa row expansion</label>
<row>
<panel>
<table id="expand_with_events">
<search>
<query>index="idx_omn" source="vs.csv"
| eval key=process+" "+oprocess_start_date
| stats values(process) as process values(oprocess_start_date) as oprocess_start_date values(oprocess_end_date) as oprocess_end_date values(otrans) as otrans values(otpm) as otpm values(oelapsed_mins) as oelapsed_mins sum(total_count) as total_count values(local_currency) as local_currency values(local_swift) as local_swift sum(local_amt) as local_amt sum(eur_local) as eur_local BY key
| table process oprocess_start_date oprocess_end_date otrans otpm oelapsed_mins total_count local_currency local_swift local_amt eur_local key</query>
<earliest>0</earliest>
<latest></latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</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>
</table>
</panel>
</row>
</dashboard>
JS:
require([
'splunkjs/mvc/tableview',
'splunkjs/mvc/chartview',
'splunkjs/mvc/searchmanager',
'splunkjs/mvc',
'underscore',
'splunkjs/mvc/simplexml/ready!'],function(
TableView,
ChartView,
SearchManager,
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._chartView = new ChartView({
// managerid: 'details-search-manager',
// 'charting.legend.placement': 'none'
//});
this._TableView = new TableView({
id: 'TestTable',
managerid: 'details-search-manager',
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 key(process and start date) cell to use its value
var processCell = _(rowData.cells).find(function (cell) {
return cell.field === 'key';
});
//update the search with the key that we are interested in
this._searchManager.set({ search: 'index=idx_omn source=vs.csv | eval key=process+" "+oprocess_start_date | search key="' + processCell.value + '" | stats values(process) as process values(oprocess_start_date) as oprocess_start_date values(oprocess_end_date) as oprocess_end_date values(otrans) as otrans values(otpm) as otpm values(oelapsed_mins) as oelapsed_mins values(total_count) as total_count values(local_currency) as local_currency values(local_swift) as local_swift values(local_amt) as local_amt values(eur_local) as eur_local BY file_number_list| table process,oprocess_start_date,oprocess_end_date,file_number_list,otrans,otpm,oelapsed_mins,total_count,local_currency,local_swift,local_amt,eur_local '});
// $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.addRowExpansionRenderer(new EventSearchBasedRowExpansionRenderer());
});
});
I did try by creating a field called "query" which has the query for the row expansion and passed it to the below JS but it didn't return any result. Please ignore this approach if there is any better solution available.
XML for passing the entire query to column called query:
<dashboard script="custom_table_row_expansion2.js">
<label>Visa row expansion Clone</label>
<row>
<panel>
<table id="expand_with_events">
<search>
<query>index="idx_omn" source="vs.csv"
| eval key=process+" "+oprocess_start_date
| eval query1 = "idx_omn source=\"visabase.csv\" | search key =\""
| eval query2 = "\"| stats values(process) as process values(oprocess_start_date) as oprocess_start_date values(oprocess_end_date) as oprocess_end_date values(otrans) as otrans values(otpm) as otpm values(oelapsed_mins) as oelapsed_mins values(total_count) as total_count values(local_currency) as local_currency values(local_swift) as local_swift values(local_amt) as local_amt values(eur_local) as eur_local BY file_number_list"
| eval query = query1+key+query2
| stats values(process) as process values(oprocess_start_date) as oprocess_start_date values(oprocess_end_date) as oprocess_end_date values(otrans) as otrans values(otpm) as otpm values(oelapsed_mins) as oelapsed_mins sum(total_count) as total_count values(local_currency) as local_currency values(local_swift) as local_swift sum(local_amt) as local_amt sum(eur_local) as eur_local values(query) as query BY key
| table process oprocess_start_date oprocess_end_date otrans otpm oelapsed_mins total_count local_currency local_swift local_amt eur_local key query</query>
<earliest>0</earliest>
<latest></latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</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>
</table>
</panel>
</row>
</dashboard>
JS for the new try which didn't redturn any result:
require([
'splunkjs/mvc/tableview',
'splunkjs/mvc/chartview',
'splunkjs/mvc/searchmanager',
'splunkjs/mvc',
'underscore',
'splunkjs/mvc/simplexml/ready!'],function(
TableView,
ChartView,
SearchManager,
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._chartView = new ChartView({
// managerid: 'details-search-manager',
// 'charting.legend.placement': 'none'
//});
this._TableView = new TableView({
id: 'TestTable',
managerid: 'details-search-manager',
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 === 'query';
});
//update the search with the sourcetype that we are interested in
this._searchManager.set({ search: 'index= "' + processCell.value + '" '});
// $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.addRowExpansionRenderer(new EventSearchBasedRowExpansionRenderer());
});
});
Thanks for sharing it. I'll help you on this. But asked to post new question to make it separate and searchable for other Community members and for those who may be in future looking for same solution . 😜😁
@vnravikumar can we use the same custom row expansion logic using XML /HTML/CSS.
Since I don't have access to upload JS file in Splunk so looking for same solution in XML/HTML/CSS?
Hi,
sorry if my question wasn't clear.
I have a dashborad and i am trying to add data to every row in a table format.
I have a base search and the panel that i want to add to the row expansion is using it.
I added the JS to the /appserver/static folder and modified the dashboard source code to add the script and the "expand_table_row".
I also tried to just create a new dashboard with the code you wrote and the add the JS, but it also didn't work .
I restarted the splunk and cleared the browser data, but i don't see any change in the dashboard (it doesn't even show the small arrow to the left of the row).
I don't know why and i can't even find a way to debug it.
When i
Hi @astatrial
Can you inspect with your browser and check whether you are getting any javascript error. And also let me know whether you are expecting the result as like below.
This is exactly what i am trying to do(!), with no success.
I don't see any javascript errors
I added a print screen of the browser inspection .
Whether javascript get invoked?
"Whether javascript get invoked?"
I am not sure what are you meaning here?
The splunk version is - 7.2.4.2
Also if it is not obvious i really appreciate your help!!
I also tried in same Splunk version. Let me know whether the javascript file that you included in the dashboard, getting called. Try to put some log statement in javascript file like console.log("Testing Javascript file -----"); I guess Javascript file not called properly.
This was exactly the problem..
I edited the JS file in a wrong way and it prevented it from being called.
By the way, do you know if there is an option to add button to the row expansion
(I just want to know if you think this thing is optional or not).
Thanks for everything !
Instead of a small triangle image do you need to add button there? If that is the case you need to handle in css.
Thanks for the response.
No, my question is if it possible that row expansion will be opened to an interactive board from which i will be able to modify things like edit lookup fields.