Splunk Search

What is my best approach to creating a expand / collapse feature on my dashboard?

bmendez0428
Explorer

I've only been "Splunking" for about a month now so I am pretty new to this.

I want to add a button to expand certain groups with the same name in the application name column. For example, my first 4 rows on my dashboard table are of the same application name. How can I group them all to the first row? And so on...After clicking the button I would like the row to expand/close by group. I'm not sure what the best approach is. I also attached the front end photo of the dashboard that I have to modify.

CSS:

    <style>
        .custom-text-value {
            font-size: 16px;
            margin: 55px auto;
            text-align: center;
            font-weight: bold;
            color: rgb(85, 85, 85);
        }
        .custom-text-value:before {
            font-family: "Splunk Icons";
            font-style: normal;
            font-weight: normal;
            text-decoration: inherit;
            font-size: 110%;
        }

        .custom-result-value {
            font-size: 16px;
            margin: 55px auto;
            text-align: center;
            font-weight: bold;
            color: rgb(85, 85, 85);
        }
        .custom-result-value:before {
            font-family: "Splunk Icons";
            font-style: normal;
            font-weight: normal;
            text-decoration: inherit;
            font-size: 110%;
        }
        .severe.custom-result-value:before {
            content: "\2297";
        }
        .severe.custom-result-value {
            color: rgb(217, 63, 60);
        }
        .high.custom-result-value {
            color: rgb(245, 143, 57);
        }
        .high.custom-result-value:before {
            content: "\ECD4";
        }
        .elevated.custom-result-value {
            color: rgb(247, 188, 56);
        }
        .elevated.custom-result-value:before {
            content: "\26A0";
        }
        .low.custom-result-value {
            color: rgb(101, 166, 55);
        }
        .low.custom-result-value:before {
            content: "\ECD3";
        }
        .guarded.custom-result-value {
            color: rgb(109, 183, 198);
        }
        .guarded.custom-result-value:before {
            content: "\0049";
        }
        .custom-result-value.icon-only {
            font-size: 90px;
        }

        td.icon {
            text-align: center;
        }
        td.icon i {
            font-size: 30px;
            text-shadow: 1px 1px #aaa;
        }
        td.icon .severe {

            color: red;
        }
        td.icon .elevated {
            color: yellow;
        }
        td.icon .low {
            color: #006400;
        }        
        .btn edit-export{
            display: none;
        }        
    </style>

JS+Search:

require([
    "splunkjs/mvc",
    "splunkjs/mvc/utils",
    "splunkjs/mvc/tokenutils",
    "underscore",
    "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",
    "splunkjs/mvc/tableview",
    "splunkjs/ready!"   
    // Add comma-separated libraries and modules manually here, for example:
    // ..."splunkjs/mvc/simplexml/urltokenmodel",
    // "splunkjs/mvc/tokenforwarder"
    ],
    function(
        mvc,
        utils,
        TokenUtils,
        _,
        $,
        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;


        //
        // 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
        //
        //Can confirm that the search query works.
    var search1 = new SearchManager({
            "id": "search1",
            "sample_ratio": null,
            "status_buckets": 0,
            "earliest_time": "-1h@h",
//            "earliest_time": "rt-3h",
            "search": "index=\"TEM_Availability_Dashboard\" |eval displayValue=case(TestResult_Value == \"PASSED\", \"low\", TestResult_Value == \"FAILED\", \"severe\") \
            |dedup Application_Name, TestCase_Value, SwimLane_Value, TestResult_Value |sort Application_Name, TestCase_Value \
|eval QA1 = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"QA1\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"QA1\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"QA1\",\"NA\") \
|eval QA2 = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"QA2\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"QA2\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"QA2\",\"NA\") \
|eval QA3 = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"QA3\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"QA3\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"QA3\",\"NA\") \
|eval QA4 = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"QA4\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"QA4\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"QA4\",\"NA\") \
|eval QA5 = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"QA5\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"QA5\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"QA5\",\"NA\") \
|eval QA6 = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"QA6\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"QA6\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"QA6\",\"NA\") \
|eval QA7 = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"QA7\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"QA7\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"QA7\",\"NA\") \
|eval STG = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"STG\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"STG\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"STG\",\"NA\")  \
|eval STG2 = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"STG2\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"STG2\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"STG2\",\"NA\") \
|eval pve = case(like(TestResult_Value,\"PASSED\") AND SwimLane_Value==\"pve\",\"low\",like(TestResult_Value,\"FAILED\") AND SwimLane_Value==\"pve\",\"severe\", like(TestResult_Value,\"NA\") AND SwimLane_Value==\"pve\",\"NA\") \
|table Application_Name, TestCase_Value, QA1,QA2,QA3,QA4,QA5,QA6,QA7,STG,STG2,pve |rename TestCase_Value AS \"Test Case\" |rename Application_Name AS \"Application Name\" \
|stats values(QA1) as QA1, values(QA2) as QA2,values(QA3) as QA3,values(QA4) as QA4,values(QA5) as QA5,values(QA6) as QA6,values(QA7) as QA7,values(STG) as STG,values(STG2) as STG2,values(pve) as pve by \"Application Name\", \"Test Case\" \
|eval QA1 = if((mvjoin(QA1, \",\") == \"low,severe\" OR mvjoin(QA1, \",\") == \"severe,low\"), \"elevated\", QA1) \
|eval QA2 = if((mvjoin(QA2, \",\") == \"low,severe\" OR mvjoin(QA2, \",\") == \"severe,low\"), \"elevated\", QA2) \
|eval QA4 = if((mvjoin(QA4, \",\") == \"low,severe\" OR mvjoin(QA4, \",\") == \"severe,low\"), \"elevated\", QA4) \
|eval QA5 = if((mvjoin(QA5, \",\") == \"low,severe\" OR mvjoin(QA5, \",\") == \"severe,low\"), \"elevated\", QA5) \
|eval QA6 = if((mvjoin(QA6, \",\") == \"low,severe\" OR mvjoin(QA6, \",\") == \"severe,low\"), \"elevated\", QA6) \
|eval QA7 = if((mvjoin(QA7, \",\") == \"low,severe\" OR mvjoin(QA7, \",\") == \"severe,low\"), \"elevated\", QA7) \
|eval STG = if((mvjoin(STG, \",\") == \"low,severe\" OR mvjoin(STG, \",\") == \"severe,low\"), \"elevated\", STG) \
|eval STG2 = if((mvjoin(STG2, \",\") == \"low,severe\" OR mvjoin(STG2, \",\") == \"severe,low\"), \"elevated\", STG2) \
|eval pve = if((mvjoin(pve, \",\") == \"low,severe\" OR mvjoin(pve, \",\") == \"severe, low\"), \"elevated\", pve) \
|eval QA3 = if((mvjoin(QA3, \",\") == \"low,severe\" OR mvjoin(QA3, \",\") == \"severe,low\"), \"elevated\", QA3)",
            "cancelOnUnload": true,
            "latest_time": "now",
//            "latest_time": "rt",
            "app": utils.getCurrentApp(),
            "auto_cancel": 90,
            "preview": true,
            "tokenDependencies": {
            },
            "runWhenTimeIsUndefined": false
        }, {tokens: true, tokenNamespace: "submitted"});


        //
        // SPLUNK LAYOUT
        //

        $('header').remove();
        new LayoutView({"hideSplunkBar": false, "hideAppBar": false, "hideChrome": 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 element1 = new TableElement({
            "id": "element1",
            "count": 20,
            "drilldown": "cell",
            drilldownRedirect: true,
            "managerid": "search1",
            "el": $('#element1')
        }, {tokens: true, tokenNamespace: "submitted"}).render();

        element1.on("click", function(e) {
            // Bypass the default behavior
            e.preventDefault();
            window.open('tem_search_ui_html?appName=' + e.data["row.Application Name"] + '&testCase=' + e.data["row.Test Case"] +  '&swimLane=' + e.data["click.name2"] +  '&earliest=' + e.data.earliest + '&latest=' + e.data.latest, "_parent");

            // Displays a data object in the console
            console.log("Clicked the table:", e.data);
            //console.log("Clicked the table:", e.data["click.value"]);
            //console.log("Clicked the table:", e.data["click.value2"]);
        });

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

        // Define icons for the custom table cell
        var ICONS = {
            severe: "alert-circle",
            elevated: "alert",
            low: "check-circle"
        };
        var colName = "";

    mvc.Components.get('element1').getVisualization(function(tableView) {
        setTimeout(function() {
            tableView.on('rendered', function() {

                $("#element1 table thead th").removeClass("sorts").removeAttr("data-sort-key");
                 // Populate dictionary with values from table
                 var tableRows = tableView.$el.find('tbody').children();

                 var tableHeaders = tableView.$el.find('th').children();

                for (var iRow = 0, row; row = tableRows[iRow]; iRow++) {

                    for (var jCol = 0, col; col = row.cells[jCol]; jCol++) {

                        switch(jCol) {
                          case 2:  
                            colName = "QA1";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=QA1&earliest=-24h@h&latest=now target=_blank>QA1</a>");
                            }
                            break;
                          case 3:
                            colName = "QA2";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=QA2&earliest=-24h@h&latest=now target=_blank>QA2</a>");
                            }
                            break;

                          case 4:
                            colName = "QA3";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=QA3&earliest=-24h@h&latest=now target=_blank>QA3</a>");
                            }
                            break;

                          case 5:
                            colName = "QA4";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=QA4&earliest=-24h@h&latest=now target=_blank>QA4</a>");
                            }
                            break;

                          case 6:
                            colName = "QA5";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=QA5&earliest=-24h@h&latest=now target=_blank>QA5</a>");
                            }
                            break;

                          case 7:
                            colName = "QA6";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=QA6&earliest=-24h@h&latest=now target=_blank>QA6</a>");
                            }
                            break;

                          case 8:
                            colName = "QA7";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=QA7&earliest=-24h@h&latest=now target=_blank>QA7</a>");
                            }
                            break;

                          case 9:
                            colName = "STG";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=STG&earliest=-24h@h&latest=now target=_blank>STG</a>");
                            }
                            break;

                          case 10:
                            colName = "STG2";
                            if (iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=STG2&earliest=-24h@h&latest=now target=_blank>STG2</a>");
                            }
                            break;

                          case 11:
                            colName = "PVE";
                            if(iRow == 0){
                                tableHeaders.eq(jCol).html("<a href=temdashboard_html?SwimLane_Value=pve&earliest=-24h@h&latest=now target=_blank>PVE</a>");
                            }

                        }
                        var value = col.firstChild.data;
                        col.field === "colName";
                        var icon = "";
                        var found = false;
                        if(ICONS.hasOwnProperty(value)) {
                            icon = ICONS[value];
                            found = true;
                        }

                        if (found){

                            //$(col).addClass("icon").html(_.template('<a href="tem_search_ui_html" target="_parent"><i class="icon-<%-icon%>  <%-colName%>"></i></a>', {
                            $(col).addClass("icon").html(_.template('<i class="icon-<%-icon%>  <%-colName%>"></i>', {
                             icon: icon,
                             colName: value
                            }
                            ));
                        }
                        ($('td:contains("NA")').css("text-align","center"));
                   }  
                }            
                 // Update table display
                 tableView.render();
            })
        }, 100);
    });


        submitTokens();

        setTimeout("location.reload();", 600 * 1000);

        //
        // DASHBOARD READY
        //

        DashboardController.ready();
        pageLoading = false;

    }
);

HTML:

<header>
    <a aria-label="Screen reader users, click here to skip the navigation bar" class="navSkip" href="#navSkip" tabIndex="1">Skip Navigation ></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>TEM Availability Dashboard - Current hour </h2>
    </div>
  <div><input type="button" onclick="location.href='tem_search_ui_html?form.sTime.earliest=-24h%40h&form.sTime.latest=now';" value="Go to Search Screen" />
        <input type="button" onclick="location.href='http://spwaitbussvs/ts/itbs/tem/Shared%20Documents1/Automation/QA%20Availability%20Dashboard%20issue%20tracker.xlsx';" value="Issue log" />
        <input type="button" onclick="location.href='http://spwaitbussvs/ts/itbs/tem/Shared%20Documents1/Automation/TEM%20QA%20Availability%20Dashboard%20FAQ.docx';" value="FAQ" />
        <p></p>
  </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="element1" class="dashboard-element table" style="width: 100%">
                        <div class="panel-body"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div style ="padding-top: 2%">
        <P>
        <p> 
        <p><font color="#008000">Green</font>:  Test case passed &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp <font color="#FFFF00>">Yellow</font>    -   At least 1 step failed&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp <font color="#FF0000>">Red</font>: All test steps failed &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Blank: No test run. See TEM team for question(s) &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp NA: Test intentionally not run
    </div>
</div>
0 Karma
Get Updates on the Splunk Community!

Ready, Set, SOAR: How Utility Apps Can Up Level Your Playbooks!

 WATCH NOW Powering your capabilities has never been so easy with ready-made Splunk® SOAR Utility Apps. Parse ...

DevSecOps: Why You Should Care and How To Get Started

 WATCH NOW In this Tech Talk we will talk about what people mean by DevSecOps and deep dive into the different ...

Introducing Ingest Actions: Filter, Mask, Route, Repeat

WATCH NOW Ingest Actions (IA) is the best new way to easily filter, mask and route your data in Splunk® ...