Rally 我怎样才能制作一个拉力赛应用程序,它可以报告所有者的任务和用户容量?

Rally 我怎样才能制作一个拉力赛应用程序,它可以报告所有者的任务和用户容量?,rally,Rally,我正在尝试在Rally中创建自定义计划页面。我想限制分配给用户的任务数量。我可以很容易地创建一个网格,列出每个用户的每个任务,但我不知道如何获得估计小时数的总和 然后,我尝试创建一个自定义报告,但该报告无法合计分配给某个人的任务小时数-即使我将任务标记给某个人并查询该小时数 有什么想法吗?这个定制应用程序通过迭代构建一个任务网格,其中包括UserIterationCapacity数据,特别是TaskEstimates和Capacity的总和 Ext.define('CustomApp', {

我正在尝试在Rally中创建自定义计划页面。我想限制分配给用户的任务数量。我可以很容易地创建一个网格,列出每个用户的每个任务,但我不知道如何获得估计小时数的总和

然后,我尝试创建一个自定义报告,但该报告无法合计分配给某个人的任务小时数-即使我将任务标记给某个人并查询该小时数


有什么想法吗?

这个定制应用程序通过迭代构建一个任务网格,其中包括UserIterationCapacity数据,特别是TaskEstimates和Capacity的总和

Ext.define('CustomApp', {
    extend: 'Rally.app.TimeboxScopedApp',
    componentCls: 'app',
    scopeType: 'iteration',
    comboboxConfig: {
        fieldLabel: 'Select an Iteration:',
        labelWidth: 100,
        width: 300
    },

    addContent: function() {

        this._makeStore();
    },

    _makeStore: function(){
         Ext.create('Rally.data.WsapiDataStore', {
            model: 'Task',
            fetch: ['FormattedID','Name','Owner','Estimate'],
            pageSize: 100,
            autoLoad: true,
            filters: [this.getContext().getTimeboxScope().getQueryFilter()],
            listeners: {
                load: this._onTasksLoaded,
                scope: this
            }
        }); 
    },

   onScopeChange: function() {
        this._makeStore();
    },

    _onTasksLoaded: function(store, data){
            this.tasks = data;
            Ext.create('Rally.data.WsapiDataStore', {
                model: 'UserIterationCapacity',
                fetch: ['User', 'TaskEstimates', 'Iteration', 'Capacity'],  
                pageSize: 100,
                autoLoad: true,
                filters: [this.getContext().getTimeboxScope().getQueryFilter()],
                listeners: {
                    load: this._onAllDataLoaded,
                    scope: this
                }
            }); 
    },
       _onAllDataLoaded: function(store, data){
                var tasks = [];
                var users = [];
                that = this
                if (data.length ===0) {
                this._createGrid();  //to refresh grid when no items in iteration
           }
                Ext.Array.each(this.tasks, function(task) {
                            var owner = task.get('Owner'); 
                            var total;
                            var cap;
                                    Ext.Array.each(data, function(capacity){
                                         //some tasks have no owner. If this condition is not checked Uncaught TypeError: Cannot read property '_refObjectName' of null 
                                        if (owner && capacity.get('User')._refObjectName === owner._refObjectName) { 
                                            total = capacity.get('TaskEstimates');
                                            cap = capacity.get('Capacity');
                                        }
                                    });
                                    var t  = {
                                FormattedID: task.get('FormattedID'),
                                _ref: task.get("_ref"), 
                                Name: task.get('Name'),
                                Estimate: task.get('Estimate'),
                                Owner: (owner && owner._refObjectName) || 'None',
                                Capacity: cap,
                                TaskEstimates: total
                            };
                                    that._createGrid(tasks);
                                    tasks.push(t);
                 });

 },

     _createGrid: function(stories) {
        var myStore = Ext.create('Rally.data.custom.Store', {
                data: stories,
                pageSize: 100,  
            });
        if (!this.grid) {
        this.grid = this.add({
            xtype: 'rallygrid',
            itemId: 'mygrid',
            store: myStore,
            columnCfgs: [
                {
                   text: 'Formatted ID', dataIndex: 'FormattedID', xtype: 'templatecolumn',
                    tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
                },
                {
                    text: 'Name', dataIndex: 'Name'
                },
                {
                    text: 'Estimate', dataIndex: 'Estimate'
                },
                 {
                    text: 'Owner', dataIndex: 'Owner'
                },
                {
                    text: 'User Iteration Capacity', dataIndex: 'Capacity'
                },
                {
                    text: 'Task Estimates Total', dataIndex: 'TaskEstimates'
                }
            ]
        });

         }else{
            this.grid.reconfigure(myStore);
         }
    }

});

我刚刚开始使用Rally,这正是我所追求的。恐怕我对添加自定义应用完全是新手,我已经尝试过了,但没有任何效果(我显然在某个地方做错了什么)

我根据答案创建了以下HTML,不知道是否有人能指出我的错误

我假设我需要创建一个div来包含网格(以及一个元素来包含迭代下拉列表),但是我不知道应该为它们分配什么html id

我的完整html如下所示,我在脚本部分复制了代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
    <title>My App</title>

    <!--App information-->
    <meta name="Name" content="App: My App"/>
    <meta name="Version" content="1.0"/>
    <meta name="Vendor" content=""/>

    <!--Include SDK-->
    <script type="text/javascript" src="/apps/1.29/sdk.js"></script>

    <!--App code-->
    <script type="text/javascript">

        function onLoad() {
            //Add app code here
            Ext.define('CustomApp', {
                extend: 'Rally.app.TimeboxScopedApp',
                componentCls: 'app',
                scopeType: 'iteration',
                comboboxConfig: {
                    fieldLabel: 'Select an Iteration:',
                    labelWidth: 100,
                    width: 300
                },

                addContent: function() {

                    this._makeStore();
                },

                _makeStore: function(){
                     Ext.create('Rally.data.WsapiDataStore', {
                        model: 'Task',
                        fetch: ['FormattedID','Name','Owner','Estimate'],
                        pageSize: 100,
                        autoLoad: true,
                        filters: [this.getContext().getTimeboxScope().getQueryFilter()],
                        listeners: {
                            load: this._onTasksLoaded,
                            scope: this
                        }
                    }); 
                },

               onScopeChange: function() {
                    this._makeStore();
                },

                _onTasksLoaded: function(store, data){
                        this.tasks = data;
                        Ext.create('Rally.data.WsapiDataStore', {
                            model: 'UserIterationCapacity',
                            fetch: ['User', 'TaskEstimates', 'Iteration', 'Capacity'],  
                            pageSize: 100,
                            autoLoad: true,
                            filters: [this.getContext().getTimeboxScope().getQueryFilter()],
                            listeners: {
                                load: this._onAllDataLoaded,
                                scope: this
                            }
                        }); 
                },
                   _onAllDataLoaded: function(store, data){
                            var tasks = [];
                            var users = [];
                            that = this
                            if (data.length ===0) {
                            this._createGrid();  //to refresh grid when no items in iteration
                       }
                            Ext.Array.each(this.tasks, function(task) {
                                        var owner = task.get('Owner'); 
                                        var total;
                                        var cap;
                                                Ext.Array.each(data, function(capacity){
                                                     //some tasks have no owner. If this condition is not checked Uncaught TypeError: Cannot read property '_refObjectName' of null 
                                                    if (owner && capacity.get('User')._refObjectName === owner._refObjectName) { 
                                                        total = capacity.get('TaskEstimates');
                                                        cap = capacity.get('Capacity');
                                                    }
                                                });
                                                var t  = {
                                            FormattedID: task.get('FormattedID'),
                                            _ref: task.get("_ref"), 
                                            Name: task.get('Name'),
                                            Estimate: task.get('Estimate'),
                                            Owner: (owner && owner._refObjectName) || 'None',
                                            Capacity: cap,
                                            TaskEstimates: total
                                        };
                                                that._createGrid(tasks);
                                                tasks.push(t);
                             });

             },

                 _createGrid: function(stories) {
                    var myStore = Ext.create('Rally.data.custom.Store', {
                            data: stories,
                            pageSize: 100,  
                        });
                    if (!this.grid) {
                    this.grid = this.add({
                        xtype: 'rallygrid',
                        itemId: 'mygrid',
                        store: myStore,
                        columnCfgs: [
                            {
                               text: 'Formatted ID', dataIndex: 'FormattedID', xtype: 'templatecolumn',
                                tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
                            },
                            {
                                text: 'Name', dataIndex: 'Name'
                            },
                            {
                                text: 'Estimate', dataIndex: 'Estimate'
                            },
                             {
                                text: 'Owner', dataIndex: 'Owner'
                            },
                            {
                                text: 'User Iteration Capacity', dataIndex: 'Capacity'
                            },
                            {
                                text: 'Task Estimates Total', dataIndex: 'TaskEstimates'
                            }
                        ]
                    });

                     }else{
                        this.grid.reconfigure(myStore);
                     }
                }

            });
        }

        rally.addOnLoad(onLoad);

    </script>

    <!--App styles-->
    <style type="text/css">

        .myApp {
            /* Add app styles here */
        }

    </style>

</head>
<body class="myApp">
<div id="mygrid"></div>
</body>
</html>

我的应用程序
函数onLoad(){
//在此处添加应用程序代码
Ext.define('CustomApp'{
扩展:“Rally.app.TimeboxScopedApp”,
组件CLS:“应用程序”,
scopeType:'迭代',
comboboxConfig:{
fieldLabel:“选择迭代:”,
标签宽度:100,
宽度:300
},
addContent:function(){
这个;
},
_makeStore:function(){
Ext.create('Rally.data.WsapiDataStore'{
模型:“任务”,
获取:['FormattedID','Name','Owner','Estimate'],
页面大小:100,
自动加载:对,
筛选器:[this.getContext().getTimeboxScope().getQueryFilter()],
听众:{
加载:此。\u onTasksLoaded,
范围:本
}
}); 
},
onScopeChange:function(){
这个;
},
_onTasksLoaded:函数(存储、数据){
这个任务=数据;
Ext.create('Rally.data.WsapiDataStore'{
模型:“UserIterationCapacity”,
获取:['User','TaskEstimates','Iteration','Capacity'],
页面大小:100,
自动加载:对,
筛选器:[this.getContext().getTimeboxScope().getQueryFilter()],
听众:{
加载:这个。_onaldataloaded,
范围:本
}
}); 
},
_onAllDataLoaded:函数(存储、数据){
var任务=[];
var用户=[];
那=这
如果(data.length==0){
这是。_createGrid();//在迭代中没有项目时刷新网格
}
Ext.Array.each(this.tasks,function(task){
var owner=task.get('owner');
总风险价值;
var上限;
Ext.Array.each(数据、功能(容量){
//某些任务没有所有者。如果未选中此条件,则未捕获类型错误:无法读取null的属性“\u REOBJECTNAME”
if(owner&&capacity.get('User')。\u-reobjectname==owner.\u-reobjectname){
总计=容量。获取('TaskEstimates');
cap=容量。获取(“容量”);
}
});
变量t={
FormattedID:task.get('FormattedID'),
_ref:task.get(“\u ref”),
名称:task.get('Name'),
估计:task.get('Estimate'),
所有者:(所有者和所有者._REOBJECTNAME)| |“无”,
容量:上限,
估计数:总数
};
创建网格(任务);
任务。推(t);
});
},
_createGrid:函数(故事){
var myStore=Ext.create('Rally.data.custom.Store'{
数据:故事,
页面大小:100,
});
如果(!this.grid){
this.grid=this.add({
xtype:“rallygrid”,
itemId:'mygrid',
商店:myStore,
专栏CFGS:[
{
text:'Formatted ID',dataIndex:'FormattedID',xtype:'templatecolumn',
第三方物流: