UI actions Archives - ServiceNow Guru https://servicenowguru.com/category/ui-actions-system-ui/ ServiceNow Consulting Scripting Administration Development Tue, 28 May 2024 20:02:40 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.2 https://servicenowguru.com/wp-content/uploads/2024/05/cropped-SNGuru-Icon-32x32.png UI actions Archives - ServiceNow Guru https://servicenowguru.com/category/ui-actions-system-ui/ 32 32 Client & Server Code in One UI Action https://servicenowguru.com/ui-actions-system-ui/client-server-code-ui-action/ https://servicenowguru.com/ui-actions-system-ui/client-server-code-ui-action/#comments Thu, 20 May 2021 10:45:36 +0000 https://servicenowguru.wpengine.com/?p=1962 Most Service-now administrators and consultants know how to configure and use UI Actions. UI Actions are UI elements that can show up on a form or a list as a button, link, or context menu. When these UI elements are clicked they execute some JavaScript. Most of the time UI Actions are used to perform

The post Client & Server Code in One UI Action appeared first on ServiceNow Guru.

]]>
Most Service-now administrators and consultants know how to configure and use UI Actions. UI Actions are UI elements that can show up on a form or a list as a button, link, or context menu. When these UI elements are clicked they execute some JavaScript. Most of the time UI Actions are used to perform some server-side update to a record or records. In other cases, you can use the ‘Client’ checkbox on the UI Action record to execute some client-side JavaScript (including checking for mandatory fields).

But what if you need to do both? The classic case is when you want to click a button to make an update to a record, but only if the user has provided the correct input first. An example would be a ‘Reopen Incident’ button that changes the state on an incident record from ‘Resolved’ to ‘Active’. Usually you want to require the user to provide some sort of comment or additional information explaining why they are reopening the ticket. The problem is that you don’t always want the ‘Comments’ field to be mandatory so the validation needs to happen at the time the ‘Reopen Incident’ button gets clicked. Validation of mandatory fields needs to happen client-side but the update to your record needs to happen server-side. How can you accomplish both of these things with a single UI Action? This article shows you how.



The basic format for using a Client Script and Business Rule in the same UI Action looks something like this…

UI Action Template
Name: -Button Name-
Action name: -button_action_name- (Should be unique per button on form and gets called from the UI Action script)
Client: True (MUST be checked)
Form button/Form Context Menu/Form Link: (UI Action must be one of these ‘Form’ types)
Onclick: -runClientCode();- (Points to the function in your script that should be run when the UI Action gets clicked)
Script:

//Client-side 'onclick' function
function runClientCode(){
if( == false){
return false; //Abort submission
}
//Call the UI Action and skip the 'onclick' function
gsftSubmit(null, g_form.getFormElement(), ''); //MUST call the 'Action name' set in this UI Action
}//Code that runs without 'onclick'
//Ensure call to server-side function with no browser errors
if(typeof window == 'undefined')
runBusRuleCode();//Server-side function
function runBusRuleCode(){
current. = ;
current.update();
gs.addInfoMessage('You did it!');
action.setRedirectURL(current);
}

So why does this work? I had to go to a Service-now developer to find out. The reason is that UI Actions can run scripts at two different times. The first time is when the UI Action gets clicked. When you define a ‘Client’ UI Action you also give that UI Action the name of a function in your ‘Script’ field to execute. This function has to be called explicitly (through the ‘onclick’ event) or it doesn’t run at all.
The second time is on the way to the server. This is how any UI Action without the ‘Client’ checkbox selected gets run. On the way to the server the entire UI Action script gets executed regardless of whether or not the ‘Client’ checkbox is checked. What this means is that any script you include in your UI Action that isn’t enclosed in a function will be run on the way to the server. The script above takes advantage of this fact by making a specific call to the ‘Client’ function, performing client-side validation, and then the UI Action calls itself if the client-side validation passes.
When the UI Action calls itself it bypasses the ‘onclick’ function because the button didn’t get clicked the second time. So the script continues to the first point where there is something to execute. At that point you can call your Server-side function! The only thing you need to be careful of is that you only call the Server-side function if the script isn’t running in the client anymore. That’s what the check in the middle does…and eliminates any browser errors saying that ‘current’ (or any other Server-side function or object) isn’t defined.

Here is a solution I’ve used in the past to give users the ability to reopen an incident record. The solution uses a UI Action button to check if the ‘Comments’ field has been filled in (this is the ‘Client-side’ portion). If the validation passes, then the incident record gets updated.

Reopen Incident UI Action

Note that this script uses the ‘State’ field rather than the ‘Incident State’ field. In my opinion, it is much better to consolidate all of your state fields into one using the ‘State’ field at the task level as described here.

Name: Reopen Incident
Action name: reopen_incident
Client: True
Form button: True
Onclick: reopen();
Condition: current.state == 6
Script:

//Client-side 'onclick' function
function reopen(){
if(g_form.getValue('comments') == ''){
//Remove any existing field message, set comments mandatory, and show a new field message
g_form.hideFieldMsg('comments');
g_form.setMandatory('comments', true);
g_form.showFieldMsg('comments','Comments are mandatory when reopening an Incident.','error');
return false; //Abort submission
}
//Call the UI Action and skip the 'onclick' function
gsftSubmit(null, g_form.getFormElement(), 'reopen_incident'); //MUST call the 'Action name' set in this UI Action
}

//Code that runs without 'onclick'
//Ensure call to server-side function with no browser errors
if(typeof window == 'undefined')
serverReopen();

function serverReopen(){
//Set the 'State' to 'Active', update and reload the record
current.state = 2;
current.update();
gs.addInfoMessage('Incident ' + current.number + ' reopened.');
action.setRedirectURL(current);
}

The post Client & Server Code in One UI Action appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/client-server-code-ui-action/feed/ 59
Open Google Map from a Location Record https://servicenowguru.com/ui-actions-system-ui/open-google-map-location-record/ https://servicenowguru.com/ui-actions-system-ui/open-google-map-location-record/#comments Wed, 15 May 2013 13:56:12 +0000 https://servicenowguru.wpengine.com/?p=4910 This week I’m blogging from Knowledge13 in Las Vegas! So far it’s been a fantastic conference with lots of great content and it’s been fun to meet with so many people interested in improving their ServiceNow implementation. I’m really looking forward to the Fred Luddy keynote this morning. Jacob Andersen and I are here representing

The post Open Google Map from a Location Record appeared first on ServiceNow Guru.

]]>
This week I’m blogging from Knowledge13 in Las Vegas! So far it’s been a fantastic conference with lots of great content and it’s been fun to meet with so many people interested in improving their ServiceNow implementation. I’m really looking forward to the Fred Luddy keynote this morning. Jacob Andersen and I are here representing our ServiceNow consulting company, Crossfuze Solutions and would love to talk with any of you who could benefit from working with the most experienced ServiceNow implementation and integration consultants in the industry. Stop by the BDNA booth (Booth 1216) during any of the expo times to visit with us and see some of our world-class Incident, Problem, Knowledge, Change, Catalog, CMS, and Asset Management solutions! I’ll also be participating in a sold out panel presentation at 1:40 today where we’ll discuss the importance of data quality in a ServiceNow implementation.

Okay, enough of the high-pressure sales pitch :). This morning I saw a post on the ServiceNow community asking how to display a google map based on a ServiceNow location record. I think this is a fantastic idea and I decided to see if I could come up with a couple of solutions for it this morning. In this post I’ll show you how you can set up a UI Action or UI Macro link to pop open a Google Map window based on any location record in your ServiceNow instance!

Location Google Map UI Macro

The simplest way to set up a Google Map link in ServiceNow is to use a client-side UI Action to construct the URL and pop open a new window. Google Map URLs follow a basic convention that can include the street address or latitude/longitude coordinates of the location you want to display like this…

http://maps.google.com/?q=1200 Pennsylvania Ave SE, Washington, District of Columbia, 20003

Here’s the code and configuration for a UI Action…

‘Open Google Map’ UI Action
Name: Open Google Map
Table: Location [cmn_location] Action name: open_google_map
Show insert: false
Client: true
Form link/List context menu: true
OnClick: openGoogleMap()
Condition: (!current.street.nil() && !current.city.nil()) || (!current.latitude.nil() && !current.longitude.nil())
Comments: Shows a google map icon on a location field if the location has a street and city listed.Crossfuze Solutions
www.crossfuze.com
Script:

//Pop open google maps window of location specified
//URL should follow this format...http://maps.google.com/?q=1200 Pennsylvania Ave SE, Washington, District of Columbia, 20003

function openGoogleMap() {
//Retrieve the 'Location' record
var sysId = typeof rowSysId == 'undefined' ? gel('sys_uniqueValue').value : rowSysId;
var gr = new GlideRecord('cmn_location');
gr.get(sysId);

//Create and display the Map URL
var mapURL = "http://maps.google.com/?q=";
//Try location and city
if(gr.street && gr.city){
mapURL = mapURL + gr.street + ',' + gr.city + ',' + gr.state + ',' + gr.zip + ',' + gr.country;
}
//Else try latitude and longitude
else if(gr.latitude && gr.longitude){
mapURL = mapURL + gr.latitude + ',' + gr.longitude;
}
//Strip '#' symbols to avoid encoding errors
mapURL = mapURL.replace(/#/g, "");
window.open(mapURL);
}

Once the UI Action is created, you should be able to right-click a location record from a list or click the ‘Open Google Map’ link as shown here…

Location Google Map UI Action

While it’s nice to be able to open a map from a location record, it’s probably even more useful to be able to open a map directly from a referenced location record. The code for the UI Macro is a bit more complex, but once created it’s very simple to include for any reference field in your system by personalizing the dictionary entry for the location reference field (or the ‘cmn_location’ table dictionary entry if you want to include the option on every location field in your system). You can create the UI Macro using these settings.

‘open_google_map’ UI Macro
Name: open_google_map
Description:Shows a google map icon on a location field if the location has a street and city listed.
Activate by adding the attribute: ref_contributions=open_google_map to a location reference fieldCrossfuze Solutions
www.crossfuze.com

Script:

<!--?xml version="1.0" encoding="utf-8" ?-->



var id = __ref__.getSysIdValue();
if (id == null)
"none";
else {
var loc = new GlideRecord('cmn_location');
loc.get(id);
if ((!loc.street.nil() $[AND] !loc.city.nil()) || (!loc.latitude.nil() $[AND] !loc.longitude.nil()))
"";
else
"none";
}

<a id="${jvar_n}" style="display: $[jvar_show_google_map_display];" title="${gs.getMessage('Open a Google Map for this location')}" name="${jvar_n}"></a>
<img src="https://servicenowguru.com/wp-content/uploads/2024/02/favicon2." width="16" height="16" border="0" />

<script>
      needsRefreshLoc = false;
      function onChange_location_show_google_map(element, original, changed, loading) {
         var s = '${ref}'.split('.');
         var referenceField = s[1];
         if (needsRefreshLoc == false) {
            needsRefreshLoc = true;
            return;
         }
         if (changed.length == 0) {
            $('${jvar_n}').hide();
            return;
         }
         var locRec = g_form.getReference(referenceField, locationGoogleMapReturn);
      }
      
      function locationGoogleMapReturn(locRec) {
         var e = $('${jvar_n}');
         if ((locRec.street $[AND] locRec.city) || (locRec.latitude $[AND] locRec.longitude))
            e.show();
         else
            e.hide();
      }
      
      //Event.observe(g_form.getControl(${ref}.split('.')[1]), 'change', onChange_cmn_location_show_google_map);
      var l = new GlideEventHandler('onChange_location_show_google_map', onChange_location_show_google_map, '${ref}');
      g_event_handlers.push(l);

      //Pop open google maps window of location specified
      //URL should follow this format...http://maps.google.com/?q=1200 Pennsylvania Ave SE, Washington, District of Columbia, 20003

      function openGoogleMap(reference) {
         var s = reference.split('.');
         var referenceField = reference.substring(s[0].length+1);
         var sysId = g_form.getValue(referenceField);
         //Retrieve the 'Location' record
         var gr = new GlideRecord('cmn_location');
         gr.get(sysId);

         //Create and display the Map URL
         var mapURL = "http://maps.google.com/?q=";
         //Try location and city
         if(gr.street $[AND] gr.city){
            mapURL = mapURL + gr.street + ',' + gr.city + ',' + gr.state + ',' + gr.zip + ',' + gr.country;
         }
         //Else try latitude and longitude
         else if(gr.latitude $[AND] gr.longitude){
            mapURL = mapURL + gr.latitude + ',' + gr.longitude;
         }
	 //Strip '#' symbols to avoid encoding errors
	 mapURL = mapURL.replace(/#/g, "");
         window.open(mapURL);
      }
   </script>

Once the UI Macro has been created and the ‘ref_contributions’ attribute added to the reference field or table dictionary, you should see a google map icon displayed next to your location field whenever a location is referenced that includes address or latitude/longitude details.

Location Google Map UI Macro

The post Open Google Map from a Location Record appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/open-google-map-location-record/feed/ 26
Show a Task Workflow Timeline https://servicenowguru.com/ui-actions-system-ui/show-task-workflow-timeline/ https://servicenowguru.com/ui-actions-system-ui/show-task-workflow-timeline/#comments Wed, 16 May 2012 11:04:29 +0000 https://servicenowguru.wpengine.com/?p=4420 Having a blast from Knowledge 12 this week! It’s been fun this year being able to relax a little bit more and take some more time to talk with people. I look forward to meeting more of you over the next couple of days. Today, I’m writing in response to a user on the ServiceNow

The post Show a Task Workflow Timeline appeared first on ServiceNow Guru.

]]>
Having a blast from Knowledge 12 this week! It’s been fun this year being able to relax a little bit more and take some more time to talk with people. I look forward to meeting more of you over the next couple of days.

Today, I’m writing in response to a user on the ServiceNow community, and a few users in the advanced admin course I was observing earlier in the week. In the advanced admin class, they show how you can click a UI action on the change form to show a workflow in progress. They also show you how you can view a timeline for a workflow context. These UI actions (and corresponding popups) can provide valuable information to both administrators and technicians to determine the status and process of a particular workflow. The only problem (in the case of the timeline) is that it can’t be accessed from the change directly. You have to navigate to the workflow context record first.

In this post I’ll show you how to create a UI action script to display a workflow timeline popup directly from any task form in the system.

Change Request Timeline

If you’re familiar with the default UI action in the system, the code below should look familiar. It is initiated from the client, gets the sys_id of the workflow context, constructs a URL to the timeline, and then pops a new window up showing the timeline. The real trick in this case is getting the correct sys_id from the workflow context record. You should be able to create the following as a UI action on your task table. It will display for any itil user on a task that has an associated workflow.

‘Show Workflow Timeline’ UI Action
Name: Show Workflow Timeline
Table: Task
Order: 200
Show Insert: False
Client: True
OnClick: showTimeline();
Form link: True
Condition: !current.isNewRecord() && (new Workflow().hasWorkflow(current)) && gs.hasRole(‘itil’)
Script:

function showTimeline() {
var wf = new GlideRecord('wf_context');
wf.addQuery('id', g_form.getUniqueValue());
wf.query();
if(wf.next()){
var url = new GlideURL('show_schedule_page.do');
url.addParam('sysparm_stack', 'no');
url.addParam('sysparm_page_schedule_type', 'workflow_context');
url.addParam('sysparm_timeline_history', wf.sys_id);
var w = getTopWindow();
w.popupOpenFocus(url.getURL(), 'show_workflow_timeline', 950, 700, '', false, false);
}
}

The post Show a Task Workflow Timeline appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/show-task-workflow-timeline/feed/ 4
Edit a Workflow Directly from a Task https://servicenowguru.com/ui-actions-system-ui/edit-workflow-ui-action/ https://servicenowguru.com/ui-actions-system-ui/edit-workflow-ui-action/#comments Wed, 22 Feb 2012 15:57:57 +0000 https://servicenowguru.wpengine.com/?p=4274 A couple of weeks ago, I saw a great idea from Alex Yupanqui, who works for ServiceNow, to create UI actions to allow users to directly edit a graphical workflow from the associated record. I’ve taken this idea and cleaned things up a bit to make it usable and secure throughout the system. You’re probably

The post Edit a Workflow Directly from a Task appeared first on ServiceNow Guru.

]]>
A couple of weeks ago, I saw a great idea from Alex Yupanqui, who works for ServiceNow, to create UI actions to allow users to directly edit a graphical workflow from the associated record. I’ve taken this idea and cleaned things up a bit to make it usable and secure throughout the system.

You’re probably already familiar with the ‘Show Workflow’ and ‘Workflow Context’ UI action links that show up on task records when a workflow gets associated to it. These UI actions are extremely useful for identifying the state of the workflow as it relates to the task. As an administrator or consultant, you’re often trying to troubleshoot or fix an issue with the workflow, which requires the workflow editor. Unfortunately, this means you have to navigate to the module in the left nav and try to find the correct workflow to edit. The purpose of this solution is to cut out all of those extra steps to allow you to edit the workflow directly from the record it is bound to.

Edit Workflow

Here’s the UI action code. Notice that it’s set on the ‘Global’ table so that it will be available as a link on every form in the system. You’ll also notice that the ‘Condition’ field is set to allow access to only the ‘workflow_admin’ role, and to only display the link when a record has a workflow associated to it.

‘Edit Workflow’ UI Action
Name: Edit Workflow
Table: Global
Action name: show_workflow_editor
Order: 205
Form link: True
Client: True
Onclick: showWorkflowEditor()
Condition: gs.hasRole(‘workflow_admin’) && new Workflow().hasWorkflow(current)
Script:

function showWorkflowEditor(){
//Open the workflow editor in a new window
var wf = new GlideRecord('wf_context');
wf.addQuery('id', g_form.getUniqueValue());
wf.query();
if(wf.next()){
getTopWindow().popupOpenFocus('workflow_ide.do?sysparm_sys_id=' + wf.workflow_version, 'show_workflow_version', 950, 700, '', false, false);
}
}

If you’ve set this global UI action up correctly, clicking the ‘Edit Workflow’ link will take you directly to the workflow editor for that specific workflow just as if you would have navigated through the module in the left nav.

Bonus UI Action

Here’s another UI action that you can use on the ‘wf_context’ table so that you have a quick link to edit the workflow when viewing a given workflow context. The basic ideas are the same, but the script and condition are a little bit different because we’re initiating the UI action from a specific table in this case.

‘Edit Workflow’ UI Action
Name: Edit Workflow
Table: Global
Action name: show_workflow_editor
Order: 105
Form link: True
Client: True
Onclick: showWorkflowEditor()
Condition: gs.hasRole(‘workflow_admin’)
Script:

function showWorkflowEditor(){
//Open the workflow editor in a new window
var id = g_form.getValue('workflow_version');
getTopWindow().popupOpenFocus('workflow_ide.do?sysparm_sys_id=' + id, 'show_workflow_version', 950, 700, '', false, false);
}

The post Edit a Workflow Directly from a Task appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/edit-workflow-ui-action/feed/ 2
Show a Table Schema Map from any Form https://servicenowguru.com/system-definition/schema-map-any-form/ https://servicenowguru.com/system-definition/schema-map-any-form/#comments Thu, 09 Feb 2012 16:56:00 +0000 https://servicenowguru.wpengine.com/?p=4174 Table schema maps are a very useful tool to aid in visualizing the setup of a table and its relationships to other tables and fields in ServiceNow. This functionality is something that every ServiceNow implementor or admin should be familiar with. Schema maps are documented here in the ServiceNow wiki. While the schema map is

The post Show a Table Schema Map from any Form appeared first on ServiceNow Guru.

]]>
Table schema maps are a very useful tool to aid in visualizing the setup of a table and its relationships to other tables and fields in ServiceNow. This functionality is something that every ServiceNow implementor or admin should be familiar with. Schema maps are documented here in the ServiceNow wiki.

While the schema map is useful, it can also be difficult to navigate to unless you know exactly where to look. The only place in the system to access the schema map is from the ‘Tables and Columns’ module and this is only available to users with the admin role. In this post I’ll show you how you can make the schema map for a given table more accessible by creating a global UI action link that allows you to display the table schema map from any form in the system – for any role you want.

Show Schema Map

Here’s the UI action code. Notice that it’s set on the ‘Global’ table so that it will be available as a link on every form in the system. You’ll also notice that the ‘Condition’ field is set to allow access to only the admin role. You can adjust this as needed to grant access to other users as well. I’ve also added a couple of checks in the script to see if the action is initiated from the dictionary or the label table. In these cases, the popup will pull from the table defined in the dictionary or label entry – rather than the actual ‘sys_dictionary’ or ‘sys_documentation’ tables.

‘Show Schema Map’ UI Action
Name: Show Schema Map
Table: Global
Action name: show_schema_map
Form link: True
Client: True
Onclick: showSchemaMap()
Condition: gs.hasRole(‘admin’)
Script:

function showSchemaMap(){
//Get the table name
var tableName = g_form.tableName;
if(tableName == 'sys_dictionary' || tableName == 'sys_documentation'){
//Use 'Table' field value for dictionary or labels
tableName = g_form.getValue('name');
}
getTopWindow().popupOpenFocus('schema_map2.do?sysparm_stack=no&sysparm_attributes=table=' + tableName, 'super_schema', 950, 700, '', false, false);
}

The post Show a Table Schema Map from any Form appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-definition/schema-map-any-form/feed/ 5
CI UI Macro Actions for the Affected CIs List https://servicenowguru.com/cmdb/show-bsm-ci-map-affected-cis-related-list/ https://servicenowguru.com/cmdb/show-bsm-ci-map-affected-cis-related-list/#comments Wed, 18 Jan 2012 13:12:25 +0000 https://servicenowguru.wpengine.com/?p=4252 The ability to associate Affected Configuration Items against a task is one of the most basic pieces of the various task forms in ServiceNow. ServiceNow gives you the ‘Configuration Item’ field to associate a single CI and the ‘Affected CIs’ related list in the event that your task needs to be associated to multiple CIs.

The post CI UI Macro Actions for the Affected CIs List appeared first on ServiceNow Guru.

]]>
The ability to associate Affected Configuration Items against a task is one of the most basic pieces of the various task forms in ServiceNow. ServiceNow gives you the ‘Configuration Item’ field to associate a single CI and the ‘Affected CIs’ related list in the event that your task needs to be associated to multiple CIs. I’ve written before about the benefits of tracking all of this information in one place to simplify reporting and usage requirements. During an onsite visit with a customer this week I noticed another opportunity to improve the functionality of the ‘Affected CIs’ related list. It would be very useful to be able to right-click items in the ‘Affected CIs’ related list and show a BSM Map or associated tasks just like you can do for the ‘Configuration Item’ field UI Macro icons. This post will show you how you can set these list context UI Actions up in your instances.

Configuration Item Reference Icons

Configuration Item Context Actions

Add a UI Action Context Menu to Show a BSM Map for a CI

This UI Action allows you to access (via a right-click context menu) a Business Service Map for any Configuration Item listed in the ‘Affected CIs’ related list.

Special thanks to Peter Oneppo for building the bulk of this script during a customer visit we had together this week!

‘Show CI map’ UI action
Name: Show CI map
Table: CI’s Affected (task_ci)
List context menu: True
Show insert: True
Show update: True
Client: True
Onclick: showBSMMapList()
Condition: gs.hasRole(‘itil’) && RP.isRelatedList()
Script:

function showBSMMapList() {
//Retrieve the 'Affected CI' record
var sysId = typeof rowSysId == 'undefined' ? gel('sys_uniqueValue').value : rowSysId;
var gr = new GlideRecord('task_ci');
gr.get(sysId);//Build the BSM map URL
var attribs = 'table=cmdb_ci';
attribs += ',id=' + gr.ci_item;
attribs += ',level=4';
attribs += ',ref=' + g_form.tableName + '.cmdb_ci';
attribs += ',ciview=';
attribs += ',restack=true';
var url = new GlideURL('bsm_map2.do');
url.addParam('sysparm_nameofstack', 'bsm');
url.addParam('sysparm_attributes', attribs);

//Open the BSM map URL in a new window
var w = getTopWindow();
w.popupOpenFocus(url.getURL(), 'show_bsm_map', 950, 700, '', false, false);
}

If you’ve set up the UI Action correctly, you should now be able to right-click a row in the ‘Affected CIs’ related list and display a BSM map by clicking the ‘Show CI Map’ option.

CI Context Action - CI BSM Map

Add a UI Action Context Menu to Show Related Tasks for a CI

Using a similar concept to that described above, you can create a context menu UI Action to display a dialog containing all associated, active tasks for any Configuration Item in the ‘Affected CIs’ related list.

‘Show Related Tasks’ UI action
Name: Show Related Tasks
Table: CI’s Affected (task_ci)
List context menu: True
Show insert: True
Show update: True
Client: True
Onclick: showTasksDialogList()
Condition: gs.hasRole(‘itil’) && RP.isRelatedList()
Script:

function showTasksDialogList() {
//Retrieve the 'Affected CI' record
var sysId = typeof rowSysId == 'undefined' ? gel('sys_uniqueValue').value : rowSysId;
var gr = new GlideRecord('task_ci');
gr.get(sysId);//Create and display the GlideDialogWindow
var w = new GlideDialogWindow('show_list');
w.setTitle('Other active tasks affecting this Configuration Item');
w.setPreference('table', 'task_list');
w.setPreference('sysparm_view', 'default');
w.setPreference('sysparm_query', "active=true^sys_id!=" + g_form.getUniqueValue() + "^SUBQUERYsys_id,task,task_ci^ci_item=" + gr.ci_item + "^ENDSUBQUERY^GROUPBYsys_class_name");
w.render();
}

If you’ve set up the UI Action correctly, you should now be able to right-click a row in the ‘Affected CIs’ related list and display a dialog showing open tasks for the CI by clicking the ‘Show Related Tasks’ option.

CI Context UI Action - Show Tasks

The post CI UI Macro Actions for the Affected CIs List appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/cmdb/show-bsm-ci-map-affected-cis-related-list/feed/ 4
Create an Attachment UI Action https://servicenowguru.com/ui-actions-system-ui/create-attachment-ui-action/ https://servicenowguru.com/ui-actions-system-ui/create-attachment-ui-action/#comments Mon, 19 Sep 2011 11:41:02 +0000 https://servicenowguru.wpengine.com/?p=4035 This post shows how you can easily create an attachment UI action for any form. The attachment capability is part of all forms in ServiceNow and is accessed via a paperclip icon in the top-right corner of the form. In some cases this icon may not be prominent enough for your end users. The simplest

The post Create an Attachment UI Action appeared first on ServiceNow Guru.

]]>
This post shows how you can easily create an attachment UI action for any form. The attachment capability is part of all forms in ServiceNow and is accessed via a paperclip icon in the top-right corner of the form. In some cases this icon may not be prominent enough for your end users. The simplest solution in that case is to set up a UI action button or link that performs the same function.


For this solution we’ll leverage the existing ‘saveAttachment’ function. This function requires a table name and a record sys_id value. The ‘getTableName’ and ‘getUniqueValue‘ client-side functions will help to identify those values. You can add this capability by creating a UI action that looks like this…

‘Save Attachment’ UI Action
Name: Save Attachment
Table: Any table of your choice (Probably Task)
Form Button: True
Client: True
Onclick:

saveAttachment(g_form.getTableName(), g_form.getUniqueValue());

The post Create an Attachment UI Action appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/create-attachment-ui-action/feed/ 11
Creating a Custom Slushbucket Popup Dialog https://servicenowguru.com/system-ui/creating-custom-slushbucket-popup-dialog/ https://servicenowguru.com/system-ui/creating-custom-slushbucket-popup-dialog/#comments Tue, 04 Jan 2011 16:29:41 +0000 https://servicenowguru.wpengine.com/?p=3194 Happy New Year! Hopefully everybody had a great holiday. Mine was spent mostly helping my kids to break in some new toys :). I did get some time to play with some new Service-now ideas as well. I’ll be sharing some very cool stuff here on SNCGuru over the next couple of weeks. I’ve seen

The post Creating a Custom Slushbucket Popup Dialog appeared first on ServiceNow Guru.

]]>
Happy New Year! Hopefully everybody had a great holiday. Mine was spent mostly helping my kids to break in some new toys :). I did get some time to play with some new Service-now ideas as well. I’ll be sharing some very cool stuff here on SNCGuru over the next couple of weeks.
I’ve seen a couple requests recently for a way to allow users to select items from a slushbucket popup dialog. The most common reason for this is to help manage manual group approvals on a task record. If you’ve worked with group approvals at all, you’ve probably noticed that they work a little bit differently than regular approval records do. Group approval records are really just task records so you can’t just hit an ‘Edit’ button and add groups to be approvers on a task. Instead, you have to repeatedly click the ‘New’ button and create a new task record for each approval group. Normally this isn’t an issue because group approvals are typically managed in workflow but if you’re manually adding a lot of these, the process can be fairly tedious.
This article shows how you can provide a better UI by creating a slushbucket popup dialog that allows users to select one or many groups to add as approvers on a task. Even though the solution is designed for a specific use case, I’ve tried to make the example shown here generic enough so that you can easily modify it for other uses as well.


The first piece to this solution is to create a trigger for the dialog. For this solution, a UI action probably makes the most sense. The end user will click a UI action to display the popup dialog and make the necessary selections there.

‘Add Approval Groups’ UI Action
Name: Add Approval Groups
Client: true
Form link: true
OnClick: addApprovalGroups()
Condition: gs.hasRole(‘itil’)
Script:

function addApprovalGroups(){
   //Open a dialog window to select Approval Groups
   var dialog = new GlideDialogWindow('add_approval_groups');
   dialog.setTitle('Add Approval Groups');
   dialog.setPreference('sysparm_groupQuery', 'active=true');
   dialog.render();
   //Make sure to not submit the form when button gets clicked
   return false;
}

The UI action opens the dialog with a call to a specific UI page. The UI page is what contains most of the logic for the slushbucket. It includes the actual HTML (which pulls in the slushbucket and UI buttons from UI macros) as well as the client script that loads the groups and makes a call to insert group approval records.

‘add_approval_groups’ UI Page
Name: add_approval_groups
HTML:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
   <TABLE BORDER="0">
      <TR>
         <TD>
            Please select the groups you wish to add as approvers.
         </TD>
      </TR>
      <TR>
         <TD>
            <!-- Include the 'ui_slushbucket' UI macro -->
            <g:ui_slushbucket/>
         </TD>
      </TR>
      <TR>
         <TD align="right">
            <!-- Include the 'dialog_buttons_ok_cancel' UI macro -->
            <g:dialog_buttons_ok_cancel ok="return continueOK()" cancel="return continueCancel()" ok_type="button" cancel_type="button"/>
         </TD>
      </TR>
   </TABLE>
</j:jelly>

Client script:

//Called when the 'OK' button gets clicked
function continueOK(){
   //Get the selected values from the right slushbucket
   var values = slush.getValues(slush.getRightSelect());
   //Get the sys_id of the current record
   var taskID = g_form.getUniqueValue();
   //Make sure we have at least one selection
   if(values == ''){
      alert("At least one group must be selected");
      return;
   }

   //Add the group approval records
   var ajax = new GlideAjax('GroupSelectAjax');
   ajax.addParam('sysparm_name', 'groupsAdd');
   ajax.addParam('sysparm_taskID', taskID);
   ajax.addParam('sysparm_values', values);
   ajax.getXML(addGroupResponse);
}

//Called when we get a response from the 'continueOK' function
function addGroupResponse(){
   GlideDialogWindow.get().destroy();
   GlideList2.get('').setFilterAndRefresh('');
   return false;
}

//Called when the 'Cancel' button gets clicked
function continueCancel(){
   //Close the dialog window
   GlideDialogWindow.get().destroy();
   return false;
}

//Called when the form loads
addLoadEvent(function(){
   //Load the groups when the form loads
   slush.clear();
   var ajax = new GlideAjax('GroupSelectAjax');
   ajax.addParam('sysparm_name', 'getGroups'); 
   ajax.getXML(loadResponse);
   return false; 
});

//Called when we get a response from the 'addLoadEvent' function
function loadResponse(response){
   //Process the return XML document and add groups to the left select
   var xml = response.responseXML;
   var e = xml.documentElement; 

   var items = xml.getElementsByTagName("item");
   if(items.length == 0)
      return;

   //Loop through item elements and add each item to left slushbucket
   for (var i = 0; i < items.length; i++) {
      var item = items[i];
      slush.addLeftChoice(item.getAttribute('value'), item.getAttribute('text'));
   }
}

Many times, you can stop with the UI page. In this case, it makes sense for us to do some of our heavy-lifting for populating the groups in the slushbucket and creating group approval records at the server. The client scripts in the UI page make GlideAjax calls to the functions in a script include. The script include performs the query and returns an XML response back to the client so that it can continue.

‘GroupSelectAjax’ Script Include
Name: GroupSelectAjax
Client callable: true
Script:

var GroupSelectAjax = Class.create();

GroupSelectAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
   //Get and return a list of groups (name and sys_id)
   getGroups: function() {  
      var gr = new GlideRecord("sys_user_group");
      gr.orderBy('name');
      gr.addQuery('active', true);  
      gr.query(); 

      //Add the available groups to select from
      while (gr.next()) {
         var item = this.newItem();
         item.setAttribute('value', gr.getValue('sys_id'));
         item.setAttribute('text', gr.getValue('name'));
      }
   },

   //Take a taskID and group sys_id values and add 'sysapproval_group' records
   groupsAdd: function() {
      var taskID = this.getParameter('sysparm_taskID');
      var values = this.getParameter('sysparm_values').split(',');
      //Iterate through the group sys_id values
      for(x in values){
         var rec = new GlideRecord('sysapproval_group');
         rec.initialize();
         rec.parent = taskID;
         rec.assignment_group = values[x];
         rec.approval = 'requested';
         rec.insert();
      }    
   }
});

The post Creating a Custom Slushbucket Popup Dialog appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-ui/creating-custom-slushbucket-popup-dialog/feed/ 36
Direct User Impersonation From a User Record https://servicenowguru.com/ui-actions-system-ui/direct-impersonation-user-record/ https://servicenowguru.com/ui-actions-system-ui/direct-impersonation-user-record/#comments Fri, 10 Dec 2010 13:53:20 +0000 https://servicenowguru.wpengine.com/?p=3080 Every now and then I get a tip from a SNCGuru reader. This post comes courtesy of Garrett Griffin who emailed me yesterday with a cool script that his organization uses to allow admins to easily impersonate users without even having to select their name from the impersonate dialog. For those of you who don’t

The post Direct User Impersonation From a User Record appeared first on ServiceNow Guru.

]]>
Every now and then I get a tip from a SNCGuru reader. This post comes courtesy of Garrett Griffin who emailed me yesterday with a cool script that his organization uses to allow admins to easily impersonate users without even having to select their name from the impersonate dialog. For those of you who don’t know about user impersonation in Service-now yet, you can read about it here. The method that Garrett shared is more convenient in many cases than the regular impersonate button and it also helps to eliminate the confusion that can be caused in the standard impersonate dialog when you’ve got more than one user with the same display name.

The scripts below use the exact same method as the regular impersonation dialog. The only difference is that they feed the user ID directly to the URL, which eliminates the need for you to choose a user to impersonate. This can be helpful when you’ve got a user record up and you want to impersonate from that user record, or when you are troubleshooting a bug in your Service-now instance that someone has reported in an incident. You can set up a UI action and/or a UI macro to easily impersonate the appropriate user in either of these scenarios.

Here’s how you could create a UI Action on the User form…

‘Impersonate’ UI Action
Name: Impersonate
Table: User (sys_user)
Action name: impersonateUser
Client: True
Form button: True
Onclick: impersonateUser()
Condition: gs.hasRole(‘admin’) && current.active == true && current.locked_out == false
Script:

function impersonateUser(){
   if(confirm('Do you want to impersonate this user?')){
      top.location.href = 'ui_page_process.do?sys_id=b071b5dc0a0a0a7900846d21db8e4db6&sys_user='+ g_form.getUniqueValue();
   }
}

And here’s how you could modify Garrett’s solution above to create a UI Macro attached any user reference field in ServiceNow…

‘user_impersonate’ UI Macro
UI Macro icons require the creation of a UI Macro record under ‘System UI -> UI Macros’ (as shown below). They also require a dictionary personalization for the reference field the macro is associated with (as explained below).

Name: impersonate_user
Description:
‘Impersonate user’ link
Activate on any ‘sys_user’ reference field as follows:
– Set the active field in this macro to true
– Add the attribute to the reference field dictionary entry: ref_contributions=impersonate_user
XML:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<g:evaluate var="jvar_guid" expression="gs.generateGUID(this)" />
<g:evaluate var="jvar_admin" expression="gs.hasRole('admin')" />
<j2:if test="${jvar_admin == true || jvar_personalizer == true}">
   <j:set var="jvar_n" value="impersonate_user_${jvar_guid}:${ref}"/>
   <g:reference_decoration id="${jvar_n}" field="${ref}"
    onclick="impersonateUser('${ref}'); "
    title="${gs.getMessage('Impersonate user')}" image="images/icons/roleKey_obj.gifx"/>

   <script>
      function impersonateUser(reference){
         var referenceField = reference.split('.')[1];
         if(confirm('Do you want to impersonate this user?')){
            top.location.href = 'ui_page_process.do?sys_id=b071b5dc0a0a0a7900846d21db8e4db6$[AMP]sys_user='+ g_form.getValue(referenceField);
         }
      }
   </script>
</j2:if>
</j:jelly>

The post Direct User Impersonation From a User Record appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/direct-impersonation-user-record/feed/ 9
‘Copy’ UI action for Change requests (Part 2!) https://servicenowguru.com/ui-actions-system-ui/copy-ui-action-change-requests-part-2/ https://servicenowguru.com/ui-actions-system-ui/copy-ui-action-change-requests-part-2/#comments Tue, 27 Jul 2010 16:42:41 +0000 https://servicenowguru.wpengine.com/?p=1838 A few months ago I wrote about copying change requests using a UI action. While that method works great, it does require you to specify each and every field and value that you want to populate into the new change request. If you’ve got a lot of fields to copy over then you might end

The post ‘Copy’ UI action for Change requests (Part 2!) appeared first on ServiceNow Guru.

]]>
A few months ago I wrote about copying change requests using a UI action. While that method works great, it does require you to specify each and every field and value that you want to populate into the new change request. If you’ve got a lot of fields to copy over then you might end up with a pretty big script and a lot of items to copy over. You also need to be aware of any new fields that get added after you create the script and make sure that they get copied if necessary.

The following method works in much the same way, but it copies by performing an insert against the current record (rather than starting from a brand new change record and supplying each value). Because of this, you’re concerned about overriding any of the values (such as start and end dates) that you DON’T want to be copied over from the record you are copying. This method works better if you know you want to copy over all (or the majority) of the field values from a given change.

Copy Change UI action
Name: Copy change
Form button: True
Table: Change Request
Condition: gs.hasRole(“itil”) && current.isValidRecord()
Script:

copyChange();
function copyChange() {
	//Get the current sys_id value for querying
	var chgID = current.sys_id.toString();
	//Initialize new change for insertion
	var newChange = current;
	newChange.number = getNextObjNumberPadded(); //Get next change number
	newChange.requested_by_date = 'NULL';
	newChange.start_date = 'NULL';
	newChange.end_date = 'NULL';
	newChange.calendar_duration = 'NULL';
	newChange.opened_at = current.opened_at;
	newChange.opened_by = current.opened_by;
	newChange.sys_created_on = current.sys_created_on;
	newChange.sys_created_by = current.sys_created_by;
	current.insert();
	
	//Copy attachments for this change
	if (typeof GlideSysAttachment != 'undefined')
		GlideSysAttachment.copy('change_request', chgID, 'change_request', newChange.sys_id);
	else
		Packages.com.glide.ui.SysAttachment.copy('change_request', chgID, 'change_request', newChange.sys_id);
	
	//Copy associated tasks and CIs
	copyTask(chgID);
	copyCI(chgID);
	gs.addInfoMessage('Change ticket ' + newChange.number + ' created.')
	action.setRedirectURL(newChange);
}

function copyTask(chgID) {
	//Find the current change tasks and copy them
	var tasks = new GlideRecord('change_task');
	tasks.addQuery('change_request', chgID);
	tasks.query();
	while(tasks.next()){
		var taskID = tasks.sys_id.toString();
		var newTask = tasks;
		if (typeof GlideNumberManager != 'undefined')
			newTask.number = GlideNumberManager.getNumber('change_task');
		else
			newTask.number = Packages.com.glide.db.NumberManager.getNumber('change_task'); //Get next change task number
		newTask.change_request = current.sys_id;
		tasks.insert();
		
		//Copy attachments for this task
		if (typeof GlideSysAttachment != 'undefined')
			GlideSysAttachment.copy('change_task', taskID, 'change_task', tasks.sys_id);
		else
			Packages.com.glide.ui.SysAttachment.copy('change_task', taskID, 'change_task', tasks.sys_id);
	}
}

function copyCI(chgID) {
	//Get the task record being copied
	var tskRec = new GlideRecord('task');
	if(tskRec.get(chgID)){
		//Copy over the affected CI list
		var cis = new GlideRecord('task_ci');
		cis.addQuery('task', chgID);
                cis.addNullQuery('u_ci_group'); //Added to ensure that copying does not duplicate Group CIs
		if(gs.getProperty('change.conflict.mode')=='advanced' && tskRec.cmdb_ci!=''){
			//Prevent duplicate CI from being added
			cis.addQuery('ci_item', '!=', tskRec.cmdb_ci.toString());
		}
		cis.query();
		while(cis.next()){
			var newCI = cis;
			newCI.task = current.sys_id;
			cis.insert();
		}
	}
}

One other method for copying a change (or any other ticket) is to reference the record to copy and copy from the referenced record. You could use the script below to copy a change that is pulled from a reference field on any form. Just provide the name of the field to grab the change from in line 3.

Copy change UI action (For copying a referenced Change Request

//Get the current sys_id value for querying
//Provide the name of the reference field to copy change from
var chgID = current.your_change_reference_field.toString();
var rec = new GlideRecord('change_request');
rec.get(chgID);
copyChange();

function copyChange() {
	//Initialize new change for insertion
	var newChange = rec;
	newChange.number = getNextObjNumberPadded(); //Get next change number
	newChange.requested_by_date = 'NULL';
	newChange.start_date = 'NULL';
	newChange.end_date = 'NULL';
	newChange.calendar_duration = 'NULL';
	newChange.opened_at = current.opened_at;
	newChange.opened_by = current.opened_by;
	newChange.sys_created_on = current.sys_created_on;
	newChange.sys_created_by = current.sys_created_by;
	rec.insert();
	
	//Copy attachments for this change
	if (typeof GlideSysAttachment != 'undefined')
		GlideSysAttachment.copy('change_request', chgID, 'change_request', newChange.sys_id);
	else
		Packages.com.glide.ui.SysAttachment.copy('change_request', chgID, 'change_request', newChange.sys_id);
	
	//Copy associated tasks and CIs
	copyTask(chgID);
	copyCI(chgID);
	gs.addInfoMessage('Change ticket ' + newChange.number + ' created.');
	action.setRedirectURL(rec);
}

function copyTask(chgID) {
	//Find the current change tasks and copy them
	var tasks = new GlideRecord('change_task');
	tasks.addQuery('change_request', chgID);
	tasks.query();
	while(tasks.next()){
		var taskID = tasks.sys_id.toString();
		var newTask = tasks;
		if (typeof GlideNumberManager != 'undefined')
			newTask.number = GlideNumberManager.getNumber('change_task');
		else
			newTask.number = Packages.com.glide.db.NumberManager.getNumber('change_task'); //Get next change task number
		newTask.change_request = rec.sys_id;
		tasks.insert();
		
		//Copy attachments for this task
		if (typeof GlideSysAttachment != 'undefined')
			GlideSysAttachment.copy('change_task', taskID, 'change_task', tasks.sys_id);
		else
			Packages.com.glide.ui.SysAttachment.copy('change_task', taskID, 'change_task', tasks.sys_id);
	}
}

function copyCI(chgID) {
	//Get the task record being copied
	var tskRec = new GlideRecord('task');
	if(tskRec.get(chgID)){
		//Copy over the affected CI list
		var cis = new GlideRecord('task_ci');
		cis.addQuery('task', chgID);
                cis.addNullQuery('u_ci_group'); //Added to ensure that copying does not duplicate Group CIs
		if(gs.getProperty('change.conflict.mode')=='advanced' && tskRec.cmdb_ci!=''){
			//Prevent duplicate CI from being added
			cis.addQuery('ci_item', '!=', tskRec.cmdb_ci.toString());
		}
		cis.query();
		
		while(cis.next()){
			var newCI = cis;
			newCI.task =
			rec.sys_id;
			cis.insert();
		}
	}
}

The post ‘Copy’ UI action for Change requests (Part 2!) appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/copy-ui-action-change-requests-part-2/feed/ 25