目次
1. はじめに
2. Checklists(チェックリスト)とは何か
2.1. 基本情報
2.2. フォーム上への配置方法
2.3. GUIによる基本操作(OOTB)
3. 関連テーブルの仕組みを完全に理解して使いこなす
3.1. 関連テーブル
3.1.1. Checklists (技術名: checklist)
3.1.2. Cheklist Items (技術名: checklist_item)
3.1.3 Checklist Templates (技術名: checklist_template)
3.2. ChecklistsテーブルのNameフィールドが空という問題
3.3.【活用例】レコードの更新をトリガーに、テンプレートを活用してチェックリストの項目を自動作成する
3.4.【応用例①】テーブル名やテンプレート名などを引数にしたScript Includeを作成する
3.5.【応用例②】チェックリストを非表示にする
3.5.1. なぜ表示・非表示の切り替えが必要か
3.5.2. 設定方法
4. さいごに
余談
1. はじめに
ServiceNowのAdvent Calenderがあるということを知り、いくつか記事を読んでいると私もServiceNowに関わる端くれとして記事を書いてみたいという欲がふつふつと湧いてきました。
ServiceNowのカレンダー | Advent Calendar 2023 - Qiita
湧いてきたら書くしかないということで、出来上がったのがこの記事です。
Checklists(チェックリスト)の標準機能(OOTB)や各関連テーブルの詳細、Business Ruleを使ってテンプレートを使いこなす方法などについて説明しています。
少しでもどこかで役立つ記事になることができていれば幸いです。
2. Checklists(チェックリスト)とは何か
まずは、ServiceNowの公式ドキュメントの情報をもとに、基本情報・フォーム上への配置方法・GUIの基本操作を説明します。
(後半で説明する関連テーブルの仕組みについては、私が調べてみた範囲では公式ドキュメントの情報を見つけることができなかったです。なので、それなりに有益な情報であるはずなので最後までお付き合いください🙏)
2.1. 基本情報
Checklists(チェックリスト)とは、レコードのフォーム上に配置してタスク管理を行うことができるフォーマッターです。
Taskから拡張されたテーブルに設定が可能なので、IncidentやChange Request(他にも多数)のフォーム上に追加することができます。
ちなみに、pluginを有効化する方法がドキュメントにありますが、最近のインスタンスではデフォルトで有効のようです。UtahバージョンのPDIでは実際にデフォルトで有効でした。
以下が公式ドキュメントに載っていたサンプルのチェックリストです。
私はこの機能を最近まで知らなかったのですが、フォーム上でToDo管理ができるので便利そうですよね。OOTBのテーブルはもちろん、Taskテーブルから拡張して作成したカスタムテーブル上でも、様々なユースケースが想定できるのではないかと思います。
2.2. フォーム上への配置方法
実際にフォーム上に配置する手順は以下です。
- Form Design(フォームデザイナー)もしくはForm Layout(フォームレイアウト)をクリック(以下Form Layoutを使用)
- Checklistを探してフォーム上に配置(PDIのIncidentレコードです)
- 表示成功
2.3. GUIによる基本操作(OOTB)
次にOOTBの機能が提供するGUIでの基本操作を整理してみていきたいと思います。
-
「Create New(新規作成)」からChecklistを作成
>「Create New(新規作成)」を押すと、項目を追加できるようになります
-
「Add Item (項目を追加)」からChecklistのアイテムを追加
>テキストを入力して左橋の+ボタンを押すか、Enterキーで追加できます
> 後述しますが、このとき裏側の仕組みとしては、Checklist (技術名: checklist) テーブルとCheklist Items (技術名: checklist_item)テーブルにレコードが作成されます
-
各項目をドラッグ&ドロップで移動
>各項目をホバーすると左端に が出てくるので、そこをつかんで引っ張ると順序をGUIで簡単に変えられます
>後述しますが、このとき裏側の仕組みとしては、Cheklist Items (技術名: checklist_item)テーブルの各レコードの「Order (技術名: order)」フィールドの値が変わっています
-
各項目の完了
>左端のチェックボックスをクリックすると、チェックマークが付いて項目名に取り消し線が引かれます
>後述しますが、このとき裏側の仕組みとしては、Cheklist Items (技術名: checklist_item)テーブルの対象レコードの「Completed (技術名: completed)」、「Complete (技術名: complete)」、「Completed by (技術名: completed by)」フィールドの値が変わっています
-
各項目の削除
>右端の-ボタンを押すと、項目が削除されます
>後述しますが、このとき裏側の仕組みとしては、Cheklist Items(技術名:checklist_item)テーブルのレコードが削除されます
-
「Remove Cheklist(チェックリストの削除)」から全項目の一括削除
>後述しますが、このとき裏側の仕組みとしては、1.で作られたChecklists (技術名: checklist) テーブルのレコードとそれに紐づくCheklist Items (技術名: checklist_item)テーブルのレコードが削除されます
-
「Save as Template(テンプレートとして保存)」からテンプレートを保存
>テンプレート化したい項目を追加後、「Save as Template(テンプレートとして保存)」を押すとポップアップが表示され、テンプレート名とテンプレートを使用できるグループを指定できます
>グループを指定しなかった場合は、作成者のみがテンプレートを使用できます( 後述しますが、グループに限らずテンプレートを活用するためのBusiness Ruleを作成するのが、この記事の主眼です)
>後述しますが、このとき裏側の仕組みとしては、Cheklist Templates(技術名:checklist_template)テーブルのレコードが作成されます
-
テンプレートを活用して項目を追加
>「Create from template…(テンプレートから作成…)」の下に作成したテンプレートの一覧が表示されるので、活用したいテンプレート名をクリックすると、テンプレートとして保存した項目が作成されます
-
テンプレートの削除
>こちらもテーブルの詳細は後述しますが、Checklist Template (技術名: checklist_template)テーブルにアクセスして該当のレコードを開き、「Delete(削除)」ボタンを押すことで、テンプレートを削除できます
3. 関連テーブルの仕組みを完全に理解して使いこなす
ここから、ドキュメントにも記載がなかった各関連テーブル間の仕組みの説明になります。
この章では、各テーブルの仕組みを完全に理解し、最後にはテンプレートを活用してチェックリストの項目を自由自在にセットするスクリプトを使いこなすことを目指します。
その他、フォーマッターであるチェックリストの表示・非表示を切り替えるClient Scriptについても説明します。
3.1. 関連テーブル
関連テーブルは以下の3つになります。
- Checklists (技術名: checklist)
- Cheklist Items (技術名: checklist_item)
- Checklist Templates (技術名: checklist_template)
3つのテーブルの関係の概要を示した図は以下です。
ChecklistsとChekclist Itemsの関係については、直接レコードのフォームを見た方が理解が進むと思います。以下がChecklistsテーブルのレコードです(関連リストにChecklist Itemsを追加しました)。
それでは次に、各テーブルのそれぞれのフィールドの説明をします。
3.1.1. Checklists (技術名: checklist)
以下の表が、Checklistsの各フィールドの説明です。
フィールド名 | タイプ | 説明 |
---|---|---|
Name(名前) | String(文字列) | 各レコードの名前が入るフィールドです。ただOOTBの挙動だと、ここの値が空欄でレコードが作成されます。 この仕様について後述します( ChecklistsテーブルのNameフィールドが空という問題 )。 |
Owner(所有者) | Reference (参照) | チェックリストの作成者が参照値として入ります。Userテーブル(sys_user)を参照しています。 |
Document(ドキュメント) | Document ID(ドキュメントID) | チェックリストを作成したレコードが参照値として入ります。Tableフィールドで指定されたテーブルを参照します。ドキュメントIDの詳細はこちらの記事を参照。 |
Table(テーブル) | Table Name(テーブル名) | チェックリストを作成したレコードのテーブル名が文字列で入ります。Table Nameは各テーブルを選択できる文字列フィールドです。 |
記事の執筆にあたって改めて公式ドキュメントを読んでいると、各フィールドタイプを網羅的に説明しているページを見つけました。いろんな場面で役立ちそうなので載せておきます。
上記のフィールドタイプの詳細を知りたい方や、ServiceNowで用意されているフィールドタイプの全体像を把握したい方は是非ご一読ください。
OOTBのデータ型を用いて少しだけややこしい作りになっていますが、チェックリストを作成した各レコードへの参照値をもっているというざっくりとした(そして当たり前な)理解で十分だと思います。
ChecklistsテーブルのNameフィールドが空という問題だけ、後半のBusiness Ruleのスクリプトでも工夫するので、後に説明を加えます。
3.1.2. Cheklist Items (技術名: checklist_item)
以下の表が、Checklist Itemsの各フィールドの説明です。
フィールド名 | タイプ | 説明 |
---|---|---|
Checklist(チェックリスト) | Reference | Checklistsのレコードへの参照値が入っています。ChecklistsテーブルのNameフィールドが空という問題のせいで、レコードを開くと、この値が空のように見える(見えるだけです)ことについて後述します。 |
Name(名前) | String | 各レコードの名前が入ります。GUIでチェックリストに追加した項目の文字列がそのまま挿入されます。 |
Complete(完了) | True/False | 各項目が完了したか否かを真偽値で管理します。GUIでチェックボックスを押して完了にすると、このフィールドがTrueになります。 |
Completed(完了日時) | Date/Time(日付/時刻) | 項目を完了にした日付が入ります。GUIでチェックボックスにチェックを入れるとその時の日付が自動で入ります。 |
Completed by(完了者) | Reference | 項目を完了にしたユーザへの参照値が入ります。Userテーブル(sys_user)を参照しています。Userテーブルこのフィールドもチェックボックスにチェックを入れた段階で自動的に値が入ります。 |
Order(順序) | Integer(整数) | 項目の表示順序の数字が入ります。GUIで項目を入れ替えると、それに連動して自動で値が更新されます。 |
Complete、Completed、Completed by、そしてOrderの4つのフィールドに関しては、 GUIによる基本操作(OOTB) を見返すと、すぐに理解できると思います。
ちなみに、GUIで項目のチェックボックスにチェックを加えたあと、もう一度チェックを外すと、CompleteフィールドのみがFalseに戻って、Completed、Completed byの値は特に変更されません。その後、もう一度チェックを付けて完了にすると、3つのフィールド(Complete、Completed、Completed by)が再度適切な値に更新されます。
また、Checklistフィールドに関しては、ChecklistsテーブルのNameフィールドが空という問題に関わるので、後に説明を加えます。
3.1.3. Checklist Templates (技術名: checklist_template)
以下の表が、Checklist Templatesの各フィールドの説明です。
フィールド名 | タイプ | 説明 |
---|---|---|
Name(名前) | String | テンプレートの名前が入ります。 GUIでテンプレートを作成した際の名前が、そのまま挿入されます。 |
User(ユーザー) | Reference | テンプレートを作成したユーザーへの参照値が入ります。Userテーブル(sys_user)を参照しています。 |
Group(グループ) | Reference | テンプレート作成時に指定したグループへの参照値が入ります。Groupテーブル(sys_user_group)を参照しています。 |
Template(テンプレート) | String | チェックリストに作成した項目の情報がJSON形式での文字列で入ります。 |
こちらも GUIによる基本操作(OOTB) のテンプレート作成部分を見返すと、すぐに理解できると思います。
テンプレート化した項目は、テンプレートの作成者と特定のグループしか使用することができない、というのがOOTBの仕様ですが、Business Ruleを作成すれば全ユーザ向けにテンプレートを活用できます。詳細は後述しますが、その際に重要なのが、Template(テンプレート)フィールドです。
Templateフィールドには、チェックリストに作成した項目の情報がJSON形式の文字列で保存されています。以下が実際に格納されている値です。
{
"owner":"217ab88a97e1f1102977f5671153af99",
"name":"",
"items":[
{"name":"TEST1","order":0},
{"name":"TEST2","order":1},
{"name":"TEST3","order":2},
{"name":"TEST4","order":3},
{"name":"TEST5","order":4}
]
}
上記のように、JSON形式の文字列で保存されいています。
このことを頭に入れておいてください。
3.2. ChecklistsテーブルのNameフィールドが空という問題
フォーム上にチェックリストを配置し、GUIの操作でチェックリストを作成して項目を追加した際、Checklists (技術名: checklist) テーブルにレコードが作成されます。
このときに作成されたレコードを開くと、以下のようにNameフィールドが空のまま作成されています。
ChecklistsテーブルのレコードのNamaフィールドが空であるせいで、Checklist ItemsのテーブルからChecklistsフィールドをみると、以下ように値が入っていないように見えます。
また、フォームを開いてみても、Checklistフィールドに値が入っていないように見えてしまいます。
ただ、Checklistフィールドでグルーピングすると分かるのですが、SysIDがきちんと入っているので、Checklistフィールドは空なように「見えている」だけで、きちんとChecklistsテーブルのレコードを参照しています。
システムの挙動としては、ChecklistsテーブルのNameフィールドが空であることによって不具合は生じないので、 ServiceNowの製品開発エンジニアの方々もこの仕様で妥協した(orそもそも気にしていない)のかと推察していますが、
調べてみると、この問題は既知のエラーとしてKBに掲載されていました。
修正は検討中で根本解決はしていないようです。
チェックリストを使いこなす側としてはNameが空だと少し気持ちが悪いので、この後Business Ruleを用いてテンプレートを活用する際は、Nameフィールドが空にならないように配慮しようと思います。詳しくは後述します。
ここまでで、テーブルの関係やフィールドの情報、さらにそれらに紐づく関連事項を完全に理解することができたはずです。
ここから、この記事の主な目標であるBusiness Ruleによってテンプレートの項目をセットする方法を説明していきたいと思います。
3.3.【活用例】レコードの更新をトリガーに、テンプレートを活用してチェックリストの項目を自動作成する
それでは、本題のBusiness Ruleを使って、各レコードのチェックリストにテンプレート化した項目を自動作成するためのスクリプトを見ていきたいと思います。サンプルのコードは以下です(Incidentのレコードでチェックリストを活用する想定です)。
ChecklistsテーブルのNameフィールドが空という問題に配慮し、NameフィールドにIncidentレコードのNumberフィールドの文字列をここではセットしています。
また、以下のスクリプトを理解する際、Checklist TemplatesテーブルのTemplateフィールドに入っていたJSON形式の情報も見直してみてください。
(function executeRule(current, previous /*null when async*/) {
//まずはChecklists (技術名: checklist)レコードを作成する
var theList = new GlideRecord("checklist");
theList.initialize();
theList.name = current.number; //NameフィールドにIncidentレコードのNumberをセット
theList.table = "incident"; //Tableフィールドにincidentテーブルをセット
theList.owner = gs.getUserID(); //Ownerフィールドにはログインユーザをセット
theList.document = current.sys_id; //Documentフィールドに対象のIncidentレコードのSysIDをセット
var listId = theList.insert(); //以下でChecklist ItemsのChecklistフィールドにセットするため変数に格納
//Checlist TemplatesのTemplateフィールドからテンプレ化した項目の情報を取得し、Checklist Itemsのレコードを作成する
var checklistArr = {}; //テンプレート化した項目のJSONを配列として受け取るための箱を用意
var grTemplate = new GlideRecord("checklist_template");
grTemplate.addQuery("name", "Test Template"); //活用する対象のテンプレート名で絞り込み
grTemplate.query();
if(grTemplate.next()){
checklistArr = JSON.parse(grTemplate.getValue('template')); //TemplateのJSON情報を配列へ
//テンプレート化した項目の数だけChecklist Itemsにレコードを作成する
for(var i = 0; i < checklistArr.items.length; i++){
var chki = new GlideRecord('checklist_item');
chki.initialize();
chki.setValue('checklist', listId); //Checklistフィールドに新規作成したChecklistsレコードをセット
chki.setValue('name', checklistArr.items[i]['name']); //項目名をセット
chki.setValue('order', checklistArr.items[i]['order']); //項目の順序をセット
chki.insert();
}
}
})(current, previous);
凡ミスですが、テンプレート名が異なっていてスクリプトが動かない場合があります。(私も同様のミスをしました)。動かす前に再度ご確認ください。
上記のスクリプトはこちらのコミュニティ記事を参考にしました。
先に触れたようにOOTBの挙動では、テンプレートを使用できるのは特定のグループかテンプレートの作成者なので、このBusiness Ruleを設定することによりグループに限らないテンプレートの活用が可能になります。
上記のスクリプトとともに任意の更新条件を設定した(私は「StateがOn Holdに変更されたとき」という条件を設定しました)Business Ruleを作成すれば、条件を満たすレコードの更新・作成が行われた際に、テンプレート化した項目がチェックリストに自動で作成されます。
実際にPDIでBusiness Ruleを設定後、IncidentレコードのStateをOn Holdに更新したところ、無事にテンプレート化した項目をチェックリストに自動作成することができました。
3.4.【応用例①】テーブル名やテンプレート名などを引数にしたScript Includeを作成する
上記のBusiness Ruleのスクリプトを、Script Includeで共通関数にしてみます。
テーブル名とテンプレート名とチェックリスト名、それから各Business ruleのcurrent変数を引数にとったScript Includeのサンプルコードは以下です。
var ChecklistsFunctions = Class.create();
ChecklistsFunctions.prototype = {
initialize: function() {
},
useTemplate: function(tableName, templateName, checklistName, current) {
var theList = new GlideRecord("checklist");
theList.initialize();
theList.name = checklistName;
theList.table = tableName;
theList.owner = gs.getUserID();
theList.document = current.sys_id;
var listId = theList.insert();
var checklistArr = {};
var grTemplate = new GlideRecord("checklist_template");
grTemplate.addQuery("name", templateName);
grTemplate.query();
if(grTemplate.next()){
checklistArr = JSON.parse(grTemplate.getValue('template'));
for(var i = 0; i < checklistArr.items.length; i++){
var chki = new GlideRecord('checklist_item');
chki.initialize();
chki.setValue('checklist', listId);
chki.setValue('name', checklistArr.items[i]['name']);
chki.setValue('order', checklistArr.items[i]['order']);
chki.insert();
}
}
},
type: 'ChecklistsFunctions'
};
上記のScript Includeを活用すると、最初のBusiness Ruleのサンプルコードは以下のように簡略化できます。
(function executeRule(current, previous /*null when async*/) {
var si = new ChecklistsFunctions(); //作成したScript Includeをインスタンス化
var tableName = current.getRecordClassName(); //現在のレコードのテーブル名を取得
var templateName = "Test Template"; //任意のテンプレート名を変数に格納
var checklistName = current.number; //ここではNumberフィールドの文字列を変数に格納
//作成したScript Includeのメソッド呼び出し
si.useTemplate(tableName, templateName, checklistName, current);
})(current, previous);
getRecordClassName() という現在のレコードのテーブル名を取得できるServiceNow独自のメソッドを使用することで、他のテーブルでも使えるサンプルコードにしています。(できる限り汎用化を目指しました)
上記のScript Includeを用いたBusiness Ruleを作成し、IncidentレコードのStateをOn Holdに更新したところ、無事にテンプレート化した項目をチェックリストに自動作成することができました。
3.5.【応用例②】チェックリストを非表示にする
最後に、チェックリストの表示・非表示を制御する方法について説明します。
3.5.1. なぜ表示・非表示の切り替えが必要か
上記のテンプレートを活用した項目の自動作成を行うとなると、Business Ruleの実行条件以外の場合は、チェクリスト自体を非表示しておきたいという要望が想定されます。
理由は、以下のような状況を防ぐためです。
- ユーザーがGUIでチェックリストの項目を作成する
- その後レコードの更新によってBusiness Ruleが実行され、テンプレートを活用したもう一つのチェックリストが作成される
- Business Ruleにより作成したチェックリストの項目が表示されない
>最初に作成された方のチェックリストが優先して表示されるようです
このような状況を防ぐ策として、Checklists(checklist)テーブルにレコードが作成された際に処理を中断するという方策も考えられますが、Checklists(checklist)テーブルにレコードが作成されるタイミングは、1.「Create New(新規作成)」 ではなく 2. 「Add Item (項目を追加)」 (記事内 GUIによる基本操作(OOTB) 参照)なので、挙動として少し不自然なものになると考えられます。
なので、今回はチェックリスト自体を非表示にする方法を見ていきましょう。
3.5.2. 設定方法
Checklistはフォーム上に配置されるので、他のフィールドと同じようにUI policyを用いて表示・非表示を設定できると最初は思っていたのですが、実際に設定しようとするとUI Policy Action(UIポリシーアクション)のフィールド選択の一覧に出てきません。すでに何度か記していますが、チェックリストはフィールドではなくフォーマッターなので、UI policyを適用することができないようです。
そこでClient Script(クライアントスクリプト)のonLoadを使って、表示・非表示の切り替えを実現します。
function onLoad() {
var state = g_form.getValue('state');
if(state != '3'){//StateがOn Hold以外のときに、以下の処理を実行
var checklistFormatter = document.getElementById('inlineChecklistApp'); //チェックリストが表示されているHTML要素を取得
checklistFormatter.style.display = "none"; //CSSのdisplay値を"none"に指定して非表示にする
}
}
上記のClient Scriptを作成する際、Isolate script(スクリプトを隔離)というチェックボックスを外す必要があります。
デフォルトだとチェックが入っているのですが、その状態だとDOMに直接アクセスできないので動作しません(この沼に1時間くらいはまっていました)。
参考コミュニティ記事
公式ドキュメント - Client Script(英語)
公式ドキュメント - クライアントスクリプト(日本語)
上記のスクリプトはこちらのコミュニティ記事を参考にしました。
上記のClient Scriptを作成し、StateがOn Holdではないレコードにアクセスすると、無事にチェックリストが非表示になりました。
4. さいごに
以上、Checklists(チェックリスト)を活用するうえでの開発者目線の小ネタでした。
「完全に理解して」と豪語したからには、説明できることは全てわかりやすく説明しきろうという意気込みでここまで書き切りましたが、いかがだったでしょうか。
地味な機能を取り上げたつもりでしたが、くまなく説明してみると、ServiceNowを開発するうえで必要なことの「いろは」を知ることができる内容になったのではないかと手前味噌ながら考えています。
ServiceNow初学者の方々にもこの記事が届くことを願って筆をおこうと思います。
不足情報や誤りがあれば、ご指摘よろしくお願いします🙇♂️
余談
ChatGPT(GPT-3.5)にChecklists(チェックリスト)について尋ねたところ、大嘘が返ってきました。
やはり、ChatGPTは検索用途には向いていないようなので、引き続き公式ドキュメントをきちんと読んだり個人開発環境(PDI)を触ったりしていこうと思わされました。それか、ServiceNowのドキュメントや設定情報を全て学習した言語モデルの構築を、中の人よろしくお願いいたします🙏(知らないだけで、すでにあるかもしれないですね。)