일정 페이지

  • 릴리스 버전: Australia
  • 업데이트 날짜 2026년 03월 12일
  • 소요 시간: 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진수 시스템 식별자의 매개변수로 설정하여 일정 페이지에 액세스할 수도 있습니다.

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

    타임라인 일정 페이지

    타임라인 일정 페이지는 시간 기반 포인트와 범위를 "타임라인"과 같은 방식으로 표시하기 위한 구성 정보를 포함하는 특정 기록입니다.

    타임라인 일정 페이지는 다양한 이벤트 및 조건에 따라 타임라인을 동적으로 수정하기 위해 AbstractTimelineSchedulePage 클래스에서 확장되는 스크립트 포함을 참조합니다. 타임라인 생성을 위한 일정 페이지와 스크립트 포함은 모두 커스터마이제이션을 지원하며 해당하는 API(애플리케이션 프로그래밍 인터페이스)를 가지고 있습니다.

    다음 단계에서는 타임라인 일정 페이지에 액세스할 때 발생하는 일련의 이벤트를 간략하게 설명합니다. 타임라인이 로드되면 타임라인 상호 작용(예: 타임라인 범위 이동)으로 인한 이벤트와 같은 모든 후속 이벤트는 getItems 이벤트에 설명된 것과 동일한 논리를 따릅니다.
    1. 클라이언트 브라우저가 일정 페이지에 액세스합니다. 요청이 서버로 전송됩니다.
    2. 서버는 일정 페이지 HTTP 요청을 해석하고 다음 URI 매개변수 중 하나에서 특정 일정 페이지에 대한 정보를 가져옵니다.
      • sysparm_page_sys_id
      • sysparm_page_schedule_type
    3. 서버는 지정된 일정 페이지의 클라이언트 스크립트 정보를 포함하는 HTTP 응답을 반환합니다.
    4. 클라이언트 브라우저는 페이지를 로드할 때 일정 페이지의 클라이언트 스크립트 섹션을 즉시 구문 분석하며, 다음을 수행합니다.
      • 구성 및 표시 옵션 설정
      • 이벤트 수신기를 등록합니다.
    5. getItems 이벤트 사용:
      1. 클라이언트 타임라인은 getItems 에 등록된 이벤트에 대한 해당 스크립트 포함에 AJAX 요청을 만들어 타임라인에 표시할 항목 및 범위 집합을 검색합니다.
      2. 서버는 요청을 수신하고 AbstractTimelineSchedulePage 클래스의 인스턴스인 지정된 스크립트 포함 내에서 getItems 코드 블록을 실행합니다. 서버는 TimelineItem 개체가 있는 XML 문서를 반환합니다.
      3. 클라이언트는 지정된 TimelineItem 개체가 있는 AJAX 응답을 수신하고 화면에 적절하게 표시합니다.

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

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

    타임라인 일정 페이지 예

    다음 예제에서는 위에서 설명한 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
    • 활성: 선택됨
    • Glide AJAX 사용: 선택됨
    • 스크립트:
    // 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://<instance>/show_schedule_page.do?sysparm_page_schedule_type=incident_timeline

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

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