Building a CRUD Dashboard Utilizing a KV Store in Splunk: Part 2

In Part 1 we covered the basic functionality of setting up our KV Store dashboard. In this part, we will cover CRUDing the KV Store data.



Part 2

In Part 1 we covered the basic functionality of setting up our KV Store dashboard. In this part, we will cover CRUDing the KV Store data.

Updating the Form Values

Now that the form populates we need to update the table to match any changed values in the form when we click on the Submit button. For that we are going to create a new search and some tokens to pass to it:

| inputlookup task_lookup | eval key=_key | WHERE key="$update_key_tok$" 
| eval Notes="$update_notes_tok$" 
| eval Estimated_Completion_Date="$update_estimated_completion_date_tok$" 
| eval Status="$update_status_tok$" | eval Task_Name="$update_task_name_tok$" 
| eval Task_Description="$update_task_description_tok$" 
| outputlookup task_lookup append=t

The structure of this search should look familiar as we covered it when we discussed updating a KV Store. The token values will be provided by the form fields.

Open up your dashboard’s source code and put in the following under the <label> section:

<search id="updateSearch" depends="$update_key_tok$, 
$update_estimated_completion_date_tok$, $update_notes_tok$, $update_status_tok$, 
$update_task_name_tok$, $update_task_description_tok$">
    <query>
      | inputlookup task_lookup | eval key=_key | WHERE key="$update_key_tok$" 
      | eval Notes="$update_notes_tok$" 
      | eval Estimated_Completion_Date="$update_estimated_completion_date_tok$" 
      | eval Status="$update_status_tok$" | eval Task_Name="$update_task_name_tok$" 
      | eval Task_Description="$update_task_description_tok$" 
      | outputlookup task_lookup append=t
    </query>  
  </search>

Here, we are giving our search an id of updateSearch, which we will reference later. Next, we are using depends to tell the search not to run unless the specific tokens listed have values.

Next, inside of the taskCollectionTable add an id of taskCollectionSearch to the search element. Your code should look like this:

   <panel id="taskCollectionPanel">
     <table id="taskCollectionTable">
       <title>Task Collection</title>
       <search id="taskCollectionSearch">
         <query>| inputlookup task_lookup | eval Update="Update" 
         | eval Delete="Delete" | table *, Update, Delete</query>
         <earliest>0</earliest>
         <latest></latest>
       </search>
       <option name="wrap">true</option>
       <option name="rowNumbers">false</option>
       <option name="dataOverlayMode">none</option>
       <option name="drilldown">cell</option>
       <option name="count">10</option>
     </table>
   </panel>

Now save your changes.

Go back into your crud.js and add the following inside the main function:

var tokens = mvc.Components.get('submitted');
/* --- Search Reference --- */
var updateSearch = mvc.Components.get('updateSearch');
var taskCollectionSearch = mvc.Components.get('taskCollectionSearch');
/* --- Table Reference --- */
var taskCollectionTable = mvc.Components.get('taskCollectionTable');

These are pulling references for our searches and our collection table.

Next, a few things will need to happen:

  1. When we click on the Submit button our token values need to be set.
  2. Once our token values are set our updateSearch will run. Remember how we used the depends attribute in our updateSearch in the Simple XML? We were essentially saying don’t run this search until the following tokens are set. When we click on the submit button all of them will be set which will cause updateSearch to run.
  3. We will then listen for when the updateSearch completes.
  4. Once updateSearch completes we will then rerun our main search called taskCollectionSearch.

Listen for the Submit Event

Below the table add the click event listener for the submit button:

$(document).on('click', '#submitButton', function(e) { });


Inside of the submit button function add:
e.preventDefault();
tokens.set('_key_tok', _key_Val);
tokens.set('estimated_completion_date_tok', estimatedCompletionDate_Input.val());
tokens.set('update_notes_tok', notes_Input.val());
tokens.set('update_status_tok', status_Input.val());
tokens.set('update_task_name_tok', taskName_Input.val());
tokens.set('update_task_description_tok', taskDescription_Input.val());

Above, we are setting all the tokens necessary for updateSearch to run. The final part of the update process is to wait until the updateSearch finishes running. This means the KV Store has had all the new values added to it. We can then successfully re-run the main search (taskCollectionSearch), which will then show the updated values we passed to the KV Store.

The final thing we need to do for our update process is to wait for the updateSearch to finish running so we can rerun our main search and show the new values:

/* --- Search Jobs --- */
updateSearch.on('search:done', function() {


    taskCollectionSearch.startSearch();
    $('form *').filter(':input').each(function(){
        $(this).val('');
    });


});

Here is the full process we are taking to update the values in our KV Store through the form:

  1. Token values are set to the current value of their corresponding input field. So, when the user changes the value in the input field it will then be passed to the token once the user clicks the submit button.
  2. Once all the token values are set then updateSearch will run.
  3. When updateSearch completes we rerun our main search which will then show the updated values in the table. Finally, we loop through each of the inputs in the form and set their value to an empty string. That way the form will be ‘refreshed’ to its default state once the values are successfully sent to the KV Store.

Creating the Data

The big difference between creating and updating is that our newly created events will not have a _key.

Edit the Simple XML

First, let's add the following into our dashboard’s Simple XML below the ‘updateSearch’ <search> element:

  <search id="createSearch" depends="$create_estimated_completion_date_tok$, 
  $create_notes_tok$, $create_status_tok$, $create_task_name_tok$, $create_task_description_tok$">
    <query>
      | inputlookup task_lookup | append [stats count | eval Estimated_Completion_Date="$create_estimated_completion_date_tok$" 
      | eval Notes="$create_notes_tok$" | eval Status="$create_status_tok$" | eval Task_Name="$create_task_name_tok$" 
      | eval Task_Description="$create_task_description_tok$" ] 
      | table Task_Name, Task_Description, Estimated_Completion_Date, Notes, Status
      | outputlookup task_lookup 
    </query>  
  </search>

Editing Our JavaScript for Create Events

Right now our Submit button click event looks like this:

$(document).on('click', '#submitButton', function(e) {


    e.preventDefault();
    tokens.set('update_key_tok', _key_Input.val());
    tokens.set('update_estimated_completion_date_tok', estimatedCompletionDate_Input.val());
    tokens.set('update_notes_tok', notes_Input.val());
    tokens.set('update_status_tok', status_Input.val());
    tokens.set('update_task_name_tok', taskName_Input.val());
    tokens.set('update_task_description_tok', taskDescription_Input.val());


});

Now, we need to create some new tokens for our create search. The first thing we will need to do is to determine whether or not a _key value exists in our form. Remember, the _key is set in a hidden field. So, when we click Update on a row in our table then it pulls the _key value from the table _row and sets it as the hidden input’s value. Otherwise, if we are creating a new row then the hidden input’s value will be blank. So, our new logic is below:

$(document).on('click', '#submitButton', function(e) {


    e.preventDefault();


    if(_key_Input.val() != '') {
        /* --- this is an update --- */
        tokens.set('update_key_tok', _key_Input.val());
        tokens.set('update_estimated_completion_date_tok', estimatedCompletionDate_Input.val());
        tokens.set('update_notes_tok', notes_Input.val());
        tokens.set('update_status_tok', status_Input.val());
        tokens.set('update_task_name_tok', taskName_Input.val());
        tokens.set('update_task_description_tok', taskDescription_Input.val());
    } else {
    	  /* --- this is new so create --- */
        tokens.set('create_tok', 'true');
        tokens.set('create_estimated_completion_date_tok', estimatedCompletionDate_Input.val());
        tokens.set('create_notes_tok', notes_Input.val());
        tokens.set('create_status_tok', status_Input.val());
        tokens.set('create_task_name_tok', taskName_Input.val());
        tokens.set('create_task_description_tok', taskDescription_Input.val());
    }


});

Above, we're saying if the value of our key input is NOT empty, then that means we are updating a currently existing row in the table.

The last thing we need to do is wait until the createSearch finishes running and then run the main search:

    createSearch.on('search:done', function() {


        taskCollectionSearch.startSearch();


        $('form *').filter(':input').each(function(){
            $(this).val('');
        });


    });

Now, save the changes and reload your dashboard. First, try updating an existing values and then try creating a new one.

Delete the Data

Edit the Simple XML

Let’s add the final search for deleting our data to the dashboard. As we covered earlier the basic structure for deleting data from our KV Store is:

| inputlookup task_lookup | eval key=_key | WHERE NOT key=<specific_id> 
| outputlookup task_lookup

Now, let's add that to our dashboard. Open up the Simple XML source for your dashboard and add the following below your createSearch <search> element:

  <search id="deleteSearch" depends="$delete_key_tok$">
    <query>
      | inputlookup task_lookup | eval key=_key | WHERE NOT key="$delete_key_tok$" | outputlookup task_lookup
    </query>
  </search>

We give the search an id of deleteSearch which we are going to reference in our JavaScript. Then we say that this search cannot run unless the $delete_key_tok$ is set.

Editing Our JavaScript for Delete Events

First, we need to set up a variable to reference our deleteSearch in the dashboard. Up top put the following:

var deleteSearch = mvc.Components.get('deleteSearch');

Save the changes and go back to your crud.js file. Inside of the click event for the taskCollectionTable we are currently checking if the the current field is ‘Update’ and if it is we set some variables. Now, we need to do something similar for ‘Delete’.

So, the basic structure is:

taskCollectionTable.on('click', function(e) {


   if(e['field'] === 'Update') { … removed for brevity ... } 


});

We need to add an else if clause to check and see if the current field is ‘Delete’ and if it is set the necessary variables, like so:

} else if(e['field'] === 'Delete') {


    tokens.set('delete_key_tok', e.data['row._key']);


}

What we are doing should look pretty familiar at this point. First, we are going to prevent the default click behavior, which in this case is to drilldown. Then we set the _key value from the current table row we click on. Then we set the $delete_key_tok$, which our deleteSearch depends on to run.

The next and final thing we need to do is wait for our deleteSearch to finish running and when it does we rerun the main search called taskCollectionSearch. Lastly, we unset the ‘delete_key_tok’ token:

deleteSearch.on('search:done', function() {


    taskCollectionSearch.startSearch();


    tokens.unset('delete_key_tok');


});

Final Words

You now have a fully functional CRUD dashboard where you can easily modify your KV Store data. There is more that can be done with this. For example, we could add some validation to form if we want our users to only provide a certain type of data depending on the field.

Hopefully you found this blog-screencast series to be helpful. Any questions, feel free to add them below in the comments section.




Close off Canvas Menu