reporting-dashboards
Build ServiceNow reports (list/bar/pie/line/pivot/single-score) on sys_report, sys_dashboard layouts with widget placement, scheduled report delivery, and drill-down configuration.
ui-actions-policies
Build ServiceNow UI Actions (form/list buttons, context menus) and UI Policies (conditional mandatory/visible/read-only) with server/client scripts and GlideAjax. Use snow_analyze_form before modifying forms.
Full skill instructions
UI Actions add buttons, links, and context menus. UI Policies control form field behavior dynamically.
Before modifying an existing form, reach for snow_analyze_form — it returns every active UI policy, client script, data policy, record + field ACL, and UI action on the target table in one call. Use it to answer "why is this form behaving like this?" before guessing.
| Type | Location | Example |
|---|---|---|
| Form Button | Form header | "Resolve Incident" |
| Form Context Menu | Right-click menu | "Copy Record" |
| Form Link | Related links | "View CI" |
| List Button | List header | "Export Selected" |
| List Context Menu | Right-click on row | "Assign to Me" |
| List Choice | Actions dropdown | "Update State" |
| List Link | List header links | "New Record" |
// Table: sys_ui_action
// Name: Resolve Incident
// Table: incident
// Form button: true
// Active: true
// Condition: current.active == true && current.state != 6
// Script (Server-side - ES5 ONLY):
;(function executeAction() {
// Validate before resolving
if (!current.resolution_code) {
gs.addErrorMessage("Please select a resolution code")
action.setRedirectURL(current)
return
}
if (!current.close_notes) {
gs.addErrorMessage("Please provide resolution notes")
action.setRedirectURL(current)
return
}
// Set resolved state
current.state = 6 // Resolved
current.resolved_at = new GlideDateTime()
current.resolved_by = gs.getUserID()
current.update()
gs.addInfoMessage("Incident " + current.number + " has been resolved")
action.setRedirectURL(current)
})()
// Table: sys_ui_action
// Name: Quick Assign
// Client: true
// Onclick: quickAssign()
// Client script (ES5 ONLY):
function quickAssign() {
// Get current user
var userId = g_user.userID
var userName = g_user.getFullName()
// Confirm action
var confirmed = confirm("Assign this incident to yourself (" + userName + ")?")
if (!confirmed) {
return false
}
// Set the field value
g_form.setValue("assigned_to", userId)
g_form.setValue("assignment_group", g_user.getGroupID())
// Save the form
gsftSubmit(null, g_form.getFormElement(), "save")
return false
}
// Table: sys_ui_action
// Name: Close Selected Incidents
// Table: incident
// List button: true
// List choice: true
// Condition: gs.hasRole('itil')
// Script (Server-side - ES5 ONLY):
;(function executeAction() {
// Get selected records
var selectedRecords = RP.getParameterValue("sysparm_checked_items")
if (!selectedRecords) {
gs.addErrorMessage("No records selected")
return
}
var sysIds = selectedRecords.split(",")
var closedCount = 0
for (var i = 0; i < sysIds.length; i++) {
var gr = new GlideRecord("incident")
if (gr.get(sysIds[i])) {
if (gr.state != 7) {
// Not already closed
gr.state = 7 // Closed
gr.closed_at = new GlideDateTime()
gr.closed_by = gs.getUserID()
gr.update()
closedCount++
}
}
}
gs.addInfoMessage("Closed " + closedCount + " incident(s)")
})()
// Client-side UI Action calling server
// Client: true
// Onclick: checkAndEscalate()
function checkAndEscalate() {
var incidentId = g_form.getUniqueValue()
// Check if escalation is allowed
var ga = new GlideAjax("IncidentAjax")
ga.addParam("sysparm_name", "canEscalate")
ga.addParam("sysparm_incident_id", incidentId)
ga.getXMLAnswer(function (answer) {
var result = JSON.parse(answer)
if (result.canEscalate) {
// Proceed with escalation
g_form.setValue("priority", 1)
g_form.setValue("escalation", 1)
gsftSubmit(null, g_form.getFormElement(), "escalate_incident")
} else {
alert("Cannot escalate: " + result.reason)
}
})
return false
}
| Field | Purpose |
|---|---|
| Short description | Policy name |
| Table | Target table |
| Conditions | When to apply |
| Reverse if false | Undo when condition false |
| On load | Run when form loads |
| UI Policy Actions | Field behaviors |
# UI Policy: Make Resolution Required on Resolve
Table: incident
Short description: Require resolution fields when resolving
Conditions: state = 6 (Resolved)
On load: true
Reverse if false: true
# UI Policy Actions:
- Field: resolution_code
Mandatory: true
Visible: true
- Field: close_notes
Mandatory: true
Visible: true
- Field: resolved_by
Read only: true
// UI Policy Script - Execute if true
// Runs when condition becomes true (ES5 ONLY!)
function onCondition() {
// Show/hide fields based on category
var category = g_form.getValue("category")
if (category === "hardware") {
g_form.setDisplay("cmdb_ci", true)
g_form.setMandatory("cmdb_ci", true)
g_form.setDisplay("software", false)
} else if (category === "software") {
g_form.setDisplay("software", true)
g_form.setMandatory("software", true)
g_form.setDisplay("cmdb_ci", false)
}
}
// UI Policy: VIP Caller Handling
// Condition: None (script handles logic)
// On load: true
// Run scripts: true
// Script - Execute if true (ES5 ONLY!):
function onCondition() {
var callerId = g_form.getValue("caller_id")
if (!callerId) {
return
}
// Check if VIP via GlideAjax
var ga = new GlideAjax("UserAjax")
ga.addParam("sysparm_name", "isVIP")
ga.addParam("sysparm_user_id", callerId)
ga.getXMLAnswer(function (answer) {
var isVIP = answer === "true"
if (isVIP) {
// Highlight form
g_form.flash("caller_id", "#FFD700", 0)
g_form.showFieldMsg("caller_id", "VIP Customer", "info")
// Set default priority
if (!g_form.getValue("priority")) {
g_form.setValue("priority", 2)
}
// Make assignment group mandatory
g_form.setMandatory("assignment_group", true)
}
})
}
// UI Policy: Show fields based on incident type
// Table: incident
// On load: true
function onCondition() {
var incidentType = g_form.getValue("u_incident_type")
// Reset all conditional fields
var conditionalFields = ["u_network_details", "u_hardware_model", "u_software_name"]
for (var i = 0; i < conditionalFields.length; i++) {
g_form.setDisplay(conditionalFields[i], false)
g_form.setMandatory(conditionalFields[i], false)
}
// Show relevant fields
switch (incidentType) {
case "network":
g_form.setDisplay("u_network_details", true)
g_form.setMandatory("u_network_details", true)
break
case "hardware":
g_form.setDisplay("u_hardware_model", true)
g_form.setMandatory("u_hardware_model", true)
break
case "software":
g_form.setDisplay("u_software_name", true)
g_form.setMandatory("u_software_name", true)
break
}
}
// Create UI Action via background script (ES5 ONLY!)
var uiAction = new GlideRecord("sys_ui_action")
uiAction.initialize()
uiAction.setValue("name", "Escalate to Manager")
uiAction.setValue("table", "incident")
uiAction.setValue("active", true)
uiAction.setValue("form_button", true)
uiAction.setValue("form_style", "btn-warning")
uiAction.setValue("hint", "Escalate this incident to the caller's manager")
uiAction.setValue("condition", "current.active == true && current.priority > 2")
uiAction.setValue(
"script",
"(function executeAction() {\n" +
" current.priority = 2;\n" +
" current.escalation = 1;\n" +
' current.work_notes = "Escalated by " + gs.getUserDisplayName();\n' +
" current.update();\n" +
' gs.addInfoMessage("Incident escalated");\n' +
" action.setRedirectURL(current);\n" +
"})();",
)
uiAction.insert()
// Create UI Policy (ES5 ONLY!)
var policy = new GlideRecord("sys_ui_policy")
policy.initialize()
policy.setValue("short_description", "Require Close Notes on Close")
policy.setValue("table", "incident")
policy.setValue("active", true)
policy.setValue("on_load", true)
policy.setValue("reverse_if_false", true)
policy.setValue("conditions", "state=7")
var policySysId = policy.insert()
// Add UI Policy Action
var action = new GlideRecord("sys_ui_policy_action")
action.initialize()
action.setValue("ui_policy", policySysId)
action.setValue("field", "close_notes")
action.setValue("mandatory", true)
action.setValue("visible", true)
action.setValue("disabled", false)
action.insert()
| Tool | Purpose |
|---|---|
snow_create_ui_action | Create UI Action |
snow_create_ui_policy | Create UI Policy |
snow_artifact_manage (action=find) | Find existing UI elements |
snow_artifact_manage (action=update) | Modify UI elements |
// 1. Create UI Action
await snow_create_ui_action({
name: "Approve Change",
table: "change_request",
form_button: true,
condition: 'current.state == "assess"',
script: "/* approval script */",
})
// 2. Create UI Policy
await snow_create_ui_policy({
short_description: "Require justification for high priority",
table: "change_request",
conditions: "priority=1",
actions: [{ field: "justification", mandatory: true }],
})
Build ServiceNow reports (list/bar/pie/line/pivot/single-score) on sys_report, sys_dashboard layouts with widget placement, scheduled report delivery, and drill-down configuration.
Make outbound REST calls from ServiceNow with sn_ws.RESTMessageV2 — basic/bearer/OAuth/API-key auth, error handling by status code, response parsing, sys_rest_message records, and retry with exponential backoff.
Use tool_search to discover and enable lazy-loaded Serac MCP tools (snow_*, jira_*, github_*, etc). Explains naming conventions, search strategies, and always-available activity tools.
Build ServiceNow Automated Test Framework tests and suites — impersonation, form steps, assertions, server-side script steps, test parameters, and execution via snow_create_atf_test / snow_execute_atf_test.
Move data in and out of ServiceNow — CSV parsing into import sets, GlideImportSetTransformer runs, CSV/JSON/XML exports, scheduled data sources, bulk update and deleteMultiple safety patterns.
Configure ServiceNow Discovery — schedules, IP ranges, credential affinities, MID Server assignment, custom probes/sensors, identification rules, and run-status monitoring on discovery_* tables.
Build ServiceNow Customer Service Management — customer_account, customer_contact, sn_customerservice_case routing, service entitlements with usage decrement, and Customer Portal case submission widgets.
Manage ServiceNow dictionary (sys_dictionary), table/field creation, choice lists, dictionary overrides, and sys_data_policy2 rules that enforce mandatory/read-only/visible field behavior on the data layer.
Configure ServiceNow Mobile (Now Mobile/Agent) — sys_sg_mobile_app screens, card builders, push notifications, offline sync rules, mobile actions for barcode/GPS, and offline-queue change processing.
Create ServiceNow sysevent_email_action notifications — templates with substitution variables, mail scripts for dynamic content/recipients/attachments, custom events, weights, and digest configuration.
Enforce ES5-only syntax for ServiceNow server-side scripts (Rhino engine) — convert const/let, arrow functions, template literals, destructuring, for-of, and async/await to ES5 equivalents.
Create and transition ServiceNow change requests (normal/standard/emergency), change tasks, affected CIs, approval routing, CAB scheduling, and conflict detection across maintenance windows.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience