スケジュールページ

  • リリースバージョン: Xanadu
  • 更新日 2024年08月01日
  • 所要時間:17分
  • スケジュールページは、カレンダーまたはタイムライン表示のカスタム生成を可能にする、スクリプトのコレクションを含むレコードです。

    タイムラインスケジュールページを作成するには、ページ/イベントフローを理解し、クライアントおよびサーバーサイドの JavaScript を作成できる必要があります。

    スケジュールページフォーム

    スケジュールページにアクセスするには、 システムスケジューラ > スケジュール > スケジュールページ.

    フォームには、選択したビュータイプに応じて次のフィールドが表示されます。
    表 : 1. スケジュールページフォーム
    フィールド フィールドタイプ 説明
    名前 文字列 現在のスケジュールページの識別に使用する一般名。
    スケジュールタイプ 文字列 スケジュールタイプは、「sysparm_page_schedule_type」URI パラメーターを介してスケジュールページを一意に識別するために使用する文字列です。たとえば、次のようにスケジュールページにアクセスできます。

    /show_schedule_page.do?sysparm_type=gantt_chart&sysparm_timeline_task_id=d530bf907f0000015ce594fd929cf6a4

    または、「sysparm_page_sys_id」URI パラメーターをスケジュールページの 32 文字からなる 16 進数で構成される一意のシステム識別子に設定すると、スケジュールページにもアクセスできます。

    ビュータイプ 選択肢 各ビュータイプには、異なるフィールドの組み合わせが表示されます。利用可能なオプションは 2 つあります。
    • カレンダー
    • タイムライン
    説明 文字列 現在のスケジュールページに関する詳細情報を表示する一般的な説明。このフィールドは必須ではありません。
    Init 関数名 文字列
    注:
    この機能は、[カレンダー] タイプのスケジュールページでのみ使用されます。
    init 関数名は、[カレンダー] タイプのスケジュールページの [クライアントスクリプト] 関数内で呼び出す JavaScript 関数の名前を指定します。
    HTML 文字列
    注:
    この機能は、[カレンダー] タイプのスケジュールページでのみ使用されます。
    HTML フィールドは、Jelly によって解析され、カレンダーの残りの部分より前に表示ページに挿入される、スクリプト可能セクションです。これはサーバーから変数を渡すために使用し、必要かつ余分なフィールドを定義できます。
    クライアントスクリプト 文字列 クライアントスクリプトは、スケジュールページの表示オプションを設定できるスクリプト作成可能なセクションです。API はスケジュールページのビュータイプによって異なり、説明は次のとおりです。
    サーバー AJAX プロセッサー 文字列
    注:
    この機能は、[カレンダー] タイプのスケジュールページでのみ使用されます。
    サーバー AJAX プロセッサーは、カレンダータイプのスケジュールページに特有のもので、表示するスケジュールアイテムとスパンのセットを返すために使用されます。

    タイムラインスケジュールページ

    タイムラインスケジュールページは、時間ベースのポイントとスパンを「タイムライン」のような形式で表示するための構成情報を含む特定のレコードです。

    タイムラインスケジュールページは、AbstractTimelineSchedulePage から拡張されたスクリプトインクルードを参照して、さまざまなイベントや条件に基づいてタイムラインを動的に変更します。スケジュールページとタイムライン生成用のスクリプトインクルードはどちらも、高度なカスタマイズが可能です。対応するアプリケーションプログラミングインターフェイス (API) を以下に示します。

    次の図は、タイムラインのスケジュールページにアクセスしたときに発生する一連のイベントを示しています。タイムラインがロードされると、タイムラインのインタラクション (タイムラインスパンの移動など) から発生するイベントなど、後続のすべてのイベントは、灰色のイベントボックスに表示されるものと同じロジックフローに従います。
    図 : 1. タイムラインフロー

    スケジュールページを使用してタイムラインを生成するアプリケーション

    • プロジェクト管理
    • メンテナンススケジュール
    • グループオンコールローテーション
    • フィールドサービス管理 (FSM)

    タイムラインスケジュールページの例

    次の例は、上記の API の大部分を利用して、対応するスクリプトインクルードでタイムラインスケジュールページを作成する方法を示しています。

    この例では、プロジェクトサポートマネージャーのインシデントサマリータイムラインを作成して、すべての新しいインシデントをビジュアル化します。すべての新しいインシデントは、ポイントアイコンの違いでインシデントの優先度が区別される、単一のポイントとして表示されます。さらに、すべてのクローズ済みインシデントは、クローズされる前のインシデントの期間を示す別のグループとしてタイムラインに表示する必要があります。プロジェクトマネージャーは、解決済みの新しいアイテムをフォームリストを使用せずに簡単にクローズできる必要があるため、垂直移動イベントを処理して、新しいインシデントをクローズ済みインシデントグループまたはその中のアイテムにドラッグできるようにします。

    スケジュールページ

    次のプロパティで新しいスケジュールページを作成します。
    • 名前:ハードウェアインシデント
    • スケジュールタイプ:incident_timeline
    • ビュータイプ:タイムライン
    • クライアントスクリプト
    // Set our page configuration
    glideTimeline.setReadOnly(false);
    glideTimeline.showLeftPane(true);
    glideTimeline.showLeftPaneAsTree(true);
    glideTimeline.showTimelineText(true);
    glideTimeline.showDependencyLines(false);
    glideTimeline.groupByParent(true);
    glideTimeline.setDefaultPointIconClass('milestone');
     
    // We will define what items to display and provide a custom event handler for moving new items to the closed state
    glideTimeline.registerEvent('getItems', 'IncidentTimelineScriptInclude');
    glideTimeline.registerEvent('elementMoveY', 'IncidentTimelineScriptInclude');

    スクリプトインクルード

    スケジュールページが作成されたので、登録されたイベントの一致するスクリプトインクルードを生成する必要があります。次のプロパティで新しいスクリプトインクルードを作成します。
    • 名前: IncidentTimelineScriptInclude
    • アクティブ:オン
    • クライアント呼び出し可能:オン
    • Script :
    // Class Imports
     
    var IncidentTimelineScriptInclude = Class.create();
    IncidentTimelineScriptInclude.prototype = Object.extendsObject(AbstractTimelineSchedulePage, {
     
      /////////////////////// // GET_ITEMS ///////////////////////////////////////
      getItems:function() { 
        // Specify the page title 
        this.setPageTitle('My Custom Incident Summary Timeline');
     
        var groupNew = new GlideTimelineItem('new');
        groupNew.setLeftLabelText('New Incidents');
        groupNew.setImage('../images/icons/all.gifx');
        groupNew.setTextBold(true);
        this.add(groupNew);
     
        var groupClosed = new GlideTimelineItem('closed');
        groupClosed.setLeftLabelText('Closed Incidents');
        groupClosed.setImage('../images/icons/all.gifx');
        groupClosed.setTextBold(true);
        groupClosed.setIsDroppable(true);
     
        // This allows us to drag an open incident onto the closed group row. 
        this.add(groupClosed);
     
        // Get all the incidents and let's add only the new/closed ones appropriately 
        var now_GR = new GlideRecord('incident');
        gr.query(); 
        while(gr.next()) { 
           // Only loop through new/closed incidents 
           if(gr.incident_state != '1' && gr.incident_state != '7') continue;
     
           // Ok, we have a new/closed incident. Create the item and the span first. 
           var item = new GlideTimelineItem(gr.getTableName(), gr.sys_id); 
           var span = item.createTimelineSpan(gr.getTableName(), gr.sys_id);
     
           // Specific properties for a new incident 
           if(gr.incident_state == '1') { // New 
             item.setParent(groupNew.getSysId()); 
             item.setImage('../images/icons/open.gifx');
             span.setTimeSpan(gr.getElement('opened_at').getGlideObject().getNumericValue(),
                              gr.getElement('opened_at').getGlideObject().getNumericValue());
     
             // We will show different colors based upon the priorities only for new incidents 
             switch(gr.getElement('priority').toString()) {
               case '1': span.setPointIconClass('red_circle'); break; 
               case '2': span.setPointIconClass('red_square'); break; 
               case '3': span.setPointIconClass('blue_circle'); break; 
               case '4': span.setPointIconClass('blue_square'); break; 
               case '5': span.setPointIconClass('sepia_circle'); break; 
               default: // Otherwise, the default point icon class will be used (Milestone)
              }
             }
            // Specific properties for a closed incident 
            else if(gr.incident_state == '7') { 
              item.setParent(groupClosed.getSysId()); 
              item.setImage('../images/icons/closed.gifx');
              span.setTimeSpan(gr.getElement('opened_at').getGlideObject().getNumericValue(),
                               gr.getElement('closed_at').getGlideObject().getNumericValue()); }
     
            // Common item properties 
            item.setLeftLabelText(gr.short_description);
     
            // Common span properties
            span.setSpanText(gr.short_description);
            span.setTooltip('<strong>' + GlideStringUtil.escapeHTML(gr.short_description) + '</strong><br>' + gr.number);
            span.setAllowXMove(false);
            span.setAllowYMove(gr.canWrite() ? true:false);
            span.setAllowYMovePredecessor(false);
            span.setAllowXDragLeft(false);
            span.setAllowXDragRight(false);
     
            // Now we add the actual item 
            this.add(item); 
            } } ,
     
     
       //////////////////////// // ELEMENT_MOVE_Y /////////////////////////////////////////////////////////////
     
       /**
       * This is one of the AbstractTimelineSchedulePage event handler methods that corresponds to a vertical
       * move. The arguments for this function are defined in the API section of the event handler methods.
       */
      elementMoveY: function(spanId, itemId, newItemId) {
     
        // Get information about the current incident 
        var now_GR = new GlideRecord('incident');
        gr.addQuery('sys_id', spanId);
        gr.query(); 
        if(!gr.next()) 
          return this.setStatusError('Error', 'Unable to lookup the current incident.');
     
        // Only allow the new incidents to have their state adjusted. 
        if(gr.incident_state != '1') 
          return this.setStatusError('Error','Only new incidents can have their state adjusted.');
     
        // Get information about the dropped GlideTimelineItem. If it was dropped in an item on the "New Incidents" 
        // group let's do nothing. If it was dropped in the "Closed Incidents" then let's adjust the state automatically. 
        var grDropped = new GlideRecord('incident');
        grDropped.addQuery('sys_id', newItemId );
        grDropped.query(); 
        if(!grDropped.next() || grDropped.incident_state == '7') { 
           // This means the dropped item was either the 'Closed Incidents' group (which has no record or sys_id) or an 
           // existing incident that is closed. The 'New Incidents' also has no sys_id; however, the default behavior for 
           // items without a sysId is to be non-droppable. This is why we explicitly denoted the 'Closed Incidents' to  
           // be marked as "droppable".
     
           // Return a dialog prompt 
           this.setStatusPrompt('Confirm', 'Are you sure you want to close: ' + 
                  '<div style="margin:10px 0 10px 14px;padding:4px;background-color:#EBEBEB;"><strong>' +
                   GlideStringUtil.escapeHTML(gr.short_description) + 
                   '</strong><br/><div class="font_smaller">' + now_GR. number + '</div></div>', 
                   'this._elementMoveYHandler_DoClose', // This function is for when the OK button is clicked. 
                   'this._elementMoveYHandler_DoNothing', // This function is for when the Cancel button is clicked. 
                   'this._elementMoveYHandler_DoNothing'); // This function is for when the Close button is clicked.
           } } ,
     
      _elementMoveYHandler_DoClose: function(spanId, itemId, newItemId) { 
        // Notice that this function takes the same function arguments as the original function for which it  
        // is a custom event handler for.
     
        // Update the database record from 'New' to 'Closed'. 
        var now_GR = new GlideRecord('incident');
        gr.addQuery('sys_id', spanId);
        gr.query();
        gr.next();
        gr.setValue('incident_state', '7');
        gr.update();
     
        // This will re-render the timeline showing the updated item in the closed group. 
        this.setDoReRenderTimeline(true);
     
        // Let's show a success message 
        this.setStatusSuccess('Success', '<strong>' + gr.short_description + '</strong> was successfully closed.'); } ,
     
      // Since the user clicked cancel or close we simply do nothing.
      _elementMoveYHandler_DoNothing: function(spanId, itemId, newItemId) { }
     
     });

    スクリーンショット/結果

    1. 移動先:

      http://[YOURINSTANCE]:8080/show_schedule_page.do?sysparm_page_schedule_type=incident_timeline

      太字のテキストは、スケジュールページの [スケジュールタイプ] フィールドの値です。

    2. ページには、スケジュールページで指定されたタイムラインと作成されたスクリプトインクルードが表示されます。このページへのリンクを作成し、必要に応じてモジュールまたは UI アクションとして配置できます。
      図 : 2. タイムラインのインシデントのプレビューの例
    3. クローズ済みインシデントをいずれかの場所に移動しようとすると、予想されるエラーメッセージが表示されます。
      図 : 3. タイムラインの移動エラーの例
    4. インシデントの移動:次の確認ボックスに「さらにメモリが必要 (I need more memory)」と表示されます 。
      図 : 4. タイムラインのクローズ確認の例
    5. [キャンセル] ボタンをクリックすると、オーバーレイが閉じられます。[OK] ボタンをクリックすると、実際にはレコードの incident_state が更新され、次の成功ボックスが表示されます。
      図 : 5. タイムラインのクローズ成功の例
    6. [OK] をクリックすると、インシデントは [クローズ済みインシデント] グループにリストされるようになります。
      図 : 6. タイムラインのインシデント更新の例
      インシデント例のタイムライン