How To Create Gmail Style Starred Cases

I created a small customisation which allows any user access to star a case. Any of who you use Gmail will probably recognise this functionality from there as that’s where I got my inspiration. It gives you quick access to cases you want to keep an eye on without impacting the case or anyone else.

It’s a nice little thing to implement for a customer, but more than that, I thought I’d share the technical side behind it to give you some ideas of what you can do within ServiceNow.

Check the YouTube video for a quick demo:


Let’s start off with the approach…

To ensure that one user starring the record did not impact another user, this needed a creation of a new table which is called ‘u_starred_cases’. This table is a simple relationship table with a many-to-many relationship between the user starring the case and the case itself.
So it had two custom fields added, both reference fields: u_case to the task table and u_user to the sys_user table.

With somewhere to store the relationship out of the way, I looked at the actual part of adding the star to the case. To do this, I created a UI Macro which I called ‘starred_case’. The premise behind this is that it had no UI element to it so it wouldn’t matter where you placed it on the form.

The first thing to do in the macro was to check if the case which you are accessing was starred already or not. This was accomplished using a simple GlideRecord in the <g2:evaluate> tag:

<g2:evaluate var="jvar_starred" jelly="true" expression="
    var starred = 'false';
    //Ensure that the Jelly variable jvar_form_sys_id is actually set.
    if (jelly.jvar_form_sys_id) {
        var gr = new GlideRecord('u_starred_cases');
        gr.addQuery('u_case', jelly.jvar_form_sys_id);
        gr.addQuery('u_user', gs.getUserID());
        gr.query();
        starred = gr.hasNext() + '';
    }
    //Return the value of the starred javascript variable the jvar_starred jelly variable so we can access it later
    starred;
"/>

Now that we know whether this case is starred or not, we can then proceed with adding the relevant coloured star to the header, white for unstarred and yellow for starred. From this point forward, there is no more Jelly coding and everything instead is Javascript running within a <script> tag.

We accomplish this using an ‘onload’ event and prototype as follows:


//Use the OOB addLoadEvent function and pass an anonymous function as the argument
addLoadEvent(function() {
    //We don't want to run this code on popups from reference fields so we ignore it here
    if ("${jvar_view_title}".toLowerCase().indexOf('sys_popup') > -1 ) {
    return;
    }
    //If the case is starred, we insert a yellow star
    if ( "$[jvar_starred]" == "true" ) {
        //We're going to insert the star right before the 'Back' button so we use prototype to find this button by ID and then call the insert() method to create an image with the appropriate id and class
        $('sysverb_back').insert({
            before: '<img id="starred_case" class="yellow" src="color_star.pngx" width="24" height="24"/>'
        });
    }
    //If it's not starred, we do exactly the same thing but insert a white star image
    else {
        $('sysverb_back').insert({
            before: '<img id="starred_case" class="white" src="white_star.pngx" width="24" height="24"/>'
        });
    }
    //Then we want to make sure that whenever we click the star, we react to it so again we use prototype and we use the observe method to wait for the click event. On clicking, we run the runStar function
    $('starred_case').observe('click', runStar);
});

Just a small point to note, I’m adding images called white_star.png and color_star.png. I just googled these and created them online, but they’re included in the update set. Also, another point which is useful to make a note of is the x at the end of png. This little x ensures the file is cached for faster loading next time. The same thing can be seen when you include javascript files into your UI pages and macros with the jsdbx extension (javascript database cache).

We’re now getting somewhere, we have a table to store our starred cases, and we have a star, but let’s quickly at this point create the formatter so you can add it to your form and test it out as you go along.

So create a formatter called ‘Starred Case’ with the following attributes:
Table:    Task
Formatter:    starred_case
Type:    Formatter

Now go to your incident record, and use ‘personalise > form layout’ and at the bottom of the list, add the formatter called Starred Case to the form. It doesn’t matter where you add it, just add it to the form. As long as you have the images above stored in your system, you should see the white star has been added to the case header already.

If you click it however, you’ll see nothing happens! In fact, if you look at your javascript debugging console in whichever browser you’re using, you’ll see a javascript error of runStar is undefined or something similar. This is because we added an onclick function above which calls this function but we haven’t defined the function, so obviously next, we’ll design the function.

For this, all we do here is create a GlideAjax call back to a client callable script include, passing back the details of the case, whether it is going from white to yellow or yellow to white and the user. Then what we expect, is on the response and successful adding/removing the record from the table, for the star to change colour.

So the first part is defining the runStar function:

function runStar() {
    //Call the function starcase within the script include star_cases
    var ga = new GlideAjax('star_cases');
    ga.addParam('sysparm_name','starcase');
    //Pass back whether the star is white or yellow by reading the class
    ga.addParam('sysparm_yellow',$('starred_case').hasClassName('yellow').toString());
    //Pass back the case sysid
    ga.addParam('sysparm_case', "$[jvar_form_sys_id]");
    //Define a callback of a function called changeStar
    ga.getXMLAnswer(changeStar);
}

And now for the changeStar callback function:

function changeStar(answer) {
    //Find the star element and store it for easy reference
    var el = $('starred_case');
    if (answer == 'yellow') {
        //Change the attributes to a yellow star
        el.src = 'color_star.pngx';
        el.removeClassName('white');
        el.addClassName('yellow');
    }
    //Otherwise do the opposite and make it a white star
    else {
        el.src = 'white_star.pngx';
        el.removeClassName('yellow');
        el.addClassName('white');
    }
}

Now for the script include. Again, it’s a very simple script just doing a GlideRecord to update the u_starred_cases table which we created earlier:

starcase: function() {
    var yellow = this.getParameter('sysparm_yellow');
    var caseID = this.getParameter('sysparm_case');
    var gr = new GlideRecord('u_starred_cases');
    //If the star was yellow, now turn it white and delete all records in the table
    if (yellow == 'true') {
        gr.addQuery('u_case', caseID);
        gr.addQuery('u_user', gs.getUserID());
        gr.query();
        gr.deleteMultiple();
        return 'white';
    }
    //Otherwise, create a new record in the table for the case
    else {
        gr.initialize();
        gr.u_case = caseID;
        gr.u_user = gs.getUserID();
        gr.insert();
        return 'yellow';
    }
}

That’s the end of the core functionality.

There’s just two more things to add: the little star on the number field on the list and the module in the navigation menu.

To add the star, I created a field style on the number field on the task table.
In the value field I added the following code:
javascript: checkStar(gs.getUserID(), current.sys_id)
And add the following CSS to the style to show the star:
background-image: url('/images/icons/kb_star_on.gif');
background-repeat: no-repeat;
background-position: 98% 5px;
padding-right: 25px;

This calls a global business rule which very simply returns true or false based on whether the case is starred or not:

function checkStar(userid, caseID) {
    //Ensure field style is used only on the list view
    if (!determineView()) {
        return false;
    }
    //Now run the GlideRecord to check if the case is starred
    var gr = new GlideRecord('u_starred_cases');
    gr.addQuery('u_user', userid);
    gr.addQuery('u_case', caseID);
    gr.query();
    return gr.hasNext();
}
//This function ensures that the view is a list view and not a case view because we don't want the star to be shown when inside the case
function determineView() {
    var listview = true;
    if (gs.getSession().isInteractive()) {
        var map = gs.action.getGlideURI().getMap();
        if (map.get('sysparm_record_target') != null) {
            listview = false;
        }
    }
return listview;
}

Finally, create a module which lists the starred cases with a fixed query of u_user = gs.getUserID() and you’re finished.

This little customisation can be now used on any record that extends task by simply adding the formatter to whatever view you want. So by adding it to the default view, you only show it on the default view and not the ESS view.

Hope you found this useful. Full update set can be found here

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s