Dashboards & Visualizations

How do you add JS in xml?

kdimaria
Communicator

I am trying to have a dashboard coded in XML with JS included but I am not sure where the script tags go. When I run my dashboard its clear that the JS isnt being hit in the code. I want to have it all in one file and not two separate files if possible. my code is below.

<dashboard>
     <label>Modal Demo</label>
  <fieldset submitButton="false">
    <!--
            Create an input to store the drilldown value. It will be hidden using custom javascript when
            the dashboard is loaded.
         -->
    <input type="text" token="sourcetype" searchWhenChanged="true"></input>
  </fieldset>
  <row>
    <panel>
      <table id="master">
        <title>Master</title>
        <searchString>index=_internal | stats count by sourcetype</searchString>
        <earliestTime>-60m@m</earliestTime>
        <latestTime>now</latestTime>
        <!-- Set the type of of drilldown, since we will always consume the same field, use row-->
        <option name="drilldown">row</option>
      </table>
    </panel>

  </row>
   <html>   
 <script >require([
    'underscore',
    'backbone',
    '../app/dev_app/components/ModalView',
    'splunkjs/mvc',
    'splunkjs/mvc/searchmanager',
    'splunkjs/mvc/simplexml/ready!'
], function(_, Backbone, ModalView, mvc, SearchManager) {

    var master = mvc.Components.get("master");
    var tokens = mvc.Components.getInstance("submitted");

    var detailSearch = new SearchManager({
            id: "detailSearch",
            earliest_time: "-24h@h",
            latest_time: "now",
            preview: true,
            cache: false,
            search: "index=_internal sourcetype=$sourcetype$ | timechart count" 
    }, {tokens: true, tokenNamespace: "submitted"});  

    master.on("click", function(e) {
        if(e.field === "sourcetype") {
            e.preventDefault();
            var _title = e.data['click.value'];
            tokens.set('sourcetype', _title);
            var modal = new ModalView({ title: _title, search: detailSearch });
            modal.show();

        }

    });

});

define([
    'underscore',
    'backbone',
    'jquery',
    'splunkjs/mvc',
    'splunkjs/mvc/searchmanager',
    'splunkjs/mvc/simplexml/element/table'
    ], function(_, Backbone, $, mvc, SearchManager, TableElement) {
           var modalTemplate = "<div id="pivotModal" class="modal">" +
                       "<div class="modal-header"><h3>Blah</h3></div>" +
                       "<div class="modal-body"></div>" +
                       "<div class="modal-footer"><button class="close">Close</button></div>" +
                       "</div>" +
                       "<div class="modal-backdrop"></div>";

    var ModalView = Backbone.View.extend({

            defaults: {
               title: 'Not set'
            },        

            initialize: function(options) {
                this.options = options;
                this.options = _.extend({}, this.defaults, this.options);
                this.childViews = [];
                console.log('Hello from the modal window: ', this.options.title);
                this.template = _.template(modalTemplate);
            },

            events: {
               'click .close': 'close',
               'click .modal-backdrop': 'close'
            },

            render: function() {
                var data = { title : this.options.title }
                this.$el.html(this.template(data));
                return this;
            },

            show: function() {
                $(document.body).append(this.render().el);

                $(this.el).find('.modal-body').append('<div id="modalVizualization"/>');

                $(this.el).find('.modal').css({
                    width:'90%',
                    height:'auto',
                    left: '5%',
                    'margin-left': '0',
                    'max-height':'100%'
                });

                var search = mvc.Components.get(this.options.search.id);

                var detailTable = new TableElement({
                        id: "detailTable",
                        managerid: search.name,
                        pageSize: "5",
                        el: $('#modalVizualization')
                }).render();

                this.childViews.push(detailTable);
                search.startSearch();                
            },

            close: function() {
               this.unbind();
               this.remove();
               _.each(this.childViews, function(childView) {

                   childView.unbind();
                   childView.remove();

               });
            }

        });

        return ModalView;

});</script></html>

</dashboard>
0 Karma
1 Solution

niketn
Legend

@kdimaria, before you switch to HTML Dashboard you should keep several things to your consideration:

  1. How often do you UI > Edit Panel vs JavaScript Change?
  2. Do you have Simple XML Chart configuration?
  3. Do you have Event Handlers in Simple XML?
  4. Do you have Power Users in your team, who are only capable of UI Edit or Simple XML Chart Configuration and no JavaScript or Splunk JS Stack or Splunk Web Framework?
  5. Are you more comfortable coding in HTML Dashboard as compared to Simple XML? There might be many more such questions, and I feel only if you/your Splunk development team is really strong you should switch away to HTML dashboard.

Moreover static files like CSS, JavaScript, Images, Icons etc are integral part of Splunk Dashboards, you should have a way of testing and promoting the same to your Splunk Environment. You may consider Non-Prod and Prod environment like a normal SDLC cycle with elevated access in Non Prod for you to promote and test your changes and your Splunk Admin to migrate the same to Prod. Even better scenario would be you create a temporary HTML dashboard (in Non Prod or Prod) to test your JavaScript changes and then work with Splunk Admin to have JavaScript changes deployed to retain your Simple XML Dashboard with static JavaScript.

There could be ways to test whether your static changes migrated to Prod or not.

1) Add console.log() in JavaScript with file version to check out deployment JavaScript version using Browser Inspector.
2) Static file once deployed can be viewed in Splunk using a path like following:

http://<YourSplunkServer>/<locale>/static/app/<YourSplunkApp>/<YourJSFile>.js

For example: http://localhost:8000/en-US/static/app/search/hello_world.js

Having said all these, once you convert Simple XML Dashboard to HTML, code gets segregated in following sections:

1. Top HTML section with html tags
2. Script section with JavaScript and Splunk JS

(a) JavaScript Section start (just below: var pageLoading = true;)
Your Modal Template and Modal View code can be kept here (since these are more like definitions, these can be kept at several places in the dashboard in fact can also be kept before Model View event is defined).

    var modalTemplate = "<div id=\"pivotModal\" class=\"modal\">" +
                   "<div class=\"modal-header\"><h3><%- title %></h3></div>" +
                   "<div class=\"modal-body\"></div>" +
                   "<div class=\"modal-footer\"><button class=\"close\">Close</button></div>" +
                   "</div>" +
                   "<div class=\"modal-backdrop\"></div>";

    var ModalView = Backbone.View.extend({

        defaults: {
           title: 'Not set'
        },        

        initialize: function(options) {
            this.options = options;
            this.options = _.extend({}, this.defaults, this.options);
            this.childViews = [];
            console.log('Hello from the modal window: ', this.options.title);
            this.template = _.template(modalTemplate);
        },

        events: {
           'click .close': 'close',
           'click .modal-backdrop': 'close'
        },

        render: function() {
            var data = { title : this.options.title }
            this.$el.html(this.template(data));
            return this;
        },

        show: function() {
            $(document.body).append(this.render().el);

            $(this.el).find('.modal-body').append('<div id="modalVizualization"/>');

            $(this.el).find('.modal').css({
                width:'90%',
                height:'auto',
                left: '5%',
                'margin-left': '0',
                'max-height':'100%'
            });

            var search = mvc.Components.get(this.options.search.id);

            var detailTable = new TableElement({
                    id: "detailTable",
                    managerid: search.name,
                    pageSize: "5",
                    el: $('#modalVizualization')
            }).render();

            this.childViews.push(detailTable);
            search.startSearch();                
        },

        close: function() {
           this.unbind();
           this.remove();
           _.each(this.childViews, function(childView) {

               childView.unbind();
               childView.remove();
           });
        }
    });

(b) Token Section

    // 
    // TOKENS
    //

The default (i.e. defaultTokenModel ) and submitted (i.e. submittedTokenModel) tokens get listed here. So if your JavaScript file has Token Handling, you should use one of these token handlers.

**(c)** Search Managers

    //
    // SEARCH MANAGERS
    //

The search managers are created here. Your code looks for detailsearch SearchManager to be created, which should go here.

      var detailSearch = new SearchManager({
                id: "detailSearch",
                earliest_time: "-24h@h",
                latest_time: "now",
                preview: true,
                cache: false,
                search: "index=_internal sourcetype=$sourcetype$ | timechart count" 
        }, {tokens: true, tokenNamespace: "submitted"});

(d) // SPLUNK LAYOUT and (e) // DASHBOARD EDITOR sections have no code changes

(f) Views : Visualization Elements, section have visualizations to be displayed on dashboard. If we have created a table with id="master", new table element master would already be present, we would need to add click event handler below the same.

    //
    // VIEWS: VISUALIZATION ELEMENTS
    //

    var master = new TableElement({
    ...
    ...
    ...
    }, {tokens: true, tokenNamespace: "submitted"}).render();

        master.on("click", function(e) {
            if(e.field === "sourcetype") {

                e.preventDefault();
                var _title = e.data['click.value'];
                submittedTokenModel.set('sourcetype', _title);
                var modal = new ModalView({ title: _title, search: detailSearch });
                modal.show();
            }
        });

(d) // VIEWS: FORM INPUTS and (e) // DASHBOARD READY sections have no code changes. (Your code mentions dynamic input to be created in comments, but not sure as I did not see the same in your code)

Following is the complete HTML as per your code (I have used Splunk Enterprise 7 to create the dashboard) :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Splunk Answers 591298 - Modal Window Using HTML Dashboard with JS HTML</title>
    <link rel="shortcut icon" href="/en-US/static/@FB592E2458E4D537E2C0C5FB336072C4851FE2C517060C29ED9A121948D79ED6/img/favicon.ico" />
    <link rel="stylesheet" type="text/css" href="{{SPLUNKWEB_URL_PREFIX}}/static/build/css/bootstrap-enterprise.css" />
    <link rel="stylesheet" type="text/css" href="{{SPLUNKWEB_URL_PREFIX}}/static/css/build/pages/dashboard-simple-bootstrap.min.css" />
    <link rel="stylesheet" type="text/css" media="all" href="{{SPLUNKWEB_URL_PREFIX}}/static/app/search/dashboard.css" />


        <meta name="referrer" content="never" />
        <meta name="referrer" content="no-referrer" />

          <script>
                window._splunk_metrics_events = {
                   push : function() {},
                   active: false,
                   }
          </script>
    </head>
<body class="simplexml preload locale-en" data-splunk-version="7.0.0" data-splunk-product="enterprise">
<!-- 
BEGIN LAYOUT
This section contains the layout for the dashboard. Splunk uses proprietary
styles in <div> tags, similar to Bootstrap's grid system. 
-->
<header>
    <a class="navSkip" href="#navSkip" tabindex="1">Screen reader users, click here to skip the navigation bar</a>
    <div class="header splunk-header">
            <div id="placeholder-splunk-bar">
                <a href="{{SPLUNKWEB_URL_PREFIX}}/app/launcher/home" class="brand" title="splunk > listen to your data">splunk<strong>></strong></a>
            </div>
                <div id="placeholder-app-bar"></div>
    </div>
    <a id="navSkip"></a>
</header>
<div class="dashboard-body container-fluid main-section-body" data-role="main">
    <div class="dashboard-header clearfix">
        <h2>Modal Demo HTML</h2>
    </div>
    <div class="fieldset">
        <div class="input input-text" id="input1">
            <label>sourcetype</label>
        </div>
    </div>


    <div id="row1" class="dashboard-row dashboard-row1">
        <div id="panel1" class="dashboard-cell" style="width: 100%;">
            <div class="dashboard-panel clearfix">

                <div class="panel-element-row">
                    <div id="master" class="dashboard-element table" style="width: 100%">
                        <div class="panel-head">
                            <h3>Master</h3>
                        </div>
                        <div class="panel-body"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- 
END LAYOUT
-->

<script src="{{SPLUNKWEB_URL_PREFIX}}/config?autoload=1" crossorigin="use-credentials"></script>
<script src="{{SPLUNKWEB_URL_PREFIX}}/static/js/i18n.js"></script>
<script src="{{SPLUNKWEB_URL_PREFIX}}/i18ncatalog?autoload=1"></script>
<script src="{{SPLUNKWEB_URL_PREFIX}}/static/build/simplexml/index.js"></script>
<script type="text/javascript">
// <![CDATA[
// <![CDATA[
//
// LIBRARY REQUIREMENTS
//
// In the require function, we include the necessary libraries and modules for
// the HTML dashboard. Then, we pass variable names for these libraries and
// modules as function parameters, in order.
// 
// When you add libraries or modules, remember to retain this mapping order
// between the library or module and its function parameter. You can do this by
// adding to the end of these lists, as shown in the commented examples below.

require([
    "splunkjs/mvc",
    "splunkjs/mvc/utils",
    "splunkjs/mvc/tokenutils",
    "underscore",
    "backbone",
    "jquery",
    "splunkjs/mvc/simplexml",
    "splunkjs/mvc/layoutview",
    "splunkjs/mvc/simplexml/dashboardview",
    "splunkjs/mvc/simplexml/dashboard/panelref",
    "splunkjs/mvc/simplexml/element/chart",
    "splunkjs/mvc/simplexml/element/event",
    "splunkjs/mvc/simplexml/element/html",
    "splunkjs/mvc/simplexml/element/list",
    "splunkjs/mvc/simplexml/element/map",
    "splunkjs/mvc/simplexml/element/single",
    "splunkjs/mvc/simplexml/element/table",
    "splunkjs/mvc/simplexml/element/visualization",
    "splunkjs/mvc/simpleform/formutils",
    "splunkjs/mvc/simplexml/eventhandler",
    "splunkjs/mvc/simplexml/searcheventhandler",
    "splunkjs/mvc/simpleform/input/dropdown",
    "splunkjs/mvc/simpleform/input/radiogroup",
    "splunkjs/mvc/simpleform/input/linklist",
    "splunkjs/mvc/simpleform/input/multiselect",
    "splunkjs/mvc/simpleform/input/checkboxgroup",
    "splunkjs/mvc/simpleform/input/text",
    "splunkjs/mvc/simpleform/input/timerange",
    "splunkjs/mvc/simpleform/input/submit",
    "splunkjs/mvc/searchmanager",
    "splunkjs/mvc/savedsearchmanager",
    "splunkjs/mvc/postprocessmanager",
    "splunkjs/mvc/simplexml/urltokenmodel"
    // Add comma-separated libraries and modules manually here, for example:
    // ..."splunkjs/mvc/simplexml/urltokenmodel",
    // "splunkjs/mvc/tokenforwarder"
    ],
    function(
        mvc,
        utils,
        TokenUtils,
        _,
        Backbone,
        $,
        DashboardController,
        LayoutView,
        Dashboard,
        PanelRef,
        ChartElement,
        EventElement,
        HtmlElement,
        ListElement,
        MapElement,
        SingleElement,
        TableElement,
        VisualizationElement,
        FormUtils,
        EventHandler,
        SearchEventHandler,
        DropdownInput,
        RadioGroupInput,
        LinkListInput,
        MultiSelectInput,
        CheckboxGroupInput,
        TextInput,
        TimeRangeInput,
        SubmitButton,
        SearchManager,
        SavedSearchManager,
        PostProcessManager,
        UrlTokenModel

        // Add comma-separated parameter names here, for example: 
        // ...UrlTokenModel, 
        // TokenForwarder
        ) {

        var pageLoading = true;


        var modalTemplate = "<div id=\"pivotModal\" class=\"modal\">" +
                       "<div class=\"modal-header\"><h3><%- title %></h3></div>" +
                       "<div class=\"modal-body\"></div>" +
                       "<div class=\"modal-footer\"><button class=\"close\">Close</button></div>" +
                       "</div>" +
                       "<div class=\"modal-backdrop\"></div>";

        var ModalView = Backbone.View.extend({

            defaults: {
               title: 'Not set'
            },        

            initialize: function(options) {
                this.options = options;
                this.options = _.extend({}, this.defaults, this.options);
                this.childViews = [];
                console.log('Hello from the modal window: ', this.options.title);
                this.template = _.template(modalTemplate);
            },

            events: {
               'click .close': 'close',
               'click .modal-backdrop': 'close'
            },

            render: function() {
                var data = { title : this.options.title }
                this.$el.html(this.template(data));
                return this;
            },

            show: function() {
                $(document.body).append(this.render().el);

                $(this.el).find('.modal-body').append('<div id="modalVizualization"/>');

                $(this.el).find('.modal').css({
                    width:'90%',
                    height:'auto',
                    left: '5%',
                    'margin-left': '0',
                    'max-height':'100%'
                });

                var search = mvc.Components.get(this.options.search.id);

                var detailTable = new TableElement({
                        id: "detailTable",
                        managerid: search.name,
                        pageSize: "5",
                        el: $('#modalVizualization')
                }).render();

                this.childViews.push(detailTable);
                search.startSearch();                
            },

            close: function() {
               this.unbind();
               this.remove();
               _.each(this.childViews, function(childView) {

                   childView.unbind();
                   childView.remove();

               });
            }

        });


        // 
        // TOKENS
        //

        // Create token namespaces
        var urlTokenModel = new UrlTokenModel();
        mvc.Components.registerInstance('url', urlTokenModel);
        var defaultTokenModel = mvc.Components.getInstance('default', {create: true});
        var submittedTokenModel = mvc.Components.getInstance('submitted', {create: true});

        urlTokenModel.on('url:navigate', function() {
            defaultTokenModel.set(urlTokenModel.toJSON());
            if (!_.isEmpty(urlTokenModel.toJSON()) && !_.all(urlTokenModel.toJSON(), _.isUndefined)) {
                submitTokens();
            } else {
                submittedTokenModel.clear();
            }
        });

        // Initialize tokens
        defaultTokenModel.set(urlTokenModel.toJSON());

        function submitTokens() {
            // Copy the contents of the defaultTokenModel to the submittedTokenModel and urlTokenModel
            FormUtils.submitForm({ replaceState: pageLoading });
        }

        function setToken(name, value) {
            defaultTokenModel.set(name, value);
            submittedTokenModel.set(name, value);
        }

        function unsetToken(name) {
            defaultTokenModel.unset(name);
            submittedTokenModel.unset(name);
        }


        //
        // SEARCH MANAGERS
        //


var search1 = new SearchManager({
            "id": "search1",
            "status_buckets": 0,
            "cancelOnUnload": true,
            "sample_ratio": null,
            "latest_time": "now",
            "search": "index=_internal    | stats count by sourcetype",
            "earliest_time": "-60m@m",
            "app": utils.getCurrentApp(),
            "auto_cancel": 90,
            "preview": true,
            "tokenDependencies": {
            },
            "runWhenTimeIsUndefined": false
        }, {tokens: true, tokenNamespace: "submitted"});


          var detailSearch = new SearchManager({
                    id: "detailSearch",
                    earliest_time: "-24h@h",
                    latest_time: "now",
                    preview: true,
                    cache: false,
                    search: "index=_internal sourcetype=$sourcetype$ | timechart count" 
            }, {tokens: true, tokenNamespace: "submitted"});  


        //
        // SPLUNK LAYOUT
        //

        $('header').remove();
        new LayoutView({"hideAppBar": false, "hideChrome": false, "hideFooter": false, "hideSplunkBar": false})
            .render()
            .getContainerElement()
            .appendChild($('.dashboard-body')[0]);

        //
        // DASHBOARD EDITOR
        //

        new Dashboard({
            id: 'dashboard',
            el: $('.dashboard-body'),
            showTitle: true,
            editable: true
        }, {tokens: true}).render();


        //
        // VIEWS: VISUALIZATION ELEMENTS
        //

        var master = new TableElement({
            "id": "master",
            "drilldown": "row",
            "managerid": "search1",
            "el": $('#master')
        }, {tokens: true, tokenNamespace: "submitted"}).render();

            master.on("click", function(e) {
                if(e.field === "sourcetype") {

                    e.preventDefault();
                    var _title = e.data['click.value'];
                    submittedTokenModel.set('sourcetype', _title);
                    var modal = new ModalView({ title: _title, search: detailSearch });
                    modal.show();
                }
            });


        //
        // VIEWS: FORM INPUTS
        //

        var input1 = new TextInput({
            "id": "input1",
            "searchWhenChanged": true,
            "value": "$form.sourcetype$",
            "el": $('#input1')
        }, {tokens: true}).render();

        input1.on("change", function(newValue) {
            FormUtils.handleValueChange(input1);
        });

        DashboardController.onReady(function() {
            if (!submittedTokenModel.has('earliest') && !submittedTokenModel.has('latest')) {
                submittedTokenModel.set({ earliest: '0', latest: '' });
            }
        });

        // Initialize time tokens to default
        if (!defaultTokenModel.has('earliest') && !defaultTokenModel.has('latest')) {
            defaultTokenModel.set({ earliest: '0', latest: '' });
        }

        if (!_.isEmpty(urlTokenModel.toJSON())){
            submitTokens();
        }


        //
        // DASHBOARD READY
        //

        DashboardController.ready();
        pageLoading = false;

    }
);
// ]]>
</script>
</body>
</html>
____________________________________________
| makeresults | eval message= "Happy Splunking!!!"

View solution in original post

niketn
Legend

@kdimaria, before you switch to HTML Dashboard you should keep several things to your consideration:

  1. How often do you UI > Edit Panel vs JavaScript Change?
  2. Do you have Simple XML Chart configuration?
  3. Do you have Event Handlers in Simple XML?
  4. Do you have Power Users in your team, who are only capable of UI Edit or Simple XML Chart Configuration and no JavaScript or Splunk JS Stack or Splunk Web Framework?
  5. Are you more comfortable coding in HTML Dashboard as compared to Simple XML? There might be many more such questions, and I feel only if you/your Splunk development team is really strong you should switch away to HTML dashboard.

Moreover static files like CSS, JavaScript, Images, Icons etc are integral part of Splunk Dashboards, you should have a way of testing and promoting the same to your Splunk Environment. You may consider Non-Prod and Prod environment like a normal SDLC cycle with elevated access in Non Prod for you to promote and test your changes and your Splunk Admin to migrate the same to Prod. Even better scenario would be you create a temporary HTML dashboard (in Non Prod or Prod) to test your JavaScript changes and then work with Splunk Admin to have JavaScript changes deployed to retain your Simple XML Dashboard with static JavaScript.

There could be ways to test whether your static changes migrated to Prod or not.

1) Add console.log() in JavaScript with file version to check out deployment JavaScript version using Browser Inspector.
2) Static file once deployed can be viewed in Splunk using a path like following:

http://<YourSplunkServer>/<locale>/static/app/<YourSplunkApp>/<YourJSFile>.js

For example: http://localhost:8000/en-US/static/app/search/hello_world.js

Having said all these, once you convert Simple XML Dashboard to HTML, code gets segregated in following sections:

1. Top HTML section with html tags
2. Script section with JavaScript and Splunk JS

(a) JavaScript Section start (just below: var pageLoading = true;)
Your Modal Template and Modal View code can be kept here (since these are more like definitions, these can be kept at several places in the dashboard in fact can also be kept before Model View event is defined).

    var modalTemplate = "<div id=\"pivotModal\" class=\"modal\">" +
                   "<div class=\"modal-header\"><h3><%- title %></h3></div>" +
                   "<div class=\"modal-body\"></div>" +
                   "<div class=\"modal-footer\"><button class=\"close\">Close</button></div>" +
                   "</div>" +
                   "<div class=\"modal-backdrop\"></div>";

    var ModalView = Backbone.View.extend({

        defaults: {
           title: 'Not set'
        },        

        initialize: function(options) {
            this.options = options;
            this.options = _.extend({}, this.defaults, this.options);
            this.childViews = [];
            console.log('Hello from the modal window: ', this.options.title);
            this.template = _.template(modalTemplate);
        },

        events: {
           'click .close': 'close',
           'click .modal-backdrop': 'close'
        },

        render: function() {
            var data = { title : this.options.title }
            this.$el.html(this.template(data));
            return this;
        },

        show: function() {
            $(document.body).append(this.render().el);

            $(this.el).find('.modal-body').append('<div id="modalVizualization"/>');

            $(this.el).find('.modal').css({
                width:'90%',
                height:'auto',
                left: '5%',
                'margin-left': '0',
                'max-height':'100%'
            });

            var search = mvc.Components.get(this.options.search.id);

            var detailTable = new TableElement({
                    id: "detailTable",
                    managerid: search.name,
                    pageSize: "5",
                    el: $('#modalVizualization')
            }).render();

            this.childViews.push(detailTable);
            search.startSearch();                
        },

        close: function() {
           this.unbind();
           this.remove();
           _.each(this.childViews, function(childView) {

               childView.unbind();
               childView.remove();
           });
        }
    });

(b) Token Section

    // 
    // TOKENS
    //

The default (i.e. defaultTokenModel ) and submitted (i.e. submittedTokenModel) tokens get listed here. So if your JavaScript file has Token Handling, you should use one of these token handlers.

**(c)** Search Managers

    //
    // SEARCH MANAGERS
    //

The search managers are created here. Your code looks for detailsearch SearchManager to be created, which should go here.

      var detailSearch = new SearchManager({
                id: "detailSearch",
                earliest_time: "-24h@h",
                latest_time: "now",
                preview: true,
                cache: false,
                search: "index=_internal sourcetype=$sourcetype$ | timechart count" 
        }, {tokens: true, tokenNamespace: "submitted"});

(d) // SPLUNK LAYOUT and (e) // DASHBOARD EDITOR sections have no code changes

(f) Views : Visualization Elements, section have visualizations to be displayed on dashboard. If we have created a table with id="master", new table element master would already be present, we would need to add click event handler below the same.

    //
    // VIEWS: VISUALIZATION ELEMENTS
    //

    var master = new TableElement({
    ...
    ...
    ...
    }, {tokens: true, tokenNamespace: "submitted"}).render();

        master.on("click", function(e) {
            if(e.field === "sourcetype") {

                e.preventDefault();
                var _title = e.data['click.value'];
                submittedTokenModel.set('sourcetype', _title);
                var modal = new ModalView({ title: _title, search: detailSearch });
                modal.show();
            }
        });

(d) // VIEWS: FORM INPUTS and (e) // DASHBOARD READY sections have no code changes. (Your code mentions dynamic input to be created in comments, but not sure as I did not see the same in your code)

Following is the complete HTML as per your code (I have used Splunk Enterprise 7 to create the dashboard) :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Splunk Answers 591298 - Modal Window Using HTML Dashboard with JS HTML</title>
    <link rel="shortcut icon" href="/en-US/static/@FB592E2458E4D537E2C0C5FB336072C4851FE2C517060C29ED9A121948D79ED6/img/favicon.ico" />
    <link rel="stylesheet" type="text/css" href="{{SPLUNKWEB_URL_PREFIX}}/static/build/css/bootstrap-enterprise.css" />
    <link rel="stylesheet" type="text/css" href="{{SPLUNKWEB_URL_PREFIX}}/static/css/build/pages/dashboard-simple-bootstrap.min.css" />
    <link rel="stylesheet" type="text/css" media="all" href="{{SPLUNKWEB_URL_PREFIX}}/static/app/search/dashboard.css" />


        <meta name="referrer" content="never" />
        <meta name="referrer" content="no-referrer" />

          <script>
                window._splunk_metrics_events = {
                   push : function() {},
                   active: false,
                   }
          </script>
    </head>
<body class="simplexml preload locale-en" data-splunk-version="7.0.0" data-splunk-product="enterprise">
<!-- 
BEGIN LAYOUT
This section contains the layout for the dashboard. Splunk uses proprietary
styles in <div> tags, similar to Bootstrap's grid system. 
-->
<header>
    <a class="navSkip" href="#navSkip" tabindex="1">Screen reader users, click here to skip the navigation bar</a>
    <div class="header splunk-header">
            <div id="placeholder-splunk-bar">
                <a href="{{SPLUNKWEB_URL_PREFIX}}/app/launcher/home" class="brand" title="splunk > listen to your data">splunk<strong>></strong></a>
            </div>
                <div id="placeholder-app-bar"></div>
    </div>
    <a id="navSkip"></a>
</header>
<div class="dashboard-body container-fluid main-section-body" data-role="main">
    <div class="dashboard-header clearfix">
        <h2>Modal Demo HTML</h2>
    </div>
    <div class="fieldset">
        <div class="input input-text" id="input1">
            <label>sourcetype</label>
        </div>
    </div>


    <div id="row1" class="dashboard-row dashboard-row1">
        <div id="panel1" class="dashboard-cell" style="width: 100%;">
            <div class="dashboard-panel clearfix">

                <div class="panel-element-row">
                    <div id="master" class="dashboard-element table" style="width: 100%">
                        <div class="panel-head">
                            <h3>Master</h3>
                        </div>
                        <div class="panel-body"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- 
END LAYOUT
-->

<script src="{{SPLUNKWEB_URL_PREFIX}}/config?autoload=1" crossorigin="use-credentials"></script>
<script src="{{SPLUNKWEB_URL_PREFIX}}/static/js/i18n.js"></script>
<script src="{{SPLUNKWEB_URL_PREFIX}}/i18ncatalog?autoload=1"></script>
<script src="{{SPLUNKWEB_URL_PREFIX}}/static/build/simplexml/index.js"></script>
<script type="text/javascript">
// <![CDATA[
// <![CDATA[
//
// LIBRARY REQUIREMENTS
//
// In the require function, we include the necessary libraries and modules for
// the HTML dashboard. Then, we pass variable names for these libraries and
// modules as function parameters, in order.
// 
// When you add libraries or modules, remember to retain this mapping order
// between the library or module and its function parameter. You can do this by
// adding to the end of these lists, as shown in the commented examples below.

require([
    "splunkjs/mvc",
    "splunkjs/mvc/utils",
    "splunkjs/mvc/tokenutils",
    "underscore",
    "backbone",
    "jquery",
    "splunkjs/mvc/simplexml",
    "splunkjs/mvc/layoutview",
    "splunkjs/mvc/simplexml/dashboardview",
    "splunkjs/mvc/simplexml/dashboard/panelref",
    "splunkjs/mvc/simplexml/element/chart",
    "splunkjs/mvc/simplexml/element/event",
    "splunkjs/mvc/simplexml/element/html",
    "splunkjs/mvc/simplexml/element/list",
    "splunkjs/mvc/simplexml/element/map",
    "splunkjs/mvc/simplexml/element/single",
    "splunkjs/mvc/simplexml/element/table",
    "splunkjs/mvc/simplexml/element/visualization",
    "splunkjs/mvc/simpleform/formutils",
    "splunkjs/mvc/simplexml/eventhandler",
    "splunkjs/mvc/simplexml/searcheventhandler",
    "splunkjs/mvc/simpleform/input/dropdown",
    "splunkjs/mvc/simpleform/input/radiogroup",
    "splunkjs/mvc/simpleform/input/linklist",
    "splunkjs/mvc/simpleform/input/multiselect",
    "splunkjs/mvc/simpleform/input/checkboxgroup",
    "splunkjs/mvc/simpleform/input/text",
    "splunkjs/mvc/simpleform/input/timerange",
    "splunkjs/mvc/simpleform/input/submit",
    "splunkjs/mvc/searchmanager",
    "splunkjs/mvc/savedsearchmanager",
    "splunkjs/mvc/postprocessmanager",
    "splunkjs/mvc/simplexml/urltokenmodel"
    // Add comma-separated libraries and modules manually here, for example:
    // ..."splunkjs/mvc/simplexml/urltokenmodel",
    // "splunkjs/mvc/tokenforwarder"
    ],
    function(
        mvc,
        utils,
        TokenUtils,
        _,
        Backbone,
        $,
        DashboardController,
        LayoutView,
        Dashboard,
        PanelRef,
        ChartElement,
        EventElement,
        HtmlElement,
        ListElement,
        MapElement,
        SingleElement,
        TableElement,
        VisualizationElement,
        FormUtils,
        EventHandler,
        SearchEventHandler,
        DropdownInput,
        RadioGroupInput,
        LinkListInput,
        MultiSelectInput,
        CheckboxGroupInput,
        TextInput,
        TimeRangeInput,
        SubmitButton,
        SearchManager,
        SavedSearchManager,
        PostProcessManager,
        UrlTokenModel

        // Add comma-separated parameter names here, for example: 
        // ...UrlTokenModel, 
        // TokenForwarder
        ) {

        var pageLoading = true;


        var modalTemplate = "<div id=\"pivotModal\" class=\"modal\">" +
                       "<div class=\"modal-header\"><h3><%- title %></h3></div>" +
                       "<div class=\"modal-body\"></div>" +
                       "<div class=\"modal-footer\"><button class=\"close\">Close</button></div>" +
                       "</div>" +
                       "<div class=\"modal-backdrop\"></div>";

        var ModalView = Backbone.View.extend({

            defaults: {
               title: 'Not set'
            },        

            initialize: function(options) {
                this.options = options;
                this.options = _.extend({}, this.defaults, this.options);
                this.childViews = [];
                console.log('Hello from the modal window: ', this.options.title);
                this.template = _.template(modalTemplate);
            },

            events: {
               'click .close': 'close',
               'click .modal-backdrop': 'close'
            },

            render: function() {
                var data = { title : this.options.title }
                this.$el.html(this.template(data));
                return this;
            },

            show: function() {
                $(document.body).append(this.render().el);

                $(this.el).find('.modal-body').append('<div id="modalVizualization"/>');

                $(this.el).find('.modal').css({
                    width:'90%',
                    height:'auto',
                    left: '5%',
                    'margin-left': '0',
                    'max-height':'100%'
                });

                var search = mvc.Components.get(this.options.search.id);

                var detailTable = new TableElement({
                        id: "detailTable",
                        managerid: search.name,
                        pageSize: "5",
                        el: $('#modalVizualization')
                }).render();

                this.childViews.push(detailTable);
                search.startSearch();                
            },

            close: function() {
               this.unbind();
               this.remove();
               _.each(this.childViews, function(childView) {

                   childView.unbind();
                   childView.remove();

               });
            }

        });


        // 
        // TOKENS
        //

        // Create token namespaces
        var urlTokenModel = new UrlTokenModel();
        mvc.Components.registerInstance('url', urlTokenModel);
        var defaultTokenModel = mvc.Components.getInstance('default', {create: true});
        var submittedTokenModel = mvc.Components.getInstance('submitted', {create: true});

        urlTokenModel.on('url:navigate', function() {
            defaultTokenModel.set(urlTokenModel.toJSON());
            if (!_.isEmpty(urlTokenModel.toJSON()) && !_.all(urlTokenModel.toJSON(), _.isUndefined)) {
                submitTokens();
            } else {
                submittedTokenModel.clear();
            }
        });

        // Initialize tokens
        defaultTokenModel.set(urlTokenModel.toJSON());

        function submitTokens() {
            // Copy the contents of the defaultTokenModel to the submittedTokenModel and urlTokenModel
            FormUtils.submitForm({ replaceState: pageLoading });
        }

        function setToken(name, value) {
            defaultTokenModel.set(name, value);
            submittedTokenModel.set(name, value);
        }

        function unsetToken(name) {
            defaultTokenModel.unset(name);
            submittedTokenModel.unset(name);
        }


        //
        // SEARCH MANAGERS
        //


var search1 = new SearchManager({
            "id": "search1",
            "status_buckets": 0,
            "cancelOnUnload": true,
            "sample_ratio": null,
            "latest_time": "now",
            "search": "index=_internal    | stats count by sourcetype",
            "earliest_time": "-60m@m",
            "app": utils.getCurrentApp(),
            "auto_cancel": 90,
            "preview": true,
            "tokenDependencies": {
            },
            "runWhenTimeIsUndefined": false
        }, {tokens: true, tokenNamespace: "submitted"});


          var detailSearch = new SearchManager({
                    id: "detailSearch",
                    earliest_time: "-24h@h",
                    latest_time: "now",
                    preview: true,
                    cache: false,
                    search: "index=_internal sourcetype=$sourcetype$ | timechart count" 
            }, {tokens: true, tokenNamespace: "submitted"});  


        //
        // SPLUNK LAYOUT
        //

        $('header').remove();
        new LayoutView({"hideAppBar": false, "hideChrome": false, "hideFooter": false, "hideSplunkBar": false})
            .render()
            .getContainerElement()
            .appendChild($('.dashboard-body')[0]);

        //
        // DASHBOARD EDITOR
        //

        new Dashboard({
            id: 'dashboard',
            el: $('.dashboard-body'),
            showTitle: true,
            editable: true
        }, {tokens: true}).render();


        //
        // VIEWS: VISUALIZATION ELEMENTS
        //

        var master = new TableElement({
            "id": "master",
            "drilldown": "row",
            "managerid": "search1",
            "el": $('#master')
        }, {tokens: true, tokenNamespace: "submitted"}).render();

            master.on("click", function(e) {
                if(e.field === "sourcetype") {

                    e.preventDefault();
                    var _title = e.data['click.value'];
                    submittedTokenModel.set('sourcetype', _title);
                    var modal = new ModalView({ title: _title, search: detailSearch });
                    modal.show();
                }
            });


        //
        // VIEWS: FORM INPUTS
        //

        var input1 = new TextInput({
            "id": "input1",
            "searchWhenChanged": true,
            "value": "$form.sourcetype$",
            "el": $('#input1')
        }, {tokens: true}).render();

        input1.on("change", function(newValue) {
            FormUtils.handleValueChange(input1);
        });

        DashboardController.onReady(function() {
            if (!submittedTokenModel.has('earliest') && !submittedTokenModel.has('latest')) {
                submittedTokenModel.set({ earliest: '0', latest: '' });
            }
        });

        // Initialize time tokens to default
        if (!defaultTokenModel.has('earliest') && !defaultTokenModel.has('latest')) {
            defaultTokenModel.set({ earliest: '0', latest: '' });
        }

        if (!_.isEmpty(urlTokenModel.toJSON())){
            submitTokens();
        }


        //
        // DASHBOARD READY
        //

        DashboardController.ready();
        pageLoading = false;

    }
);
// ]]>
</script>
</body>
</html>
____________________________________________
| makeresults | eval message= "Happy Splunking!!!"

kdimaria
Communicator

Thank you so much you are the greatest. Our team never uses the UI to edit panels. All of our dashboards have been switched to HTML so we just edit the HTML and JS code. I am not familiar with simple XML but was trying to follow a tutorial in simple XML and then I wanted to convert it to HTML so I could figure out how to incorporate that functionality into my teams dashboard.

0 Karma

niketn
Legend

@kdimaria, Glad it worked. If your entire team specializes in HTML dashboard then it is great. You will open up your dashboard to all the possibilities you can imagine 🙂

____________________________________________
| makeresults | eval message= "Happy Splunking!!!"
0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

hi @kdimaria,

1) Create a javascript file myjavascript.js in SPLUNK_HOME/etc/app/MYAPP/appserver/static/ folder. Create folders if not exists and put you javascript code in it.

require([
     'underscore',
     'backbone',
     '../app/dev_app/components/ModalView',
     'splunkjs/mvc',
     'splunkjs/mvc/searchmanager',
     'splunkjs/mvc/simplexml/ready!'
 ], function(_, Backbone, ModalView, mvc, SearchManager) {

     var master = mvc.Components.get("master");
     var tokens = mvc.Components.getInstance("submitted");

     var detailSearch = new SearchManager({
             id: "detailSearch",
             earliest_time: "-24h@h",
             latest_time: "now",
             preview: true,
             cache: false,
             search: "index=_internal sourcetype=$sourcetype$ | timechart count" 
     }, {tokens: true, tokenNamespace: "submitted"});  

     master.on("click", function(e) {
         if(e.field === "sourcetype") {
             e.preventDefault();
             var _title = e.data['click.value'];
             tokens.set('sourcetype', _title);
             var modal = new ModalView({ title: _title, search: detailSearch });
             modal.show();

         }

     });

 });

 define([
     'underscore',
     'backbone',
     'jquery',
     'splunkjs/mvc',
     'splunkjs/mvc/searchmanager',
     'splunkjs/mvc/simplexml/element/table'
     ], function(_, Backbone, $, mvc, SearchManager, TableElement) {
            var modalTemplate = "<div id="pivotModal" class="modal">" +
                        "<div class="modal-header"><h3>Blah</h3></div>" +
                        "<div class="modal-body"></div>" +
                        "<div class="modal-footer"><button class="close">Close</button></div>" +
                        "</div>" +
                        "<div class="modal-backdrop"></div>";

     var ModalView = Backbone.View.extend({

             defaults: {
                title: 'Not set'
             },        

             initialize: function(options) {
                 this.options = options;
                 this.options = _.extend({}, this.defaults, this.options);
                 this.childViews = [];
                 console.log('Hello from the modal window: ', this.options.title);
                 this.template = _.template(modalTemplate);
             },

             events: {
                'click .close': 'close',
                'click .modal-backdrop': 'close'
             },

             render: function() {
                 var data = { title : this.options.title }
                 this.$el.html(this.template(data));
                 return this;
             },

             show: function() {
                 $(document.body).append(this.render().el);

                 $(this.el).find('.modal-body').append('<div id="modalVizualization"/>');

                 $(this.el).find('.modal').css({
                     width:'90%',
                     height:'auto',
                     left: '5%',
                     'margin-left': '0',
                     'max-height':'100%'
                 });

                 var search = mvc.Components.get(this.options.search.id);

                 var detailTable = new TableElement({
                         id: "detailTable",
                         managerid: search.name,
                         pageSize: "5",
                         el: $('#modalVizualization')
                 }).render();

                 this.childViews.push(detailTable);
                 search.startSearch();                
             },

             close: function() {
                this.unbind();
                this.remove();
                _.each(this.childViews, function(childView) {

                    childView.unbind();
                    childView.remove();

                });
             }

         });

         return ModalView;

 });

2) update your XML coce and add javascript file.

<form script="myjavascript.js">
  <label>Modal Demo</label>
   <fieldset submitButton="false">
     <!--
             Create an input to store the drilldown value. It will be hidden using custom javascript when
             the dashboard is loaded.
          -->
     <input type="text" token="sourcetype" searchWhenChanged="true"></input>
   </fieldset>
   <row>
     <panel>
       <table id="master">
         <title>Master</title>
         <searchString>index=_internal | stats count by sourcetype</searchString>
         <earliestTime>-60m@m</earliestTime>
         <latestTime>now</latestTime>
         <!-- Set the type of of drilldown, since we will always consume the same field, use row-->
         <option name="drilldown">row</option>
       </table>
     </panel>

   </row>
</form>

Please try this and let check below link for more info.

http://dev.splunk.com/view/webframework-developapps/SP-CAAAE4A

Happy Splunking

0 Karma

kdimaria
Communicator

Sorry but in the question I asked if it was possible to keep it all in one file..

0 Karma

niketn
Legend

@kdimaria, you can add CSS using HTML panels in Simple XML but JS files have to be external which have to be included using script="<YourJSFileName>.js" attribute in your dashboard or form. Everything at one place i.e. CSS, JavaScript is possible only in HTML Dashboards not simple XML.

What is the issue with having a separate JavaScript file? Are you comfortable switching from Simple XML to HTML dashboard (knowing that reverse process is not possible)?

____________________________________________
| makeresults | eval message= "Happy Splunking!!!"
0 Karma

kdimaria
Communicator

I work using Splunk in an environment where I do not have permissions to see or change the SPLUNK_HOME/etc/app/MYAPP/appserver/static/ folder and add a java script file. I can pretty much just modify the dashboards HTML or XML code.

kdimaria
Communicator

When I convert the dashboard to HMTL I dont know how to incorporate in that JS.

0 Karma
Get Updates on the Splunk Community!

Cloud Platform & Enterprise: Classic Dashboard Export Feature Deprecation

As of Splunk Cloud Platform 9.3.2408 and Splunk Enterprise 9.4, classic dashboard export features are now ...

Explore the Latest Educational Offerings from Splunk (November Releases)

At Splunk Education, we are committed to providing a robust learning experience for all users, regardless of ...

New This Month in Splunk Observability Cloud - Metrics Usage Analytics, Enhanced K8s ...

The latest enhancements across the Splunk Observability portfolio deliver greater flexibility, better data and ...