Reporting Archives - ServiceNow Guru https://servicenowguru.com/category/reporting/ ServiceNow Consulting Scripting Administration Development Mon, 30 Sep 2024 23:29:33 +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 Reporting Archives - ServiceNow Guru https://servicenowguru.com/category/reporting/ 32 32 Leveraging ServiceNow with Highcharts: Transforming Data into Insight https://servicenowguru.com/service-portal/leveraging-servicenow-with-highcharts-transforming-data-into-insight/ https://servicenowguru.com/service-portal/leveraging-servicenow-with-highcharts-transforming-data-into-insight/#comments Tue, 08 Oct 2024 10:00:44 +0000 https://servicenowguru.com/?p=15549 In today's data-driven world, organizations are constantly seeking innovative solutions to transform complex datasets into actionable insights. ServiceNow, a leading cloud-based platform for digital workflows, provides extensive data handling and management capabilities. However, to truly leverage the power of data visualized effectively, integrating a robust tool like Highcharts can elevate the presentation and interpretation of

The post Leveraging ServiceNow with Highcharts: Transforming Data into Insight appeared first on ServiceNow Guru.

]]>
In today’s data-driven world, organizations are constantly seeking innovative solutions to transform complex datasets into actionable insights. ServiceNow, a leading cloud-based platform for digital workflows, provides extensive data handling and management capabilities. However, to truly leverage the power of data visualized effectively, integrating a robust tool like Highcharts can elevate the presentation and interpretation of data. This article explores how combining ServiceNow with Highcharts can transform raw data into clear, insightful visual representations, aiding businesses in making better-informed decisions. We’ll delve into the benefits of this integration, practical use cases, and tips for seamless implementation, setting the stage for a more intuitive and strategic approach to enterprise data analysis.

Highcharts is a flexible, feature-rich JavaScript library that allows developers to create interactive charts for the web. By integrating Highcharts with ServiceNow, you can transform static data into engaging visualizations, providing your users with a more intuitive, interactive experience. In this article, I’ll walk you through the process of integrating Highcharts with ServiceNow, showcasing use cases, and tips to get the most out of this powerful combination.

Why Integrate Highcharts with ServiceNow?

ServiceNow provides basic reporting and visualization features, but for more advanced charting needs—such as interactive dashboards or detailed drill-down capabilities—Highcharts offers several advantages:

  • Customization: Highcharts offers a wide range of chart types (line, bar, pie, scatter, etc.), and the ability to customize almost every aspect of the chart.
  • Interactivity: With Highcharts, users can interact with charts by zooming, clicking data points, and receiving real-time feedback, making data exploration more engaging.
  • Real-time Data: You can easily configure charts to update in real-time, providing up-to-the-minute insights.
  • Extensibility: Highcharts offers numerous plugins and extensions, allowing you to extend functionality as needed.

By combining ServiceNow’s robust data management with Highcharts’ visualization capabilities, organizations can create more effective reports and dashboards that drive better decision-making.

 

 

Licensing:

For this article, which has educational purposes, I will download version 11.4.3 of the library and use it in my PDI. For commercial use, it is recommended that you purchase licenses directly through their website. Another option is to use the version available within the platform, which in my research (<instance-name>/scripts/glide-highcharts.js) is 9.3.2.

Using the paid version:

In my article “Importing Excel to Servinow” I showed how to import a library into SN. Just follow the same steps to import the Highcharts library.

Using the version available on the platform:

Just create a JS Include in the Portal Theme added to the library already available on the platform:

 

Basic usage example:

For this first example I will create a simple widget with hard-coded data just to show how to use the library. To make things easier I will use a basic example that can be found in the documentation. This example was made using the version of the library that already comes with the platform.

 

Widget Basic Highchart Example
Widget Component: Client Script
Script:

<div class="page-header">
  <h1>ServiceNow Guru - Basic Highchart Example</h1>
</div>

<div id="container" style="width:100%; height:400px;"></div>

 

Widget Basic Highchart Example
Widget Component: HTML Template
Script:

var chartConfirObj = {
  chart: {
    type: 'bar',
  },
  title: {
    text: 'Fruit Consumption',
  },
  xAxis: {
    categories: ['Apples', 'Bananas', 'Oranges'],
  },
  yAxis: {
    title: {
      text: 'Fruit eaten',
    },
  },
  series: [
    {
      name: 'Jane',
      data: [1, 0, 4],
    },
    {
      name: 'John',
      data: [5, 7, 3],
    },
  ],
};

var chart = Highcharts.chart('container', chartConfirObj);

 

In this example, we see that to build the chart we need to pass an object containing the chart settings we want. The library is huge and I could spend hours here talking about each item in this object and also about each customization possibility, but the library documentation is incredibly complete and can answer all questions:

 

Now let’s give our graph a bit more reality and bring real data to it.

 

Widget Highchart Pie Example
Widget Component: Server Script
Script:

//variables that will be used to customize the graph
data.font_family = options.font_family || 'SourceSansPro,Helvetica,Arial,sans-serif';
data.fill_color = options.fill_color || '#fff';

data.title = options.title || 'Chart Title';
data.title_color = options.title_color || '#fff';
data.title_size = options.title_size || '14px';
data.title_weight = options.title_weight || 'normal';

data.label_color = options.label_color || '#fff';
data.label_size = options.label_size || '12px';
data.label_weight = options.label_weight || 'normal';
data.label_connector_color = options.label_connector_color || '#fff';

data.slice_label_size = options.slice_label_size || '14px';
data.slice_label_outline = options.slice_label_outline || 'transparent';
data.slice_label_opacity = options.slice_label_opacity || 1;
data.slice_label_weight = options.bar_label_weight || 'bold';

data.table = options.table || 'change_request';
data.agg_field = options.agg_field || 'risk';

data.graphData = [];

//get total requests
var reqCount = new global.GlideQuery(data.table).count();

// get the total requests by risk
var agg = new GlideAggregate(data.table);
agg.addAggregate('COUNT', data.agg_field);
agg.orderBy(data.agg_field);
agg.query();
while (agg.next()) {

    var count = parseInt(agg.getAggregate('COUNT', data.agg_field));
    var percentTemp = 100 * count / reqCount;
    var percent = Math.round(percentTemp * 100) / 100;

    var objReq = {
        name: agg.getDisplayValue(data.agg_field),
        y: count,
        percent: percent.toFixed(2)
    };

    // if the risk is Very High the pie should be sliced and red
    if (agg.getValue(data.agg_field) == 1) {
        objReq.sliced = true;
        objReq.selected = true;
        objReq.color = 'red';
    }

    data.graphData.push(objReq);

}

 

Widget Highchart Pie Example
Widget Component: Client Script
Script:

var chartConfirObj = {
  chart: {
    type: "pie",
    backgroundColor: c.data.fill_color,
  },
  title: {
    text: c.data.title,
    style: {
      fontFamily: c.data.font_family,
      color: c.data.title_color,
      fontSize: c.data.title_size,
      fontWeight: c.data.title_weight,
    },
  },
  tooltip: {
    formatter: function () {
      return (
        "<b>" +
        this.point.name +
        " </b>: " +
        this.y +
        " </b> (" +
        this.point.percent +
        "%)"
      );
    },
  },
  plotOptions: {
    series: {
      allowPointSelect: true,
      cursor: "pointer",
      dataLabels: [
        {
          enabled: true,
          distance: 20,
          connectorColor: c.data.label_connector_color,
          formatter: function () {
            return this.point.name + " </br>" + this.point.percent + "%";
          },
          style: {
            fontFamily: c.data.font_family,
            color: c.data.label_color,
            fontSize: c.data.label_size,
            fontWeight: c.data.label_weight,
            textOutline: c.data.bar_label_outline,
          },
        },
        {
          enabled: true,
          distance: -30,
          format: "{y}",
          style: {
            textOutline: c.data.slice_label_outline,
            fontSize: c.data.slice_label_size,
            opacity: c.data.slice_label_opacity,
            fontWeight: c.data.slice_label_weight,
            textAling: "center",
          },
        },
      ],
    },
  },
  series: [
    {
      name: "Percentage",
      colorByPoint: true,
      data: c.data.graphData,
      dataLabels: {
        style: {
          color: c.data.bar_label_color,
          fontSize: c.data.bar_label_size,
          textOutline: c.data.bar_label_outline,
          fontWeight: c.data.bar_label_weight,
        },
      },
    },
  ],
};

var chart = Highcharts.chart("containerPie", chartConfirObj);

 

Widget Highchart Pie Example
Widget Component: HTML Template
Script:

<div id="containerPie"></div>

 

Widget Highchart Pie Example
Widget Component: Option Schema
JSON:

[
    {
        "name": "table",
        "section": "other",
        "default_value": "change_request",
        "label": "Table",
        "type": "string"
    },
    {
        "name": "agg_field",
        "section": "other",
        "default_value": "risk",
        "label": "Field used to aggregate",
        "type": "string"
    },
    {
        "name": "font_family",
        "section": "other",
        "default_value": "SourceSansPro,Helvetica,Arial,sans-serif",
        "label": "Font family",
        "type": "string"
    },
    {
        "name": "fill_color",
        "section": "other",
        "default_value": "#fff",
        "label": "Fill color",
        "type": "string"
    },
    {
        "name": "title",
        "section": "other",
        "default_value": "Chart title",
        "label": "Title",
        "type": "string"
    },
    {
        "name": "title_color",
        "section": "other",
        "default_value": "#fff",
        "label": "Title color",
        "type": "string"
    },
    {
        "name": "title_size",
        "section": "other",
        "default_value": "14px",
        "label": "Title Size",
        "type": "string"
    },
    {
        "name": "title_weight",
        "section": "other",
        "default_value": "normal",
        "label": "Title weight",
        "type": "string"
    },
    {
        "name": "label_color",
        "section": "other",
        "default_value": "#fff",
        "label": "Label Color",
        "type": "string"
    },
    {
        "name": "label_size",
        "section": "other",
        "default_value": "11px",
        "label": "Label size",
        "type": "string"
    },
    {
        "name": "label_weight",
        "section": "other",
        "default_value": "normal",
        "label": "Label weight",
        "type": "string"
    },
    {
        "name": "label_connector_color",
        "section": "other",
        "default_value": "#fff",
        "label": "Label connector color",
        "type": "string"
    }
]

 

Now, with everything we have shown in this article, we have the possibility of building complex dashboards like the one we saw at the beginning of this article.

 

Conclusion

Integrating Highcharts with ServiceNow allows you to take your data visualization to the next level, enabling more interactive, detailed, and dynamic reporting. With its wide range of customization options and ability to handle real-time data, Highcharts is an ideal tool for organizations looking to enhance their ServiceNow dashboards and reports. Whether you’re visualizing incident trends, service performance, or asset utilization, this integration can provide critical insights to drive better decision-making.

By following the steps in this article, you’ll be well on your way to creating powerful, interactive charts in ServiceNow, enabling users to explore and understand complex data sets with ease.

The post Leveraging ServiceNow with Highcharts: Transforming Data into Insight appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/service-portal/leveraging-servicenow-with-highcharts-transforming-data-into-insight/feed/ 3
How to use a ServiceNow Read Replica https://servicenowguru.com/performance/how-to-use-servicenow-read-replica/ https://servicenowguru.com/performance/how-to-use-servicenow-read-replica/#comments Tue, 04 Jun 2024 14:56:54 +0000 https://servicenowguru.com/?p=16004 We have all heard about dynamic scaling or horizontal scaling in the cloud but can our SaaS offering from ServiceNow scale like this?  The answer, YES!  The platform can scale with more app nodes, but the real horsepower comes from scaling the back end using Read Replicas. Before we go further, I would like to

The post How to use a ServiceNow Read Replica appeared first on ServiceNow Guru.

]]>
We have all heard about dynamic scaling or horizontal scaling in the cloud but can our SaaS offering from ServiceNow scale like this?  The answer, YES!  The platform can scale with more app nodes, but the real horsepower comes from scaling the back end using Read Replicas.

Before we go further, I would like to take a second and give a brief description to those of us asking “What is a read replica and do I really need one?” A read replica in ServiceNow is a database instance that is configured to handle read-only operations, helping to offload traffic from the primary database and improve performance as well as improving user experience through response times.

Do I have a Read Replica?

Before you go check if you have a Read Replica, please don’t everyone at once start banging down ServiceNow’s doors demanding Read Replicas.  Not everyone will have a Read Replica, nor will everyone need one.  Having a Read Replica is based on instance size, performance and many other factors.  Work with your Account Team to determine if one is right for your instance.

One of the larger instances I have worked on had a database footprint of 100TB+ and had multiple read replicas.  You’re probably asking how do I know if I need a read replica which we will not cover here, however we will go over how to check if you have one:

First we can check our “Secondary Database Pools” to see if we have data in the table:

sys_db_pool

Once we verify we have read replicas we need to check our “categories”.

sys_db_category

If both of these tables show up on your instance and have data in the tables, then you have a read replica!  Now onto how we use it.

How to use it:

ServiceNow will tune your queries to automatically go to a read replica more often than not without you the customer doing a thing.  However, there are some scenarios where you will want to use a query category to ensure it is forced to the correct place, aka a Read Replica!

From our previous steps, we can see our categories (sys_db_category) but the two I find myself using to start with are “reporting” for report-type queries and scripts and “reroute” for most other things.

Scenario 1:

I want to query data and have NO intention to write back to the database:

In this scenario, I want to bring back a list of all Active incidents.  This can be an expensive query in a large-scale instance and could put undue load on the primary database.  Using the “setCategory” in our GlideRecord will force this query to use the read replicas configured within the “reroute” category.

//return back a list of all active incident

var gr = new GlideRecord('incident');
gr.addActiveQuery();
gr.setCategory("reroute"); //This forces it to a read replica
gr.query();

Scenario 2:

In this scenario, I have a reporting engineer who needs to report off-platform and will be making an API query to bring back those same Active incidents.  Since this is reporting and we don’t want to hammer our primary DB we should instruct our API consumer to pass in a parameter that will ensure that this API query goes to a read replica:

URL Parameter:  sysparm_query_category=reporting

https://instance.service-now.com/api/now/table/incident?sysparm_query=active%3Dtrue&&sysparm_query_category=reporting

When NOT to use a Read Replica:

If we are going to be checking if a record exists before inserting it, then we should NOT use a Read Replica.  This is due to replication lag between the primary and the replica.

In closing, Read Replicas are not the only way to improve performance but are part of a holistic architecture to help improve platform performance.  How are you using read replicas today or how do you plan on using them in the future?  Let us know in the comments!

Pro tip:  Troll your slow query log for the top 20 and fix those first. Then do the same next month.

The post How to use a ServiceNow Read Replica appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/performance/how-to-use-servicenow-read-replica/feed/ 4
Harnessing the Power of Dynamic Filters in ServiceNow https://servicenowguru.com/reporting/harnessing-power-dynamic-filters-servicenow/ https://servicenowguru.com/reporting/harnessing-power-dynamic-filters-servicenow/#comments Fri, 04 Sep 2015 12:14:54 +0000 https://servicenowguru.wpengine.com/?p=5637 ServiceNow adds a ton of great functionality to each new product release. Often times, the most helpful and useful features (at least to a long-time user of the system) are enhancements to simplify or improve on existing functionality. Unfortunately, these are often some of the most under-appreciated and end up getting lost in the marketing

The post Harnessing the Power of Dynamic Filters in ServiceNow appeared first on ServiceNow Guru.

]]>
ServiceNow adds a ton of great functionality to each new product release. Often times, the most helpful and useful features (at least to a long-time user of the system) are enhancements to simplify or improve on existing functionality. Unfortunately, these are often some of the most under-appreciated and end up getting lost in the marketing hype of all of the brand new capabilities that you may or may not use. One such example that recently arrived to ServiceNow is ‘Dynamic filters’. In this post, I’ll share what dynamic filters are, and show how you can extend and leverage this capability to improve your own ServiceNow system.

DynamicallyFilteredList

The ServiceNow wiki does a decent job of explaining the basic concept and usage of dynamic filters. There are 1000’s of scenarios where users of the system need to query for information, display a list of data, generate a report, or values from a reference field based on a specific, logical filter criteria. There are many examples of this…my Group’s work, my approvals, records assigned to other members of my groups, etc. These types of scenarios, though simple on the surface, actually require sometimes very complex code to query for and return the correct data. ServiceNow has always allowed you to do this, of course, but the approach (asking a typical end-user to remember and correctly populate a specific query string with a function call directly in the filter) really isn’t one that works well — even if that user happens to be an admin of the system. Those query strings generally look something like this and can be pasted directly into any filter criteria to return information…

javascript:gs.getUserID();
javascript:getRoledUsers();
etc...

The general idea behind dynamic filters is to allow a ServiceNow administrator to pre-define the filter query logic to return the correct information from a back-end function, then set up a dynamic filter definition to point to that information via a simple label invoked from any filter field criteria in the system. These dynamic filters can be as flexible and complex as you need them to be, but the end-user doesn’t need to know or understand any of that complexity in order to benefit from them!

There are several of these dynamic filters defined out-of-box that you can use right away as examples for creating your own. You can find them under ‘System Definition -> Dynamic Filter Options’ in your left nav. For more complex scenarios, you’ll actually point your dynamic filter to a back-end Script Include function that contains all of the logic and does the heavy lifting.

One common filter criteria that I hear about all of the time that isn’t handled out-of-box is to filter for records associated to members of my groups via some user field (usually an assignment or ownership of some sort). Tickets assigned to members of my groups, outstanding approvals for members of my groups, etc. This configuration can be added to your system by following a few simple steps as shown below…

    1. Create a new ‘On Demand’ Script Include function.

I’ve written about this capability before so you can reference that article for more details if you need. Creating this script include will allow us to easily call a reusable function to return the data we want…in this case a list of users that belong to the same group as the current user. The basic idea for this function is to get a user’s groups, then find the active group members sys_id values associated with those groups and add them to an array to be returned. You can navigate to ‘System Definition -> Script Includes’ in your left nav to create this. Don’t forget that the ‘Name’ value of any on demand script include (like this one) needs to exactly match the name of the function you’re calling in the script!

‘getMyGroupMembers’ Script Include
Name: getMyGroupMembers
Active: True
Client callable: True
Description: Queries for members of groups that the currently logged-in user is also a member of.
Script:

function getMyGroupMembers(){
var myGroups = gs.getUser().getMyGroups();
var groupsArray = new Array();
var it = myGroups.iterator();
var i=0;
var groupMemberArray = new Array();
while(it.hasNext()){
var myGroup = it.next();
//Query for group members
var grMem = new GlideRecord('sys_user_grmember');
grMem.addQuery('group', myGroup);
//Only return active users
grMem.addQuery('user.active', true);
grMem.query();
while(grMem.next()){
//Add to user sys_id to array
groupMemberArray.push(grMem.user.toString());
}
i++;
}
return groupMemberArray;
}
    1. Create a new ‘Dynamic Filter’ record

      The on-demand function is great and allows you to easily return the data you want. From any place you can call scripts in the system. This is fantastic for business rules, workflow scripts, etc. but the average user running a report or filtering a list is not going to know (nor should they need to know) the exact syntax and function name to call. This is where Dynamic Filters come in! We can wrap that script call in a friendly label that displays in any filter anywhere in the system so that a normal human being can access it as well. Your dynamic filter for the script above should look just like I’ve shown in the screenshot below. You can create it by navigating to ‘System Definition -> Dynamic Filter Options’

DynamicFilter

 

NOTE: One interesting bit of information I discovered while working with dynamic filters is the way that the system handles the encoded query strings for them. You end up with a query string (that you could reuse) that looks like this…

assigned_toDYNAMIC1a570fd90856c200aa4521695cf1eb24

The ‘DYNAMIC’ keyword indicates the use of a dynamic filter, and what follows is the sys_id of the corresponding dynamic filter record.

The end result is a nice, dynamic filter option for filtering where the user listed in a user field is a member of one of your groups! This is just one example of a fantastic capability in ServiceNow. There are lots of other use cases that you can add using this same approach.

DynamicallyFilteredList

The post Harnessing the Power of Dynamic Filters in ServiceNow appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/reporting/harnessing-power-dynamic-filters-servicenow/feed/ 10
Identify which ServiceNow Record Producer was used to create a record https://servicenowguru.com/reporting/identify-servicenow-record-producer-create-record/ https://servicenowguru.com/reporting/identify-servicenow-record-producer-create-record/#comments Thu, 22 Jan 2015 16:42:42 +0000 https://servicenowguru.wpengine.com/?p=5518 Record producers are a great piece of ServiceNow functionality that allows for the creation of records in any table via the standard Service Catalog interface. This capability has been around for quite a while and odds are that you’re already using it in your system to allow end-users to create new incidents…among other things. Over

The post Identify which ServiceNow Record Producer was used to create a record appeared first on ServiceNow Guru.

]]>
Record producers are a great piece of ServiceNow functionality that allows for the creation of records in any table via the standard Service Catalog interface. This capability has been around for quite a while and odds are that you’re already using it in your system to allow end-users to create new incidents…among other things.

Over the years I’ve worked with ServiceNow, I’ve seen several requests to be able to report on or identify the record producer used to create a particular record. This would allow for easier identification of the entry point for record producer transactions. Unfortunately, ServiceNow doesn’t give us a simple way of accomplishing this. Even though there is a record producer ‘Script’ field and a ‘producer’ script object to work with, nothing is built to be able to dynamically identify the record producer used. This means that you’re stuck hard-coding values in a script or adding unnecessary variables to your record producer forms for every single record producer in your system. Read on for a fairly simple solution to this problem!

Record Producer Populated

This configuration can be accomplished in a few simple steps as shown below…

    1. Create a new field to store the value of the record producer used.

      We’ll want to store the record producer value on each target record that is created. As such, you’ll need a field to store that value in. I think the best solution is simply to create a new reference field referencing the ‘Record producer’ [sc_cat_item_producer] table named ‘Record producer’ [u_record_producer] on the ‘task’ table. That way, you can have one shared field that will be available to almost everything that you’ll usually use with record producers. If you’ve got additional tables that don’t extend ‘task’, just repeat the same step there as well.

 

    1. Create a new business rule on the ‘Record Producer [sc_cat_item_producer]’ table.

      The purpose of the business rule is to overcome the issue this article is about. We do this by leveraging the record producer ‘Script’ field to populate the ‘Record producer’ [u_record_producer] field created in the previous step. The business rule simply populates the record producer sys_id value into the record producer ‘Script’ field every time the record producer is inserted or updated and then the standard record producer script/creation process takes over and writes the producer Sys ID to the field per normal operations. If you need this to work for non-task tables, you can simply create a duplicate business rule there.

‘Force population of record producer used’ Business rule
Name: Force population of record producer used
Table: Record producer [sc_cat_item_producer] When: Before
Insert: True
Update: True
Advanced: True
Order: 1100
Condition: current.script.indexOf(‘Force population of record producer’) == -1
Script:

/***There is no dynamic way to record the record producer used so we can force it here
by modifying the script field entry on the record producer. Record producer will be
populated in a reference field on the target record named 'u_record_producer' (which
will need to be created).***/current.script = current.script + '\n\n\n' + '/***DO NOT REMOVE OR MODIFY THIS SECTION!!! Automatically added by "Force population of record producer used" business rule. \nForces population of this record producer sys_id into the target record for reporting purposes.***/\n' + 'current.u_record_producer = ' + '"' + current.sys_id + '";';

 

Please note that you will need to manually update every record producer in the system that you want this to work with in order for the producer script to be updated as necessary!

If you’ve done all of the above steps correctly, you should end up with a nicely-populated ‘Record producer’ reference field on each generated record. This value can then be used for reporting or other purposes in your system!

Record Producer Populated

The post Identify which ServiceNow Record Producer was used to create a record appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/reporting/identify-servicenow-record-producer-create-record/feed/ 22
Building a CI Change Calendar Macro – On The Fly https://servicenowguru.com/reporting/ci-change-calendar-macro/ https://servicenowguru.com/reporting/ci-change-calendar-macro/#comments Wed, 20 Jul 2011 12:39:19 +0000 https://servicenowguru.wpengine.com/?p=3920 A co-worker asked me for some help yesterday fulfilling an interesting requirement. He needed to set up a configuration item reference field or catalog variable that would display a calendar macro that, when clicked, would open a popup window containing a change calendar report for that configuration item. I figured this idea might be of

The post Building a CI Change Calendar Macro – On The Fly appeared first on ServiceNow Guru.

]]>
A co-worker asked me for some help yesterday fulfilling an interesting requirement. He needed to set up a configuration item reference field or catalog variable that would display a calendar macro that, when clicked, would open a popup window containing a change calendar report for that configuration item. I figured this idea might be of use to others so I’m posting it here!

CI Change Calendar Report Macro Popup

I’ve written before about UI macros, and different types of popups on SNGuru. I’ve also written about how your change management process can be a valuable input into your other ITIL processes such as incident management. You can refer to those posts if you’re interested in more detail on some of the ideas used in this article.

The real magic of this solution is how you can create this calendar report ‘on-the fly’ simply by constructing the correct URL. This is something that a colleague of mine, Bobby Edmonds, tipped me off to a couple of years ago. The URL contains several ‘sysparm_’ parameters that point to the fields on the report form. Once you know those, you just have to pass them the correct values. The URL for the calendar report needs to look something like this…

sys_report_template.do?sysparm_table=change_request&sysparm_type=calendar&sysparm_cal_field=end_date&sysparm_from_list=true&sysparm_manual_labor=true&sysparm_query=^end_date%3Ejavascript:gs.endOfLastMonth()'^cmdb_ci=YOUR_CI_SYS_ID_HERE
I plan on writing a post about creating on-the-fly reports soon, but you can piece together the necessary URL parameters for a report by poking around any existing report in your system with a DOM inspector to see what parameters are necessary.

You might be asking, “Why don’t you just point directly to the existing change calendar report URL?”. You could certainly do that, and avoid all of the above, but the requirement in this case is to have the calendar report filtered based on the CI chosen in the field, so it needs to be dynamic.

Because this URL will be initiated from a UI macro (for this example) we’ll need to escape the ampersands and you can see that I’ve done that in the code below. The rest of the code is almost identical to the out-of-box ‘user_show_incidents’ UI macro that you see on the incident ‘Caller’ field. Once the URL is constructed we can use ‘popupOpen’ to display the report in a popup!

Your UI macro should look like this. Once set up, it can be added to the CI reference field of your choice by adding the ‘ref_contributions=ci_show_change_calendar’ attribute to the dictionary entry ‘Attributes’ field of that CI reference field.

‘ci_show_change_calendar’ UI macro
Name: ci_show_change_calendar
Description:
Show CI change calendar popup link
Activate by:
– set the active field in this macro to true
– adding the attribute to a dictionary field: ref_contributions=ci_show_change_calendar
Script:

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



<script>
function showCIChangeCalendar(reference) {
   //Construct the calendar report URL
   var url = 'sys_report_template.do?sysparm_table=change_request$[AMP]sysparm_type=calendar$[AMP]sysparm_cal_field=end_date$[AMP]sysparm_from_list=true$[AMP]sysparm_manual_labor=true$[AMP]sysparm_query=^end_date%3Ejavascript:gs.endOfLastMonth()^cmdb_ci=';
   
   var s = reference.split('.');
   var referenceField = s[1];
   var v = g_form.getValue(referenceField);
   url = url + v;
   //Open the popup 
   var features = "width=700,height=650,toolbar=no,status=no,directories=no,menubar=no,resizable=yes,scrollbars=1";
   popupOpen(url, 'show_calendar', 700, 650, features, true);
}
</script>

 

Add a Change Calendar Macro to a Catalog Reference Variable

You can use a similar technique to add a calendar macro icon next to a catalog reference variable. The big, additional challenge in the service catalog is that reference field macros are not supported for catalog variables. In order to add one you have two options. The first would be to create a UI page or UI macro-type variable similar to the example above. The big drawback would be that the icon wouldn’t appear right next to the reference variable without some clever client scripting.
The second option (which I chose) is to use a catalog client script to construct the macro on-the-fly and place it in the correct spot next to the reference field. This technique is based on a previous solution I wrote about in another SNCGuru article about placing macros next to non-reference fields.

Your catalog client script should look like this. Just add the name of your CI reference variable in the ‘ciVarName’ line below.

‘Add CI Change Calendar Macro’ Catalog Client Script
Name: Add CI Change Calendar Macro
Applies to: Catalog item or variable set of your choice
Type: onLoad
Script (Pre-Fuji version):

function onLoad() {
//The reference variable name to put the icon next to
var ciVarName = 'cmdb_ci';//Add the icon decoration to the reference field
var ciEl = 'lookup.' + g_form.getControl(ciVarName).id;
$(ciEl).insert({
after: '<a id="cmdb_ci_calendar_macro" style="padding-right: 4px;"></a><img title="CI Change Calendar" src="images/icons/dayview.gifx" alt="CI Change Calendar" />'
});
//Add the 'onclick' event
$('cmdb_ci_calendar_macro').observe('click', showCIChangeCalendar);

function showCIChangeCalendar(){
//Construct the calendar report URL
var url = 'sys_report_template.do?sysparm_table=change_request&sysparm_type=calendar&sysparm_cal_field=end_date&sysparm_from_list=true&sysparm_manual_labor=true&sysparm_query=^end_date%3Ejavascript:gs.endOfLastMonth()';
if(g_form.getValue(ciVarName) != ''){
url = url + '^cmdb_ci=' + g_form.getValue(ciVarName);
}

//Open the popup
var features = "width=700,height=650,toolbar=no,status=no,directories=no,menubar=no,resizable=yes,scrollbars=1";
popupOpen(url, 'show_calendar', 700, 650, features, true);
}
}

Script (Fuji version):

function onLoad() {
//The reference variable name to put the icon next to
var ciVarName = 'cmdb_ci';

//Add the icon decoration to the reference field
var ciEl = 'lookup.' + g_form.getControl(ciVarName).id;
$(ciEl).insert({
after: '<a id="cmdb_ci_calendar_macro" class="icon-calendar btn btn-default sn-tooltip-basic" style="padding: 6px 10px; vertical-align: text-bottom;" title="" data-original-title="CI Change Calendar"></a>'
});
//Add the 'onclick' event
$('cmdb_ci_calendar_macro').observe('click', showCIChangeCalendar);

function showCIChangeCalendar(){
//Construct the calendar report URL
var url = 'sys_report_template.do?sysparm_table=change_request&sysparm_type=calendar&sysparm_cal_field=end_date&sysparm_from_list=true&sysparm_manual_labor=true&sysparm_query=^end_date%3Ejavascript:gs.endOfLastMonth()';
if(g_form.getValue(ciVarName) != ''){
url = url + '^cmdb_ci=' + g_form.getValue(ciVarName);
}

//Open the popup
var features = "width=700,height=650,toolbar=no,status=no,directories=no,menubar=no,resizable=yes,scrollbars=1";
popupOpen(url, 'show_calendar', 700, 650, features, true);
}
}

When you’re done, your catalog variable will have a calendar link next to it that looks like this…
CI Change Calendar Macro Catalog Variable

The post Building a CI Change Calendar Macro – On The Fly appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/reporting/ci-change-calendar-macro/feed/ 5
Restrict Report Table Selection by Role https://servicenowguru.com/reporting/restrict-report-table-selection-role/ https://servicenowguru.com/reporting/restrict-report-table-selection-role/#comments Mon, 20 Dec 2010 13:51:01 +0000 https://servicenowguru.wpengine.com/?p=3108 Update: ServiceNow has introduced new ACL functionality that allows you to do basically the same thing as described in this article. They’re also taking a drastically new direction with reporting starting with the Fuji release, but being introduced in the back-end code in the Eureka release. As such, the solution described here is obsolete and

The post Restrict Report Table Selection by Role appeared first on ServiceNow Guru.

]]>
Update: ServiceNow has introduced new ACL functionality that allows you to do basically the same thing as described in this article. They’re also taking a drastically new direction with reporting starting with the Fuji release, but being introduced in the back-end code in the Eureka release. As such, the solution described here is obsolete and no longer supported. Check out this wiki article to see how to restrict report table selection using standard ServiceNow ACLs.

Reporting in Service-now.com is usually very simple. One challenge I’ve seen before with the Service-now reporting interface is that it displays a lot of tables to most users as tables they can report on. The list of reportable tables is controlled by system security ACLs. If a user can read a table in the system they can also report on that table. There are many cases where users need to be able to read from a table in order for the system to work correctly for them, but you may not want users running reports on that table just because they see it as an option in the reporting interface. I’ve created the Restrict Report Tables update set as a solution to this problem. It gives Service-now report administrators granular control over which tables in the system show up as selectable options in the report interface.

Before



After


Please note that this functionality has no bearing on overall table security in your system. Users can still run filters, create bar and list charts, and otherwise run ad-hoc list reporting on any table in the system that they have read access to. If a user does not have read access to a table (as defined by your security ACLs) the functionality described here honors that security.

This customization includes the following features:

  • Limit the ‘Table’ options that display in the reporting interface by role
  • Simple script manipulation to limit any override roles for this behavior

Core components:

This solution includes three primary components. The first is the ‘Report Tables’ table definition along with the ‘Report Tables’ module. This component is restricted to users with the ‘admin’ or ‘report_admin’ role by default.

The second component is the ‘RemoveReportOptions’ UI script which handles the showing and hiding of report form elements. It also controls the override roles (‘admin’ and ‘report_admin’ by default) for the entire behavior.

Finally, the ‘GetReportTables’ Script Include handles the back-end query and selection of reportable tables based on the user role.

Usage:

This customization is only offered as an update set through ServiceNowGuru.com. You’ll need to install an update set into your instance to get this functionality. Installation and download instructions can be found below.

There are really only two configuration options that you’ll need to worry about. The first is the ‘Report Tables’ definition as shown in the screenshot below. Simply define the tables (and associated roles) that the tables should be available to. The second is the override roles contained in the ‘RemoveReportOptions’ UI script. By default, the ‘admin’ and ‘report_admin’ roles are not impacted by this behavior. You can modify that by changing or adding to the lines at the top of that script. UI Scripts are found under the ‘System UI’ application.

The post Restrict Report Table Selection by Role appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/reporting/restrict-report-table-selection-role/feed/ 28
Automatically Filter Report Homepage https://servicenowguru.com/reporting/automatically-filter-report-homepage/ https://servicenowguru.com/reporting/automatically-filter-report-homepage/#comments Fri, 23 Jul 2010 11:48:10 +0000 https://servicenowguru.wpengine.com/?p=1818 I just figured out a cool little reporting feature today that might end up helping somebody. On the reports homepage (‘report_home.do’) in Service-now.com, users have the ability to type filter text to restrict the types of reports that they see. So, if I wanted to see just those reports on the ‘Change request’ table, I

The post Automatically Filter Report Homepage appeared first on ServiceNow Guru.

]]>
I just figured out a cool little reporting feature today that might end up helping somebody. On the reports homepage (‘report_home.do’) in Service-now.com, users have the ability to type filter text to restrict the types of reports that they see. So, if I wanted to see just those reports on the ‘Change request’ table, I could simply type ‘change request’ for my filter text as shown below…

Now for the cool part… This filter text can actually be passed over a URL as a parameter to automatically bring a user to a filtered report homepage view. This might be useful if you wanted to create a UI action on the change request table that brought the user to the change request reports when clicked for example.
The parameter is ‘sysparm_reportquery’ and is used like this in a URL…

To navigate to the report homepage without navigation (filtering on ‘change request’)
https://demo.service-now.com/report_home.do?sysparm_reportquery=change request

To navigate to the report homepage with navigation (filtering on ‘change_request’)
https://demo.service-now.com/nav_to.do?uri=report_home.do?sysparm_reportquery=change request

Filtering on additional report attributes with a hidden background filter

You can also use the regular ‘sysparm_query’ parameter just like you would in a module or filter definition to filter a list of records. This might be useful for filtering on other attributes on the report definition. For example, if I wanted to show a list of just Pie Chart reports in the system WITHOUT having my query appear in the filter box, I could set up my report page URL like this…
https://demo.service-now.com/nav_to.do?uri=report_home.do?sysparm_query=type=pie

The post Automatically Filter Report Homepage appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/reporting/automatically-filter-report-homepage/feed/ 7
Group Member Counts Reports https://servicenowguru.com/reporting/group-member-counts-reports/ https://servicenowguru.com/reporting/group-member-counts-reports/#comments Wed, 21 Jul 2010 12:32:21 +0000 https://servicenowguru.wpengine.com/?p=1811 Over the last couple of weeks I’ve seen the same type of question a few times. The questions center on group membership reporting and usually look something like the following… “How can I generate a report showing which groups in my system have no users?” “How can I generate a report showing which groups have

The post Group Member Counts Reports appeared first on ServiceNow Guru.

]]>
Over the last couple of weeks I’ve seen the same type of question a few times. The questions center on group membership reporting and usually look something like the following…

“How can I generate a report showing which groups in my system have no users?”
“How can I generate a report showing which groups have no active users?”
“Is it possible to report on the number of active users in a group?”


The biggest challenge in answering these questions is not around reporting on active users, but in reporting on groups that have no users. How do you bring up a report of records that don’t exist? When designing your Service-now implementation, its always important to understand the end reporting goals that correspond to each particular process. Reporting on groups with no members is a good example of a scenario where you’ll need to perform some sort of calculation and then capture that calculation somewhere where the data can be reported on.
The questions above can be answered by doing the following…

1- Create 2 new integer fields on the Group (‘sys_user_group’) table — one called ‘Group members’ and one called ‘Active group members’. These fields will store the count of each of these group metrics and will be populated by a scheduled script job at a specified interval.

2- Create a new Scheduled Job entry (‘System Definition’ -> Scheduled Jobs) to automatically run a script of your choosing and use the following script…

//Query the sys_user_group table for all groups
var grp = new GlideRecord('sys_user_group');
grp.query();
while(grp.next()){
//Query for the number of group members
var grpm = new GlideAggregate('sys_user_grmember');
grpm.addQuery('group', grp.sys_id);
grpm.addAggregate('COUNT');
grpm.query();
var groupMembers = 0;
if(grpm.next()){
groupMembers = grpm.getAggregate('COUNT');
grp.u_group_members = groupMembers;
}

//Query for the number of active group members
var grpma = new GlideAggregate('sys_user_grmember');
grpma.addQuery('group', grp.sys_id);
grpma.addQuery('user.active', true);
grpma.addAggregate('COUNT');
grpma.query();
var activeGroupMembers = 0;
if(grpma.next()){
activeGroupMembers = grpma.getAggregate('COUNT');
grp.u_active_group_members = activeGroupMembers;
}

//Update the group record with the new counts
grp.update();
}

The script will run at the interval you specify and populate counts on each group record for the number of group members and also the number of active group members. Once you have that information, its very simple to create reports based on the group table that display the needed information.

The post Group Member Counts Reports appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/reporting/group-member-counts-reports/feed/ 2
Viewing CI Subscription Notifications https://servicenowguru.com/reporting/viewing-ci-subscription-notifications/ https://servicenowguru.com/reporting/viewing-ci-subscription-notifications/#comments Tue, 26 Jan 2010 14:36:45 +0000 https://servicenowguru.wpengine.com/?p=717 The Subscription-based Notification plugin allows Service-now users to manage their subscriptions for any notification in the system. It also allows users to subscribe to particular Configuration Items in your CMDB that they may be interested in. As an administrator or process owner, it may be necessary for you to be able to view or report

The post Viewing CI Subscription Notifications appeared first on ServiceNow Guru.

]]>
The Subscription-based Notification plugin allows Service-now users to manage their subscriptions for any notification in the system. It also allows users to subscribe to particular Configuration Items in your CMDB that they may be interested in.
As an administrator or process owner, it may be necessary for you to be able to view or report on which users have subscribed to updates for a particular configuration item. You may also want to see what configuration items a particular user has subscribed to without opening up their subscriptions page.

Fortunately, this information is all contained in a table that you can show on both a configuration item form and a user record. The name of the table is ‘Notification Messages’ (cmn_notif_message). Since this table contains all notification subscriptions for your system, you’ll want to filter the list so that it only shows you records with a ‘Notification Message’ value of ‘CI Affected’. You could also personalize the related lists for either table and add the ‘Notification Messages -> Configuration Item/User’ related list to your form.

The post Viewing CI Subscription Notifications appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/reporting/viewing-ci-subscription-notifications/feed/ 1