Skip to content

Commit 516c790

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into improve-ci-classes-readme
2 parents a890824 + 02ea335 commit 516c790

File tree

11 files changed

+217
-14
lines changed

11 files changed

+217
-14
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
**Use-case:**
2+
The primary goal of this UI Action is load-balancing.
3+
It assigns tasks based on the fewest currently Active tasks assigned to a member in a group.
4+
5+
**Example Scenario**:
6+
An assignment group has 10 members. Instead of assigning a new task to the whole group or any random member, the user/agent clicks on
7+
"Smart Assign" to find the member with the fewest currently Active tasks in the same group and assign the task to them.
8+
9+
**UI Action Name:**
10+
Smart Assign
11+
12+
**Condition**: !current.assignment_group.nil() && current.assigned_to.nil()
13+
14+
**How it works:**
15+
1. The code queries the Group members table to find every single user associated with the currently selected assignment group.
16+
If someone removes a previous assignement group and then clicks on Smart Assign button, they are shown an error message to choose an Assignment group.
17+
2. There is a loop on the task table. This loop uses GlideAggregate to count how many active records are assigned to a specific user.
18+
3. It tracks the user that has the lowest count of tasks assigned to them and assigns the current task to them.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
var assignedToId = '';
2+
var minOpenTasks = 77777;
3+
var targetGroup = current.assignment_group;
4+
5+
if (!targetGroup) {
6+
gs.addErrorMessage('Please select an Assignment Group first.');
7+
action.setRedirectURL(current);
8+
}
9+
10+
//Finding all active members in the target group
11+
var member = new GlideRecord('sys_user_grmember');
12+
member.addQuery('group', targetGroup);
13+
member.query();
14+
15+
while (member.next()) {
16+
var userId = member.user.toString();
17+
18+
//CountIng the number of active tasks currently assigned to the member
19+
var taskCountGR = new GlideAggregate('task');
20+
taskCountGR.addQuery('assigned_to', userId);
21+
taskCountGR.addQuery('active', true);
22+
taskCountGR.addAggregate('COUNT');
23+
taskCountGR.query();
24+
25+
var openTasks = 0;
26+
if (taskCountGR.next()) {
27+
openTasks = taskCountGR.getAggregate('COUNT');
28+
}
29+
30+
//Checking if this member has fewer tasks than the current minimum
31+
if (openTasks < minOpenTasks) {
32+
minOpenTasks = openTasks;
33+
assignedToId = userId;
34+
}
35+
}
36+
37+
//Assigning the current record to the chosen user
38+
if (assignedToId) {
39+
current.assigned_to = assignedToId;
40+
current.work_notes = 'Assigned via Smart Assign to the user with the fewest active tasks (' + minOpenTasks + ' open tasks).';
41+
current.update();
42+
gs.addInfoMessage('Incident assigned to ' + current.assigned_to.getDisplayValue() + '.');
43+
} else {
44+
gs.addErrorMessage('Could not find an active member in the group to assign the task.');
45+
}
46+
47+
action.setRedirectURL(current);
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
Widget will create a button that will only be visable to users with the itil role that will take them to the same record in platform. will work with the form and standard ticket pages (or anywhere with the table and sysId in the url.
1+
**This is an enhancement to the current code**
2+
1. Added "open in SOW" Button to open the record in service operations workspace, since it is gaining popularity now.
3+
2. Enhanced the visibility condition so that the button is only visible on pages having sys_id and table in url.
4+
3. Enhanced css to improve visibility of button.
25

3-
see also [on Share](https://developer.servicenow.com/connect.do#!/share/contents/6592535_open_in_platform_widget?t=PRODUCT_DETAILS)
6+
Widget will create a button that will only be visable to users with the itil role that will take them to the same record in platform. will work with the form and standard ticket pages (or anywhere with the table and sysId in the url.
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<div>
2-
<span ng-if="::data.role==true">
3-
<a href="{{::data.url}}" target='_blank'class='btn btn-default'>{{::options.button_text}}</a>
4-
</span>
2+
<span class="btn-cntr" ng-if="::data.role==true">
3+
<a href="{{::data.platform_url}}" target='_blank'class='btn btn-default'>{{::options.open_in_platform}}</a><br> <!--Platform button configuration-->
4+
<a href="{{::data.sow_url}}" target='_blank'class='btn btn-default'>{{::options.open_in_sow}}</a> <!--SOW button configuration-->
5+
</span>
56
</div>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
This styling will align buttons on 2 ends of the div.
3+
*/
4+
.btn-cntr{
5+
display: flex;
6+
justify-content: space-between;
7+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[
2+
{
3+
"name":"open_in_platform",
4+
"type":"string",
5+
"label":"Name for Plarform Button",
6+
"default_value":"Open in Platform"
7+
},
8+
{
9+
"name":"open_in_sow",
10+
"type":"string",
11+
"label":"Name for SOW Button",
12+
"default_value":"Open in SOW"
13+
}
14+
]
Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
(function() {
2-
data.table = input.table || $sp.getParameter("table");
3-
data.sys_id = input.sys_id || $sp.getParameter("sys_id");
4-
5-
data.url = "/nav_to.do?uri="+data.table+".do?sys_id="+data.sys_id;
6-
7-
data.role = false;
8-
if (gs.hasRole("itil")){
9-
data.role = true;
10-
}
2+
/*
3+
Code will get table and sys_id parameter from url and create url for platform and sow.
4+
This widget can be used in any page having sys_id and table in url , eg: ticket page.
5+
*/
6+
data.table = input.table || $sp.getParameter("table"); // get table from url
7+
data.sys_id = input.sys_id || $sp.getParameter("sys_id"); // get sys_id from url
8+
9+
data.platform_url = "/nav_to.do?uri=" + data.table + ".do?sys_id=" + data.sys_id;
10+
data.sow_url = "now/sow/record/" + data.table + "/" + data.sys_id;
11+
12+
data.role = false;
13+
if (gs.hasRole("itil") && data.table && data.sys_id) { // only visible to users with itil role and if url has required parameters.
14+
data.role = true;
15+
}
1116
})();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
(function executeRule(current, previous /*null when async*/ ) {
2+
3+
/*
4+
Inputs
5+
1. Opened(opened_at)
6+
2. Resolved(resolved_at)
7+
8+
Checks & Validation
9+
1. It will check the Date/Time validation whether it Resolved time should be greater than Open time
10+
2. And it will not calculate the empty values
11+
12+
Outputs
13+
1. If everthing has a right value like the Opened < Resolve Date/Time then Duration will be calculated and populated in the respective field
14+
2. Negative case if Opened > Resolved the duration will not calculate and it will Abort the action to save the record with Error message.
15+
*/
16+
17+
// Getting both the date from the record
18+
var opened = GlideDateTime(current.opened_at.getDisplayValue());
19+
var resolved = GlideDateTime(current.resolved_at.getDisplayValue());
20+
21+
//If the opened and resolved times are present, calculate the duration
22+
if (opened && resolved) {
23+
var difference = GlideDateTime.subtract(opened, resolved);
24+
if (difference.getYearUTC() >= 1970)
25+
current.calendar_duration.setValue(difference);
26+
else {
27+
current.calendar_duration.setValue(null);
28+
current.resolved_at.setValue(null);
29+
current.setAbortAction(true);
30+
gs.addErrorMessage("Incident Resolve date/time must be greater than incident Opened date/time");
31+
}
32+
}
33+
34+
35+
36+
})(current, previous);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Calculate Incident Duration and Validation.
2+
3+
Script Type : Business Rule Trigger: before update Table: incident Condition: Resolved Changes or Opened Changes
4+
5+
Goal : To calculate the duration of a particular record and how much time has been spent on a particular ticket.
6+
7+
Walk through of code :
8+
So when the Resolved Changes or Opened Changes in a particular record to calculate the duration will this Business rule will pull those values
9+
And then check whether the Opened Data/Time is lesser than the Resolved Date/Time the will calculate the duration
10+
Else it will throw the Error Message and then Abort that action and won't save the record and will clear the values.
11+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
**Dynamic Catalog Task Generator**
2+
3+
This Script Include provides a flexible, maintainable way to create one or more Service Catalog Tasks (sc_task) on a Request Item (sc_req_item). Instead of relying on complex, branching logic within a single Workflow or Flow, this script determines which tasks to create based on the value selected by the user in a single variable on the catalog form.
4+
5+
6+
**Centralizes Task Logic**: Keeps all task definitions (short descriptions, assignment groups, order) in one easy-to-read script.
7+
8+
**Improves Maintainability**: You only update this single script when task requirements change, not a sprawling visual flow.
9+
10+
**Increases Flow Reusability**: The core Flow/Workflow remains simple, focused only on calling this generator.

0 commit comments

Comments
 (0)