How to query for all Artifacts of a Milestone - rally

I am attempting to create reports on Milestones using App SDK 2.0 and would like to find all User Stories that have been assigned to the Milestone.
I tried pulling out the Artifacts from a Milestone using getCollection.
Ext.create('Rally.data.wsapi.Store', {
model : 'Milestone',
filters : [ {
property : 'ObjectID',
operator : '=',
value : milestone.get("ObjectID")
} ],
fetch : [ 'Artifacts' ],
limit : Infinity,
autoLoad : true,
listeners : {
load : function(store, records) {
var record = records[0];
var info = record.get('Artifacts');
var count = info.Count;
record.getCollection('Artifacts').load({
fetch : [ 'ObjectID' ],
callback : function(records, operation, success) {
Ext.Array.each(records, function(artifact) {
console.log(artifact.get('ObjectID'));
});
}
});
}
}
});
I get the following error:
Uncaught Rally.data.ModelFactory.getModel(): Could not find registered
factory for type: Artifact sdk-debug.js:7078
From https://rally1.rallydev.com/slm/doc/webservice/, it doesn't seem that Milestones is query able on the User Story or PortfolioItem. I tried it anyway using Tasks syntax and it nothing was returned.
Ext.create('Rally.data.wsapi.Store', {
model : 'UserStory',
filters : [ {
property : 'Milestones',
operator : 'contains',
value : milestone.get("_ref")
} ],
fetch : [ 'ObjectID' ],
limit : Infinity,
autoLoad : true,
listeners : {
load : function(store, records) {
console.log(records);
}
}
});

There is a defect in AppSDK2 that it does not work with abstract types, e.g. Artifact, UserPermissions.
Your first code example ran into that defect.
But your second code example must work. I suspect if it does not work for you it is a matter of scoping. Perhaps the milestone you filter by is not in the project you are scoped to. You may hard code a project ref in the context of the store to make sure it is looking in the right project. I initially tested your code in my default project and it worked as is, and then I modified it as follows to make sure it finds a milestone in a non-default project:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
Ext.create('Rally.data.wsapi.Store', {
model : 'UserStory',
context:{
project: '/project/16662089077'
},
filters : [
{
property : 'Milestones',
operator : 'contains',
value : "/milestone/33215216897"
}
],
fetch : [ 'ObjectID' ],
limit : Infinity,
autoLoad : true,
listeners : {
load : function(store, records) {
console.log(records);
}
}
});
}
});

Related

Hydrate object fields

I want to get Feature object for User Stories that I got from lookback API.
But when I try to hydrate Feature I get only UnFormatted feature ID.
Can I get real Feature objects for User Stories from lookback result set?
Below the example of code that I use for retrieving data:
storeConfig: {
find: {
"_TypeHierarchy": { '$in' : [-51038] },
"Children": null
},
fetch: ["ScheduleState", "PlanEstimate", "ObjectID", "_ValidFrom", "_ValidTo", "c_BaselineDeliveryConfidence", "Name", "Feature"],
hydrate: ["ScheduleState", "c_BaselineDeliveryConfidence", "Name", "Feature"],
sort: {
"_ValidFrom": 1
},
compress: true,
useHttpPost: true
It is not possible to hydrate objects straight out of the LBAPI. However, I have been working on a helper class to do just that, using a method similar to what Nick suggested.
https://github.com/ConnerReeves/RallyHelpers/blob/master/RecordHydrator/RecordHydrator.js
Here's an example of how it's used. I'm gathering all leaf User Stories (that have an iteration assignment) and then hydrating that Initiative field:
launch: function() {
var self = this;
Ext.create('Rally.data.lookback.SnapshotStore', {
limit : Infinity,
fetch : ['Name','Iteration'],
filters : [{
property : '__At',
value : 'current'
},{
property : '_TypeHierarchy',
value : 'HierarchicalRequirement'
},{
property : 'Iteration',
operator : '!=',
value : null
},{
property : 'Children',
value : null
}]
}).load({
params : {
compress : true,
removeUnauthorizedSnapshots : true
},
callback : function(records, operation, success) {
self._hydrateRecords(records);
}
});
},
_hydrateRecords: function(records) {
Ext.create('CustomApp.RecordHydrator', {
fields: [{
name : 'Iteration',
hydrate : ['Name','StartDate','EndDate']
}]
}).hydrate(records).then({
success: function(hydratedRecords) {
console.log(_.groupBy(hydratedRecords, function(record) {
return record.get('Iteration') && record.get('Iteration').get('Name');
}));
}
});
}
Feature is a full object to which a user story has a reference to (via Feature attribute).
Your code which is similar to this query:
https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/111/artifact/snapshot/query.js?find={"_TypeHierarchy":"HierarchicalRequirement"}&fields=["Name","ScheduleState","PlanEstimate","Feature"]&hydrate=["ScheduleState"]
will return something like this:
{
Feature: 12483739639,
Name: "my story",
ScheduleState: "Defined",
PlanEstimate: 3
}
where 12483739639 is ObjectID of the Feature. Adding "Feature" to the hydrate will not make a difference.
If you want to get the full Feature object or some of its attributes, in your code you may use the OID of the feature and issue a separate query. You may also push those OIDs into an array and use $in operator in that second query.

How to get Intiative and total number of defects for the initiative via 2.0p5

I want to display the initiative and total number of defects raised for the initiative.
Tried with following snippet, but i was not able to relate initiative and the defect.
_getInitiatives: function () {
Ext.create("Rally.data.WsapiDataStore", {
model: "PortfolioItem/initiative",
fetch: ["Project", "Notes", "Name", "Children", "FormattedID"],
limit: 1 / 0,
context: {
project: "/project/xxx",
projectScopeDown: !0,
projectScopeUp: !1
},
autoLoad: !0,
listeners: {
load:this._onDefectsLoaded,
scope: this
}
})
},
_onDefectsLoaded: function(store,data){
this.stories = data;
Ext.create('Rally.data.WsapiDataStore',{
model: 'User Story',
limit: "Infinity",
context: {
project :'/project/xxx',
projectScopeUp: false,
projectScopeDown: true
},
autoLoad: true,
fetch:['FormattedID','Name','Defects','Feature'],
scope:this,
listeners: {
//load: this._onAllDefectsLoaded,
load: this._onDataLoaded,
scope: this
}
});
}
Please provide fix/suggestion for the above mentioned problem
I have found that it is easier to use the Lookback API for requests which reference the RPM, rather than WSAPI. Here is some code which gets all the Initiative records from the project, and then fetches the defect counts for each initiative and applies that count to the record. Hope this helps!
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
Ext.create('Rally.data.lookback.SnapshotStore', {
fetch : ['Name','ObjectID'],
filters : [{
property : '__At',
value : 'current'
},{
property : '_TypeHierarchy',
value : 'PortfolioItem/Initiative'
}]
}).load({
params : {
compress : true,
removeUnauthorizedSnapshots : true
},
callback : function(records, operation, success) {
var me = this;
Deft.Promise.all(Ext.Array.map(records, function(record) {
return me.getInitiativeDefectCount(record.get('ObjectID')).then({
success: function(defectCount) {
record.set('DefectCount', defectCount);
}
});
})).then({
success: function() {
console.log(records);
}
});
},
scope : this
});
},
getInitiativeDefectCount: function(initiativeObjectID) {
var deferred = Ext.create('Deft.Deferred');
Ext.create('Rally.data.lookback.SnapshotStore', {
pageSize : 1,
filters : [{
property : '__At',
value : 'current'
},{
property : '_TypeHierarchy',
value : 'Defect'
},{
property : '_ItemHierarchy',
operator : 'in',
value : initiativeObjectID
}]
}).load({
params : {
compress : true,
removeUnauthorizedSnapshots : true
},
callback : function(records, operation, success) {
deferred.resolve(operation.resultSet.totalRecords);
}
});
return deferred.promise;
}
});

Custom Cycle Time

How do I determine how long something spent in a state? Here is a query I have for pulling specifics on a user story, but I'm trying to understand how to get the duration something spent in In Progress before going to completed. To be more specific, customizing Cycle Time
https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/xxxx/artifact/snapshot/query.js?find={"FormattedID":"US41","_PreviousValues.ScheduleState":"In-Progress"}&fields=["ScheduleState","_ValidFrom","_ValidTo","_PreviousValues"]&hydrate=["ScheduleState","_ValidFrom","_ValidTo","_PreviousValues"]&sort={_ValidFrom: -1}&pagesize=1
I don't see where the ValidFrom and ValidTo provides that information.
This solution seems to be working for me. Hope it helps!
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
Ext.create('Rally.data.lookback.SnapshotStore', {
fetch : ['ScheduleState'],
hydrate : ['ScheduleState'],
filters : [{
property : '_UnformattedID',
value : 41
}],
sorters : [{
property : '_ValidTo',
direction : 'ASC'
}]
}).load({
params : {
compress : true,
removeUnauthorizedSnapshots : true
},
callback : function(records, operation, success) {
var cycleTime = Rally.util.DateTime.getDifference(new Date(Rally.util.Array.last(Ext.Array.filter(records, function(record) {
return record.get('ScheduleState') === 'Accepted';
})).get('_ValidFrom')), new Date(Rally.util.Array.last(Ext.Array.filter(records, function(record) {
return record.get('ScheduleState') === 'In-Progress';
})).get('_ValidFrom')), 'day'));
}
});
}
});

Obtaining Object IDs for Schedule States in Rally

I have set up a "checkbox group" with the five schedule states in our organization's workspace. I would like to query using the Lookback API with the selected schedule states as filters. Since the LBAPI is driven by ObjectIDs, I need to pass in the ID representations of the schedule states, rather than their names. Is there a quick way to get these IDs so I can relate them to the checkbox entries?
Lookback API will accept string-valued ScheduleStates as query arguments. Thus the following query:
{
find: {
_TypeHierarchy: "HierarchicalRequirement",
"ScheduleState": "In-Progress",
__At:"current"
}
}
Works correctly for me. If you want/need OIDs though, and add &fields=true to the end of your REST query URL, you'll notice the following information coming back:
GeneratedQuery: {
{ "fields" : true,
"find" : { "$and" : [ { "_ValidFrom" : { "$lte" : "2013-04-18T20:00:25.751Z" },
"_ValidTo" : { "$gt" : "2013-04-18T20:00:25.751Z" }
} ],
"ScheduleState" : { "$in" : [ 2890498684 ] },
"_TypeHierarchy" : { "$in" : [ -51038,
2890498773,
10487547445
] },
"_ValidFrom" : { "$lte" : "2013-04-18T20:00:25.751Z" }
},
"limit" : 10,
"skip" : 0
}
}
You'll notice the ScheduleState OID here:
"ScheduleState" : { "$in" : [ 2890498684 ] }
So you could run a couple of sample queries on different ScheduleStates and find their corresponding OIDs.

node.updateInfo is not a function while appending node in extjs

I am trying to load data into an extjs 4 TreeStore but while appending node, I am getting node.updateInfo is not a function error.
My model classes are as follows :
Dimension.js
Ext.define('ilp.model.Dimension', {
extend : 'Ext.data.Model',
require : [
'ilp.model.DimensionLevel'
],
fields : [
'actualName',
'displayName'
],
hasMany : {model : 'ilp.model.DimensionLevel', name : 'dimensionLevels'}
});
DimensionLevel.js
Ext.define('ilp.model.DimensionLevel', {
extend : 'Ext.data.Model',
fields : [
{name : 'name', type : 'string'},
{name : 'totalTrainees', type : 'int'}
]
});
and tree store code is as follows :
Ext.define('ilp.store.DimensionTree', {
extend : 'Ext.data.TreeStore',
requires : [
'ilp.model.Dimension',
'ilp.model.DimensionLevel'
],
model : 'ilp.model.Dimension',
root: {
name: 'Dimensions'
},
proxy: {
type: 'ajax',
url: 'http://localhost:8080/pentaho/content/cda/doQuery',
reader: {
type: 'pentahoReader',
root: 'resultset'
},
extraParams: {
path: 'RINXDashboards%2FCDAs%2FILP_Employee_Qeries.cda',
dataAccessId:'Get_All_Levels_From_All_Dimensions',
userid : 'joe',
password : 'password'
}
},
listeners: {
append : function(parentNode, newNode, index, options) {
if(newNode.get('text') != 'Root') {
console.log('newNode text value = ' + newNode.get('text'));
newNode.set('checked', null);
newNode.set('expandable', true);
if(Ext.ClassManager.getName(newNode) == "ilp.model.Dimension") {
newNode.set('expanded', true);
newNode.set('text', newNode.get('displayName'));
if(newNode.dimensionLevels().getCount() > 0) {
newNode.dimensionLevels().each(function(level) {
newNode.appendChild(level);
});
} else {
newNode.set('leaf', true);
}
}else if(Ext.ClassManager.getName(newNode) == "ilp.model.DimensionLevel") {
newNode.set('leaf', true);
newNode.set('text', newNode.get('name'));
}
}
}
}
});
I am getting above error on following line :
newNode.dimensionLevels().each(function(level) {
while debugging I have found that updateInfo() method of newNode is undefined.
Can anyone please tell me why this error is coming? I am totally clueless now !!!
May this is caused by the bug EXTJSIV-6051
see Sencha Forum for further infos
I think your problem comes from :
root: {
name: 'Dimensions'
},
root attribute must be of type: Ext.data.Model/Ext.data.NodeInterface/Object. So try to replace 'root' attribute by this:
root: {
text: "Dimensions",
leaf: false
}
Check Sencha doc for more information: http://docs.sencha.com/ext-js/4-1/#!/api/Ext.tree.Panel-cfg-root