Quantcast
Channel: Service-Now | John Andersen
Viewing all 82 articles
Browse latest View live

New ServiceNow API Documentation

$
0
0
Click here to view the New ServiceNow API documentation site

Click here to view the new ServiceNow API documentation site

While the ServiceNow wiki has been a great resource for those configuring the platform, there have been times when developers have been frustrated due to the lack of full documentation of the officially supported API library. When new functions get added to libraries, they haven’t always been added to the wiki.

Coinciding with the Fuji release, ServiceNow is releasing a new API documentation site. The documentation on this site is generated from the API code that ServiceNow creates. This means that you are always up-to-date with the latest API capabilities.

Of course, ServiceNow will only post officially supported APIs on this site. Documentation for the former packages objects will not be posted on this site as they are unofficial APIs and ServiceNow discourages the use of them as they may change or remove them at any time.

The new site is easy to use, and not only explains each function that is available per library, but also lists the input and output parameters as well as provides handy code examples. You can check out the API documentation today at: The ServiceNow API documentation page

The post New ServiceNow API Documentation appeared first on John Andersen.


Showing Timecards Related to a Project in ServiceNow

$
0
0

projTimeCards

I was recently asked how I might show a related list of all time cards belonging to a project or any of its sub projects.

A project record has a related list for time cards by default. However, it only lists those timecards that are written against the Project directly. What if we wanted to get all time cards associated for a project and all of its sub projects or project tasks?

The following solution may be better implemented with a faster algorithm, but please give me a break, I wrote this solution during a dance recital dress rehearsal so I didn’t have a lot of time to think :)

The challenge here is that there can be any number of sub projects to a given project. The code I wrote here has a hard coded maximum sub-project depth of 10, but you could choose a value that makes the most sense to you.

I went to System Definition > Relationships and created a new relationship with the following:

Name: Project Timecards
Applies to table: Project
Queries from table: Time Card

Query with

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var maxLevels = 10;
var tcids = rptGetTimeCards(parent.sys_id, "task", "", maxLevels);

if( tcids ){
  current.addEncodedQuery("sys_idIN"+tcids);
}

function rptGetTimeCards( projID, refFieldPath,  timecards, levels ){
  if( levels==0 ){
    return timecards;
  }
  var gr = new GlideRecord("time_card");
  gr.addQuery(refFieldPath, projID);
  gr.query();
  while(gr.next()){
    timecards += ","+gr.sys_id;
  }
  return rptGetTimeCards(projID, refFieldPath+".parent", timecards, (levels-1));
}

Once you have this, you can add the related list to your project form.

Of course, I would recommend some try/catch statements and maybe the creation of a dynamic query script or a script include, etc. But this gives the general idea.

The post Showing Timecards Related to a Project in ServiceNow appeared first on John Andersen.

Updated Sublime Text Editor for ServiceNow

$
0
0

Screenshot_9_18_15__4_50_AM

A few weeks ago, I shared a spectacular week with my new team in Hyderabad, India. We shared a fun-filled week geeking out on integration and application development on the ServiceNow platform. These folks are going to have a lot of fun with the types of projects coming our way.

Within the next few months the world will see how the built-in ServiceNow editors have continued to get more and more functional and feature rich (oooh….can’t wait for that Geneva release!). However, some people continue to use traditional native text editors for typing their code. After spending time with my teams both in the US and in India, I continued to see a large amount of copy-paste action happening from text editors into the ServiceNow browser windows, I decided that I needed to resurrect my 7 year old Python skills and update the ever-useful ServiceNow plugin for the Sublime Text editor which was original written by some talented friends at Fruition Partners (Original Sublime Text Plugin). I actually wrote about this plugin last year in “Using the SublimeEditor to write ServiceNow code“, but decided that it needed a little updating.

I have forked the original Fruition version of the plugin and have created a version that has the following enhancements:

Support for Sublime Text 3
One of the first things people ask me when I have tried to introduce the ServiceNow plugin for Sublime is whether it works with Sublime 3. I have always had to tell them that unfortunately they would be sticking with Sublime Text 2 if they wanted to use the plugin. Well, no more! The ServcieNow plugging or Sublime now works on both Sublime 2 as well as Sublime 3.

Enhanced Messaging to the End User
In the past, if there was a connection or other error during the sync process, an error would get output to the log behind the scenes, but the end user would have no clue that their changes were never uploaded to the server. I have added modal dialog boxes that will notify the user when there are such errors and provide some basic text around the error. More detailed text can be found in the behind-the-scenes debug log still as well. This will provide better user confidence in their use of the plugin.

Conflict Detection
This feature is the one I am most excited about as it fixes one of the biggest impediments for me in using this plugin in a team environment. In the past, if people were to change the source within the ServiceNow instance between the times when I was saving my version within the sublime editor, their changes would be overwritten by my copy. I have enhanced the plugin such that it will pull the current instance version of the data and do a conflict detection routine before it tries to update the server. If there appears to be a mismatch of any kind, the save action will be aborted and the user will be notified that they need to resolve the differences between the instance version of the data and their own. This should help prevent Sublime users from inadvertently overwriting important changes that are done within the instance on the same record.

To get the newest version of this plugin, please visit: Enhanced Sublime Text Plugin for ServiceNow

Instructions

The instructions for using this plugin are the same as the original plugin. At the top of the record text in Sublime, add a comment section to indicate where the text will be saved. Your comment block will contain three parameters:

  • __fileURL – This is the full direct URL to the record. Don’t use the url that leverages “nav_to.do”. Use only the direct URL.
  • __fieldName – This is the field that will contain the text you save in your editor. It is the database name for the field, not the label of the field
  • __authentication – This is your credentials for that instance in this format: username:password. After the save, the text will be replaced with “STORED”.

A couple of examples of your Sublime Text Comment Block Include:

XML / HTML Fields

1
2
3
4
5
<!--
// __fileURL = https://myinstance.service-now.com/sys_ui_page.do?sys_id=2d8dcb5e6f2d060009125ee44b3ee4b9
// __fieldName = html
// __authentication = STORED
-->

Javascript Fields

1
2
3
// __fileURL = https://myinstance.service-now.com/sys_ui_page.do?sys_id=2d8dcb5e6f2d060009125ee44b3ee4b9
// __fieldName = html
// __authentication = STORED

Video


Updated Sublime Text 3 Plugin for ServiceNow

Get the Plugin

Click below to download your item:
This file is not supported nor authored by Service-now.com. Please use at your own risk.

The post Updated Sublime Text Editor for ServiceNow appeared first on John Andersen.

Making Linky-Lists in ServiceNow list views

$
0
0

Due to the fact that forms and lists are an integral part of the a back-end fulfiller’s experience within ServiceNow, we find we want to tailor the list experience more and more.

Some members of my team (Matt Metten and Mahathi Nalluri) recently made a wonderful little storyboard app where people could write out potential flows of experience based on a persona (or potential user) of a ServiceNow application. People would enter in stories and individual scenes. When they were done they could generate a graphical storyboard.

As people used the application, they realized that they wanted to have a clickable link within the list view of the storyboards that they use to open up a new window with the corresponding story board page.

ServiceNow

Implementing this is not too tough, but there is a specific “gotcha” you have to worry about. I thought I would outline the process here:

1. Create a field that will contain your link
I started out with a URL field. These are clickable in a list view, but found that URL’s could get pretty long which can mess up your list formatting mojo.

The other option is to create a String field. Make sure to give it a large enough Max Length. I gave mine 1000 characters. The other trick…the one that caused me the most consternation, is that you have to give that field an attribute of “No Truncate”. This is VERY important. I found if I didn’t use this, then longer URL’s would be truncated in the list view for some reason.

My dictionary entry for the URL field I created to contain my URL.  Click to view in detail.

My dictionary entry for the URL field I created to contain my URL. Click to view in detail.

2. Create a business rule to auto generate the link
In our scenario, we are opening a UI page and passing a URL parameter for the storyboard “sys_id”.

I created a business rule that, when the record is saved, and the URL field is empty, I generate the URL.

For this to work, you have to wrap your link HTML code within the [code] [/code] tags.

1
[code]<a href='/mylink_to_the_resource'>Click Me</a>[/code]

My onBefore business rule generates the necessary text following this format. Here is the business rule code:

1
2
3
4
5
6
function onBefore(current, previous) {
   //This function will be automatically called when this rule is processed.
   current.url = "[code]<a href='";
  current.url += "/x_snc_story_board_storyboard.do?sysparm_recid="+current.sys_id;
  current.url += "' target='_blank'>View Story</a>[/code]";
}

3. Configure your form and your list
Last step is to configure your form and your list views.

Hide the field from your form as it shows as a text edit field and does you little good.

Expose the field on the List View Configuration so that it shows up in one of the columns of your list.

The Result
ezgif-19878262

The post Making Linky-Lists in ServiceNow list views appeared first on John Andersen.

Legacy Mobile UI Deactivation Tool for ServiceNow

$
0
0

As the standard ServiceNow browser interface becomes increasingly responsive, many people have found that it is easier to bypass the forced mobile web interface that was introduced on the platform back several years ago.

The instructions to do this are available in a combination of wiki and HI KB articles. rather than search for these steps and recreate them, I created a utility that lets you deactivate the Legacy Mobile UI at the click of a button. It will store your old settings before doing so.

You can always revert back to the legacy mobile UI if you run into any problems. Simply browse to the utility and activate it once again. Your settings will be restored.

Cursor_and_LegacyMobileUiUtility

Users that are currently logged in with their phones will need to log out before they get the correct view again.

Also, if your organization uses the legacy native iOS application, then you will want to keep the legacy UI enabled as the old app is dependent on it. The native iOS app released in 2015 does not require the legacy UI.

You can download the utility from share:
Deactivate the Legacy Mobile UI on ServiceNow

The post Legacy Mobile UI Deactivation Tool for ServiceNow appeared first on John Andersen.

Angular Service for manipulating User_Image fields on ServiceNow forms

$
0
0

System_Administrator___ServiceNow

There is a special field type on ServiceNow forms called the “user_image”. This allows you to upload or delete an image right from the record form, as well as have it displayed. As we have been playing with custom interfaces and portals lately, we have been wanting a way to interact with these field types using AngularJS.

How do the user_image field types work

User_image field type still use the sys_attachment table as other attachments on a form. They just have a special convention surrounding them.

1) File name
The filename for the image has to be the name of the database field that is hosting the user_image. For example, on the “sys_user” table, there is a field called “photo”. If I were to upload an attachment to the record called “photo”, it would show up in the Photo field on the form.

2) Multiple files of same name
If there are multiple attachments on the form with that name, then you will just get one of them consistently on the form. You won’t see the others. If, for example, I had five files on the sys_user record, only one of them will show on the form. If I delete it from the form, then next one will show up automatically.

3) ZZ_YY Table Names
The sys_attachment table will list the image in a special format by default. When using the user_image interface on the form to upload an image, you will notice on the sys_attachment table that it saves the attachment but records the table with a prefix of “ZZ_YY”. This tells the system not to show the file as an attachment on the form. However, in the case of user_image files, it will show them in the field itself. If you were to remove the “ZZ_YY” prefix on the sys_attachment record, it would still show up on the field, but it would also show up in the attachment list at the top of the record.

bothplaces

Also, files without the ZZ_YY prefix take precedence over those with the ZZ_YY prefix on the user_image field.

Please note: as of the writing of this article (2016-April), the ServiceNow table API does not support the “ZZ_YY” prefix fully, so this solution will store user_image attachments in the regular format, causing the attachment to show up in the title of the form as well as being displayed in the field.

The snUserImage Angular Service

Because we have been using user_image fields quite a bit, I wanted to create a reusable AngularJS service that gives me some of my most used function around user_image fields. I created it as a service so that it could be loaded as part of any Angular app.

The snUserImage service contains the following functions which are documented in the code snippet I’ll show below.

  • uploadImage
  • getImageSysId
  • deleteImage
  • replaceImage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
var snResources = angular.module("snResources", []);
snResources.service('snUserImage', ['$http', function ($http) {

    /**
     * Uploads a file to a specific User_Image field on a ServiceNow table
     *
     * @param {file} file The binary file object on the client device
     * @param {string} table_name The table where the User_Image field resides
     * @param {string} table_sys_id The sys_id of the record on the table for file image to be stored
     * @param {string} field_name The name of the field on the form (database name, not label)
    */

    this.uploadImage = function(file, table_name, table_sys_id, field_name){
        var urlUpload = "/api/now/v1/attachment/file?table_name="+table_name+
        "&table_sys_id="+table_sys_id+
        "&file_name="+field_name;

        $http.post(urlUpload, file, {
            transformRequest: angular.identity,
            headers: {'Content-Type': file.type,
                      'Accept': "application/json, text/plain, */*",
                      'X-UserToken': window.userToken}
        })
        .then(function successCallback(response) {
        // this callback will be called asynchronously
        // when the response is available
        }, function errorCallback(response) {
        // called asynchronously if an error occurs
        // or server returns response with an error status.
        });
    };

    /**
     * Retrieves the current user_image's sys_attachment sys_id if there is one that exists
     * (Please note: as of 2016-Apr, the ServiceNow API we are using does not yet support ZZ_YY
     *  table prefixes to hide the attachment from the record.)
     *
     * @param {string} table_name The table where the User_Image field resides
     * @param {string} table_sys_id The sys_id of the record we want to query
     * @param {string} field_name The name of the field on the form (database name, not label)
     * @param {function} return_val A callback function to execute once the record API returns its response
    */

    this.getImageSysId = function(table_name, table_sys_id, field_name, return_val){
        var urlGet = "/api/now/v1/attachment" +
                "?sysparm_query=table_name%3D"+table_name+
                "%5Etable_sys_id%3D"+table_sys_id+
                "%5Efile_name%3D"+field_name;
        var parent = this;
        $http.get(urlGet, {
            headers: {'Content-Type': "application/json",
                      'Accept': "application/json",
                      'X-UserToken': window.userToken}
        })
        .then(function successCallback(response) {
        // this callback will be called asynchronously
        // when the response is available
            if( response && response.data && response.data.result
                            && response.data.result.length
                            && response.data.result.length > 0 ){
                return_val(response.data.result[0].sys_id);
            } else {
                return_val(null);
            }
           
        }, function errorCallback(response) {
        // called asynchronously if an error occurs
        // or server returns response with an error status.
        });
    };    

    /**
     * Deletes the specified attachment record (and hence deletes the image on the user_image field)
     *
     * @param {string} sys_id The sys_attachment record storing the User_Image file
    */

    this.deleteImage = function(sys_id){
        var urlDelete = "/api/now/v1/attachment/"+sys_id;
        $http.delete(urlDelete, {
            headers: {'Content-Type': "application/json",
                      'Accept': "application/json",
                      'X-UserToken': window.userToken}
        })
        .then(function successCallback(response) {
        // this callback will be called asynchronously
        // when the response is available
        }, function errorCallback(response) {
        // called asynchronously if an error occurs
        // or server returns response with an error status.
        });
    };    

   
    /**
     * Replaces the current user_image with a new image
     * (Please Note: as of 2016-Apr the standard ServiceNow REST API does not support
     * the ZZ_YY table prefix that allows you to see attachments hidden from the form.
     * However, it will still replace the image on the form.)
     *
     * @param {file} file The binary file object on the client device
     * @param {string} table_name The table where the User_Image field resides
     * @param {string} table_sys_id The sys_id of the record on the table for file image to be stored
     * @param {string} field_name The name of the field on the form (database name, not label)
    */

    this.replaceImage = function( file, table_name, table_sys_id, field_name ){
        var parent = this;
        this.getImageSysId( table_name, table_sys_id, field_name,
            function(sys_id){
                if( sys_id ){
                    parent.deleteImage(sys_id);  
                }
                parent.uploadImage(file, table_name, table_sys_id, field_name);
            });
    };


}]);

As of April, 2016, the Table and Attachment REST API‘s in service now do not support the replacing of an attachment. Therefore, if I want to replace an image, I have to check to see if an image exists, grab the sys_id of the image, and delete the image, all before I upload the new image. The “replaceImage” takes care of this for me.

Example

Here is a simple UI page and Angular App I created to demonstrate the usage of this new service.

1) I stored my snUserImage service in a UI Script on the ServiceNow Instance

2) I created a small Angular app / directive / controller in another UI Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Setting up my app and I am injecting my snResources service
var myApp = angular.module('myApp', ['snResources']);

// Using this to determine when I should hid the file Upload control on the page
myApp.loaded = false;

// Handy fileModel directive that allows me to capture the file information
myApp.directive('fileModel', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var model = $parse(attrs.fileModel);
            var modelSetter = model.assign;
           
            element.bind('change', function(){
                scope.$apply(function(){
                    modelSetter(scope, element[0].files[0]);
                });
            });
        }
    };
}]);

// File upload controller
myApp.controller('myCtrl', ['$scope', 'snUserImage', function($scope, snUserImage){

    $scope.setImage = function(){
        var file = $scope.myFile;
        snUserImage.replaceImage(file, "sys_user", window.currentUser, "photo");
        $scope.loaded = true;
    };
   
}]);

3) I created a UI page importing the angular code and building out a simple file input form

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
 
  <!-- Load Angular using CDN for this example -->
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>

  <!-- Load my Angular App and my Services in UI Page using method found:
      http://www.john-james-andersen.com/blog/service-now/linking-several-javascript-libraries-servicenow-ui-pages.html
    This method helps to avoid unwanted browser caching issues
  -->
  <g:evaluate object="true">
    var uiscripts = [
                     //BEGIN EDIT
                     "jjaTestImageAppV1",  //My angular app and controller
                     "snResources"         //The angular Resource for ServiceNow
                     //END EDIT
                    ];
    var jslibs = [];
    for( var key in uiscripts ){
      var gr = new GlideRecord('sys_ui_script');  
      gr.addQuery("name", uiscripts[key]);
      gr.query();  
      gr.next();  
      jslibs.push( {"name": gr.name, "ts": gr.sys_updated_on } );  
    }
  </g:evaluate>  
  <j:forEach var="jvar_js_lib" indexVar="jvar_js_index" items="${jslibs}">
    <g:evaluate jelly="true">
      var js_lib_name = jelly.jvar_js_lib.name;
      var js_lib_ts = jelly.jvar_js_lib.ts;
    </g:evaluate>
    <g:requires name="${js_lib_name}.jsdbx" params="cache=${js_lib_ts}" />  
  </j:forEach>


  <!-- Get the User session and Current User Sys_id -->
  <g:evaluate object="true">
    var token = gs.getSessionToken();
    var user = gs.getUserID();
  </g:evaluate>
  <script>  
      window.userToken = "${token}";
    window.currentUser = "${user}";
  </script>
 

  <!-- Set up the Angular File control -->
  <div ng-app="myApp">
    <div ng-controller = "myCtrl">
      <div ng-show="!loaded">
        <input type="file" file-model="myFile"/>
        <button ng-click="setImage()">upload me</button>
      </div>
      <div ng-show="loaded">
        Success -- <a href='/sys_user.do?sys_id=${user}'>View the record</a>
      </div>
    </div>
  </div>

</j:jelly>

You can see an animation of the result here:

exampleWithImages

The post Angular Service for manipulating User_Image fields on ServiceNow forms appeared first on John Andersen.

My new ServiceNow Adventure: Yansa Labs

$
0
0

Some of you may have wondered where I have been the last year with my youtube videos and my blog. Several months ago I decided to embark on an exciting journey to start a new company focused on building powerful solutions on the ServiceNow platform.

Here is the short version of the story!

After watching the video be sure to check out our new company at: http://www.yansa.io

Interning at Yansa Labs

$
0
0

My name is Aylee Andersen and I have been invited to contribute to my Dad’s ServiceNow blog. This summer I am working as an intern for John Andersen and Ben Hollifield at Yansa Labs, I will be doing a series of blogs on the elements of ServiceNow that I am being introduced to. I am currently studying computer science at Utah State University, so this internship is a great opportunity for me to see real life applications of what I am learning at school. My goal for my contributions to this blog is to explain things in a way that is understandable and effective. I look forward to learning new concepts and sharing them with you!


Securing Tables and Fields Using Access Control Lists

$
0
0

The most confusing part of an Access Control List (ACL) is the field list. When you select a table from the Name field, it secures the table and all of its records. If you select any of the fields or the * in the second field, the ACL will secure that specific field in the table. As an example, if I were to select Comments from the drop down, it would restrict access to the Comments field in the Employee table. More information about the two fields can be found in the Access control rules article in the ServiceNow docs.

The two options I want to cover are the –None– and choices. They have similar purposes but yield different results. It took me a while to gain an understanding of when and where to use them. The To * or Not to * training module helped me figure them out.

The — None — Option

The None option says there are no restrictions on the table as long as you pass the required permissions.

In the example above, employees are allowed to see all the records in the Employee table that have them as the user. After making the employee specific ACL, I would proceed to make an ACL for the managers where they can see the records of their employees (see my post about Dynamic Filter Options). I would also make an ACL for the admins where they can see every record.

The * Option

The * option says there are no restrictions on the fields inside of the table as long as the user passes the permissions.

This ACL lets the employees, managers, and admins read all the fields in a record from the Employee table.

Restricting Certain Fields

If we want to restrict a user from seeing a certain field, we need to give them access to all the fields first. We did this in the previous example. To restrict the employees from seeing the comments field, we would create a new ACL with Comments selected and have admin and manager as required roles. We do not have employee as a required role since we do not want them to have access to the comments field.

This ACL is allowing admins and managers to read the comments field in the Employee table. If we hadn’t previously made an ACL that let employees, admins, and managers read all the fields, the comments field would be the only field they would have access to see. If you only want a few fields restricted, it is important to remember to allow all the roles access to every field first, then use additional ACLs to restrict access on some fields.

Putting it all Together

After making all the ACLs, both admins and managers should be able to see all the records and all the fields in the Employee table. Employees should be able to see all the fields except for Comments in the records where they are the users.

Video Tutorial

Meeting the Permissions in an Access Control List

$
0
0

Access Control Lists (ACLs) are an effective way to provide security for an application. They can be customized to restrict users from reading, writing, creating, or deleting certain records and fields. For example, you can use an ACL to ensure only users with the role of an admin can delete records.

When creating an ACL, you will need to include permissions. Permissions are requirements that the user has to pass in order to gain access to the record or field.

There are three permissions on an ACL:

  • Requires role
  • Condition
  • Script

We will cover all three permissions in this post.

 

Requires role

The specified roles determine which users can perform a particular action on a record or field. If for example, you wanted only admins and managers to be able to read the records, you would include both the admin and manager roles in the Requires role field. If a user with the role of an employee tries to view those records, the ACL will not pass the check and will prevent access. If the user passes the Requires role check, they move on to the next check.

 

Condition

The conditions determine which of the records the user can see. As you change the conditions, the blue message will update to tell you how many records match the condition you created. If we wanted to make an ACL that lets an employee only see their records, we would have the Requires role set to employee and then a condition that says [User] [is (dynamic)] [Me]. First, the ACL makes sure that the user is an employee, then it goes through the records in the table and lets the user view the ones where they are the user. The user can only read the records if they get permission from both the Requires role and Condition checks.

 

Script

The script field is only shown when Advanced is selected from the top of the form. Once Advanced is selected, the following field appears:

The script is the third and final check to give permission to the user. There must be some condition that sets the answer variable to true or false inside of the script logic. The script is used to gather more specific information, such as the sys_id of the user, or whether or not the user is logged in. A list of other GlideSystem methods can be found here. The ACL grants access to the records if the Required roles, Condition, and Script all evaluate to true.

 

Once all the permissions are established, you can check your ACL by assigning desired roles to users and impersonating them on your developer instance. More information can be found in the training modules for Creating and Editing Access Controls.

 

Video Tutorial

Creating Dynamic Filters for Access Control Lists

$
0
0

Although Access Control Lists (ACLs) provide the most common filters in their conditions, they do not always offer what we need for our applications. Recently, I was trying to create an ACL that let managers see the records of their employees. I wanted a dynamic condition that checked if the record’s user was an employee of the manager. While doing some research, I came across an article that talked about creating a dynamic filter option. In this post, I will expand on those ideas and give a step by step guide that shows how to create a dynamic filter that can be used for ACLs.

Step 1 – Setting up the Dynamic Filter Option

While in the Global scope, navigate to System Definition > Dynamic Filter Options and click New.

The Label is what appears in the condition. Make sure to choose a name that will make sense in the condition statement.

For my dynamic filter, I made a reference to the User table. This just means that the User table is where the ACL will be pulling records from.

I also made sure that the Roles field was set to the manager since that is the only role that this filter applies to.

 

Step 2 – Script Functions

The Script field contains the name of the function that you are using for your script. For basic filters, you can simply call GlideSystem methods. For more complicated filters, you will want to write your own script and call your function in the Script field.

Step 3 – Reference Script

To make a more complicated filter, you will want to write either a business rule or a client-callable script include. Use the Reference script field to navigate to your script.

The function inside my script include matches the function I used in the previous step.

Now, my dynamic filter knows to look for the getManagedEmployees function inside of the Employee script include.

Dynamic Filter in Action

 

Video Tutorial

Using URLs to set Default Values in a Record Producer

$
0
0

One complication I came across while building my Generate Sprints record producer was setting the default value of the Simple SDLC project field to the project that was generating the sprints. After some research, I discovered that you can pass values through the URL. With that in mind, I used a UI action form link to direct users to the record producer while adding the sys_id of the project to the URL.

Once that was established, I used the getParameterValue function from Mark Stanger’s article on parsing URL parameters, and put it in a catalog client script, adjusting some parts to better fit my needs.

This made it so that the project sys_id could be taken from the URL and placed into the Simple SDLC project field on the record producer. Now, when a user opens a project and wants to generate sprints, the project field is already populated with the project they were working on.

Slack Integration to ServiceNow – Use Case

$
0
0

Yansa Labs has been working on a simple project management tool called Simple SDLC. I was asked to integrate Slack into their application for improved project communication. I’ll go over how I did that in this post.

There are three main steps I took to integrate Slack into an application: adding an incoming webhook to Slack, creating a script include to handle the message, and getting a business rule to execute the script include.

Incoming Webhook

In Slack, there is an option to add an app to a channel that you have created. For the Simple SDLC application, I added an Incoming Webhook configuration. Once the webhook is all set up, it’s important to copy the Webhook URL.

For Simple SDLC, I put the Webhook URL into the Slack Integration Endpoint field on the Project table. This is where I’m going to pull the endpoint from later in this post.

Script Include

I used a server side script include to format the message the way that I wanted. My constructor took a project as a parameter and then used that to access the endpoint. Next, I had a function that formatted a bunch of name/value pairs. The final part of the script include uses the endpoint to send the message to the Slack channel.

 

Business Rule

My last step was to create a business rule that would execute the functions in my script include. The goal was to receive a slack message every time a new Story was created. The first thing my business rule did was pass in the current project to the constructor. Then it passed in the sys_id of the story as well as an array of name/value pairs so that it could generate the message.

Now, whenever a new story is created, my Slack channel gets a message that looks like this:

 

Video Tutorial

Cascade Deleting Records

$
0
0

Recently, while working on Yansa Lab’s Simple SDLC application, I came across a problem with deleting records. When I would delete a project, the sub-records would not be deleted. In Simple SDLC, projects have sprints and sprints have stories. If I deleted a project, none of the sprints or stories would get deleted. Similarly, if I deleted a sprint, none of the stories would be affected. While trying to figure out how to fix this problem, I came across ServiceNow’s documentation on configuring cascade delete rules.

I discovered that if you configure the dictionary on a reference field, there is an option to delete all referenced records when that record is deleted. This option is called “Cascade” and can be found under Reference Specification – Additional Customization > Reference cascade rule in the advanced view of the dictionary.

 

Once I had all of my reference fields set to Cascade, they deleted the correct records. Now, when I delete a project, I am also deleting all of its sprints and stories.

Navigating Transform Scripts in ServiceNow

$
0
0

Since there are so many different options for when to run a transform script, it can be difficult to determine what will work best for your application. In this post, I’ll go over the different types of scripts as well as the variables that are available to each one. ServiceNow has some documentation on how to map with transform event scripts that I used as a reference while I was playing around with transform maps. I’ll just dive a little deeper into those concepts in this post. The following scripts are listed in the order that they execute in.

The following scripts are listed in the order that they execute in:

Below is a diagram of a sample import set. Each script will have another diagram that shows when they run.

 

On Start

Variables: source, import_set, map, log, ignore, error

Note: Only the variables listed above apply to the current script. A list of all the variables and how they work can be found at the bottom of the post.

Summary: onStart runs at the very beginning of the import before any of the records are processed. None of the fields can be accessed on the source or target tables since they have not been set up yet. If you try to access fields in the onStart script, the transform will not run. If you wanted to inform a user that more records were being imported, you could use the onStart script to send out the message that the import has started.

 

On Before

Variables: source, target, import_set, map, log, action, ignore, status_message, error, error_message

Summary: onBefore runs before every row is processed. This script runs for each individual record. If you want to set or alter values on the source table (see Temperature example explained in the Field Level Source Script section below) it can be done here. onBefore scripts can be used to verify that the value of a source field is valid. If the value is invalid, the script can take action.

 

Field Level Source Script

Variables: source, target, answer, map, log, action

Summary: The source script replaces the source field in the field map. It gives the target field a value. This is used when you want to change an individual field on each record. For example, if I had a Temperature field in my source table that was in Fahrenheit and I wanted it to be in Celsius on my target table, I would do the conversion in the field level source script. This will modify the temperature value for every record.

On Foreign Insert

Variables: source, target, map, log, action, name, value, action, ignore, error

Summary: onForeignInsert runs before a new referenced record is created. Since this script only runs on an insert, the choice action “create” has to be selected for that field map. If “create” is not selected, the script will never run.

At this point, we can access values on the source table. Fields on the target table, however, have not yet been modified. onForeinInsert scripts can manage what happens when a new record is added to a referenced table, such as filling out other fields on that table.

On Choice Create

Variables: source, target, map, log, action, name, value, ignore, error

Summary: onChoiceCreate runs before a new choice is created on a choice field. Since this script runs when a choice is created, “create” has to be selected as the choice action for that field map. If it is not selected, the script will not run. Because onChoiceCreate is a before action, only the source table record has set values. Similar to onForeignInsert, the onChoiceCreate script can take additional action when a new choice is created on a field.

On Reject

Variables: source, target, map, action, log

Summary: onReject runs before a record (often a referenced record) is rejected. In order for this script to run, “reject” has to be selected as the choice action for that field map.

Since onReject runs before the record is rejected, the value of the fields in the source table can still be accessed and stored. Once the script runs, the record is rejected and is not inserted into the target table. The onReject script is useful for gathering information about the rejected record and storing it or reporting it back to the user.

Record Level Script

Variables: source, target, map, log

Summary: Record level scripts run alongside the field maps as they transform fields from the source table to the target table. Both the target and source tables are accessible for this script. Since the script will execute for every record, the record level script is where you want to alter record values. If I had a Firstname and Lastname field on my source table and I wanted to merge them into a Name field on my target table, I would do that with the record level script since I have access to all the fields in both the source and target tables.

 

On After

Variables: source, target, import_set, map, log, action, status_message, error, error_message

 

Summary: onAfter runs after every row has been processed. Fields on the target table can be accessed from this point. They contain the value that was just inserted. At the time that this script runs, the source and target field values should be the same. With onAfter scripts, you can take the values of the fields that were just inputted and use them to fill out record fields on other tables.

On Complete

Variables: source, target, import_set, map, log, error

Summary: onComplete runs once the import has been completed and all records have been transformed. The script will only run once. As an example, you could use the onComplete script to send out a message saying that new records have just been added to the table.

 

Variables

There are many variables that can be used in transform scripts. Here is a list of all the variables and how they work:

action – returns “insert” or “update” depending on if the current record was or is being added or updated

error – a boolean that will stop the transformation and send an error message if set to true

error_message – the message sent if an error occurs

ignore – a boolean that will stop the transformation and ignore all following rows

import_set – the import set being transformed at that moment

log – function used for debugging the transformation (log.info(), log.error(), etc.)

map – information about the transform map record being processed

name – the name of the field on the target record that is currently being processed

source – A GlideRecord of the row being read in and processed

status_message – an output message sent in the XML response

target – A GlideRecord of the record being added to the target table

value – the display value of the field on the source record that is currently being processed


Adding an Attachment Icon for Lists of Records

$
0
0

ServiceNow provides users with an option to add attachments to records. However, the user cannot see if a record has an attachment unless they open it up. In this post, I’ll go through how to add an attachment icon to lists of records so that users can easily see which records have attachments, and it will show how many attachments it has.

Add Attachment Field to the Dictionary

So the first thing we need to is open up the dictionary to the table we want the attachment icon on. I’ll use the Incident table for this example.

Now we need to create a new field for Attachments. Make sure the default value is set to 0.

Once the Attachments field is created, configure the List Layout of the table to add our field.

 

Create a Field Style

Now that we have the Attachments field created and in place, we will need to create a style for it. Navigate to System UI > Field Styles. The form should be filled out as follows:

The Value above is making sure that the style only applies when there is at least one attachment on the record. Getting the background image was a little tricky. I came across a blog on ServiceNow Icons and Images that said you could find the icons that ServiceNow uses by typing image_picker.do in the Navigator. Using this method, I picked a paperclip icon for the Attachments image.

 

Create an Attachment Counter Business Rule

The final step to adding our attachment icon is to create a Business Rule to count the number of attachments on each record. We want the Business Rule to run every time an attachment is added or removed. Using the Filter Conditions, you can have the Business Rule run for multiple tables as long as they each have the Attachments field and a Field Style to go with it.

Here is the script that I used to count the number of attachments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
(function executeRule(current, previous /*null when async*/) {
checkAttachment();

function checkAttachment(){
var attachCount = new GlideAggregate('sys_attachment');
attachCount.addQuery('table_sys_id',current.table_sys_id);
attachCount.addQuery('table_name',current.table_name);
attachCount.addAggregate('COUNT');
attachCount.query();

var numAttachments = 0;
if (attachCount.next()) {
numAttachments = attachCount.getAggregate("COUNT");
setAttachmentNum(numAttachments);
}
else {
setAttachmentNum(numAttachments);
}

}

function setAttachmentNum(num){
var task = new GlideRecord(current.table_name);
task.get(current.table_sys_id);
if(task.isValidRecord()) {
task.u_attachments = num;
task.autoSysFields(false); //Don't set the lastUpdatedTime or the Simultaneous Update Alert will likely get triggered
task.setWorkflow(false); //Don't allow other business rules to run, otherwise multiple notifications will likely be sent
task.update();
}
}

})(current, previous);

Once the Business Rule is complete, the attachment icon should appear on the table, showing how many attachments there are for each record.

Demo Video

Using Record Producers to Create Multiple Records

$
0
0

Recently, I was working on a record producer to create multiple sprints for a given project. Up to that point, I had never used a record producer so it was quite the learning experience. In this post, I’d like to share what I learned about record producers and explain why they are so useful.

If you have a handful of records you need to create, it can be tedious to enter all the information in over and over again. That is where record producers come into play. A record producer asks the user a series of questions that can be used to generate many records at a time. In my case, I wanted a user to be able to create sprints for a project. My record producer gathered information like how many sprints they wanted, what project the sprints would fall under, and when they wanted to start the sprints.

Record producers have the appearance of a form to make navigation easier for users. However, instead of using fields, record producers have variables.

Once you have your variables generated, you can preview your record producer and get it the way you want using catalog client scripts and UI policies.

 

Now that the record producer is set up the way we want, we need to add script logic that will tell the record producer how to create the records. For my sprint records, I used the script to fill in the name, start date, and end date fields based on the information I gathered from the user.

 

Now, when I fill out the record producer, it automatically generates sprints based on the information the user gave. Here is an example of the record producer in action:

 

Adding an Attachment Icon for Lists of Records – Method 2

$
0
0

ServiceNow provides users with an option to add attachments to records. However, the user cannot see if a record has an attachment unless they open it up. After playing around with different ideas, I came across two straightforward solutions:

Method 1: Creating a Business Rule to calculate the number of attachments whenever one is added or removed.

Method 2: Adding a Calculated Value to an attachments field.

In this post, I’ll go through the second method (using a Calculated Value to count attachments). The downside to this method is that the processing speed is slower since it runs every time the list loads. However, an advantage to this method is that it counts old attachments as well as new ones. So, if speed is not an important factor for you, this is the way to go.

Add Attachment Field to the Dictionary

So the first thing we need to is open up the dictionary to the table we want the attachment icon to show up on. I’ll use the Incident table for this example. Now we need to create a new field for Attachments.

For my field, I set the following values in the advanced view:

Table: Incident

Type: Integer

Column Label: Attachments

Column Name: u_attachments

Next, I set the Calculated Value. Here is the script that I used to count the number of attachments:

1
2
3
4
5
6
7
8
9
10
11
12
13
(function calculatedFieldValue(current) {
var attachCount = new GlideAggregate('sys_attachment');
attachCount.addQuery('table_sys_id', current.sys_id);
attachCount.addQuery('table_name',current.getTableName());
attachCount.addAggregate('COUNT');
attachCount.query();

var numAttachments = 0;
if (attachCount.next()) {
numAttachments = attachCount.getAggregate("COUNT");
}
return numAttachments;
})(current);

Once the Attachments field is created, configure the List Layout of the table to add our field.

Create a Field Style

Now that we have the Attachments field created and in place, we will need to create a style for it. Navigate to System UI > Field Styles. The form should be filled out as follows:

The Value above is making sure that the style only applies when there is at least one attachment on the record. Getting the background image was a little tricky. I came across a blog on ServiceNow Icons and Images that said you could find the icons that ServiceNow uses by typing image_picker.do in the Navigator. Using this method, I picked a paperclip icon for the Attachments image.

 

Result

Now that we have a field style for an attachments field that calculates the number of attachments, our table should look like this:

 

Demo Video

Endpoints in Integrations – Use Case

$
0
0

Recently I was asked to figure out a way to convert a web address into a fully qualified domain name using regex. The idea was to have a user type in the base instance or server name for an integration. I’ll walk through an example of how to do that in this post.

Add a New Field

The first this I did was add a URL field to the table that needed to contain the endpoint.

Create a Business Rule

The next thing I did was create a Business Rule that runs whenever the endpoint changes. I wanted the Business Rule to convert a URL into a fully qualified domain name, like the examples below.

https://www.myserver.mycompany.com/    –    www.myserver.mycompany.com

http://myserver.mycompany.com    –    myserver.mycompany.com

www.myserver.mycompany.com/    –    www.myserver.mycompany.com

myserver.mycompany.com/login    –    myserver.mycompany.com

 

Here is the script I used:

1
2
3
4
5
6
7
8
(function executeRule(current, previous /*null when async*/) {

var endpoint = current.web_endpoint.toString();
endpoint = endpoint.match(/^(?:http(?:s)?\:\/\/)?(.*[^/])\/?.*$/i)[1];
endpoint = encodeURI(endpoint);
current.web_endpoint = endpoint;

})(current, previous);

*Note: I had to put [1] after my regex to access the first group since that’s what contained the correct endpoint*

Final Result

Once the business rule was applied to the field, I had the following result:

 

Creating list-based UI Actions without selecting a record

$
0
0

On occasion, I need a general UI Action on a List in ServiceNow that is not specific to any one record in the list. For example, I might have a table that lists all of the Fruit inventory of a store. Let’s say that every night, we have have a job that runs and calculates any fruit that may have reached it’s expiration date so that it can dispose of them or signal them for markdown.

Sometimes, however, an administrator might be viewing the fruit and realize that we need to do that calculation right away rather than wait until the next scheduled evaluation period.

The administration might want a List Button or a List Link that they can push to tell the backend system to process the scheduled job to evaluate all of the fruit.

At first glance, you may do what I always do, and try to write a quick Server-side UI Action to trigger that event. However, when you click the button, you get the following error:

Error: No Records Selected

Error: No Records Selected

Since this is a list action, the system wants you to select records in the list before trying to click the server-side operation, even though your UI Action has nothing to do with a specific record on the list.

One way around this is to create a client-based UI Action. The error will not come up on the client portion of the UI Action’s function. However, if you want your client script to trigger a server-side operation that pesky error will pop up again. You could have your client script redirect the user to some processor, portal page, etc that triggers the job to execute, but that is a lot of overhead and has some potential security concerns if you don’t build it properly.

The quickest way to solve this problem is to create a client/server combination UI Action where the “Action” field has a name that starts with “sysverb_”.

Here is a sample UI Action:

Name: Recalculate expiration status
Action name: sysverb_recalculate_expirations
Client: true
List link: true
Onclick: processExpirations()
Script:

1
2
3
4
5
6
7
8
9
10
11
function processExpirations() {
    g_list.action('d8c74edadb5e4810262673e1ba961939', 'sysverb_recalculate_expirations');  
}

if (typeof window == 'undefined') {
    processServerSide();
}

function processServerSide() {
    //execute code to calculate fruit expirations
}

Now, I can click the link on the list without selecting any records and it will kick off my process for my fruit.

Viewing all 82 articles
Browse latest View live