The Splunk submit button is one of the most unusable things that I have ever seen. Based off two years of Slack usergroups conversations, Splunk Answers, and my own constant struggle with this damn thing, the Splunk community desperately has need for a comprehensive workaround. Is it unreasonable to expect a company valued at a billion dollars to have a working, you know, button?
*Issues, for all released Splunk versions *
Does anyone have a comprehensive submit button replacement that solves all of these issues?
Below is a run anywhere example. I asked this question so that I could detail a comprehensive workaround for the Splunk community. This is a list of some of the relevant issues here, many thanks to @niketn and @vnravikumar for their help!
https://answers.splunk.com/answers/758332/is-it-impossible-to-resubmit-a-dashboard-search-in.html
https://answers.splunk.com/answers/742451/searchwhenchangedfalse-not-honored-1.html
https://answers.splunk.com/answers/758726/how-can-i-implement-a-pseudo-searchwhenchanged-fun-1.html
https://answers.splunk.com/answers/758977/how-to-adjust-the-click-width-of-a-js-button.html
https://answers.splunk.com/answers/758599/is-it-possible-to-add-a-button-in-line-with-inputs.html
SimpleXML:
<dashboard theme="light" script="button_submit.js">
<label>Non-Trash Submit Button</label>
<description></description>
<row>
<panel>
<html depends="$hide$">
<style>
#submit_button{
width:80px !important;
}
#submit_button div[data-component="splunk-core:/splunkjs/mvc/components/LinkList"]{
width:80px !important;
}
#submit_button button{
padding: 6px 15px !important;
border-radius: 3px !important;
font-weight: 500 !important;
background-color: #5cc05c !important;
border: transparent !important;
color: #fff !important;
}
#submit_button button:hover{
background-color: #40a540 !important;
border-color: transparent !important;
}
</style>
</html>
<input type="time" id="timepicker">
<label>Time range:</label>
<default>
<earliest>@d</earliest>
<latest>now</latest>
</default>
<change>
<eval token="earliest_epoch_onChange">case(isnum($earliest$), $earliest$, $earliest$=="now", time(), $earliest$="", 0, true(), relative_time(time(), $earliest$))</eval>
<eval token="latest_epoch_onChange">case(isnum($latest$), $latest$, $latest$=="now", time(), true(), relative_time(time(), $latest$))</eval>
</change>
</input>
<input type="text" token="network_id_onChange">
<label>NetworkID:</label>
<default></default>
</input>
<input type="link" id="submit_button">
<label></label>
<choice value="submit">Submit</choice>
</input>
</panel>
</row>
<row>
<panel>
<title></title>
<table>
<search>
<query>
| makeresults | eval user="$network_id$" | eval trigger="$submit_trigger$" | table user
</query>
<earliest>$earliest_epoch$</earliest>
<latest>$latest_epoch$</latest>
</search>
<option name="wrap">true</option>
<option name="rowNumbers">false</option>
<option name="drilldown">none</option>
<option name="dataOverlayMode">none</option>
<option name="count">20</option>
</table>
</panel>
</row>
</dashboard>
button_submit.js
require([
'jquery',
'splunkjs/mvc',
'splunkjs/mvc/simplexml/ready!'
], function($,mvc){
var submittedTokens = mvc.Components.get("submitted");
$("#submit_button").click(function(){
submittedTokens.set("submit_trigger", ""+Math.random());
submittedTokens.set("earliest_epoch",submittedTokens.get("earliest_epoch_onChange"));
submittedTokens.set("latest_epoch",submittedTokens.get("latest_epoch_onChange"));
submittedTokens.set("network_id",submittedTokens.get("network_id_onChange"));
});
});
Comments
|makeresults
search, you still need to write stanzas of earliest of 1 and latest of 2, for example, or else that search will run whenever the timepicker is adjusted). Also, none of this works in Splunk Mobile.
The simpleXML submit button is horribly broken and for complex usecases, cannot be made to work. Try this dahsboard's no-JavaScript approach instead:
<form theme="dark">
<label>PoC demonstrating a fully-functioning no-JS SUBMIT "button" (actually "checkbox").</label>
<description>https://community.splunk.com/t5/Dashboards-Visualizations/SimpleXML-Inherent-brokenness-regarding-autorun-and-Submit/m-p/407351 For intricate technical reasons that Splunk considers "working as intended", the "real" SUBMIT button is fundamentally broken and CANNOT BE MADE TO WORK for many usecases (i.e. when you must use "true" for "searchWhenChanged"). Fortunately, the method demonstrated herein does everything that anyone could desire with only 1 downside which is this: there is no way to make the dashboard autorun on first load (not even if you click the CHECKBOX with a URI in the URL). Notice that even though some of the controls interact with one-another, the actual search does not run until the SUBMIT box is checked. Here are the pieces that are required. 1: DO NOT CHANGE ANYTHING ABOUT THE "SUBMIT" checkbox other than cosmetic things (e.g. html). 2: Ensure that EVERY OTHER CONTROL has a "<change>...</change>" section that unsets BOTH these tokens: {"SUBMIT_CHECKBOX", "form.SUBMIT_CHECKBOX"}. 3: Ensure that 1 search in every chain of searches uses the do-nothing "$SUBMIT_CHECKBOX$" token somewhere (i.e. if all searches are driven by a base search, this only has to be done in the base search, not the post-process searches). This token will always be either unset or blank so it does not matter where you put it. 4: Neither the individual "searchWhenChanged" values of the controls NOR the global "Autorun dashboard" value makes any difference. For support contact woodcock@splunxter.com.</description>
<fieldset submitButton="false" autoRun="true">
<input type="multiselect" token="INDEX" searchWhenChanged="true">
<label>Select Index value(s)</label>
<fieldForLabel>label</fieldForLabel>
<fieldForValue>value</fieldForValue>
<default>*</default>
<search>
<query>|tstats count dc(host) WHERE index=* AND $SOURCETYPE$ BY index
| rename index AS value
| eval label = value
| append [|makeresults | eval label = "All", value="*"]
| table label value</query>
<earliest>$timepicker.earliest$</earliest>
<latest>$timepicker.latest$</latest>
</search>
<delimiter> OR index=</delimiter>
<valuePrefix>"</valuePrefix>
<valueSuffix>"</valueSuffix>
<prefix>(index=</prefix>
<change>
<eval token="form.INDEX">case(mvcount($form.INDEX$) == 2 AND mvindex($form.INDEX$, 0) == "*", mvindex($form.INDEX$, 1), mvfind($form.INDEX$, "^[*]") == mvcount($form.INDEX$) - 1, "*", true(), $form.INDEX$)</eval>
<unset token="SUBMIT_CHECKBOX"></unset>
<unset token="form.SUBMIT_CHECKBOX"></unset>
</change>
<suffix>)</suffix>
</input>
<input type="multiselect" token="SOURCETYPE" searchWhenChanged="true">
<label>Select sourcetype value(s)</label>
<fieldForLabel>label</fieldForLabel>
<fieldForValue>value</fieldForValue>
<default>*</default>
<search>
<query>|tstats count dc(host) WHERE $INDEX$ AND sourcetype=* BY sourcetype
| rename sourcetype AS value
| eval label = value
| append [|makeresults | eval label = "All", value="*"]
| table label value</query>
<earliest>$timepicker.earliest$</earliest>
<latest>$timepicker.latest$</latest>
</search>
<delimiter> OR sourcetype=</delimiter>
<valuePrefix>"</valuePrefix>
<valueSuffix>"</valueSuffix>
<prefix>(sourcetype=</prefix>
<change>
<eval token="form.SOURCETYPE">case(mvcount($form.SOURCETYPE$) == 2 AND mvindex($form.SOURCETYPE$, 0) == "*", mvindex($form.SOURCETYPE$, 1), mvfind($form.SOURCETYPE$, "^[*]") == mvcount($form.SOURCETYPE$) - 1, "*", true(), $form.SOURCETYPE$)</eval>
<unset token="SUBMIT_CHECKBOX"></unset>
<unset token="form.SUBMIT_CHECKBOX"></unset>
</change>
<suffix>)</suffix>
</input>
<input type="text" token="COUNT">
<label>Name for "count" field</label>
<default>count</default>
<change>
<unset token="SUBMIT_CHECKBOX"></unset>
<unset token="form.SUBMIT_CHECKBOX"></unset>
</change>
</input>
<input type="time" token="timepicker" searchWhenChanged="true">
<label>Timepicker</label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
<change>
<unset token="SUBMIT_CHECKBOX"></unset>
<unset token="form.SUBMIT_CHECKBOX"></unset>
</change>
</input>
<input id="submit_checkbox" type="checkbox" token="SUBMIT_CHECKBOX">
<label></label>
<delimiter> </delimiter>
<choice value="">SUBMIT</choice>
</input>
<html depends="$hide$">
<style>
#submit_checkbox{
width:80px !important;
}
#submit_checkbox
div[data-component="splunk-core:/splunkjs/mvc/components/LinkList"]{
width:80px !important;
}
#submit_checkbox button{
padding: 6px 15px !important;
border-radius: 3px !important;
font-weight: 500 !important;
background-color: #5cc05c !important;
border: transparent !important;
color: #fff !important
}
#submit_checkbox button:hover{
background-color: #40a540 !important;
border-color: transparent !important;
}
</style>
</html>
</fieldset>
<row>
<panel>
<table>
<title>Searches ONLY on checking the SUBMIT box (which resets itself)</title>
<search>
<query>|tstats count AS $COUNT|s$ dc(host) WHERE $INDEX$ AND $SOURCETYPE$ BY index sourcetype $SUBMIT_CHECKBOX$</query>
<earliest>$timepicker.earliest$</earliest>
<latest>$timepicker.latest$</latest>
</search>
<option name="refresh.display">progressbar</option>
</table>
</panel>
</row>
</form>
Below is a run anywhere example. I asked this question so that I could detail a comprehensive workaround for the Splunk community. This is a list of some of the relevant issues here, many thanks to @niketn and @vnravikumar for their help!
https://answers.splunk.com/answers/758332/is-it-impossible-to-resubmit-a-dashboard-search-in.html
https://answers.splunk.com/answers/742451/searchwhenchangedfalse-not-honored-1.html
https://answers.splunk.com/answers/758726/how-can-i-implement-a-pseudo-searchwhenchanged-fun-1.html
https://answers.splunk.com/answers/758977/how-to-adjust-the-click-width-of-a-js-button.html
https://answers.splunk.com/answers/758599/is-it-possible-to-add-a-button-in-line-with-inputs.html
SimpleXML:
<dashboard theme="light" script="button_submit.js">
<label>Non-Trash Submit Button</label>
<description></description>
<row>
<panel>
<html depends="$hide$">
<style>
#submit_button{
width:80px !important;
}
#submit_button div[data-component="splunk-core:/splunkjs/mvc/components/LinkList"]{
width:80px !important;
}
#submit_button button{
padding: 6px 15px !important;
border-radius: 3px !important;
font-weight: 500 !important;
background-color: #5cc05c !important;
border: transparent !important;
color: #fff !important;
}
#submit_button button:hover{
background-color: #40a540 !important;
border-color: transparent !important;
}
</style>
</html>
<input type="time" id="timepicker">
<label>Time range:</label>
<default>
<earliest>@d</earliest>
<latest>now</latest>
</default>
<change>
<eval token="earliest_epoch_onChange">case(isnum($earliest$), $earliest$, $earliest$=="now", time(), $earliest$="", 0, true(), relative_time(time(), $earliest$))</eval>
<eval token="latest_epoch_onChange">case(isnum($latest$), $latest$, $latest$=="now", time(), true(), relative_time(time(), $latest$))</eval>
</change>
</input>
<input type="text" token="network_id_onChange">
<label>NetworkID:</label>
<default></default>
</input>
<input type="link" id="submit_button">
<label></label>
<choice value="submit">Submit</choice>
</input>
</panel>
</row>
<row>
<panel>
<title></title>
<table>
<search>
<query>
| makeresults | eval user="$network_id$" | eval trigger="$submit_trigger$" | table user
</query>
<earliest>$earliest_epoch$</earliest>
<latest>$latest_epoch$</latest>
</search>
<option name="wrap">true</option>
<option name="rowNumbers">false</option>
<option name="drilldown">none</option>
<option name="dataOverlayMode">none</option>
<option name="count">20</option>
</table>
</panel>
</row>
</dashboard>
button_submit.js
require([
'jquery',
'splunkjs/mvc',
'splunkjs/mvc/simplexml/ready!'
], function($,mvc){
var submittedTokens = mvc.Components.get("submitted");
$("#submit_button").click(function(){
submittedTokens.set("submit_trigger", ""+Math.random());
submittedTokens.set("earliest_epoch",submittedTokens.get("earliest_epoch_onChange"));
submittedTokens.set("latest_epoch",submittedTokens.get("latest_epoch_onChange"));
submittedTokens.set("network_id",submittedTokens.get("network_id_onChange"));
});
});
Comments
|makeresults
search, you still need to write stanzas of earliest of 1 and latest of 2, for example, or else that search will run whenever the timepicker is adjusted). Also, none of this works in Splunk Mobile.
Thanks, this helped me so much! To make this perfect, I would suggest the following:
Simplify the javascript so that it only sets submit_trigger
. That way it can be used in more than one dashboard and you don't have to keep tweaking it when you develop your dashboard. To prevent the annoyance of the searchWhenChanged=false
being ignored again, simply add this to the search that is to be ran when submit is pressed:
<search>
<done>
<unset token="submit_trigger"/>
</done>
...
That way, after the search is ran once, you can take your time to adjust your inputs and only when you're ready you can click submit to run it again. Works a treat.
Finally, unlike what I initially assumed when I saw your solution, the inputs (including the submit button) can be part of the standard <fieldset>
at the top of your dashboard, in case you want them to have a grey background as usual, not a white one.
Also, it's worth noting that your solution allows to hide the submit button with a "depends" clause so that it only appears if the inputs satisfy some kind of condition. I found that useful.
Thanks again!
Related: here is my guide to implementing multiple time-pickers in conjunction with this solution. https://answers.splunk.com/answers/763194/how-do-you-create-two-epoch-generating-on-submit-t.html
@nick405060 thanks a lot for documenting this solution. My inspiration for the possibility of user controlled Submit button was the following blog by Octoinsight. It was a stepping stone for my understanding of Simple XML JS extension.
https://www.google.com/amp/s/blog.octoinsight.com/there-can-be-only-one-submit-button/amp/
Also as mentioned in one of the answers you have quoted, I was able to grasp the behaviour of Submit button with Default
and Submitted
Token models through the Developer Gadgets App for Splunk by @rjthibod