Wondering what would be the rally-node or RallyRestToolkitFor.NET code equivalent for the following query. Rally portal returns 200+ but when implementing this code in rally-node and RallyRestToolkitFor.NET I get far less results. Thanks
(((((((((((((ClosedDate >= 2016-12-22)) OR (State != Closed)) AND
(FunctionalArea != Documentation)) AND (FunctionalArea != Testing)) AND
(FunctionalArea != Performance)) AND (FunctionalArea != "QW")) AND
(FunctionalArea != "QLR")) AND (FunctionalArea != "TSD")) AND (FunctionalArea !=
"TUL")) AND (FunctionalArea != "D")) AND (Tags.Name != "NCI")) AND (CreationDate
<= 2016-12-21))
restApi.query({
type: 'defect',
limit: Infinity, //the maximum number of results to return- enables auto paging
fetch: ['FormattedID', 'Name', 'ScheduleState', 'PlanEstimate', 'Iteration', "Tasks", "Release", 'CreationDate', 'ClosedDate', "Project", "Owner"],
query: query,
}, function(error, result) {
if(error) {
console.log(error);
} else {
//console.log(result.Results);
//console.log(js2xmlparser.parse("Defects", result.Results));
var file = 'rally.json'
jsonfile.writeFileSync(file, result.Results)
}
});
or
Request request = new Request("Defect");
string queryString = "big_blob_of_query";
request.Query = new Query(queryString);
request.Fetch = new List<string>() { "Name", "Description", "FormattedID", "CreationDate", "ClosedDate", "Project"};
QueryResult queryResult = restApi.Query(request);
My guess is project scoping. It doesn't look like you're supplying any project scoping information, so the query is probably just defaulting to your default project scope (probably not what you want).
If you set a project + scope up/down do you get the results you'd expect?
restApi.query({
scope: {
project: '/project/12345',
down: true
}
});
or
request.setProject("/project/12345");
request.setProjectScopeDown(true);
Related
I have a kendo grid my paging is in the server side but the filter is in the client side.
I have a problem with the paging in server side when I change the page number and I try to make a filter, the controller take in his parameter "paginator " another page number, here is my code:
public JsonResult ObtenerFURReporte(string ano_seleccionado, Paginador pagina) {
try {
if (ano_seleccionado == null) {
BoletoAereoBLL boletoBLL = new BoletoAereoBLL();
var ListaFURReporte = boletoBLL.ObtenerFURReporte(pagina.page, pagina.pageSize, pagina.skip, pagina.take);
var counter = ListaFURReporte.Item2;
return Json(new { Result = "OK", Records = ListaFURReporte.Item1, Total = counter }, JsonRequestBehavior.AllowGet);
} else {
int anoBuscar = Convert.ToInt32(ano_seleccionado);
BoletoAereoBLL boletoBLL = new BoletoAereoBLL();
var ListaFURReporte = boletoBLL.ObtenerFURReportePorAno(anoBuscar);
var counter = ListaFURReporte.Item2;
return Json(new { Result = "OK", Records = ListaFURReporte.Item1, Total = counter }, JsonRequestBehavior.AllowGet);
}
} catch (Exception ex) {
return Json(new { Result = "ERROR", Message = ex.Message }, JsonRequestBehavior.AllowGet);
}
}
In my configuration in JavaScript:
serverPaging: true
scrollable: true,
selectable: "simple",
sortable: true,
resizable: true,
filterable: {
extra: false,
operators: {
string: {
contains: "Contiene"
}
}
},
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
So I am making a custom HTML app that uses the Defect List Example (available here). I've added multiple queries to filter the results on the 3 queries/criterias that I need.
What I've noticed is that only the last query is being applied (e.g. only queryConfig[2] applies). I know this is the case because I will still have some defects with state 'Closed' showing up even though I want everything BUT closed states (as shown by queryConfig[1]).
Is there something that I'm doing wrong here? Here's the code for my queries below:
var queryConfig = [];
queryConfig[0] = {
type : 'defect',
key : 'defects',
query: '(c_DeliveryVersionIntroduced contains "Version 1.1")',
fetch: ['Name','State','Severity','FormattedID','Project','ObjectID']
};
queryConfig[1] = {
type : 'defect',
key : 'defects',
query: '(State != Closed)',
fetch: ['Name','State','Severity','FormattedID','Project','ObjectID']
};
queryConfig[2] = {
type: 'defect',
key: 'defects',
query: '(CreationDate = "Today-3")',
fetch: ['Name', 'State', 'Severity', 'FormattedID','Project','ObjectID']
};
var rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
rallyDataSource.findAll(queryConfig, displayDefects);
An SDK 1.0 query config array doesn't work additively like that. The query config array is used to run multiple queries at once via a single callback, and reference the results via different keys. For example:
var queryConfig = [];
queryConfig[0] = {
type : 'HierarchicalRequirement',
key : 'stories',
query: '(ScheduleState = Completed)',
fetch: 'Name,FormattedID'
};
queryConfig[1] = {
type : 'defect',
key : 'defects',
query: '(State = Fixed)',
fetch: 'Name,FormattedID'
};
var rallyDataSource;
rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
rallyDataSource.findAll(queryConfig, processResults);
}
In this situation, the processResults callback would receive results grouped as follows:
var processResults = function(results) {
var stories = results['stories'];
var defects = results['defects'];
};
By re-using the key 'defects', the results of the last entry in the queryConfig array clobber the previous queries.
To achieve your desired result, assuming you intend to AND your conditions together, you would need to implement a single query with multiple conditions, i.e.:
queryConfig = {
type : 'defect',
key : 'defects',
query: '(((c_DeliveryVersionIntroduced contains "Version 1.1") AND (State != Closed)) AND (CreationDate = today-3))',
fetch: 'Name,State,Severity,FormattedID,Project,ObjectID'
};
var rallyDataSource;
rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
rallyDataSource.findAll(queryConfig, processResults);
}
I have build one app, which shows two things for each team based on selected releases.
Rework - Which is Completed Stories in sprint n / Completed stories in sprint n
Defect/ Story - New defects in sprint n / Completed stories in sprint n-1
But I am not able to get which are the new defects in sprint n,
I want the cumulative activated count as shown in Defect Trend Chart, which I can access from Reports.
Which is a new defect count for me.
Below is my code, where I am considering that defects which are !ACCEPTED are new defects but it's not right.
Any help or suggestions on this, how Rally shows cumulative activated count as shown in Defect Trend Chart?
_fetchByArrayOfValues:function(oids,field_name){
var filters = null;
//this.logger.log("_fetchByArrayOfValues (", model_name, ",", oids.length, ",", field_name ,")");
var deferred = Ext.create('Deft.Deferred');
filters = Ext.create('Rally.data.QueryFilter',{
property:field_name,
operator: '=',
value:oids[0]
});
for ( var i=1;i<oids.length;i++ ) {
filters = filters.or(Ext.create('Rally.data.QueryFilter',{
property:field_name,
value:oids[i]
}));
}
this.flows_by_iteration_id = {}; // key is iteration_id
this.iterations = {}; // key is iteration_id
this.iterations_defined = false;
//this.old_iterations = {};
this.addIterations();
var created = Ext.create('Rally.data.wsapi.artifact.Store', {
autoLoad: true,
models: ['UserStory','Defect'],
context: {
project: this.getContext().getProject()._ref,
projectScopeDown: true,
projectScopeUp: false
},
filters: filters,
limit: Infinity,
fetch: ['Name','Iteration','ScheduleState', 'InProgressDate', 'LastUpdateDate'],
listeners: {
load: function(store, records) {
var defectHash = {};
var storyHash = {};
Ext.Array.each(records, function(item){
var itData = this.iterations[item.data.Iteration._ref];
//var id = this.iterations[item.data.Iteration._ref]
if ( ! defectHash[itData.Ref] ) { defectHash[itData.Ref] = { "NewCount": 0, "CompletedCount":0}; }
if ( ! storyHash[itData.Ref] ) { storyHash[itData.Ref] = { "Count": 0}; }
if(item.data._type == "defect" && itData.Ref == item.data.Iteration._ref && itData.Name == item.data.Iteration.Name) {
if (item.data.ScheduleState != "Accepted") {
defectHash[itData.Ref].NewCount += 1;
} else if (item.data.ScheduleState == "Accepted") {
defectHash[itData.Ref].CompletedCount += 1;
}
//+= value.Accept;
} else if (item.data._type == "hierarchicalrequirement" && item.data.ScheduleState == "Accepted" && itData.Ref == item.data.Iteration._ref && itData.Name == item.data.Iteration.Name) {
storyHash[itData.Ref].Count += 1;
}
}, this);
this.commit_data_set = [defectHash, storyHash];
deferred.resolve(created);
},
scope: this
}
}, this);
return deferred.promise;
},
Is there a way to calculate the number of days since the card has been in the first state? Lets use say I use a custom field \for the kanban states. 1,2,3,4 If a card is in state 3 then how long has it been since # 1?
I am not sure of a way to automate it or flag items but if you review the US/DE in question just take a quick look at the revision history.
Any changes in state should be logged in the history.
Use Lookback API to access historic data.
Lookback API allows to see what any work item or collection of work items looked like in the past. This is different from using WS API directly, which can provide you with the current state of objects, but does not have historical data.
LBAPI documentation is available here
Here is an example that builds a grid of stories with a Kanban state. When a story's row is double-clicked, the time this story has spent in three Kanban states is calculated and a grid is built to show the values:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function(){
var x = Ext.create('Rally.data.lookback.SnapshotStore', {
fetch : ['Name','c_Kanban','_UnformattedID', '_TypeHierarchy'],
filters : [{
property : '__At',
value : 'current'
},
{
property : '_TypeHierarchy',
value : 'HierarchicalRequirement'
},
{
property : '_ProjectHierarchy',
value : 22222
},
{
property : 'c_Kanban', //get stories with Kanban state
operator : 'exists',
value : true
}
],
hydrate: ['_TypeHierarchy', 'c_Kanban'],
listeners: {
load: this.onStoriesLoaded,
scope: this
}
}).load({
params : {
compress : true,
removeUnauthorizedSnapshots : true
}
});
},
//make grid of stories with Kanban state
onStoriesLoaded: function(store, data){
var that = this;
var stories = [];
var id;
Ext.Array.each(data, function(record) {
var artifactType = record.get('_TypeHierarchy');
if (artifactType[artifactType.length - 1] == "HierarchicalRequirement") {
id = 'US' + record.get('_UnformattedID');
} else if (artifactType[artifactType.length - 1] == "Defect") {
id = 'DE' + record.get('_UnformattedID');
}
stories.push({
Name: record.get('Name'),
FormattedID: id,
UnformattedID: record.get('_UnformattedID'),
c_Kanban: record.get('c_Kanban')
});
console.log(stories);
});
var myStore = Ext.create('Rally.data.custom.Store', {
data: stories
});
if (!this.down('#allStoriesGrid')) {
this.add({
xtype: 'rallygrid',
id: 'allStoriesGrid',
store: myStore,
width: 500,
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID',
},
{
text: 'Name', dataIndex: 'Name', flex: 1,
},
{
text: 'Kanban', dataIndex: 'c_Kanban'
}
],
listeners: {
celldblclick: function( grid, td, cellIndex, record, tr, rowIndex){
id = grid.getStore().getAt(rowIndex).get('UnformattedID');
console.log('id', id);
that.getStoryModel(id); //to eventually build a grid of Kanban allowed values
}
}
});
}else{
this.down('#allStoriesGrid').reconfigure(myStore);
}
},
getStoryModel:function(id){
console.log('get story model');
var that = this;
this.arr=[];
//get a model of user story
Rally.data.ModelFactory.getModel({
type: 'User Story',
context: {
workspace: '/workspace/11111',
project: 'project/22222'
},
success: function(model){
//Get store instance for the allowed values
var allowedValuesStore = model.getField('c_Kanban').getAllowedValueStore( );
that.getDropdownValues(allowedValuesStore, id);
}
});
},
getDropdownValues:function(allowedValuesStore, id){
var that = this;
//load data into the store
allowedValuesStore.load({
scope: this,
callback: function(records, operation, success){
_.each(records, function(val){
//AllowedAttributeValue object in WS API has StringValue
var v = val.get('StringValue');
that.arr.push(v);
});
console.log('arr', this.arr);
that.getStoryById(id); //former makeStore
}
});
},
getStoryById:function(id){
var that = this;
var snapStore = Ext.create('Rally.data.lookback.SnapshotStore', {
fetch: ['c_Kanban', 'Blocked'],
hydrate:['c_Kanban','Blocked'],
filters : [
{
property : '_UnformattedID',
value : id //15
}
],
sorters:[
{
property : '_ValidTo',
direction : 'ASC'
}
]
});
snapStore.load({
params: {
compress: true,
removeUnauthorizedSnapshots : true
},
callback : function(records, operation, success) {
that.onDataLoaded(records, id);
}
});
},
onDataLoaded:function(records, id){
var times = [];
var measure = 'second';
//-----------------------backlog
var backlog = _.filter(records, function(record) {
return record.get('c_Kanban') === 'backlog';
});
console.log('backlog',backlog);
var cycleTimeFromBacklogToInProgress = '';
if (_.size(backlog) > 0) {
var backlog1 = _.first(backlog);
var backlog2 = _.last(backlog);
var backlogDate1 = new Date(backlog1.get('_ValidFrom'));
if (backlog2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
backlogDate2 = new Date(); //now
}
else{
var backlogDate2 = new Date(backlog2.get('_ValidTo'));
}
cycleTimeFromBacklogToInProgress = Rally.util.DateTime.getDifference(backlogDate2,backlogDate1, measure );
}
times.push(cycleTimeFromBacklogToInProgress);
//console.log(cycleTimeFromBacklogToInProgress);
//----------------------in progress
var inProgress = _.filter(records, function(record) {
return record.get('c_Kanban') === 'in-progress';
});
console.log('in-progress',inProgress);
var cycleTimeFromInProgressToDone = '';
if (_.size(inProgress) > 0) {
var inProgress1 = _.first(inProgress);
var inProgress2 = _.last(inProgress);
var inProgressDate1 = new Date(inProgress1.get('_ValidFrom'));
if (inProgress2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
inProgressDate2 = new Date(); //now
}
else{
var inProgressDate2 = new Date(inProgress2.get('_ValidTo'));
}
cycleTimeFromInProgressToDone = Rally.util.DateTime.getDifference(inProgressDate2,inProgressDate1, measure );
}
times.push(cycleTimeFromInProgressToDone);
//console.log(cycleTimeFromInProgressToDone);
//------------------------done
var done = _.filter(records, function(record) {
return record.get('c_Kanban') === 'done';
});
console.log('done',done);
var cycleTimeFromDoneToReleased = '';
if (_.size(done) > 0) {
var done1 = _.first(done);
var done2 = _.last(done);
var doneDate1 = new Date(done1.get('_ValidFrom'));
if (done2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
doneDate2 = new Date(); //now
}
else{
var doneDate2 = new Date(done2.get('_ValidTo'));
}
cycleTimeFromDoneToReleased = Rally.util.DateTime.getDifference(doneDate2,doneDate1, measure );
}
times.push(cycleTimeFromDoneToReleased);
//console.log(cycleTimeFromDoneToReleased);
/**********
skip first '' element of the this.arr and last 'released' element of this.arr because
do not care for cycle times in first and last kanban states
Originally: arr ["", "backlog", "in-progress", "done", "released"] ,shorten to: ["backlog", "in-progress", "done"]
**********/
this.arrShortened = _.without(this.arr, _.first(this.arr),_.last(this.arr)) ;
console.log('this.arrShortened with first and last skipped', this.arrShortened); //["backlog", "in-progress", "done"]
cycleTimes = _.zip(this.arrShortened, times);
//console.log('cycleTimes as multi-dimentional array', cycleTimes);
cycleTimes = _.object(cycleTimes);
//console.log('cycleTimes as object', cycleTimes); //cycleTimes as object Object {backlog: 89, in-progress: 237, done: 55}
var cycleTimesArray = [];
cycleTimesArray.push(cycleTimes);
console.log('cycleTimesArray',cycleTimesArray);
var store = Ext.create('Rally.data.custom.Store',{
data: cycleTimesArray,
pageSize: 100
});
var columnConfig = [];
_.each(cycleTimes,function(c,key){
var columnConfigElement = _.object(['text', 'dataIndex', 'flex'], ['time spent in ' + key, key, 1]);
columnConfig.push(columnConfigElement);
});
var title = 'Kanban cycle time for US' + id + ' in ' + measure + 's'
if (!this.grid) {
this.grid = this.add({
xtype: 'rallygrid',
title: title,
width: 500,
itemId: 'grid2',
store: store,
columnCfgs: columnConfig
});
}
else{
this.down('#grid2').reconfigure(store);
}
}
});
I'm trying to change the value of a dojo tree to display the correct icon. I was hopping that I could get the object with fetchItemByIdentity() and change the value there but the item is null
_target: null,
_treeModel: null,
constructor: function(target, uuid) {
this._target = target;
this._uuid = uuid;
// from somewhere else the value get's changed
topic.subscribe("questionChanged", lang.hitch(this, function(object, id) {
var item = this._treeModel.fetchItemByIdentity({
identifier: id,
onItem: function(item, request) { alert("item " + item); }
});
}));
},
buildTree: function() {
xhr.get({
// The URL to request
url: er.getAbsoluteUrl("/secure/staticquestion/tree?uuid=" + this._uuid),
handleAs: "json",
headers: {
"Content-Type": "application/json; charset=utf-8"
},
preventCache: 'true',
// The method that handles the request's successful result
load: lang.hitch(this, function(response) {
var rawdata = new Array();
rawdata.push(response);
var store = new ItemFileReadStore({
data: {
identifier: "uuid",
label: "name",
items: rawdata
}
});
this._loadtree(store);
}),
error: function(err, ioArgs) {
errorDialog.show(err.message);
}
});
},
_loadtree: function(store) {
this._treeModel = new TreeStoreModel({
store: store,
query: {
name: 'root'
},
childrenAttrs: [ "children" ],
mayHaveChildren: function(object) {
return object.children.length > 0;
}
});
var tree = new Tree({ // create a tree
model: this._treeModel, // give it the model
showRoot: false,
getIconClass: function(/* dojo.data.Item */item, /* Boolean */opened) {
if (!item || this.model.mayHaveChildren(item)) {
return opened ? "dijitFolderOpened" : "dijitFolderClosed";
} else if (item.comment == 'false') {
return (item.answer == 'YES') ? "dijitLeafNoCommentYes"
: ((item.answer == 'NO') ? "dijitLeafNoCommentNo" : "dijitLeafNoComment");
} else if (item.comment == 'true') {
return (item.answer == 'YES') ? "dijitLeafYes" : ((item.answer == 'NO') ? "dijitLeafNo"
: "dijitLeaf");
}
return "dijitLeaf";
},
}, this._target); // target HTML element's id
tree.on("click", function(object) {
topic.publish("staticQuestionSelected", object);
}, true);
tree.startup();
}
I'm glad for help, thanks!
Ok, I found my issue: I need to use a ItemFileWriteStore and there I can change values with store.setValue(item, attribute, value). The tree updates itself afterwards.