일정 페이지

  • 릴리스 버전: Xanadu
  • 업데이트 날짜 2024년 08월 01일
  • 읽기16분
  • 일정 페이지는 달력 또는 타임라인 표시를 사용자 지정하여 생성할 수 있는 스크립트 모음이 포함된 기록입니다.

    타임라인 일정 페이지를 만들려면 페이지/이벤트 흐름을 이해하고 클라이언트 및 서버 측 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진수 시스템 식별자로 설정하여 일정 페이지에 액세스할 수도 있습니다.

    뷰 유형 선택 각 뷰 유형에는 서로 다른 필드 조합이 표시됩니다. 다음 두 가지 옵션을 사용할 수 있습니다.
    • 달력
    • 타임라인
    설명 문자열 현재 일정 페이지에 대한 추가 정보를 제공하는 일반 설명입니다. 이 필드는 필수가 아닙니다.
    Init 함수 이름 문자열
    주:
    이 기능은 달력 유형 일정 페이지에서만 사용됩니다.
    init 함수 이름은 달력 유형 일정 페이지의 클라이언트 스크립트 함수 내에서 호출할 JavaScript 함수의 이름을 지정합니다.
    HTML 문자열
    주:
    이 기능은 달력 유형 일정 페이지에서만 사용됩니다.
    HTML 필드는 Jelly에 의해 구문 분석되고 나머지 달력 전에 표시 페이지에 삽입되는 스크립팅 가능한 섹션입니다. 서버에서 변수를 전달하고 필요한 추가 필드를 정의하는 데 사용할 수 있습니다.
    클라이언트 스크립트 문자열 클라이언트 스크립트는 일정 페이지 표시의 옵션을 구성할 수 있는 스크립팅 가능한 섹션입니다. API는 일정 페이지 뷰 유형에 따라 다르며 아래에 설명되어 있습니다.
    서버 AJAX 프로세서 문자열
    주:
    이 기능은 달력 유형 일정 페이지에서만 사용됩니다.
    서버 AJAX 프로세서는 표시할 일정 항목 및 범위 집합을 반환하는 데 사용되는 달력 유형 일정 페이지와 관련이 있습니다.

    타임라인 일정 페이지

    타임라인 일정 페이지는 패션과 같은 "타임라인"에 시간 기반 포인트 및 범위를 표시하기 위한 구성 정보가 포함된 특정 기록입니다.

    타임라인 일정 페이지는 AbstractTimelineSchedulePage에서 확장되는 스크립트 포함을 참조하여 다양한 이벤트 및 조건에 따라 타임라인에 대한 동적 수정을 수행합니다. 타임라인 생성을 위한 일정 페이지와 스크립트 포함은 모두 극도의 사용자 지정을 허용하며 해당 API(애플리케이션 프로그래밍 인터페이스)는 아래에 설명되어 있습니다.

    다음 다이어그램에서는 타임라인 일정 페이지에 액세스할 때 발생하는 일련의 이벤트를 보여줍니다. 타임라인이 로드되면 타임라인 상호 작용(예: 타임라인 범위 이동)으로 인한 이벤트와 같은 모든 후속 이벤트는 회색 이벤트 상자에 표시된 것과 동일한 논리 흐름을 따릅니다.
    그림 1. 타임라인 플로우

    일정 페이지를 사용하여 타임라인을 생성하는 애플리케이션

    • 프로젝트 관리
    • 유지관리 일정
    • 그룹 당직 교대
    • 현장 서비스 관리

    타임라인 일정 페이지 예

    다음 예제에서는 위에서 설명한 대부분의 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');

    Script Includes

    이제 일정 페이지가 생성되었으므로 등록된 이벤트에 대해 일치하는 스크립트 포함을 생성해야 합니다. 다음 속성을 사용하여 새 스크립트 포함을 만듭니다.
    • 이름: IncidentTimelineScriptInclude
    • 활성: 선택됨
    • 클라이언트 호출 가능: 선택됨
    • 스크립트:
    // 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://[사용자 인스턴스]:8080/show_schedule_page.do?sysparm_page_schedule_type=incident_timeline

      굵은 글씨체는 일정 페이지 일정 유형 필드의 값입니다.

    2. 이 페이지에는 일정 페이지와 스크립트 포함에 지정된 대로 타임라인이 표시됩니다. 이 페이지에 대한 링크는 필요에 따라 작성하여 모듈 또는 UI 작업으로 배치할 수 있습니다.
      그림 2. 타임라인 예시 인시던트 미리 보기
    3. 종결된 인시던트를 다른 위치로 이동하려고 하면 예상된 오류 메시지가 표시됩니다.
      그림 3. 타임라인 예 이동 오류
    4. 인시던트를 이동하면 다음 확인 상자가 표시됩니다.
      그림 4. 타임라인 예시 종결 확인
    5. 취소 버튼을 클릭하면 오버레이가 닫힙니다. 확인 단추를 클릭하면 실제로 기록의 incident_state 업데이트되고 다음 성공 상자가 표시됩니다.
      그림 5. 타임라인 예 종결 성공
    6. 확인을 클릭하면 이제 인시던트가 종결된 인시던트 그룹에 나열됨이 분명합니다.
      그림 6. 타임라인 예 업데이트된 인시던트
      인시던트 예시의 타임라인