Skip to content

Commit 56e404f

Browse files
authored
Merge branch 'main' into hacktoberfest2025-serviceportal-contribution
2 parents a08b2b5 + 05b9e6a commit 56e404f

178 files changed

Lines changed: 6486 additions & 33 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
var GetRecentRequestValues = Class.create();
2+
GetRecentRequestValues.prototype = Object.extendsObject(AbstractAjaxProcessor, {
3+
getValues: function() {
4+
var userID = this.getParameter('sysparm_user');
5+
var itemID = this.getParameter('sysparm_item');
6+
var result = { found: false, values: {} };
7+
8+
var gr = new GlideRecord('sc_req_item');
9+
gr.addQuery('requested_for', userID);
10+
gr.addQuery('cat_item', itemID);
11+
gr.orderByDesc('sys_created_on');
12+
gr.setLimit(1);
13+
gr.query();
14+
15+
if (gr.next()) {
16+
result.found = true;
17+
18+
19+
var vars = gr.variables;
20+
result.values = {
21+
'requested_for': vars.requested_for + '',
22+
'location': vars.location + '',
23+
'department': vars.department + ''
24+
};
25+
}
26+
27+
return JSON.stringify(result);
28+
}
29+
});
30+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
function onLoad() {
2+
var user = g_user.userID;
3+
var itemID = g_form.getUniqueValue();
4+
5+
var ga = new GlideAjax('GetRecentRequestValues');
6+
ga.addParam('sysparm_name', 'getValues');
7+
ga.addParam('sysparm_user', user);
8+
ga.addParam('sysparm_item', itemID);
9+
ga.getXMLAnswer(function(response) {
10+
var data = JSON.parse(response);
11+
if (data && data.found) {
12+
var confirmFill = confirm("We found a similar request. Do you want to autofill fields?");
13+
if (confirmFill) {
14+
for (var field in data.values) {
15+
if (g_form.getControl(field)) {
16+
g_form.setValue(field, data.values[field]);
17+
console.log("Set " + field + " to " + data.values[field]);
18+
} else {
19+
console.log("Field not found: " + field);
20+
}
21+
}
22+
}
23+
} else {
24+
console.log("No previous request found.");
25+
}
26+
});
27+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Recent Request Autofill for ServiceNow Catalog.it automatically offers to fill in fields based on the user's most recent similar request.
2+
Features
3+
- Detects previous requests for the same catalog item
4+
- Prompts user to reuse values from their last submission
5+
- Autofills fields like location, department, and justification
6+
7+
<img width="878" height="395" alt="image" src="https://github.com/user-attachments/assets/33ceabf5-2bbc-43e3-8792-f1f9a99699d2" />
8+
9+
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
var SentimentAnalyzer = Class.create();
2+
SentimentAnalyzer.prototype = Object.extendsObject(AbstractAjaxProcessor, {
3+
getSentiment: function() {
4+
var text = (this.getParameter('sysparm_text') || '').toLowerCase();
5+
var positive = ['thanks', 'great', 'resolved', 'appreciate'];
6+
var negative = ['issue', 'error', 'not working', 'fail', 'problem'];
7+
8+
var score = 0;
9+
positive.forEach(function(word) { if (text.includes(word)) score++; });
10+
negative.forEach(function(word) { if (text.includes(word)) score--; });
11+
12+
if (score > 0) return 'Positive';
13+
if (score < 0) return 'Negative';
14+
return 'Neutral';
15+
}
16+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading || !newValue) return;
3+
4+
var ga = new GlideAjax('SentimentAnalyzer');
5+
ga.addParam('sysparm_name', 'getSentiment');
6+
ga.addParam('sysparm_text', newValue);
7+
ga.getXMLAnswer(function(sentiment) {
8+
g_form.addInfoMessage('Sentiment: ' + sentiment);
9+
g_form.setValue('u_sentiment', sentiment);
10+
});
11+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Incident Sentiment Detector (No AI, Pure JavaScript)
2+
3+
A lightweight ServiceNow utility that detects sentiment (Positive / Negative / Neutral) of an Incident’s short description or comments using simple keyword matching — no AI APIs or external libraries required.
4+
5+
Useful for support teams to auto-tag sentiment and analyze user frustration or satisfaction trends without expensive integrations.
6+
7+
🚀 Features
8+
9+
✅ Detects sentiment directly inside ServiceNow ✅ Works without external APIs or ML models ✅ Instant classification on form update ✅ Adds detected sentiment to a custom field (u_sentiment) ✅ Simple to extend — just add more positive/negative keywords
10+
11+
🧩 Architecture Overview
12+
13+
The solution consists of two main scripts:
14+
15+
Component Type Purpose SentimentAnalyzer Script Include Processes text and returns sentiment Client Script (onChange) Client Script Calls SentimentAnalyzer via GlideAjax on short description change 🧱 Setup Instructions 1️⃣ Create Custom Field
16+
17+
Create a new field on the Incident table:
18+
19+
Name: u_sentiment
20+
21+
Type: Choice
22+
23+
Choices: Positive, Neutral, Negative
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# MRVS - Normalise and Reset Rows on Change
2+
3+
## What this solves
4+
When a controlling variable changes (for example, Environment), existing MRVS rows may no longer be valid. This client script:
5+
- Clears or normalises specific MRVS columns
6+
- Deduplicates rows
7+
- Optionally sorts rows for a cleaner UX
8+
- Works entirely client-side using MRVS JSON
9+
10+
## Where to use
11+
Catalog Item → OnChange client script on your controlling variable.
12+
13+
## How it works
14+
- Reads the MRVS value as JSON via `g_form.getValue('my_mrvs')`
15+
- Applies transforms (clear columns, unique by key, sort)
16+
- Writes back the JSON with `g_form.setValue('my_mrvs', JSON.stringify(rows))`
17+
18+
## Setup
19+
1. Replace `CONTROLLING_VARIABLE` with your variable name.
20+
2. Replace `MY_MRVS` with your MRVS variable name.
21+
3. Adjust `COLUMNS_TO_CLEAR`, `UNIQUE_KEY`, and `SORT_BY` as needed.
22+
23+
## Notes
24+
- To clear the MRVS entirely, set `rows = []` before `setValue`.
25+
- Works with Catalog Client Scripts; no server call required.
26+
27+
## References
28+
- GlideForm API (client): `getValue`, `setValue`, `clearValue`
29+
https://www.servicenow.com/docs/bundle/zurich-api-reference/page/app-store/dev_portal/API_reference/GlideForm/concept/c_GlideFormAPI.html
30+
- Working with MRVS values on the client (community examples)
31+
https://www.servicenow.com/community/developer-articles/accessing-multi-row-variable-set-value-outside-the-multi-row/ta-p/2308876
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading) return;
3+
4+
var MRVS_NAME = 'MY_MRVS'; // your MRVS variable name
5+
var COLUMNS_TO_CLEAR = ['env', 'owner']; // MRVS column names to clear
6+
var UNIQUE_KEY = 'hostname'; // MRVS column that should be unique
7+
var SORT_BY = 'hostname'; // MRVS column to sort by
8+
9+
try {
10+
var raw = g_form.getValue(MRVS_NAME);
11+
var rows = raw ? JSON.parse(raw) : [];
12+
if (!Array.isArray(rows)) rows = [];
13+
14+
// Clear specified columns
15+
rows.forEach(function(row) {
16+
COLUMNS_TO_CLEAR.forEach(function(col) { if (row.hasOwnProperty(col)) row[col] = ''; });
17+
});
18+
19+
// Deduplicate by UNIQUE_KEY
20+
if (UNIQUE_KEY) {
21+
var seen = {};
22+
rows = rows.filter(function(row) {
23+
var key = String(row[UNIQUE_KEY] || '').toLowerCase();
24+
if (!key || seen[key]) return false;
25+
seen[key] = true;
26+
return true;
27+
});
28+
}
29+
30+
// Sort (case-insensitive)
31+
if (SORT_BY) {
32+
rows.sort(function(a, b) {
33+
var A = String(a[SORT_BY] || '').toLowerCase();
34+
var B = String(b[SORT_BY] || '').toLowerCase();
35+
if (A < B) return -1;
36+
if (A > B) return 1;
37+
return 0;
38+
});
39+
}
40+
41+
g_form.setValue(MRVS_NAME, JSON.stringify(rows));
42+
} catch (e) {
43+
console.error('MRVS normalise failed', e);
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading) return;
3+
4+
var MRVS_NAME = 'MY_MRVS';
5+
var COLUMNS_TO_CLEAR = ['env', 'region'];
6+
7+
var rows = [];
8+
try { rows = JSON.parse(g_form.getValue(MRVS_NAME) || '[]'); } catch (e) {}
9+
if (!Array.isArray(rows)) rows = [];
10+
11+
rows.forEach(function(row) {
12+
COLUMNS_TO_CLEAR.forEach(function(col) { if (row.hasOwnProperty(col)) row[col] = ''; });
13+
});
14+
15+
g_form.setValue(MRVS_NAME, JSON.stringify(rows));
16+
}
17+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading) {
3+
return;
4+
}
5+
6+
var maxChars = 100;//count of charaters
7+
var currentLength = newValue.length;
8+
9+
// Clear previous messages
10+
g_form.clearMessages();
11+
12+
// Show info message
13+
g_form.addInfoMessage('Character count: ' + currentLength + ' / ' + maxChars);
14+
15+
if (currentLength > maxChars) {
16+
// Show error message
17+
g_form.addErrorMessage('Character limit exceeded! Please shorten your text.');
18+
g_form.showFieldMsg('short_description', 'Too many characters!', 'error');
19+
20+
// Make field mandatory to block submission
21+
g_form.setMandatory('short_description', true);
22+
} else {
23+
// Remove mandatory if valid
24+
g_form.setMandatory('short_description', false);
25+
}
26+
}

0 commit comments

Comments
 (0)