The Now Platform® Washington DC release is live. Watch now!

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
beingfluid
Tera Guru
Tera Guru

Hi Developers,

In the last article, we have seen, how to make use of the out of the box related links on task records to make a conference call or send a message. In this article we will be creating a custom icon using UI Macro on incident form that will allow an Resolver to directly make a conference call with the Incident Caller. Seems interesting? it is!

UI macros are discrete scripted components administrators can add to the user interface. Wonder what does it mean? You might have seen little action icons next to fields on forms, for example :

find_real_file.png

This little user (Add me) icon next to the 'Assigned to' field, when clicked, adds currently logged in user to the Assigned to field.

You can visit SNGuru or check out TechNow Episode 3 video on ServiceNow Jelly Scripting by none other than @Chuck Tomasi to check the scripting logic behind this.

find_real_file.png

UI macros are typically controls that provide inputs or information not provided by existing field types. Let us understand this by means of an example :

find_real_file.png

The Show Related Incidents icon is a reference icon that appears beside the Caller field on the default incident form, when the field is populated. When clicked, it opens a browser window displaying a list of other incidents for same caller.

Now if you have got an idea about what UI Macros are and what it does, let us proceed with the development of our business requirement. Here, we will be making use of some Jelly, do not worry if you are not familiar with Jelly yet.

Step 1) Navigate to System UI > UI Macros and click 'New'

find_real_file.png

Step 2) Give it a unique name

find_real_file.png

Step 3) Replace the existing code of XML field by the following snippet :

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
	<style>
		.hide_icon {
			visibility: hidden;
		}
		.show_icon {
			visibility: visible;
		}
	</style>
	<g2:evaluate var="jvar_show_hide_icon" object="true" jelly="true">
		var r=new myNotifyHandler().macroVisibility();
		r;
   </g2:evaluate>
	<j:set var="jvar_n" value="Make a Call ${ref}" />
	<a id="${jvar_n}" onclick="makeCall('${ref}')" class="$[jvar_show_hide_icon]">
		<span class="glyphicon glyphicon-headphones" style="font-size:25px;color:black;text-shadow:2px 2px 4px #000000;"></span>
	</a>
	
	<script>
	function makeCall(reference){
		var a=reference.split('.');
		var referenceField=a[1];
		var c=g_form.getValue(referenceField);
		 var createRes = new GlideAjax('myNotifyHandler');
                createRes.addParam('sysparm_name', 'callCaller');
                createRes.addParam('sysparm_c', c);
                createRes.getXML();
		}
	</script>
</j:jelly>

Now let us understand the above code.

<j:set var="jvar_n" value="Make a Call ${ref}" />

In the above code Jelly tag 'set' sets a variable 'jvar_n' to the value returned from value attribute. in this particular case it will be 'Make a Call ${ref}' where '${ref}' will be replaced by the referenced field as 'incident.caller_id' and the final value will become 'Make a Call incident.caller_id'.

<a id="${jvar_n}" onclick="makeCall('${ref}')" class="$[jvar_show_hide_icon]">
		<span class="glyphicon glyphicon-headphones" style="font-size:25px;color:black;text-shadow:2px 2px 4px #000000;"></span>
	</a>

In the above code 'a' tag will create a link to our bootstrap icon specified in 'span' tag. The onclick attribute onclick="makeCall('${ref}')" fires on a mouse click on the element and Execute a JavaScript code written in 'makeCall' function when an icon is clicked.

<g2:evaluate var="jvar_show_hide_icon" object="true" jelly="true">
		var r=new myNotifyHandler().macroVisibility();
		r;
   </g2:evaluate>

The evaluate tag evaluates JavaScript code (server side), and makes variables visible to future code. Unlike other tags, the evaluate tag evaluates the content that is inside the tag as server side JavaScript. In the above code we will be calling a script include named 'myNotifyHandler' and it's function 'macroVisibility' to check whether macro should be visible to the currently logged in user or not. We will see how to write this Script Include in later steps. This function will return a class value to be set in our anchor tag later.

<style>
		.hide_icon {
			visibility: hidden;
		}
		.show_icon {
			visibility: visible;
		}
	</style>

The 'style' tag specifies styles to be applied to an element for a specified class. In our case. it will hide the icon if class is be hide_icon or will display the icon if it is show_icon.

<script>
	function makeCall(reference){
		var a=reference.split('.');
		var referenceField=a[1];
		var c=g_form.getValue(referenceField);
		 var createRes = new GlideAjax('myNotifyHandler');
                createRes.addParam('sysparm_name', 'callCaller');
                createRes.addParam('sysparm_c', c);
                createRes.getXML();
		}
	</script>

The 'script' tag is used to embed a client-side script (JavaScript). Whenever the icon is clicked this script will be executed. The parameter 'reference', in this case, will have field name as 'incident.caller_id'. Our code will retrieve the field name 'caller_id' by splitting the value and then it will call g_form method to retrieve field Caller's sys_id. Then we are calling 'callCaller' function and passing the caller sys_id to it for further processing.

I would suggest you to go through ServiceNow documentation for learning more about Jelly Tags and https://www.w3schools.com/ for HTML, CSS, Bootstrap or XML.

find_real_file.png

Step 4) Click 'Submit'

find_real_file.png

Step 5) Navigate to System UI > Script Includes and click 'New'

find_real_file.png

Step 6) Give it a (unique) name as 'myNotifyHandler' (Since, we have used the same script include name to be called in our macro).

find_real_file.png

Step 7) Make it accessible from 'All application scopes'

find_real_file.png

Step 😎 Make it 'Client callable'

find_real_file.png

Step 9) Replace the existing 'Script' by the following code snippet :

var myNotifyHandler = Class.create();
myNotifyHandler.prototype = Object.extendsObject(AbstractAjaxProcessor, {
    callCaller: function() {
        var c = this.getParameter('sysparm_c');
        var gc = new GlideRecord('sys_user');
        gc.get(c);
        var cm = gc.getValue('mobile_phone');

        var r = gs.getUserID();
        var gr = new GlideRecord('sys_user');
        gr.get(r);
        var rm = gr.getValue('mobile_phone');

        var notify = new SNC.Notify();
        var from = gs.getProperty('glide.notify.task.phone_number');
        var participants = [cm.toString(), rm.toString()];

        // set up a conference call
        var conferenceCall = notify.conferenceCall();

        // set up the outbound calls for all conference call participants
        for (var i in participants) {
            var to = participants[i];
            notify.call(from, to, conferenceCall);
        }

    },
	macroVisibility: function() {
		if(gs.hasRole('itil')){
			return 'show_icon';
		}else{
			return 'hide_icon';
		}
    },
    type: 'myNotifyHandler'
});

Let us understand what this script does. let us first look at the function 'macroVisibility' :

macroVisibility: function() {
		if(gs.hasRole('itil')){
			return 'show_icon';
		}else{
			return 'hide_icon';
		}
    },

here, gs.hasRole('itil') will return true only if currently logged in user will have an role 'itil', in which case it will return 'show_icon' and tell our macro to be visible. If user doesn't have the role we will be returning 'hide_icon' and will hide the macro. Thereby we will be controlling the icon to be visible to only Resolvers or users having ITIL role in other words. 

The GlideSystem (referred to by the variable name 'gs' in any server-side JavaScript) API provides a number of convenient methods to get information about the system, the current logged in user, etc. hasRole(String roleName) method determines if the current user has at least one of the passed-in roles.  You can read more about it here.

find_real_file.png

Now let us take a look at our other function 'callCaller' :

callCaller: function() {
        var c = this.getParameter('sysparm_c');
        var gc = new GlideRecord('sys_user');
        gc.get(c);
        var cm = gc.getValue('mobile_phone');

        var r = gs.getUserID();
        var gr = new GlideRecord('sys_user');
        gr.get(r);
        var rm = gr.getValue('mobile_phone');

        var notify = new SNC.Notify();
        var from = gs.getProperty('glide.notify.task.phone_number');
        var participants = [cm.toString(), rm.toString()];

        // set up a conference call
        var conferenceCall = notify.conferenceCall();

        // set up the outbound calls for all conference call participants
        for (var i in participants) {
            var to = participants[i];
            notify.call(from, to, conferenceCall);
        }

    },

here, In the following lines of code we will be getting mobile numbers of caller of the incident and the resolver who clicked the icon :

var c = this.getParameter('sysparm_c');
        var gc = new GlideRecord('sys_user');
        gc.get(c);
        var cm = gc.getValue('mobile_phone');

        var r = gs.getUserID();
        var gr = new GlideRecord('sys_user');
        gr.get(r);
        var rm = gr.getValue('mobile_phone');

In the ServiceNow documentation here, you will find all the scripts that you can use with Notify to interact with calls and SMS messages, or to provide a custom client interface.

find_real_file.png

Notify - conferenceCall() Creates a new conference call. We have copied the code snippet available here and modified it for our purpose :

find_real_file.png

If you compare both the codes, you will realize,

var from = '+14041234567';
var participants = ['+31612345678', '+31623456789', '+31687654321'];

the above code from example snippet has been changed in our code to :

var from = gs.getProperty('glide.notify.task.phone_number');
        var participants = [cm.toString(), rm.toString()];

The system property 'glide.notify.task.phone_number' stores Notify phone number used for sending SMS-s and starting conference calls from any record that belongs to the task table (or table that extends task table).

Step 10) Click 'Submit'

find_real_file.png

Step 11) Navigate to Incident > All and open any incident record

find_real_file.png

Step 12) Right click the 'Caller' field and select 'Configure Dictionary'

find_real_file.png

Step 13) Add the attribute ref_contributions=ui_macro_name to the Attributes field and click 'Update'

find_real_file.png

Dictionary attributes alter the behavior of the table or element that the dictionary record describes.

Dictionary attribute ref_contributions displays an icon for a reference field and when the field renders on a form, it invokes the named UI macro. If there are more than one macro like in this case, they are separated by semicolons (;).

Step 14) Navigate back to your incident form and you'll see an icon next to Caller field if you will have 'itil' role.

find_real_file.png

Step 15) Click the new icon we added and you'll be added to the conference call with the caller of the current incident.

find_real_file.png

So we have created an icon next to caller that, when clicked, will allow a user with ITIL role to connect with the incident caller directly in conference call.

In next article, we will solve another business requirement. Till the time, I would recommend you to visit the sources that I have mentioned in the article to have better idea about UI Macros :

Also there is an awesome and short similar community article 'Integrating ServiceNow with Twilio Services with the help of Notify API' written by @Abhishek Gardade that would help you to picture the scenerio in one shot and it will provide the ready-made update set that you can directly download and import.

find_real_file.png

If you have any queries regarding, UI Page, UI Macro, Jelly, or Twilio, Please mention in the comments or post a question to the ServiceNow Community. We would love to help.

Thank you.

Vishal Ingle

ServiceNow Certified System Administrator

DxSherpa Technologies Pvt. Ltd.

Pune, MH, IN.

 

Comments
Sonia BEN ABDEL
Tera Expert

Hello,

 

Thank you very much for sharing knowledge. We tried this and works great !
I just have a question if you have an idea please.

We would like, instead of triggering a conference call only to trigger a simple call where the receiver will receive a message then it would hangup.

We tried to replace :

 

notify.call(from, to, conferenceCall);

by

notify.call(from, to);

 

as mentioned in the documentation of the API, but this resulted an error saying that no conference was assigned.

Do you have an idea how to deal with this please? We Would be thankfull.

Rahsal
Kilo Contributor

Hello,

Tried the same way to create a system that will call a particular user when an incident arises.

Also, I have another requirement that when that user answers the call, He/She should get an autonomous voice like "An incident has been raised".

var from = '+1xxxxxx';
var to = '+91xxxx';

var notifyAction = new SNC.NotifyAction();

var usSay = notifyAction.addSay();
usSay.setText('Welcome. I can speak english');
usSay.setLanguage('en-US');
	
new SNC.Notify().call(from, to);

I tried something like this.

Is the requirement possible? How?

Rmaren
Tera Contributor

Its unfortunate not a single reply to 2 important questions.

Saurav Bhardwa2
Tera Contributor
var from = '+1xxxxxx';
var to = '+91xxxx';

var notifyAction = new SNC.NotifyAction();

var usSay = notifyAction.addSay();
usSay.setText('Welcome. I can speak english');
usSay.setLanguage('en-US');
	
new SNC.Notify().call(from, to);

I have tried this, but it's not reading the above text. May I know how to achieve this please??

Vishnu_27
Tera Contributor

@Saurav Bhardwa2 @Rahsal @beingfluid 
Hey Sourav/Rahsal/Vishal,

 

I have come across the same functionality of calling a user and announcing details about a task record and then hanging up.
Were you able to achieve the functionality, if yes , could you provide me with some insights?

 

Thank you

Version history
Last update:
‎09-10-2020 08:09 AM
Updated by: