mcpField
U
ui-actions-policies

ui-actions-policies

github.com/serac-labs开发7758 次安装9 周前更新
代码仓库

关于 ui-actions-policies

用于管理 ServiceNow UI Actions 和 UI Policies 的技能,介绍表单与列表操作、动态字段行为及脚本配置,并建议先分析现有表单。

主要功能

  1. 01配置表单与列表 UI Actions
  2. 02通过 UI Policies 控制字段
  3. 03按条件动态显示字段
  4. 04使用 ES5 脚本创建元素
  5. 05分析表单现有配置

适用场景

  1. 01添加事件处理按钮或列表操作
  2. 02按记录条件调整字段行为
  3. 03排查表单策略与脚本冲突

MCP 相关

文档介绍了使用 snow_create_ui_action 和 snow_create_ui_policy 创建元素,并通过 snow_artifact_manage 查找或更新现有 UI 元素;修改表单前可调用 snow_analyze_form 分析配置。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/serac-labs/serac --skill ui-actions-policies

安装后在 Claude Code 中输入/ui-actions-policies确认已加载。

详细介绍

ServiceNow 的 UI 操作与 UI 策略

UI 操作可添加按钮、链接和上下文菜单。UI 策略可动态控制表单字段行为。

修改现有表单前,先使用 snow_analyze_form——它会通过一次调用,返回目标表上所有启用的 UI 策略、客户端脚本、数据策略、记录级与字段级 ACL,以及 UI 操作。先用它回答“这个表单为什么会这样运行?”,再进行推测。

UI 操作

UI 操作类型
类型位置示例
表单按钮表单页眉“解决事件”
表单上下文菜单右键菜单“复制记录”
表单链接相关链接“查看 CI”
列表按钮列表页眉“导出所选项”
列表上下文菜单右键单击行“分配给我”
列表选项操作下拉菜单“更新状态”
列表链接列表页眉链接“新建记录”
表单按钮 UI 操作(ES5)
// 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)
})()
客户端 UI 操作(ES5)
// 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
}
列表 UI 操作(ES5)
// 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)")
})()
使用 GlideAjax 的 UI 操作(ES5)
// 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
}

UI 策略

UI 策略结构
字段用途
简短描述策略名称
表目标表
条件何时应用
条件为假时反转条件为假时撤销
加载时表单加载时运行
UI 策略操作字段行为
基本 UI 策略(无脚本)
# 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 策略(ES5)
// 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 策略脚本(ES5)
// 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)
    }
  })
}
动态字段可见性(ES5)
// 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
  }
}

通过脚本创建(ES5)

以编程方式创建 UI 操作
// 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()
以编程方式创建 UI 策略
// 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()

MCP 工具集成

可用工具
工具用途
snow_create_ui_action创建 UI 操作
snow_create_ui_policy创建 UI 策略
snow_artifact_manage (action=find)查找现有 UI 元素
snow_artifact_manage (action=update)修改 UI 元素
工作流示例
// 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 }],
})

最佳实践

  1. 使用描述性名称 - 在名称中清楚说明用途
  2. 优先设置条件 - 使用条件,而非脚本
  3. 脚本精简 - 保持脚本简短
  4. 条件为假时反转 - 清理字段状态
  5. 充分测试 - 测试多种场景
  6. 角色安全性 - 添加角色条件
  7. 仅使用 ES5 - 不使用现代 JavaScript 语法
  8. 区分表单与列表 - 选择合适的操作类型

评论

支持 Markdown