0

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

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

有任何想法吗?

4

2 回答 2

0

我刚刚开始使用 Rally,这正是我所追求的。恐怕我对添加自定义应用程序完全陌生,我已经尝试过,但没有呈现任何内容(我显然在某处做错了什么)

我根据nickm 的回答创建了以下 HTML,并想知道是否有人能指出我哪里出错了。

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

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

<!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>

非常感谢您的帮助

于 2013-11-06T10:44:39.973 回答
0

此自定义应用程序通过迭代构建任务网格,其中包括 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);
         }
    }

});
于 2013-08-06T22:12:55.897 回答