通过TimeSpent获取具有任务的接受故事

时间:2015-09-08 13:10:05

标签: rally appsdk2

我正在编写一个应用程序,该应用程序应该在Time Spent字段中加载具有整数任务的已接受故事。

正如我在某些测试中所看到的,我通过UserStory访问的任务字段为:'Tasks', 'TaskActualTotal', 'TaskEstimateTotal', 'TaskRemainingTotal' and 'TaskStatus'

Tasks有一个_ref属性,其中包含指向此故事所有任务的JSON链接。我如何使用Rally API来探索这个?或者有更好的方法吗?

更新

所以这就是我现在所拥有的。

var storiesCall = Ext.create('Rally.data.WsapiDataStore', {
                model: 'UserStory',
                fetch: ['Tasks']
            });
storiesCall.load().then({
                success: this.loadTasks,
                scope: this
            });


loadTasks: function(stories) {
        storiesCall = _.flatten(stories);
        console.log(stories.length);

        _.each(stories, function(story) {
            var tasks = story.get('Tasks');

            if(tasks.Count > 0) {
                tasks.store = story.getCollection('Tasks', {fetch: ['Name','FormattedID','Workproduct','Estimate','TimeSpent']});
                console.log(tasks.store.load().deferred);
            }
            else{
                console.log('no tasks');
            }
        });
}

tasks.store.load().deferred返回以下对象:

enter image description here

请注意,我们可以在value[0]上看到任务数据,但是当我尝试用tasks.store.load().deferred.value[0]崩溃时将其包装出来。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

Per WS API doc,Task对象上的TimeSpent字段(从Rally Timesheet / Time Tracker模块中的条目自动填充)不能在查询中使用,因此像这样的东西(TimeSpent> 0)将不起作用。

此外,UserStory对象(在WS API中称为HierarchicalRequirement)没有子任务的字段' TimeSpent汇总到类似儿童任务的故事。估计在故事上累积到TaskEstimateTotal。

可以为每个任务获取TimeSpent,然后通过访问此应用中的故事任务集合来添加它们:

Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    launch: function() {
        var initiatives = Ext.create('Rally.data.wsapi.Store', {
            model: 'PortfolioItem/Initiative',
            fetch: ['Children']
        });
        initiatives.load().then({
            success: this.loadFeatures,
            scope: this
        }).then({                          
            success: this.loadParentStories,
            scope: this
        }).then({                          
            success: this.loadChildStories,
            scope: this
        }).then({                          
            success: this.loadTasks,
            failure: this.onFailure,
            scope: this
        }).then({
            success: function(results) {
                results = _.flatten(results);
                _.each(results, function(result){
                    console.log(result.data.FormattedID, 'Estimate: ', result.data.Estimate, 'WorkProduct:', result.data.WorkProduct.FormattedID, 'TimeSpent', result.data.TimeSpent );
                });
                this.makeGrid(results);
            },
            failure: function(error) {
                console.log('oh, noes!');
            },
            scope: this
        });
    },

    loadFeatures: function(initiatives) {
        var promises = [];
        _.each(initiatives, function(initiative) {
            var features = initiative.get('Children');
            if(features.Count > 0) {
                features.store = initiative.getCollection('Children',{fetch: ['Name','FormattedID','UserStories']});
                promises.push(features.store.load());
            }
        });
        return Deft.Promise.all(promises);
    },
    loadParentStories: function(features) {
        features = _.flatten(features);
        var promises = [];
        _.each(features, function(feature) {
            var stories = feature.get('UserStories');
            if(stories.Count > 0) {
                stories.store = feature.getCollection('UserStories', {fetch: ['Name','FormattedID','Children']});
                promises.push(stories.store.load());
            }
        });
        return Deft.Promise.all(promises);
    },
     loadChildStories: function(parentStories) {
        parentStories = _.flatten(parentStories);
        var promises = [];
        _.each(parentStories, function(parentStory) {
            var children = parentStory.get('Children');
            if(children.Count > 0) {
                children.store = parentStory.getCollection('Children', {fetch: ['Name','FormattedID','Tasks']});
                promises.push(children.store.load());
            }
        });
        return Deft.Promise.all(promises);
    },
    loadTasks: function(stories) {
        stories = _.flatten(stories);
        var promises = [];
        _.each(stories, function(story) {
            var tasks = story.get('Tasks');
            if(tasks.Count > 0) {
                tasks.store = story.getCollection('Tasks', {fetch: ['Name','FormattedID','Workproduct','Estimate','TimeSpent']});
                promises.push(tasks.store.load());
            }
            else{
                console.log('no tasks');
            }
        });
        return Deft.Promise.all(promises);
    },
    makeGrid:function(tasks){
        var data = [];
        _.each(tasks, function(task){
            data.push(task.data);
        });

        _.each(data, function(record){
            record.Story = record.WorkProduct.FormattedID + " " + record.WorkProduct.Name;
        });

        this.add({
            xtype: 'rallygrid',
            showPagingToolbar: true,
            showRowActionsColumn: true,
            editable: false,
            store: Ext.create('Rally.data.custom.Store', {
                data: data,
                groupField: 'Story'
            }),
            features: [{ftype:'groupingsummary'}],
            columnCfgs: [
                {
                    xtype: 'templatecolumn',text: 'ID',dataIndex: 'FormattedID',width: 100,
                    tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate'),
                    summaryRenderer: function() {
                        return "Totals"; 
                    }
                },
                {
                    text: 'Name',dataIndex: 'Name'
                },
                {
                    text: 'TimeSpent',dataIndex: 'TimeSpent',
                    summaryType: 'sum'
                },
                {
                    text: 'Estimate',dataIndex: 'Estimate',
                    summaryType: 'sum'
                }
            ]
        });

    }
});