2016-02-16 43 views
-3

我在拉力賽工具中創建自定義HTML頁面以編寫代碼,以獲得每個故事在進入狀態之日起每個故事在看板中處於的每個狀態的總天數直到它離開狀態,如下圖所示:[在圖像中,uid12處於「就緒狀態」狀態10天,目前處於最近2天的「發展狀態」狀態。在故事uid34中,它的總數完成所有狀態是32]。任何人都可以請幫助我,因爲我是新來的集會。生成看板板狀態的週期時間報告

1

回答

0

這是基於AppSDK2一個JS代碼可以編譯使用rally-app-builder

Ext.define('CustomApp', { 
    extend: 'Rally.app.App', 
    componentCls: 'app', 
    launch: function(){ 
     var context = this.getContext(); 
     var project = context.getProject()['ObjectID']; 
     console.log(project); 
     var that = this; 
     var panel = Ext.create('Ext.panel.Panel', { 
      layout: 'hbox', 
      itemId: 'parentPanel', 
      componentCls: 'panel', 
      items: [ 

       { 
       xtype: 'panel', 
       width: 600, 
       itemId: 'childPanel1' 
       }, 
       { 
       xtype: 'panel', 
       width: 600, 
       itemId: 'childPanel2' 
       } 
      ], 
     }); 
     this.add(panel); 
     Ext.create('Rally.data.lookback.SnapshotStore', { 
      fetch : ['Name','c_KanbanState','_UnformattedID', '_TypeHierarchy'], 
      filters : [{ 
       property : '__At', 
       value : 'current' 
      }, 
      { 
       property : '_TypeHierarchy', 
       value : 'HierarchicalRequirement' 
      }, 
      { 
       property : '_ProjectHierarchy', 
       value: project 
      }, 
      { 
      property : 'c_KanbanState', 
      operator : 'exists', 
      value : true 
      } 
      ], 
      hydrate: ['_TypeHierarchy', 'c_KanbanState'], 
      listeners: { 
       load: this.onStoriesLoaded, 
       scope: this 
      } 
      }).load({ 
       params : { 
        compress : true, 
        removeUnauthorizedSnapshots : true 
       } 
      }); 

    }, 
    onStoriesLoaded: function(store, data){ 
     var that = this; 
     var stories = []; 
     var id; 
     _.each(data, function(record) { 
      var artifactType = record.get('_TypeHierarchy'); 
      if (artifactType[artifactType.length - 1] == "HierarchicalRequirement") { 
       id = 'US' + record.get('_UnformattedID'); 
      } else if (artifactType[artifactType.length - 1] == "Defect") { 
       id = 'DE' + record.get('_UnformattedID'); 
      } 
      stories.push({ 
       Name: record.get('Name'), 
       FormattedID: id, 
       UnformattedID: record.get('_UnformattedID'), 
       c_KanbanState: record.get('c_KanbanState') 
      }); 
      console.log(stories); 
      }); 

      var myStore = Ext.create('Rally.data.custom.Store', { 
       data: stories 
      }); 

      if (!this.down('#allStoriesGrid')) { 
       this.down('#childPanel1').add({ 
        xtype: 'rallygrid', 
        id: 'allStoriesGrid', 
        store: myStore, 
        columnCfgs: [ 
         { 
          text: 'Formatted ID', dataIndex: 'FormattedID', 
         }, 
         { 
          text: 'Name', dataIndex: 'Name', flex: 1, 
         }, 
         { 
          text: 'Current Kanban State', dataIndex: 'c_KanbanState' 
         } 
        ], 
        listeners: { 
         cellclick: function(grid, td, cellIndex, record, tr, rowIndex){ 
          id = grid.getStore().getAt(rowIndex).get('UnformattedID'); 
          console.log('id', id); 
          that.getStoryModel(id);//to build a grid of Kanban allowed values 
          } 
        } 
       }); 
      }else{ 
       this.down('#allStoriesGrid').reconfigure(myStore); 
      } 
    }, 

    getStoryModel:function(id){ 
     var workspace = this.getContext().getWorkspaceRef(); 
     var project = this.getContext().getProjectRef(); 
     console.log('workspace',workspace); 
     console.log('project',project); 
     console.log('get story model'); 
     var that = this; 
     this.arr=[]; 
     Rally.data.ModelFactory.getModel({ 
      type: 'User Story', 
      success: function(model){ 
       var allowedValuesStore = model.getField('c_KanbanState').getAllowedValueStore(); 
       that.getDropdownValues(allowedValuesStore, id); 
      } 

     }); 
    }, 


    getDropdownValues:function(allowedValuesStore, id){ 
     var that = this; 
     allowedValuesStore.load({ 
      scope: this, 
      callback: function(records, operation, success){ 
       _.each(records, function(val){ 
        //AllowedAttributeValue object in WS API has StringValue 
        var v = val.get('StringValue'); 
        that.arr.push(v); 
       }); 
       console.log('arr', this.arr); 
       that.getStoryById(id); 
      } 
     }); 
    }, 

    getStoryById:function(id){ 
     var that = this; 
     var snapStore = Ext.create('Rally.data.lookback.SnapshotStore', { 
      fetch: ['c_KanbanState', 'Blocked'], 
      hydrate:['c_KanbanState','Blocked'], 
      filters : [ 
       { 
        property : '_UnformattedID', 
        value : id 
       } 
      ], 
      sorters:[ 
       { 
        property : '_ValidTo', 
        direction : 'ASC' 
       } 
      ] 
     }); 
     snapStore.load({ 
      params: { 
       compress: true, 
       removeUnauthorizedSnapshots : true 
      }, 
      callback : function(records, operation, success) { 
       that.onDataLoaded(records, id); 
      } 
     }); 
    }, 

    onDataLoaded:function(records, id){ 
     var times = []; 
     var measure = 'second'; 

     //-----------------------ready 

     var ready = _.filter(records, function(record) { 
        return record.get('c_KanbanState') === 'ready'; 
     }); 
     var cycleTimeFromReadyToDev = ''; 
     if (_.size(ready) > 0) { 
      var ready1 = _.first(ready); 
      var ready2 = _.last(ready); 
      var readyDate1 = new Date(ready1.get('_ValidFrom')); 
      if (ready2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity 
       readyDate2 = new Date(); //now 
      } 
      else{ 
       var readyDate2 = new Date(ready2.get('_ValidTo')); 
      } 

      cycleTimeFromReadyToDev = Rally.util.DateTime.getDifference(readyDate2,readyDate1, measure); 
     } 
     times.push(cycleTimeFromReadyToDev); 


     //----------------------dev 


     var dev = _.filter(records, function(record) { 
        return record.get('c_KanbanState') === 'dev'; 
     }); 
     var cycleTimeFromDevToDone = ''; 
     if (_.size(dev) > 0) { 
      var dev1 = _.first(dev); 
      var dev2 = _.last(dev); 
      var devDate1 = new Date(dev1.get('_ValidFrom')); 
      if (dev2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity 
       devDate2 = new Date(); //now 
      } 
      else{ 
       var devDate2 = new Date(dev2.get('_ValidTo')); 
      } 
      cycleTimeFromInProgressToDone = Rally.util.DateTime.getDifference(devDate2,devDate1, measure); 
     } 
     times.push(cycleTimeFromDevToDone); 


     //------------------------done 

     var done = _.filter(records, function(record) { 
        return record.get('c_KanbanState') === 'done'; 
     }); 
     console.log('done',done); 
     var cycleTimeFromDoneToReleased = ''; 
     if (_.size(done) > 0) { 
      var done1 = _.first(done); 
      var done2 = _.last(done); 
      var doneDate1 = new Date(done1.get('_ValidFrom')); 
      if (done2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity 
       doneDate2 = new Date(); //now 
      } 
      else{ 
       var doneDate2 = new Date(done2.get('_ValidTo')); 
      } 
      cycleTimeFromDoneToReleased = Rally.util.DateTime.getDifference(doneDate2,doneDate1, measure); 
     } 
     times.push(cycleTimeFromDoneToReleased); 


     //skip first '' element of the this.arr and last 'released' element of this.arr because 
     //do not care for cycle times in first and last kanban states 

     this.arrShortened = _.without(this.arr, _.first(this.arr),_.last(this.arr)) ; 
     cycleTimes = _.zip(this.arrShortened, times); 
     cycleTimes = _.object(cycleTimes); 
     var cycleTimesArray = []; 
     cycleTimesArray.push(cycleTimes); 
     var store = Ext.create('Rally.data.custom.Store',{ 
      data: cycleTimesArray, 
      pageSize: 100 
     }); 
     var columnConfig = []; 
     _.each(cycleTimes,function(c,key){ 
      var columnConfigElement = _.object(['text', 'dataIndex', 'flex'], ['time spent in ' + key, key, 1]); 
      columnConfig.push(columnConfigElement); 
     }); 
     var title = 'KanbanState cycle time for US' + id + ' in ' + measure + 's' 
     if (!this.grid) { 
      this.grid = this.down('#childPanel2').add({ 
       xtype: 'rallygrid', 
       title: title, 
       itemId: 'grid2', 
       store: store, 
       columnCfgs: columnConfig 
      }); 
     } 
     else{ 
      this.down('#grid2').reconfigure(store); 
     } 
    } 
}); 

你可以用這個例子作爲出發點,以HTML。當單擊第一個網格中的一行時,它會生成第二個循環時間網格。我的示例中的KanbanState字段具有「就緒」,「開發」和「完成」允許值 enter image description here