ui-generation について
ServiceNow の開発者や市民開発者向けに、自然言語の要件からクライアントスクリプト、Service Portal ウィジェット、UI Builder ページなどを生成するスキルです。既存パターンの検索と生成物の検証も手順に含みます。
主な機能
- 01要件からコンポーネントと動作を特定
- 02フォーム用クライアントスクリプトの生成
- 03Service Portal ウィジェットの作成
- 04UI Builder ページとイベント対応の構築
- 05既存コンポーネントの検索と生成物の検証
活用シーン
- 01業務要件からフォームの動作を生成
- 02Service Portal ウィジェットの試作
- 03データリソース付きワークスペースページの構築
- 04UI 操作用イベントハンドラーの作成
MCP 対応
MCP ツールで既存の UI コンポーネントを検索し、スクリプトやページ設定を作成・更新します。データバインディングに必要なテーブルスキーマの確認にも使います。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ happy-technologies-llc/ happy-platform-skills --skill ui-generationインストール後、Claude Code で/ui-generationを入力して読み込まれたか確認します。
詳細
自然言語からの UI 生成
概要
このスキルでは、自然言語による説明から ServiceNow の UI コンポーネントを生成します。
- フォームとリスト用のクライアントスクリプト(onChange、onLoad、onSubmit、onCellEdit)の作成
- UI Builder と Service Portal ウィジェット用のデータバインディング設定の構築
- ユーザー操作向けイベントハンドラーロジックの生成
- Jelly/HTML テンプレートと処理スクリプトを使用した UI Pages の作成
- AngularJS コントローラーと HTML テンプレートを使用した Service Portal ウィジェットの構築
- データリソースとイベントマッピングを使用した UI Builder エクスペリエンスページの生成
- 再利用可能なフォーム装飾とフォーマッター向けの UI マクロの作成
使用する場面: 開発者や市民開発者が、平易な言葉で記述されたビジネス要件から UI コンポーネントを作成する必要がある場合や、フォームの動作、ポータルウィジェット、ワークスペースページを迅速にプロトタイプ作成する場合に使用します。
前提条件
- ロール:
admin、personalize_form、またはsp_admin(Service Portal ウィジェット用) - プラグイン:
com.glide.ui.ui_page(UI Pages)、com.glide.service-portal(Service Portal)、com.sn_ui_builder(UI Builder) - アクセス権:
sys_script_client、sys_ui_page、sp_widget、sys_ux_page_registryテーブルへの書き込みアクセス権 - 知識: JavaScript の基礎、GlideForm API、AngularJS の基礎(Service Portal 用)、UI Builder の概念
- 関連スキル: クライアントスクリプトのパターンについては
development/client-scripts、カタログフォームの動作についてはcatalog/ui-policies
手順
ステップ 1:自然言語の説明を解析する
ユーザーのリクエストを分析し、次の項目を特定します。
- コンポーネントの種類: クライアントスクリプト、UI ページ、Service Portal ウィジェット、UI Builder ページ、UI マクロ
- 対象のテーブル/フォーム: コンポーネントを適用するテーブルまたはフォーム
- 動作: 実行する処理(フィールドの表示/非表示、データの検証、レコードの取得、UI の描画)
- トリガー: 動作を開始するイベント(フィールド変更、フォーム読み込み、ボタンクリック、ページ読み込み)
- データ依存関係: コンポーネントが読み取りまたは書き込みを必要とするデータ
ステップ 2:既存のコンポーネントを照会してパターンを確認する
MCP アプローチ:
Tool: SN-Query-Table
Parameters:
table_name: sys_script_client
query: table=incident^active=true^typeLIKEonChange
fields: sys_id,name,table,type,field_name,script,active,ui_type
limit: 10
REST アプローチ:
GET /api/now/table/sys_script_client
?sysparm_query=table=incident^active=true^typeLIKEonChange
&sysparm_fields=sys_id,name,table,type,field_name,script,active,ui_type
&sysparm_limit=10
ステップ 3:クライアントスクリプトを生成する
自然言語を GlideForm API の呼び出しに変換します。一般的なパターンは次のとおりです。
onChange -- フィールドの表示/非表示:
MCP アプローチ:
Tool: SN-Create-Record
Parameters:
table_name: sys_script_client
data:
name: "Show VPN fields when category is Network"
table: incident
type: onChange
field_name: category
ui_type: 0
active: true
script: |
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading) return;
var isNetwork = (newValue == 'network');
g_form.setVisible('u_vpn_type', isNetwork);
g_form.setVisible('u_network_segment', isNetwork);
if (isNetwork) {
g_form.setMandatory('u_vpn_type', true);
} else {
g_form.setMandatory('u_vpn_type', false);
}
}
REST アプローチ:
POST /api/now/table/sys_script_client
Body: {
"name": "Show VPN fields when category is Network",
"table": "incident",
"type": "onChange",
"field_name": "category",
"ui_type": "0",
"active": "true",
"script": "function onChange(control, oldValue, newValue, isLoading) { ... }"
}
ステップ 4:フォーム初期化用の onLoad スクリプトを生成する
MCP アプローチ:
Tool: SN-Create-Record
Parameters:
table_name: sys_script_client
data:
name: "Initialize priority banner on form load"
table: incident
type: onLoad
ui_type: 0
active: true
script: |
function onLoad() {
var priority = g_form.getValue('priority');
if (priority == '1') {
g_form.showFieldMsg('priority', 'Critical incident - follow P1 procedures', 'error');
g_form.setReadOnly('category', true);
g_form.setReadOnly('subcategory', true);
}
}
ステップ 5:onSubmit 検証スクリプトを生成する
MCP アプローチ:
Tool: SN-Create-Record
Parameters:
table_name: sys_script_client
data:
name: "Validate resolution notes before close"
table: incident
type: onSubmit
ui_type: 0
active: true
script: |
function onSubmit() {
var state = g_form.getValue('state');
if (state == '6') {
var resolution = g_form.getValue('close_notes');
if (!resolution || resolution.trim().length < 20) {
g_form.showFieldMsg('close_notes', 'Resolution notes must be at least 20 characters', 'error');
return false;
}
}
return true;
}
ステップ 6:Service Portal ウィジェットを生成する
MCP アプローチ:
Tool: SN-Create-Record
Parameters:
table_name: sp_widget
data:
name: "Team Incident Dashboard"
id: "team-incident-dashboard"
template: |
<div class="panel panel-default">
<div class="panel-heading"><h3>{{c.data.title}}</h3></div>
<div class="panel-body">
<div ng-repeat="inc in c.data.incidents track by inc.sys_id">
<div class="alert alert-{{inc.priorityClass}}">
<strong>{{inc.number}}</strong> - {{inc.short_description}}
<span class="pull-right badge">{{inc.state}}</span>
</div>
</div>
<p ng-if="c.data.incidents.length === 0">No open incidents.</p>
</div>
</div>
client_script: |
api.controller = function($scope) {
var c = this;
};
server_script: |
(function() {
data.title = "My Team's Open Incidents";
var gr = new GlideRecord('incident');
gr.addQuery('assignment_group', gs.getUser().getMyGroups());
gr.addActiveQuery();
gr.orderByDesc('priority');
gr.setLimit(20);
gr.query();
data.incidents = [];
while (gr.next()) {
data.incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue('number'),
short_description: gr.getValue('short_description'),
state: gr.getDisplayValue('state'),
priority: gr.getValue('priority'),
priorityClass: {'1':'danger','2':'warning','3':'info','4':'success'}[gr.getValue('priority')] || 'default'
});
}
})();
REST アプローチ:
POST /api/now/table/sp_widget
Body: {
"name": "Team Incident Dashboard",
"id": "team-incident-dashboard",
"template": "<div class='panel panel-default'>...</div>",
"client_script": "api.controller = function($scope) { var c = this; };",
"server_script": "(function() { ... })();"
}
ステップ 7:UI Builder エクスペリエンスページを生成する
MCP アプローチ:
Tool: SN-Create-Record
Parameters:
table_name: sys_ux_page_registry
data:
title: "Executive Incident Overview"
path: /executive-incident-overview
description: "Executive dashboard showing incident metrics and trends"
category: workspace
active: true
ページのデータリソースを設定します。
Tool: SN-Create-Record
Parameters:
table_name: sys_ux_data_broker_transform
data:
name: "Incident Metrics Data Resource"
page: "<page_sys_id>"
table: incident
query: "active=true^priority<=2"
fields: "number,short_description,priority,state,assigned_to,sys_created_on"
max_rows: 50
ステップ 8:イベントハンドラーを生成する
UI Builder のイベントからアクションへのマッピングを設定します。
MCP アプローチ:
Tool: SN-Create-Record
Parameters:
table_name: sys_ux_event
data:
name: "Row Click Navigate to Record"
page: "<page_sys_id>"
component: "<component_sys_id>"
event_name: "click"
action_type: "navigate"
action_config: {
"route": "/record/incident/${sys_id}",
"target": "_self"
}
ステップ 9:フォーム装飾用の UI マクロを生成する
MCP アプローチ:
Tool: SN-Create-Record
Parameters:
table_name: sys_ui_macro
data:
name: "sla_countdown_banner"
description: "Displays a countdown timer for SLA breach on incident form"
xml: |
<?xml version="1.0" encoding="utf-8"?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide">
<g:evaluate var="jvar_sla_info" expression="
var sla = new GlideRecord('task_sla');
sla.addQuery('task', current.sys_id);
sla.addQuery('has_breached', false);
sla.addActiveQuery();
sla.orderBy('planned_end_time');
sla.setLimit(1);
sla.query();
sla.next() ? sla.getDisplayValue('planned_end_time') : 'N/A';
"/>
<div style="background:#fff3cd;padding:10px;border-radius:4px;margin-bottom:10px;">
<strong>SLA Target:</strong> ${jvar_sla_info}
</div>
</j:jelly>
ステップ 10:生成したコンポーネントを検証してテストする
MCP アプローチ:
Tool: SN-Query-Table
Parameters:
table_name: sys_script_client
query: sys_id=<created_sys_id>
fields: sys_id,name,table,type,active,sys_updated_on
limit: 1
最近の更新レコードについて sys_update_xml テーブルを確認し、スクリプト構文エラーがないことを検証します。
Tool: SN-Query-Table
Parameters:
table_name: sys_update_xml
query: name=sys_script_client_<sys_id>^ORDERBYDESCsys_created_on
fields: sys_id,name,action,sys_created_on
limit: 1
ツールの使用
| ツール | 目的 | 使用する場面 |
|---|---|---|
| SN-Query-Table | パターンを確認するために既存の UI コンポーネントを検索する | パターンの発見、検証 |
| SN-Create-Record | クライアントスクリプト、ウィジェット、UI ページを作成する | 新しい UI コンポーネントの構築 |
| SN-Update-Record | スクリプト、テンプレート、設定を変更する | 生成したコンポーネントの反復的な改善 |
| SN-Get-Table-Schema | データバインディング用のフィールド名を確認する | フォームフィールドとデータモデルの把握 |
ベストプラクティス
ui_typeは常に正しく設定してください -- デスクトップには0、モバイル/サービスポータルには1、両方には2を使用します- クライアントスクリプトでは、直接 DOM を操作するのではなく、
g_formAPI メソッドを使用してください - クライアントスクリプトでのサーバー呼び出しは最小限にしてください -- 非同期のサーバー検索には GlideAjax を使用します
- クライアントスクリプトのスコープを適切に設定してください -- IIFE を使用してグローバルスコープの汚染を避けます
- 複数のブラウザーでテストしてください -- 特定のブラウザーに依存する JavaScript 機能は避けます
- 空のフィールド値に対応するため、生成するすべての onChange ハンドラーに null チェックを含めてください
- フォームの読み込み中に実行されないよう、onChange スクリプトで
isLoadingガードを使用してください - 二重送信を防ぐため、サーバー呼び出し中は ウィジェットを読み取り専用にしてください
- アクセシビリティ基準に従ってください -- カスタムウィジェットには ARIA ラベルとキーボード操作を含めます
- バージョン管理 -- 作成前に、UI コンポーネントを必ず更新セットに関連付けてください
トラブルシューティング
| 問題 | 原因 | 解決方法 |
|---|---|---|
| クライアントスクリプトが実行されない | type または field_name の値が正しくない | type がイベントと一致し、field_name がカラム名と一致していることを確認します |
| g_form が未定義というエラー | フォームのコンテキスト外でスクリプトが実行されている | スクリプトが正しいテーブルと ui_type に紐付いていることを確認します |
| ウィジェットのデータが読み込まれない | サーバースクリプトの GlideRecord クエリエラー | サーバースクリプトのテーブル権限とクエリ構文を確認します |
| UI ページが空白になる | XML の Jelly 構文エラー | XML 構造を検証し、エスケープされていない文字がないか確認します |
| イベントハンドラーが応答しない | コンポーネント ID の不一致 | イベント設定のコンポーネント sys_id を確認します |
| フォームフィールドが非表示にならない | フィールド名とラベルの不一致 | ラベルではなくカラム名(例:u_vpn_type)を使用します |
例
例 1:自然言語からクライアントスクリプトを生成
入力:「インシデントフォームでカテゴリとして『Hardware』が選択されたとき、モデルとシリアル番号のフィールドを必須にし、入力を促すメッセージを表示してください。」
生成結果: incident.category の onChange クライアントスクリプト。newValue == 'hardware' の場合に、u_model と u_serial_number に対して g_form.setMandatory() と g_form.showFieldMsg() を呼び出します。
例 2:自然言語から Service Portal ウィジェットを生成
入力:「ログイン中のユーザーの未完了リクエストを、完了率を示すステータスバー付きで表示するウィジェットを作成してください。」
生成結果: 現在のユーザーを対象に sc_req_item を検索するサーバースクリプト、Bootstrap のプログレスバーで描画するクライアント側の AngularJS、クリックして移動する機能を備えた Service Portal ウィジェットです。
例 3:自然言語から UI Builder ページを生成
入力:「優先度別のインシデントを示すグラフと、その下にチームの未完了インシデント一覧を表示するワークスペースページを作成してください。」
生成結果: 2 つのデータリソース(グラフ用の集計とテーブル用の一覧)を含む UI Builder ページの登録、優先度の集計に紐付けられた棒グラフコンポーネント、行クリックで移動できるデータテーブルコンポーネントです。
関連スキル
development/client-scripts- クライアントスクリプト開発パターンの詳細development/ui-actions- UI アクションのボタンとリンクcatalog/ui-policies- カタログ固有の UI ポリシーdevelopment/scripted-rest-apis- ウィジェットデータ用のバックエンド APIgenai/flow-generation- UI によってトリガーされるプロセス向けの Flow Designer 自動化