rallyappsdk2

Getting Accepted Stories that have Tasks with TimeSpent


I'm writing an application that should load Accepted stories that have tasks with integer in the Time Spent field.

As I can see in some tests I made the task fields that are accessible through UserStory is: 'Tasks', 'TaskActualTotal', 'TaskEstimateTotal', 'TaskRemainingTotal' and 'TaskStatus'.

Tasks has a _ref attribute with a link to a JSON with all tasks for this story. How may I explore this since I'm using Rally API? Or Is there a better way to do this?

UPDATE:

So this is pretty much i have now.

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 is returning the following object:

enter image description here

Note that we can see the task data on value[0] but when i try to wrap it out with tasks.store.load().deferred.value[0] its crashing.

Any thoughts?


Solution

  • Per WS API doc, TimeSpent field on Task object (which is populated automatically from entries in Rally Timesheet/Time Tracker module) cannot be used in queries, so something like this (TimeSpent > 0) will not work.

    Also, a UserStory object (referred to as HierarchicalRequirement in WS API) does not have a field where child tasks' TimeSpent rolls up to the story similar to how child tasks' Estimate rolls up to TaskEstimateTotal on a story.

    It is possible to get TimeSpent for each task and then add them up by accessing a story's Tasks collection as done in this app:

    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'
                    }
                ]
            });
    
        }
    });