In this snippet you will create a custom spider web using a custom page and populating data using Highcharts native library
Step 1: Create a new Widget
Go to Service Portal > Widget > Click New
Name: Custom productionProcess
Id: custom-gojs-productionProcess
Click on submit
Body HTML template
Copy and paste below HTML Code in Widget’s HTML Template section
<div>
<!-- chart -->
<div id="container"></div>
<p class="highcharts-description">
A spiderweb chart or radar chart is a variant of the polar chart.
Spiderweb charts are commonly used to compare multivariate data sets,
like this demo using six variables of comparison.
</p>
</div>
CSS/SCSS
Copy and paste below CSS in Widget’s CSS/SCSS Section
/* to be completed */
Client Side Scripts
Copy and Paste below Script in Widget’s Client Side Section
api.controller=function($rootScope, $scope, $window, $interval, spUtil) {
/* widget controller */
var c = this;
/** Chart source: https://www.highcharts.com/demo/polar-spider*/
var options = {
credits: {
enabled: false
},
chart: {
renderTo: 'container', // change chart_id if needed
polar: true,
type: 'line'
},
accessibility: {
description: 'A spiderweb chart compares the allocated budget against actual spending within an organization. The spider chart has six spokes. Each spoke represents one of the 6 departments within the organization: sales, marketing, development, customer support, information technology and administration. The chart is interactive, and each data point is displayed upon hovering. The chart clearly shows that 4 of the 6 departments have overspent their budget with Marketing responsible for the greatest overspend of $20,000. The allocated budget and actual spending data points for each department are as follows: Sales. Budget equals $43,000; spending equals $50,000. Marketing. Budget equals $19,000; spending equals $39,000. Development. Budget equals $60,000; spending equals $42,000. Customer support. Budget equals $35,000; spending equals $31,000. Information technology. Budget equals $17,000; spending equals $26,000. Administration. Budget equals $10,000; spending equals $14,000.'
},
title: {
text: 'Budget vs spending',
x: -80
},
pane: {
size: '80%'
},
xAxis: {
categories: ['Sales', 'Marketing', 'Development', 'Customer Support',
'Information Technology', 'Administration'],
tickmarkPlacement: 'on',
lineWidth: 0
},
yAxis: {
gridLineInterpolation: 'polygon',
lineWidth: 0,
min: 0
},
tooltip: {
shared: true,
pointFormat: '<span style="color:{series.color}">{series.name}: <b>${point.y:,.0f}</b><br/>'
},
legend: {
align: 'right',
verticalAlign: 'middle',
layout: 'vertical'
},
series: [{
name: 'Allocated Budget',
data: [43000, 19000, 60000, 35000, 17000, 10000],
pointPlacement: 'on'
}, {
name: 'Actual Spending',
data: [50000, 39000, 42000, 31000, 26000, 14000],
pointPlacement: 'on'
}],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
align: 'center',
verticalAlign: 'bottom',
layout: 'horizontal'
},
pane: {
size: '70%'
}
}
}]
}
};
/*Generate chart*/
var chart = new Highcharts.Chart(options);
/* improvements: next step would be to have a ng-selector in HTML and use record watcher to keep data up do date */
};
Step 2: Add native Highcharts library to your widget as widget dependencies
***Go to Service Portal > Widget ***
Search for your previous widget created “Custom Spider Web” (custom-spider-web) and open the record.
On the related tab Dependencies, click on Edit button.
Search for PA Widget (4fbe3df5673322002c658aaad485ef29) and add to your list.
Click on Save button to save the change.
Step 3: Create a new Page
Go to Service Portal > Page > Click New
Name: spiderweb – Test Page
ID: spiderweb
Click on Submit button.
Once submitted, Click on Open in Page Designer related link
In Page designer, Place custom-spider-web widget inside a container > row > Column at top location.
View paget from following link http://instance-name.service-now.com/sp?id=spiderweb.
Sources
Any of following links are not under my surveilance or maintenance
How many times did you write the code to find the previous value on a specific field? Long time ago I found a library called “HistoryWalker” and since then its been on my must-have snippets on my utils. This library sn_hw is not “public” available but you can see lot of scripts using it. Quite useful 🙂
getHistoryWalker: function(grObject,field) {
var answer = [];
var previousValue;
var hw = new sn_hw.HistoryWalker(grObject.getRecordClassName(), grObject.getUniqueValue());
hw.walkTo(grObject.sys_mod_count);
do {
var wr = hw.getWalkedRecordCopy();
var currentValue = wr.getValue(field);
if (currentValue != previousValue) {
previousValue = currentValue;
answer.push(wr.getValue(field) + '');
}
} while (hw.walkBackward());
return answer;
},
Error: Execute operation on script include ‘todoPageUtils’ from scope ‘GRC: Risk Management’ was denied. The application ‘GRC: Risk Management’ must declare a cross scope access privilege. Please contact the application admin to update their access requests.
How to fix this issue?
Go to “Application Restricted Caller Access” (sys_restricted_caller_access) table
Change status to “Allowed”.
* Make sure you’ve captured the entry into your update set.
I had few incidents in the past when entities get inactivated by mistake so I decided to leverage our entity management and improve UX to allow them (managers) to receive a popup message before they proceed with inactivation of an entity
Steps:
Mark “Active” as read-only at dictionary level.
Change your scope to “GRC: Profile”.
Go to Profile [sn_grc_profile] and create a UI action called “Mark as inactive” with the following conditions:
Name: Mark as inactive Action name: entity_retire Form button: true Show insert: true Show update: true Form style: destructive List style: destructive Client: true
Onclick: confirmAndRetireEntity() Condition: gs.getUser().hasRole(‘sn_grc.manager’) && current.active == true Script: function confirmAndRetireEntity() { var gwt = new GwtMessage(); var title = gwt.getMessage('When a entity is retired, all related risks and controls are retired. Are you sure you want to continue?'); var modal = new GlideModal("sn_grc_retire_popup", false, 600, 450); modal.setTitle(gwt.getMessage('Confirmation')); modal.setPreference('sysparm_title', title); modal.setPreference('sysparm_sysid', g_form.getUniqueValue()); modal.setBackdropStatic(true); modal.setPreference('focusTrap', true); modal.setPreference('action_name', 'entity_retire'); modal.render(); return false; } if (typeof window == 'undefined') updateStatus(); function updateStatus() { current.setValue('active', 'false'); current.update(); action.setRedirectURL(current); }
Result:
Note:
1. This pop up can be widely used (its generic) but it was originally created for Policies.
2. You need to create another button called “Mark as active” to perform the opposite behavior of this UI action. I gave “entity_enroll” as action name, change condition to run only on inactive records, change function name “confirmAndEnrollEntity()”, change line to “current.setValue(‘active’,’true’)” and thats it.
The article below is intended for any person customise your Workflows. Javascript knowledge is useful but not required.
As I mentioned in other articles, regardless of your task, there aren’t always enough hours in the day to get everything done. As a result, you constantly feel like you’re always behind. And that’s just not good for your productivity or your health. Instead of putting in those extra hours, you can become more effective at work by focusing on what really matters. And you can get started with that ASAP by applying this quick scalable solution to your scripts.
Here’s a few things we will cover:
Use Case
Example
Automate properties (sys_properties)System properties store configuration information that rarely or never changes. Each time you change or add a system property, the system flushes the cache to keep all nodes in the cluster in synch. This cache flush has a very high performance cost for one to 10 minutes, which can potentially cause an outage if done excessively. To prevent such outages, do not use a system property to store configuration information that changes more than once or twice a month.
I usually identify what can change in the future, like “group id”, “names”, etc.
Use Case Walkthrough
In the Navigation filter, enter sys_properties.list.The entire list of properties in the System Properties [sys_properties] table appears.
Verify that the property does not exist by searching for the property name.
Click New. Usually I use “company.workflow.default.L1″.
Complete the System Property form. Type: String Value: <sys_user_group_id>
Navigate to Workflow > Workflow Editor
Edit your workflow and change script as appropriate.
Unfortunately there is no magic formula to identify which task or script or variable should be considered as system properties but to start you should think what can change over the time.
Example #1:
Found some quite simple use case in the communities (link). A user would like to add a IF condition in the workflow to verify if the sys_property value is equal to true and then, the requester assigned will be XXX company and eventually will fire the next sc task.
answer = ifScript();
function ifScript() {
var prop = gs.getProperty('ab.provision.workflow');
var comp = current.u_requestor.company.getDisplayValue(); //I am assuming u_requestor is the field company name
if (prop == 'true' && comp == 'company name') {
return 'yes';
}
return 'no';
}
Conclusion
System properties are not limited to just Notifications or Workflows, they’re part of the NOW Platform and can include anything we have in the Platform. Try to automate your instance and try to centralize all your “customer” data in one place. Use all the tools at your disposal to make that happen.
I will try to collect a use case for each type in order to help you to identify on which cases you should apply the sys property technique.
var p_dropdown = request.getParameter('dropdownId');
// For debugging
gs.info("MyDebug -INFO- Received form value for process ->" + p_dropdown);
gs.log("MyDebug -INFO- Received form, value for process ->" + p_dropdown);
"Being a Jedi is not just about power, or lightsabers, or even skill with the Force. It is about connection. Being part of something bigger. I am stronger as part of the Jedi Order than I could ever be alone."